Update from chromium https://crrev.com/304586
Review URL: https://codereview.chromium.org/732423002
diff --git a/.clang-format b/.clang-format
index a543137..a7d210d 100644
--- a/.clang-format
+++ b/.clang-format
@@ -16,4 +16,5 @@
AllowShortBlocksOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: true
+BreakBeforeBinaryOperators: NonAssignment
Cpp11BracedListStyle: false # but see http://llvm.org/PR21457
diff --git a/DEPS b/DEPS
index 635d015..509fe9d 100644
--- a/DEPS
+++ b/DEPS
@@ -22,15 +22,15 @@
'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d',
'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95',
'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
- 'skia_revision': 'bc97c9378bf8b89cc17280a2a04a5c3a9405e6ab',
+ 'skia_revision': 'a8f38238d6fccd0f05a15654518dbcd3f1152418',
# 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': '43ced1bd1528ea8b4d9299d2c8f7c6a81921457b',
+ 'v8_revision': '5aafcb15f979432736a03bc286177387b8cd03f1',
# 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": "ea0c84d1779b3e0408aa03efd8167d9e1c40cc3a",
+ "angle_revision": "e1425d95ba0ab095c5d64536bbeb3f78adcbf79f",
# 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.
@@ -38,7 +38,7 @@
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling PDFium
# and whatever else without interference from each other.
- 'pdfium_revision': '173f919d0ec99a1a973c9d3a82b474f761d5bce1',
+ 'pdfium_revision': '1dc4f4112d72c63e465d6f09695ebea1119d39a6',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling BoringSSL
# 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' + '@' + 'd8b2a9d7b0039a4950ee008c5b1d998902c44c60', # from svn revision 292476
+ Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + '6242e2fbb36f486f2c0addd1c3cef67fc4ed33fb', # from svn revision 292476
'src/third_party/libc++/trunk':
Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' + Var('libcxx_revision'),
diff --git a/base/BUILD.gn b/base/BUILD.gn
index a0cdf66..959d462 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -399,6 +399,7 @@
"metrics/histogram_delta_serialization.cc",
"metrics/histogram_delta_serialization.",
"metrics/histogram_flattener.h",
+ "metrics/histogram_macros.h",
"metrics/histogram_samples.cc",
"metrics/histogram_samples.h",
"metrics/histogram_snapshot_manager.cc",
@@ -1402,6 +1403,11 @@
sources += [ "debug/proc_maps_linux_unittest.cc" ]
set_sources_assignment_filter(sources_assignment_filter)
}
+
+ if (is_win) {
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ cflags = [ "/wd4267" ]
+ }
}
if (is_android) {
diff --git a/base/OWNERS b/base/OWNERS
index 92844b6..03c20e7 100644
--- a/base/OWNERS
+++ b/base/OWNERS
@@ -45,3 +45,8 @@
per-file callback_unittest.h=ajwong@chromium.org
per-file callback_unittest.nc=ajwong@chromium.org
per-file security_unittest.cc=jln@chromium.org
+
+# For Android-specific changes:
+per-file *android*=nyquist@chromium.org
+per-file *android*=rmcilroy@chromium.org
+per-file *android*=yfriedman@chromium.org
diff --git a/base/base.gypi b/base/base.gypi
index 416a7e5..39bb08b 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -393,6 +393,7 @@
'metrics/histogram_delta_serialization.cc',
'metrics/histogram_delta_serialization.h',
'metrics/histogram_flattener.h',
+ 'metrics/histogram_macros.h',
'metrics/histogram_samples.cc',
'metrics/histogram_samples.h',
'metrics/histogram_snapshot_manager.cc',
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h
index 159100f..91eb046 100644
--- a/base/cancelable_callback.h
+++ b/base/cancelable_callback.h
@@ -55,13 +55,13 @@
template <typename Sig>
class CancelableCallback;
-template <>
-class CancelableCallback<void(void)> {
+template <typename... A>
+class CancelableCallback<void(A...)> {
public:
CancelableCallback() : weak_factory_(this) {}
// |callback| must not be null.
- explicit CancelableCallback(const base::Callback<void(void)>& callback)
+ explicit CancelableCallback(const base::Callback<void(A...)>& callback)
: weak_factory_(this),
callback_(callback) {
DCHECK(!callback.is_null());
@@ -84,7 +84,7 @@
// Sets |callback| as the closure that may be cancelled. |callback| may not
// be null. Outstanding and any previously wrapped callbacks are cancelled.
- void Reset(const base::Callback<void(void)>& callback) {
+ void Reset(const base::Callback<void(A...)>& callback) {
DCHECK(!callback.is_null());
// Outstanding tasks (e.g., posted to a message loop) must not be called.
@@ -97,173 +97,36 @@
}
// Returns a callback that can be disabled by calling Cancel().
- const base::Callback<void(void)>& callback() const {
+ const base::Callback<void(A...)>& callback() const {
return forwarder_;
}
private:
- void Forward() {
- callback_.Run();
+ void Forward(A... args) const {
+ callback_.Run(args...);
}
// Helper method to bind |forwarder_| using a weak pointer from
// |weak_factory_|.
void InitializeForwarder() {
- forwarder_ = base::Bind(&CancelableCallback<void(void)>::Forward,
+ forwarder_ = base::Bind(&CancelableCallback<void(A...)>::Forward,
weak_factory_.GetWeakPtr());
}
// Used to ensure Forward() is not run when this object is destroyed.
- base::WeakPtrFactory<CancelableCallback<void(void)> > weak_factory_;
+ // TODO(ckehoe): This should be the last class member.
+ // Move it there when crbug.com/433583 is fixed.
+ base::WeakPtrFactory<CancelableCallback<void(A...)> > weak_factory_;
// The wrapper closure.
- base::Callback<void(void)> forwarder_;
+ base::Callback<void(A...)> forwarder_;
// The stored closure that may be cancelled.
- base::Callback<void(void)> callback_;
+ base::Callback<void(A...)> callback_;
DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
};
-template <typename A1>
-class CancelableCallback<void(A1)> {
- public:
- CancelableCallback() : weak_factory_(this) {}
-
- // |callback| must not be null.
- explicit CancelableCallback(const base::Callback<void(A1)>& callback)
- : weak_factory_(this),
- callback_(callback) {
- DCHECK(!callback.is_null());
- InitializeForwarder();
- }
-
- ~CancelableCallback() {}
-
- // Cancels and drops the reference to the wrapped callback.
- void Cancel() {
- weak_factory_.InvalidateWeakPtrs();
- forwarder_.Reset();
- callback_.Reset();
- }
-
- // Returns true if the wrapped callback has been cancelled.
- bool IsCancelled() const {
- return callback_.is_null();
- }
-
- // Sets |callback| as the closure that may be cancelled. |callback| may not
- // be null. Outstanding and any previously wrapped callbacks are cancelled.
- void Reset(const base::Callback<void(A1)>& callback) {
- DCHECK(!callback.is_null());
-
- // Outstanding tasks (e.g., posted to a message loop) must not be called.
- Cancel();
-
- // |forwarder_| is no longer valid after Cancel(), so re-bind.
- InitializeForwarder();
-
- callback_ = callback;
- }
-
- // Returns a callback that can be disabled by calling Cancel().
- const base::Callback<void(A1)>& callback() const {
- return forwarder_;
- }
-
- private:
- void Forward(A1 a1) const {
- callback_.Run(a1);
- }
-
- // Helper method to bind |forwarder_| using a weak pointer from
- // |weak_factory_|.
- void InitializeForwarder() {
- forwarder_ = base::Bind(&CancelableCallback<void(A1)>::Forward,
- weak_factory_.GetWeakPtr());
- }
-
- // Used to ensure Forward() is not run when this object is destroyed.
- base::WeakPtrFactory<CancelableCallback<void(A1)> > weak_factory_;
-
- // The wrapper closure.
- base::Callback<void(A1)> forwarder_;
-
- // The stored closure that may be cancelled.
- base::Callback<void(A1)> callback_;
-
- DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
-};
-
-template <typename A1, typename A2>
-class CancelableCallback<void(A1, A2)> {
- public:
- CancelableCallback() : weak_factory_(this) {}
-
- // |callback| must not be null.
- explicit CancelableCallback(const base::Callback<void(A1, A2)>& callback)
- : weak_factory_(this),
- callback_(callback) {
- DCHECK(!callback.is_null());
- InitializeForwarder();
- }
-
- ~CancelableCallback() {}
-
- // Cancels and drops the reference to the wrapped callback.
- void Cancel() {
- weak_factory_.InvalidateWeakPtrs();
- forwarder_.Reset();
- callback_.Reset();
- }
-
- // Returns true if the wrapped callback has been cancelled.
- bool IsCancelled() const {
- return callback_.is_null();
- }
-
- // Sets |callback| as the closure that may be cancelled. |callback| may not
- // be null. Outstanding and any previously wrapped callbacks are cancelled.
- void Reset(const base::Callback<void(A1, A2)>& callback) {
- DCHECK(!callback.is_null());
-
- // Outstanding tasks (e.g., posted to a message loop) must not be called.
- Cancel();
-
- // |forwarder_| is no longer valid after Cancel(), so re-bind.
- InitializeForwarder();
-
- callback_ = callback;
- }
-
- // Returns a callback that can be disabled by calling Cancel().
- const base::Callback<void(A1, A2)>& callback() const {
- return forwarder_;
- }
-
- private:
- void Forward(A1 a1, A2 a2) const {
- callback_.Run(a1, a2);
- }
-
- // Helper method to bind |forwarder_| using a weak pointer from
- // |weak_factory_|.
- void InitializeForwarder() {
- forwarder_ = base::Bind(&CancelableCallback<void(A1, A2)>::Forward,
- weak_factory_.GetWeakPtr());
- }
-
- // The wrapper closure.
- base::Callback<void(A1, A2)> forwarder_;
-
- // The stored closure that may be cancelled.
- base::Callback<void(A1, A2)> callback_;
-
- // Used to ensure Forward() is not run when this object is destroyed.
- base::WeakPtrFactory<CancelableCallback<void(A1, A2)> > weak_factory_;
- DISALLOW_COPY_AND_ASSIGN(CancelableCallback);
-};
-
typedef CancelableCallback<void(void)> CancelableClosure;
} // namespace base
diff --git a/base/debug/trace_event_impl.cc b/base/debug/trace_event_impl.cc
index ce62766..1a64eb0 100644
--- a/base/debug/trace_event_impl.cc
+++ b/base/debug/trace_event_impl.cc
@@ -1185,6 +1185,12 @@
// find the generation mismatch and delete this buffer soon.
}
+TraceLogStatus::TraceLogStatus() : event_capacity(0), event_count(0) {
+}
+
+TraceLogStatus::~TraceLogStatus() {
+}
+
// static
TraceLog* TraceLog::GetInstance() {
return Singleton<TraceLog, LeakySingletonTraits<TraceLog> >::get();
@@ -1586,10 +1592,12 @@
return it != enabled_state_observer_list_.end();
}
-float TraceLog::GetBufferPercentFull() const {
+TraceLogStatus TraceLog::GetStatus() const {
AutoLock lock(lock_);
- return static_cast<float>(static_cast<double>(logged_events_->Size()) /
- logged_events_->Capacity());
+ TraceLogStatus result;
+ result.event_capacity = logged_events_->Capacity();
+ result.event_count = logged_events_->Size();
+ return result;
}
bool TraceLog::BufferIsFull() const {
diff --git a/base/debug/trace_event_impl.h b/base/debug/trace_event_impl.h
index 6075e2d..ce2e017 100644
--- a/base/debug/trace_event_impl.h
+++ b/base/debug/trace_event_impl.h
@@ -420,6 +420,13 @@
bool enable_systrace;
};
+struct BASE_EXPORT TraceLogStatus {
+ TraceLogStatus();
+ ~TraceLogStatus();
+ size_t event_capacity;
+ size_t event_count;
+};
+
class BASE_EXPORT TraceLog {
public:
enum Mode {
@@ -495,7 +502,7 @@
void RemoveEnabledStateObserver(EnabledStateObserver* listener);
bool HasEnabledStateObserver(EnabledStateObserver* listener) const;
- float GetBufferPercentFull() const;
+ TraceLogStatus GetStatus() const;
bool BufferIsFull() const;
// Not using base::Callback because of its limited by 7 parameters.
@@ -603,7 +610,6 @@
static void DeleteForTesting();
// Allow tests to inspect TraceEvents.
- size_t GetEventsSize() const { return logged_events_->Size(); }
TraceEvent* GetEventByHandle(TraceEventHandle handle);
void SetProcessID(int process_id);
diff --git a/base/debug/trace_event_unittest.cc b/base/debug/trace_event_unittest.cc
index 69b5743..0904954 100644
--- a/base/debug/trace_event_unittest.cc
+++ b/base/debug/trace_event_unittest.cc
@@ -1366,8 +1366,7 @@
TEST_F(TraceEventTestFixture, StaticStringVsString) {
TraceLog* tracer = TraceLog::GetInstance();
// Make sure old events are flushed:
- EndTraceAndFlush();
- EXPECT_EQ(0u, tracer->GetEventsSize());
+ EXPECT_EQ(0u, tracer->GetStatus().event_count);
const unsigned char* category_group_enabled =
TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED("cat");
@@ -1384,8 +1383,7 @@
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
"arg1", TRACE_STR_COPY("argval"),
"arg2", TRACE_STR_COPY("argval"));
- size_t num_events = tracer->GetEventsSize();
- EXPECT_GT(num_events, 1u);
+ EXPECT_GT(tracer->GetStatus().event_count, 1u);
const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
ASSERT_TRUE(event1);
@@ -1414,8 +1412,7 @@
TRACE_EVENT_PHASE_INSTANT, category_group_enabled, "name2", 0, 0,
"arg1", TRACE_STR_COPY(str1),
"arg2", TRACE_STR_COPY(str2));
- size_t num_events = tracer->GetEventsSize();
- EXPECT_GT(num_events, 1u);
+ EXPECT_GT(tracer->GetStatus().event_count, 1u);
const TraceEvent* event1 = tracer->GetEventByHandle(handle1);
const TraceEvent* event2 = tracer->GetEventByHandle(handle2);
ASSERT_TRUE(event1);
diff --git a/base/files/file_util.cc b/base/files/file_util.cc
index e60dcd9..32dab6b 100644
--- a/base/files/file_util.cc
+++ b/base/files/file_util.cc
@@ -47,12 +47,6 @@
return internal::MoveUnsafe(from_path, to_path);
}
-bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
- if (from_path.ReferencesParent() || to_path.ReferencesParent())
- return false;
- return internal::CopyFileUnsafe(from_path, to_path);
-}
-
bool ContentsEqual(const FilePath& filename1, const FilePath& filename2) {
// We open the file in binary format even if they are text files because
// we are just comparing that bytes are exactly same in both files and not
diff --git a/base/files/file_util.h b/base/files/file_util.h
index ecc0d58..7f169f1 100644
--- a/base/files/file_util.h
+++ b/base/files/file_util.h
@@ -421,11 +421,6 @@
BASE_EXPORT bool MoveUnsafe(const FilePath& from_path,
const FilePath& to_path);
-// Same as CopyFile but allows paths with traversal components.
-// Use only with extreme care.
-BASE_EXPORT bool CopyFileUnsafe(const FilePath& from_path,
- const FilePath& to_path);
-
#if defined(OS_WIN)
// Copy from_path to to_path recursively and then delete from_path recursively.
// Returns true if all operations succeed.
diff --git a/base/files/file_util_mac.mm b/base/files/file_util_mac.mm
index 695935a..acac8d7 100644
--- a/base/files/file_util_mac.mm
+++ b/base/files/file_util_mac.mm
@@ -14,16 +14,15 @@
#include "base/threading/thread_restrictions.h"
namespace base {
-namespace internal {
-bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
ThreadRestrictions::AssertIOAllowed();
+ if (from_path.ReferencesParent() || to_path.ReferencesParent())
+ return false;
return (copyfile(from_path.value().c_str(),
to_path.value().c_str(), NULL, COPYFILE_DATA) == 0);
}
-} // namespace internal
-
bool GetTempDir(base::FilePath* path) {
NSString* tmp = NSTemporaryDirectory();
if (tmp == nil)
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index 0bf41a5..dad8edd 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -845,6 +845,56 @@
}
#endif // !defined(OS_ANDROID)
+#if !defined(OS_MACOSX)
+// Mac has its own implementation, this is for all other Posix systems.
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+ ThreadRestrictions::AssertIOAllowed();
+ File infile;
+#if defined(OS_ANDROID)
+ if (from_path.IsContentUri()) {
+ infile = OpenContentUriForRead(from_path);
+ } else {
+ infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+ }
+#else
+ infile = File(from_path, File::FLAG_OPEN | File::FLAG_READ);
+#endif
+ if (!infile.IsValid())
+ return false;
+
+ File outfile(to_path, File::FLAG_WRITE | File::FLAG_CREATE_ALWAYS);
+ if (!outfile.IsValid())
+ return false;
+
+ const size_t kBufferSize = 32768;
+ std::vector<char> buffer(kBufferSize);
+ bool result = true;
+
+ while (result) {
+ ssize_t bytes_read = infile.ReadAtCurrentPos(&buffer[0], buffer.size());
+ if (bytes_read < 0) {
+ result = false;
+ break;
+ }
+ if (bytes_read == 0)
+ break;
+ // Allow for partial writes
+ ssize_t bytes_written_per_read = 0;
+ do {
+ ssize_t bytes_written_partial = outfile.WriteAtCurrentPos(
+ &buffer[bytes_written_per_read], bytes_read - bytes_written_per_read);
+ if (bytes_written_partial < 0) {
+ result = false;
+ break;
+ }
+ bytes_written_per_read += bytes_written_partial;
+ } while (bytes_written_per_read < bytes_read);
+ }
+
+ return result;
+}
+#endif // !defined(OS_MACOSX)
+
// -----------------------------------------------------------------------------
namespace internal {
@@ -874,56 +924,6 @@
return true;
}
-#if !defined(OS_MACOSX)
-// Mac has its own implementation, this is for all other Posix systems.
-bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
- ThreadRestrictions::AssertIOAllowed();
- int infile = HANDLE_EINTR(open(from_path.value().c_str(), O_RDONLY));
- if (infile < 0)
- return false;
-
- int outfile = HANDLE_EINTR(creat(to_path.value().c_str(), 0666));
- if (outfile < 0) {
- close(infile);
- return false;
- }
-
- const size_t kBufferSize = 32768;
- std::vector<char> buffer(kBufferSize);
- bool result = true;
-
- while (result) {
- ssize_t bytes_read = HANDLE_EINTR(read(infile, &buffer[0], buffer.size()));
- if (bytes_read < 0) {
- result = false;
- break;
- }
- if (bytes_read == 0)
- break;
- // Allow for partial writes
- ssize_t bytes_written_per_read = 0;
- do {
- ssize_t bytes_written_partial = HANDLE_EINTR(write(
- outfile,
- &buffer[bytes_written_per_read],
- bytes_read - bytes_written_per_read));
- if (bytes_written_partial < 0) {
- result = false;
- break;
- }
- bytes_written_per_read += bytes_written_partial;
- } while (bytes_written_per_read < bytes_read);
- }
-
- if (IGNORE_EINTR(close(infile)) < 0)
- result = false;
- if (IGNORE_EINTR(close(outfile)) < 0)
- result = false;
-
- return result;
-}
-#endif // !defined(OS_MACOSX)
-
} // namespace internal
#endif // !defined(OS_NACL_NONSFI)
diff --git a/base/files/file_util_unittest.cc b/base/files/file_util_unittest.cc
index 08c9587..29d5133 100644
--- a/base/files/file_util_unittest.cc
+++ b/base/files/file_util_unittest.cc
@@ -1471,30 +1471,29 @@
FilePath dest_file = dir_name_from.Append(FILE_PATH_LITERAL("DestFile.txt"));
ASSERT_TRUE(CopyFile(file_name_from, dest_file));
- // Copy the file to another location using '..' in the path.
+ // Try to copy the file to another location using '..' in the path.
FilePath dest_file2(dir_name_from);
dest_file2 = dest_file2.AppendASCII("..");
dest_file2 = dest_file2.AppendASCII("DestFile.txt");
ASSERT_FALSE(CopyFile(file_name_from, dest_file2));
- ASSERT_TRUE(internal::CopyFileUnsafe(file_name_from, dest_file2));
FilePath dest_file2_test(dir_name_from);
dest_file2_test = dest_file2_test.DirName();
dest_file2_test = dest_file2_test.AppendASCII("DestFile.txt");
- // Check everything has been copied.
+ // Check expected copy results.
EXPECT_TRUE(PathExists(file_name_from));
EXPECT_TRUE(PathExists(dest_file));
const std::wstring read_contents = ReadTextFile(dest_file);
EXPECT_EQ(file_contents, read_contents);
- EXPECT_TRUE(PathExists(dest_file2_test));
- EXPECT_TRUE(PathExists(dest_file2));
+ EXPECT_FALSE(PathExists(dest_file2_test));
+ EXPECT_FALSE(PathExists(dest_file2));
}
TEST_F(FileUtilTest, CopyFileACL) {
// While FileUtilTest.CopyFile asserts the content is correctly copied over,
// this test case asserts the access control bits are meeting expectations in
- // CopyFileUnsafe().
+ // CopyFile().
FilePath src = temp_dir_.path().Append(FILE_PATH_LITERAL("src.txt"));
const std::wstring file_contents(L"Gooooooooooooooooooooogle");
CreateTextFile(src, file_contents);
diff --git a/base/files/file_util_win.cc b/base/files/file_util_win.cc
index 733c32c..b511d3c 100644
--- a/base/files/file_util_win.cc
+++ b/base/files/file_util_win.cc
@@ -210,7 +210,7 @@
<< target_path.value().c_str();
success = false;
}
- } else if (!internal::CopyFileUnsafe(current, target_path)) {
+ } else if (!CopyFile(current, target_path)) {
DLOG(ERROR) << "CopyDirectory() couldn't create file: "
<< target_path.value().c_str();
success = false;
@@ -722,6 +722,37 @@
return std::min(whole_path_limit, static_cast<int>(max_length));
}
+bool CopyFile(const FilePath& from_path, const FilePath& to_path) {
+ ThreadRestrictions::AssertIOAllowed();
+ if (from_path.ReferencesParent() || to_path.ReferencesParent())
+ return false;
+
+ // NOTE: I suspect we could support longer paths, but that would involve
+ // analyzing all our usage of files.
+ if (from_path.value().length() >= MAX_PATH ||
+ to_path.value().length() >= MAX_PATH) {
+ return false;
+ }
+
+ // Unlike the posix implementation that copies the file manually and discards
+ // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
+ // bits, which is usually not what we want. We can't do much about the
+ // SECURITY_DESCRIPTOR but at least remove the read only bit.
+ const wchar_t* dest = to_path.value().c_str();
+ if (!::CopyFile(from_path.value().c_str(), dest, false)) {
+ // Copy failed.
+ return false;
+ }
+ DWORD attrs = GetFileAttributes(dest);
+ if (attrs == INVALID_FILE_ATTRIBUTES) {
+ return false;
+ }
+ if (attrs & FILE_ATTRIBUTE_READONLY) {
+ SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY);
+ }
+ return true;
+}
+
// -----------------------------------------------------------------------------
namespace internal {
@@ -760,35 +791,6 @@
return ret;
}
-bool CopyFileUnsafe(const FilePath& from_path, const FilePath& to_path) {
- ThreadRestrictions::AssertIOAllowed();
-
- // NOTE: I suspect we could support longer paths, but that would involve
- // analyzing all our usage of files.
- if (from_path.value().length() >= MAX_PATH ||
- to_path.value().length() >= MAX_PATH) {
- return false;
- }
-
- // Unlike the posix implementation that copies the file manually and discards
- // the ACL bits, CopyFile() copies the complete SECURITY_DESCRIPTOR and access
- // bits, which is usually not what we want. We can't do much about the
- // SECURITY_DESCRIPTOR but at least remove the read only bit.
- const wchar_t* dest = to_path.value().c_str();
- if (!::CopyFile(from_path.value().c_str(), dest, false)) {
- // Copy failed.
- return false;
- }
- DWORD attrs = GetFileAttributes(dest);
- if (attrs == INVALID_FILE_ATTRIBUTES) {
- return false;
- }
- if (attrs & FILE_ATTRIBUTE_READONLY) {
- SetFileAttributes(dest, attrs & ~FILE_ATTRIBUTE_READONLY);
- }
- return true;
-}
-
bool CopyAndDeleteDirectory(const FilePath& from_path,
const FilePath& to_path) {
ThreadRestrictions::AssertIOAllowed();
diff --git a/base/i18n/streaming_utf8_validator_perftest.cc b/base/i18n/streaming_utf8_validator_perftest.cc
index ac2eb08..6b8c17b 100644
--- a/base/i18n/streaming_utf8_validator_perftest.cc
+++ b/base/i18n/streaming_utf8_validator_perftest.cc
@@ -134,6 +134,10 @@
const char* function_name;
};
+bool IsStringUTF8(const std::string& str) {
+ return base::IsStringUTF8(base::StringPiece(str));
+}
+
// IsString7Bit is intentionally placed last so it can be excluded easily.
const TestFunctionDescription kTestFunctions[] = {
{&StreamingUtf8Validator::Validate, "StreamingUtf8Validator"},
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 43e7462..9ee172e 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -50,9 +50,12 @@
// at the low end of the histogram scale, but allows the histogram to cover a
// gigantic range with the addition of very few buckets.
-// Usually we use macros to define and use a histogram. These macros use a
-// pattern involving a function static variable, that is a pointer to a
-// histogram. This static is explicitly initialized on any thread
+// Usually we use macros to define and use a histogram, which are defined in
+// base/metrics/histogram_macros.h. Note: Callers should include that header
+// directly if they only access the histogram APIs through macros.
+//
+// Macros use a pattern involving a function static variable, that is a pointer
+// to a histogram. This static is explicitly initialized on any thread
// that detects a uninitialized (NULL) pointer. The potentially racy
// initialization is not a problem as it is always set to point to the same
// value (i.e., the FactoryGet always returns the same value). FactoryGet
@@ -67,7 +70,6 @@
#include <string>
#include <vector>
-#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
@@ -76,6 +78,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/metrics/bucket_ranges.h"
#include "base/metrics/histogram_base.h"
+// TODO(asvitkine): Migrate callers to to include this directly and remove this.
+#include "base/metrics/histogram_macros.h"
#include "base/metrics/histogram_samples.h"
#include "base/time/time.h"
@@ -84,234 +88,11 @@
namespace base {
-class Lock;
-//------------------------------------------------------------------------------
-// Histograms are often put in areas where they are called many many times, and
-// performance is critical. As a result, they are designed to have a very low
-// recurring cost of executing (adding additional samples). Toward that end,
-// the macros declare a static pointer to the histogram in question, and only
-// take a "slow path" to construct (or find) the histogram on the first run
-// through the macro. We leak the histograms at shutdown time so that we don't
-// have to validate using the pointers at any time during the running of the
-// process.
-
-// The following code is generally what a thread-safe static pointer
-// initialization looks like for a histogram (after a macro is expanded). This
-// sample is an expansion (with comments) of the code for
-// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
-
-/*
- do {
- // The pointer's presence indicates the initialization is complete.
- // Initialization is idempotent, so it can safely be atomically repeated.
- static base::subtle::AtomicWord atomic_histogram_pointer = 0;
-
- // Acquire_Load() ensures that we acquire visibility to the pointed-to data
- // in the histogram.
- base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
- base::subtle::Acquire_Load(&atomic_histogram_pointer)));
-
- if (!histogram_pointer) {
- // This is the slow path, which will construct OR find the matching
- // histogram. FactoryGet includes locks on a global histogram name map
- // and is completely thread safe.
- histogram_pointer = base::Histogram::FactoryGet(
- name, min, max, bucket_count, base::HistogramBase::kNoFlags);
-
- // Use Release_Store to ensure that the histogram data is made available
- // globally before we make the pointer visible.
- // Several threads may perform this store, but the same value will be
- // stored in all cases (for a given named/spec'ed histogram).
- // We could do this without any barrier, since FactoryGet entered and
- // exited a lock after construction, but this barrier makes things clear.
- base::subtle::Release_Store(&atomic_histogram_pointer,
- reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
- }
-
- // Ensure calling contract is upheld, and the name does NOT vary.
- DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
-
- histogram_pointer->Add(sample);
- } while (0);
-*/
-
-// The above pattern is repeated in several macros. The only elements that
-// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
-// of which FactoryGet method to use. The different FactoryGet methods have
-// various argument lists, so the function with its argument list is provided as
-// a macro argument here. The name is only used in a DCHECK, to assure that
-// callers don't try to vary the name of the histogram (which would tend to be
-// ignored by the one-time initialization of the histogtram_pointer).
-#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
- histogram_add_method_invocation, \
- histogram_factory_get_invocation) \
- do { \
- static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
- base::HistogramBase* histogram_pointer( \
- reinterpret_cast<base::HistogramBase*>( \
- base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
- if (!histogram_pointer) { \
- histogram_pointer = histogram_factory_get_invocation; \
- base::subtle::Release_Store(&atomic_histogram_pointer, \
- reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
- } \
- if (DCHECK_IS_ON) \
- histogram_pointer->CheckName(constant_histogram_name); \
- histogram_pointer->histogram_add_method_invocation; \
- } while (0)
-
-
-//------------------------------------------------------------------------------
-// Provide easy general purpose histogram in a macro, just like stats counters.
-// The first four macros use 50 buckets.
-
-#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromSeconds(10), 50)
-
-// For folks that need real specific times, use this to select a precise range
-// of times you want plotted, and the number of buckets you want used.
-#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
- base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
- base::HistogramBase::kNoFlags))
-
-#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 1000000, 50)
-
-#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
- LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
-
-#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
- LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
-
-#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::Histogram::FactoryGet(name, min, max, bucket_count, \
- base::HistogramBase::kNoFlags))
-
-// This is a helper macro used by other macros and shouldn't be used directly.
-#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
- flag))
-
-#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
- LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
-
-#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
- base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
-
-// Support histograming of an enumerated value. The samples should always be
-// strictly less than |boundary_value| -- this prevents you from running into
-// problems down the line if you add additional buckets to the histogram. Note
-// also that, despite explicitly setting the minimum bucket value to |1| below,
-// it is fine for enumerated histograms to be 0-indexed -- this is because
-// enumerated histograms should never have underflow.
-#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
- boundary_value + 1, base::HistogramBase::kNoFlags))
-
-// Support histograming of an enumerated value. Samples should be one of the
-// std::vector<int> list provided via |custom_ranges|. See comments above
-// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
-// You can use the helper function CustomHistogram::ArrayToCustomRanges to
-// transform a C-style array of valid sample values to a std::vector<int>.
-#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::CustomHistogram::FactoryGet(name, custom_ranges, \
- base::HistogramBase::kNoFlags))
-
-#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1000, 500000, 50)
-
-//------------------------------------------------------------------------------
-// The following macros provide typical usage scenarios for callers that wish
-// to record histogram data, and have the data submitted/uploaded via UMA.
-// Not all systems support such UMA, but if they do, the following macros
-// should work with the service.
-
-#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromSeconds(10), 50)
-
-#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(10), \
- base::TimeDelta::FromMinutes(3), 50)
-
-// Use this macro when times can routinely be much longer than 10 seconds.
-#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromHours(1), 50)
-
-// Use this macro when times can routinely be much longer than 10 seconds and
-// you want 100 buckets.
-#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
- name, sample, base::TimeDelta::FromMilliseconds(1), \
- base::TimeDelta::FromHours(1), 100)
-
-#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
- base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 1000000, 50)
-
-#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 100, 50)
-
-#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 10000, 50)
-
-#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::Histogram::FactoryGet(name, min, max, bucket_count, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1000, 500000, 50)
-
-#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
- name, sample, 1, 1000, 50)
-
-#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
- UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
-
-#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
- base::BooleanHistogram::FactoryGet(name, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-// The samples should always be strictly less than |boundary_value|. For more
-// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
-#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
- HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
- base::HistogramBase::kUmaTargetedHistogramFlag)
-
-// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
-// histograms. Use this if recording a histogram that should be part of the
-// initial stability log.
-#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
- HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
- base::HistogramBase::kUmaStabilityHistogramFlag)
-
-#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
- STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
- base::CustomHistogram::FactoryGet(name, custom_ranges, \
- base::HistogramBase::kUmaTargetedHistogramFlag))
-
-//------------------------------------------------------------------------------
-
-class BucketRanges;
-class SampleVector;
-
class BooleanHistogram;
class CustomHistogram;
class Histogram;
class LinearHistogram;
+class SampleVector;
class BASE_EXPORT Histogram : public HistogramBase {
public:
diff --git a/base/metrics/histogram_macros.h b/base/metrics/histogram_macros.h
new file mode 100644
index 0000000..a9996d1
--- /dev/null
+++ b/base/metrics/histogram_macros.h
@@ -0,0 +1,232 @@
+// 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 BASE_METRICS_HISTOGRAM_MACROS_H_
+#define BASE_METRICS_HISTOGRAM_MACROS_H_
+
+#include "base/atomicops.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/metrics/histogram.h"
+#include "base/time/time.h"
+
+//------------------------------------------------------------------------------
+// Histograms are often put in areas where they are called many many times, and
+// performance is critical. As a result, they are designed to have a very low
+// recurring cost of executing (adding additional samples). Toward that end,
+// the macros declare a static pointer to the histogram in question, and only
+// take a "slow path" to construct (or find) the histogram on the first run
+// through the macro. We leak the histograms at shutdown time so that we don't
+// have to validate using the pointers at any time during the running of the
+// process.
+
+// The following code is generally what a thread-safe static pointer
+// initialization looks like for a histogram (after a macro is expanded). This
+// sample is an expansion (with comments) of the code for
+// LOCAL_HISTOGRAM_CUSTOM_COUNTS().
+
+/*
+ do {
+ // The pointer's presence indicates the initialization is complete.
+ // Initialization is idempotent, so it can safely be atomically repeated.
+ static base::subtle::AtomicWord atomic_histogram_pointer = 0;
+
+ // Acquire_Load() ensures that we acquire visibility to the pointed-to data
+ // in the histogram.
+ base::Histogram* histogram_pointer(reinterpret_cast<base::Histogram*>(
+ base::subtle::Acquire_Load(&atomic_histogram_pointer)));
+
+ if (!histogram_pointer) {
+ // This is the slow path, which will construct OR find the matching
+ // histogram. FactoryGet includes locks on a global histogram name map
+ // and is completely thread safe.
+ histogram_pointer = base::Histogram::FactoryGet(
+ name, min, max, bucket_count, base::HistogramBase::kNoFlags);
+
+ // Use Release_Store to ensure that the histogram data is made available
+ // globally before we make the pointer visible.
+ // Several threads may perform this store, but the same value will be
+ // stored in all cases (for a given named/spec'ed histogram).
+ // We could do this without any barrier, since FactoryGet entered and
+ // exited a lock after construction, but this barrier makes things clear.
+ base::subtle::Release_Store(&atomic_histogram_pointer,
+ reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer));
+ }
+
+ // Ensure calling contract is upheld, and the name does NOT vary.
+ DCHECK(histogram_pointer->histogram_name() == constant_histogram_name);
+
+ histogram_pointer->Add(sample);
+ } while (0);
+*/
+
+// The above pattern is repeated in several macros. The only elements that
+// vary are the invocation of the Add(sample) vs AddTime(sample), and the choice
+// of which FactoryGet method to use. The different FactoryGet methods have
+// various argument lists, so the function with its argument list is provided as
+// a macro argument here. The name is only used in a DCHECK, to assure that
+// callers don't try to vary the name of the histogram (which would tend to be
+// ignored by the one-time initialization of the histogtram_pointer).
+#define STATIC_HISTOGRAM_POINTER_BLOCK(constant_histogram_name, \
+ histogram_add_method_invocation, \
+ histogram_factory_get_invocation) \
+ do { \
+ static base::subtle::AtomicWord atomic_histogram_pointer = 0; \
+ base::HistogramBase* histogram_pointer( \
+ reinterpret_cast<base::HistogramBase*>( \
+ base::subtle::Acquire_Load(&atomic_histogram_pointer))); \
+ if (!histogram_pointer) { \
+ histogram_pointer = histogram_factory_get_invocation; \
+ base::subtle::Release_Store(&atomic_histogram_pointer, \
+ reinterpret_cast<base::subtle::AtomicWord>(histogram_pointer)); \
+ } \
+ if (DCHECK_IS_ON) \
+ histogram_pointer->CheckName(constant_histogram_name); \
+ histogram_pointer->histogram_add_method_invocation; \
+ } while (0)
+
+
+//------------------------------------------------------------------------------
+// Provide easy general purpose histogram in a macro, just like stats counters.
+// The first four macros use 50 buckets.
+
+#define LOCAL_HISTOGRAM_TIMES(name, sample) LOCAL_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromSeconds(10), 50)
+
+// For folks that need real specific times, use this to select a precise range
+// of times you want plotted, and the number of buckets you want used.
+#define LOCAL_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+ base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+ base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_COUNTS(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000000, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_100(name, sample) \
+ LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 100, 50)
+
+#define LOCAL_HISTOGRAM_COUNTS_10000(name, sample) \
+ LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, 1, 10000, 50)
+
+#define LOCAL_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::Histogram::FactoryGet(name, min, max, bucket_count, \
+ base::HistogramBase::kNoFlags))
+
+// This is a helper macro used by other macros and shouldn't be used directly.
+#define HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary, flag) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::LinearHistogram::FactoryGet(name, 1, boundary, boundary + 1, \
+ flag))
+
+#define LOCAL_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+ LOCAL_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define LOCAL_HISTOGRAM_BOOLEAN(name, sample) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+ base::BooleanHistogram::FactoryGet(name, base::Histogram::kNoFlags))
+
+// Support histograming of an enumerated value. The samples should always be
+// strictly less than |boundary_value| -- this prevents you from running into
+// problems down the line if you add additional buckets to the histogram. Note
+// also that, despite explicitly setting the minimum bucket value to |1| below,
+// it is fine for enumerated histograms to be 0-indexed -- this is because
+// enumerated histograms should never have underflow.
+#define LOCAL_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::LinearHistogram::FactoryGet(name, 1, boundary_value, \
+ boundary_value + 1, base::HistogramBase::kNoFlags))
+
+// Support histograming of an enumerated value. Samples should be one of the
+// std::vector<int> list provided via |custom_ranges|. See comments above
+// CustomRanges::FactoryGet about the requirement of |custom_ranges|.
+// You can use the helper function CustomHistogram::ArrayToCustomRanges to
+// transform a C-style array of valid sample values to a std::vector<int>.
+#define LOCAL_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::CustomHistogram::FactoryGet(name, custom_ranges, \
+ base::HistogramBase::kNoFlags))
+
+#define LOCAL_HISTOGRAM_MEMORY_KB(name, sample) LOCAL_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1000, 500000, 50)
+
+//------------------------------------------------------------------------------
+// The following macros provide typical usage scenarios for callers that wish
+// to record histogram data, and have the data submitted/uploaded via UMA.
+// Not all systems support such UMA, but if they do, the following macros
+// should work with the service.
+
+#define UMA_HISTOGRAM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromSeconds(10), 50)
+
+#define UMA_HISTOGRAM_MEDIUM_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(10), \
+ base::TimeDelta::FromMinutes(3), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds.
+#define UMA_HISTOGRAM_LONG_TIMES(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromHours(1), 50)
+
+// Use this macro when times can routinely be much longer than 10 seconds and
+// you want 100 buckets.
+#define UMA_HISTOGRAM_LONG_TIMES_100(name, sample) UMA_HISTOGRAM_CUSTOM_TIMES( \
+ name, sample, base::TimeDelta::FromMilliseconds(1), \
+ base::TimeDelta::FromHours(1), 100)
+
+#define UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddTime(sample), \
+ base::Histogram::FactoryTimeGet(name, min, max, bucket_count, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_COUNTS(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000000, 50)
+
+#define UMA_HISTOGRAM_COUNTS_100(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 100, 50)
+
+#define UMA_HISTOGRAM_COUNTS_10000(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 10000, 50)
+
+#define UMA_HISTOGRAM_CUSTOM_COUNTS(name, sample, min, max, bucket_count) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::Histogram::FactoryGet(name, min, max, bucket_count, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#define UMA_HISTOGRAM_MEMORY_KB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1000, 500000, 50)
+
+#define UMA_HISTOGRAM_MEMORY_MB(name, sample) UMA_HISTOGRAM_CUSTOM_COUNTS( \
+ name, sample, 1, 1000, 50)
+
+#define UMA_HISTOGRAM_PERCENTAGE(name, under_one_hundred) \
+ UMA_HISTOGRAM_ENUMERATION(name, under_one_hundred, 101)
+
+#define UMA_HISTOGRAM_BOOLEAN(name, sample) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, AddBoolean(sample), \
+ base::BooleanHistogram::FactoryGet(name, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+// The samples should always be strictly less than |boundary_value|. For more
+// details, see the comment for the |LOCAL_HISTOGRAM_ENUMERATION| macro, above.
+#define UMA_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+ HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+ base::HistogramBase::kUmaTargetedHistogramFlag)
+
+// Similar to UMA_HISTOGRAM_ENUMERATION, but used for recording stability
+// histograms. Use this if recording a histogram that should be part of the
+// initial stability log.
+#define UMA_STABILITY_HISTOGRAM_ENUMERATION(name, sample, boundary_value) \
+ HISTOGRAM_ENUMERATION_WITH_FLAG(name, sample, boundary_value, \
+ base::HistogramBase::kUmaStabilityHistogramFlag)
+
+#define UMA_HISTOGRAM_CUSTOM_ENUMERATION(name, sample, custom_ranges) \
+ STATIC_HISTOGRAM_POINTER_BLOCK(name, Add(sample), \
+ base::CustomHistogram::FactoryGet(name, custom_ranges, \
+ base::HistogramBase::kUmaTargetedHistogramFlag))
+
+#endif // BASE_METRICS_HISTOGRAM_MACROS_H_
diff --git a/base/strings/string_util.cc b/base/strings/string_util.cc
index 43f15a3..f77034b 100644
--- a/base/strings/string_util.cc
+++ b/base/strings/string_util.cc
@@ -406,7 +406,7 @@
}
#endif
-bool IsStringUTF8(const std::string& str) {
+bool IsStringUTF8(const StringPiece& str) {
const char *src = str.data();
int32 src_len = static_cast<int32>(str.length());
int32 char_index = 0;
diff --git a/base/strings/string_util.h b/base/strings/string_util.h
index 1e2ac70..5ab2ad5 100644
--- a/base/strings/string_util.h
+++ b/base/strings/string_util.h
@@ -248,7 +248,7 @@
//
// IsStringASCII assumes the input is likely all ASCII, and does not leave early
// if it is not the case.
-BASE_EXPORT bool IsStringUTF8(const std::string& str);
+BASE_EXPORT bool IsStringUTF8(const StringPiece& str);
BASE_EXPORT bool IsStringASCII(const StringPiece& str);
BASE_EXPORT bool IsStringASCII(const StringPiece16& str);
// A convenience adaptor for WebStrings, as they don't convert into
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
index 0d885ee..829053f 100644
--- a/base/sys_info_android.cc
+++ b/base/sys_info_android.cc
@@ -59,8 +59,8 @@
// cannot be acquired. Use the latest Android release with a higher bug fix
// version to avoid unnecessarily comparison errors with the latest release.
// This should be manually kept up-to-date on each Android release.
-const int kDefaultAndroidMajorVersion = 4;
-const int kDefaultAndroidMinorVersion = 4;
+const int kDefaultAndroidMajorVersion = 5;
+const int kDefaultAndroidMinorVersion = 0;
const int kDefaultAndroidBugfixVersion = 99;
// Parse out the OS version numbers from the system properties.
diff --git a/base/test/multiprocess_test_android.cc b/base/test/multiprocess_test_android.cc
index 4cfae5e..8f54b82 100644
--- a/base/test/multiprocess_test_android.cc
+++ b/base/test/multiprocess_test_android.cc
@@ -2,13 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/posix/global_descriptors.h"
#include "base/test/multiprocess_test.h"
#include <unistd.h>
+#include "base/base_switches.h"
+#include "base/command_line.h"
#include "base/containers/hash_tables.h"
#include "base/logging.h"
+#include "base/posix/global_descriptors.h"
#include "testing/multiprocess_func_list.h"
namespace base {
@@ -16,7 +18,6 @@
// A very basic implementation for Android. On Android tests can run in an APK
// and we don't have an executable to exec*. This implementation does the bare
// minimum to execute the method specified by procname (in the child process).
-// - |base_command_line| is ignored.
// - All options except |fds_to_remap| are ignored.
ProcessHandle SpawnMultiProcessTestChild(const std::string& procname,
const CommandLine& base_command_line,
@@ -60,6 +61,13 @@
}
close(old_fd);
}
+ CommandLine::Reset();
+ CommandLine::Init(0, nullptr);
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ command_line->InitFromArgv(base_command_line.argv());
+ if (!command_line->HasSwitch(switches::kTestChildProcess))
+ command_line->AppendSwitchASCII(switches::kTestChildProcess, procname);
+
_exit(multi_process_function_list::InvokeChildProcessTest(procname));
return 0;
}
diff --git a/build/all.gyp b/build/all.gyp
index d47fc79..a11ee7a 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -42,13 +42,13 @@
# NOTE: This list of targets is present because
# mojo_base.gyp:mojo_base cannot be built on iOS, as
# javascript-related targets cause v8 to be built.
- '../mojo/edk/mojo_edk_tests.gyp:mojo_public_bindings_unittests',
- '../mojo/edk/mojo_edk_tests.gyp:mojo_public_environment_unittests',
- '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_perftests',
- '../mojo/edk/mojo_edk_tests.gyp:mojo_public_system_unittests',
- '../mojo/edk/mojo_edk_tests.gyp:mojo_public_utility_unittests',
+ '../mojo/edk/mojo_edk.gyp:mojo_public_bindings_unittests',
+ '../mojo/edk/mojo_edk.gyp:mojo_public_environment_unittests',
+ '../mojo/edk/mojo_edk.gyp:mojo_public_system_perftests',
+ '../mojo/edk/mojo_edk.gyp:mojo_public_system_unittests',
+ '../mojo/edk/mojo_edk.gyp:mojo_public_utility_unittests',
'../mojo/edk/mojo_edk.gyp:mojo_system_impl',
- '../mojo/edk/mojo_edk_tests.gyp:mojo_system_unittests',
+ '../mojo/edk/mojo_edk.gyp:mojo_system_unittests',
'../mojo/mojo_base.gyp:mojo_common_lib',
'../mojo/mojo_base.gyp:mojo_common_unittests',
'../mojo/public/mojo_public.gyp:mojo_cpp_bindings',
@@ -689,6 +689,13 @@
'../third_party/webrtc/tools/tools.gyp:frame_analyzer',
'../third_party/webrtc/tools/tools.gyp:rgba_to_i420_converter',
],
+ 'conditions': [
+ ['remoting==1', {
+ 'dependencies': [
+ '../remoting/remoting.gyp:*',
+ ],
+ }],
+ ],
}, # target_name: chromium_builder_webrtc
{
'target_name': 'chromium_builder_chromedriver',
@@ -868,6 +875,8 @@
'../tools/android/android_tools.gyp:android_tools',
'../tools/android/android_tools.gyp:memconsumer',
# Unit test bundles packaged as an apk.
+ '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
+ '../components/devtools_bridge.gyp:devtools_bridge_tests2_apk',
'../content/content_shell_and_tests.gyp:content_browsertests_apk',
],
}, # target_name: android_builder_chromium_webrtc
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
index d113842..530512a 100755
--- a/build/android/buildbot/bb_device_steps.py
+++ b/build/android/buildbot/bb_device_steps.py
@@ -124,6 +124,9 @@
args += ['--target', 'Release']
else:
args += ['--target', 'Debug']
+ if options.flakiness_server:
+ args += ['--flakiness-dashboard-server=%s' %
+ options.flakiness_server]
args += cmd
RunCmd(args, cwd=DIR_BUILD_ROOT)
@@ -150,9 +153,6 @@
args.append('--tool=asan')
if options.gtest_filter:
args.append('--gtest-filter=%s' % options.gtest_filter)
- if options.flakiness_server:
- args.append('--flakiness-dashboard-server=%s' %
- options.flakiness_server)
for suite in suites:
bb_annotations.PrintNamedStep(suite)
diff --git a/build/android/buildbot/bb_run_bot.py b/build/android/buildbot/bb_run_bot.py
index 38678d1..8c853e7 100755
--- a/build/android/buildbot/bb_run_bot.py
+++ b/build/android/buildbot/bb_run_bot.py
@@ -123,6 +123,8 @@
std_test_steps = ['extract_build']
std_tests = ['ui', 'unit']
telemetry_tests = ['telemetry_perf_unittests']
+ telemetry_tests_user_build = ['telemetry_unittests',
+ 'telemetry_perf_unittests']
flakiness_server = (
'--flakiness-server=%s' % constants.UPSTREAM_FLAKINESS_SERVER)
experimental = ['--experimental']
@@ -171,6 +173,8 @@
['--experimental', flakiness_server,
'--coverage-bucket', CHROMIUM_COVERAGE_BUCKET,
'--cleanup'])),
+ B('user-build-fyi-tests-dbg', H(std_test_steps),
+ T(telemetry_tests_user_build)),
B('fyi-component-builder-tests-dbg',
H(compile_step, extra_gyp='component=shared_library'),
T(std_tests, ['--experimental', flakiness_server])),
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index ee27544..7be93ec 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -23,5 +23,5 @@
M V EI2: org.chromium.content_public.browser.LoadUrlParams.setPostData(byte[]) may expose internal representation by storing an externally mutable object into LoadUrlParams.mPostData At LoadUrlParams.java
M V EI: org.chromium.content_public.browser.LoadUrlParams.getPostData() may expose internal representation by returning LoadUrlParams.mPostData At LoadUrlParams.java
M D NP: Read of unwritten public or protected field data in org.chromium.components.devtools_bridge.SessionDependencyFactory$DataChannelObserverAdapter.onMessage(DataChannel$Buffer) At SessionDependencyFactory.java
-M D NP: Read of unwritten public or protected field mandatory in org.chromium.components.devtools_bridge.SessionDependencyFactory.createPeerConnection(RTCConfiguration, AbstractPeerConnection$Observer) At SessionDependencyFactory.java
+M D NP: Read of unwritten public or protected field mandatory in org.chromium.components.devtools_bridge.SessionDependencyFactory.createPeerConnectionConstraints() At SessionDependencyFactory.java
M V EI2: org.chromium.net.ChromiumUrlRequest.setUploadData(String, byte[]) may expose internal representation by storing an externally mutable object into ChromiumUrlRequest.mUploadData At ChromiumUrlRequest.java
diff --git a/build/android/gyp/create_java_binary_script.py b/build/android/gyp/create_java_binary_script.py
new file mode 100755
index 0000000..d632728
--- /dev/null
+++ b/build/android/gyp/create_java_binary_script.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Creates a simple script to run a java "binary".
+
+This creates a script that sets up the java command line for running a java
+jar. This includes correctly setting the classpath and the main class.
+"""
+
+import optparse
+import os
+import sys
+
+from util import build_utils
+
+# The java command must be executed in the current directory because there may
+# be user-supplied paths in the args. The script receives the classpath relative
+# to the directory that the script is written in and then, when run, must
+# recalculate the paths relative to the current directory.
+script_template = """\
+#!/usr/bin/env python
+#
+# This file was generated by build/android/gyp/create_java_binary_script.py
+
+import os
+import sys
+
+self_dir = os.path.dirname(__file__)
+classpath = [{classpath}]
+if os.getcwd() != self_dir:
+ offset = os.path.relpath(self_dir, os.getcwd())
+ classpath = [os.path.join(offset, p) for p in classpath]
+java_args = [
+ "java",
+ "-classpath", ":".join(classpath),
+ \"{main_class}\"] + sys.argv[1:]
+os.execvp("java", java_args)
+"""
+
+def main(argv):
+ argv = build_utils.ExpandFileArgs(argv)
+ parser = optparse.OptionParser()
+ build_utils.AddDepfileOption(parser)
+ parser.add_option('--output', help='Output path for executable script.')
+ parser.add_option('--jar-path', help='Path to the main jar.')
+ parser.add_option('--main-class',
+ help='Name of the java class with the "main" entry point.')
+ parser.add_option('--classpath', action='append',
+ help='Classpath for running the jar.')
+ options, _ = parser.parse_args(argv)
+
+ classpath = [options.jar_path]
+ for cp_arg in options.classpath:
+ classpath += build_utils.ParseGypList(cp_arg)
+
+ run_dir = os.path.dirname(options.output)
+ classpath = [os.path.relpath(p, run_dir) for p in classpath]
+
+ with open(options.output, 'w') as script:
+ script.write(script_template.format(
+ classpath=('"%s"' % '", "'.join(classpath)),
+ main_class=options.main_class))
+
+ os.chmod(options.output, 0750)
+
+ if options.depfile:
+ build_utils.WriteDepfile(
+ options.depfile,
+ build_utils.GetPythonDependencies())
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv[1:]))
diff --git a/build/android/gyp/test/BUILD.gn b/build/android/gyp/test/BUILD.gn
new file mode 100644
index 0000000..6621489
--- /dev/null
+++ b/build/android/gyp/test/BUILD.gn
@@ -0,0 +1,11 @@
+import("//build/config/android/rules.gni")
+
+java_library("hello_world_java") {
+ java_files = [ "java/org/chromium/helloworld/HelloWorldPrinter.java" ]
+}
+
+java_binary("hello_world") {
+ deps = [ ":hello_world_java" ]
+ java_files = [ "java/org/chromium/helloworld/HelloWorldMain.java" ]
+ main_class = "org.chromium.helloworld.HelloWorldMain"
+}
diff --git a/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldMain.java b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldMain.java
new file mode 100644
index 0000000..10860d8
--- /dev/null
+++ b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldMain.java
@@ -0,0 +1,15 @@
+// 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.
+
+package org.chromium.helloworld;
+
+public class HelloWorldMain {
+ public static void main(String[] args) {
+ if (args.length > 0) {
+ System.exit(Integer.parseInt(args[0]));
+ }
+ HelloWorldPrinter.print();
+ }
+}
+
diff --git a/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldPrinter.java b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldPrinter.java
new file mode 100644
index 0000000..b09673e
--- /dev/null
+++ b/build/android/gyp/test/java/org/chromium/helloworld/HelloWorldPrinter.java
@@ -0,0 +1,12 @@
+// 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.
+
+package org.chromium.helloworld;
+
+public class HelloWorldPrinter {
+ public static void print() {
+ System.out.println("Hello, world!");
+ }
+}
+
diff --git a/build/android/gyp/write_build_config.py b/build/android/gyp/write_build_config.py
index 722d18c..d26e6d3 100755
--- a/build/android/gyp/write_build_config.py
+++ b/build/android/gyp/write_build_config.py
@@ -12,10 +12,6 @@
etc. It also includes the information needed to create the build_config for
other targets that depend on that one.
-There are several different types of build_configs:
- android_library: An android library containing java code.
- android_resources: A target containing android resources.
-
Android build scripts should not refer to the build_config directly, and the
build specification should instead pass information in using the special
file-arg syntax (see build_utils.py:ExpandFileArgs). That syntax allows passing
@@ -76,11 +72,17 @@
help='Java package name for these resources.')
parser.add_option('--android-manifest', help='Path to android manifest.')
- # android_library/apk options
+ # java library options
parser.add_option('--jar-path', help='Path to target\'s jar output.')
+ parser.add_option('--supports-android', action='store_true',
+ help='Whether this library supports running on the Android platform.')
+ parser.add_option('--requires-android', action='store_true',
+ help='Whether this library requires running on the Android platform.')
+
+ # android library options
parser.add_option('--dex-path', help='Path to target\'s dex output.')
- # apk native library options
+ # native library options
parser.add_option('--native-libs', help='List of top-level native libs.')
parser.add_option('--readelf-path', help='Path to toolchain\'s readelf.')
@@ -91,25 +93,31 @@
if not options.type in [
- 'android_library', 'android_resources', 'android_apk']:
+ 'java_library', 'android_resources', 'android_apk']:
raise Exception('Unknown type: <%s>' % options.type)
-
required_options = ['build_config'] + {
- 'android_library': ['jar_path', 'dex_path'],
+ 'java_library': ['jar_path'],
'android_resources': ['resources_zip'],
'android_apk': ['jar_path', 'dex_path', 'resources_zip']
}[options.type]
if options.native_libs:
- required_options += ['readelf_path']
+ required_options.append('readelf_path')
build_utils.CheckOptions(options, parser, required_options)
+ if options.type == 'java_library':
+ if options.supports_android and not options.dex_path:
+ raise Exception('java_library that supports Android requires a dex path.')
+
+ if options.requires_android and not options.supports_android:
+ raise Exception(
+ '--supports-android is required when using --requires-android')
+
possible_deps_config_paths = build_utils.ParseGypList(
options.possible_deps_configs)
-
allow_unknown_deps = options.type == 'android_apk'
unknown_deps = [
c for c in possible_deps_config_paths if not os.path.exists(c)]
@@ -123,8 +131,8 @@
direct_deps_configs = [GetDepConfig(p) for p in direct_deps_config_paths]
all_deps_configs = [GetDepConfig(p) for p in all_deps_config_paths]
- direct_library_deps = DepsOfType('android_library', direct_deps_configs)
- all_library_deps = DepsOfType('android_library', all_deps_configs)
+ direct_library_deps = DepsOfType('java_library', direct_deps_configs)
+ all_library_deps = DepsOfType('java_library', all_deps_configs)
direct_resources_deps = DepsOfType('android_resources', direct_deps_configs)
all_resources_deps = DepsOfType('android_resources', all_deps_configs)
@@ -132,6 +140,7 @@
# Initialize some common config.
config = {
'deps_info': {
+ 'name': os.path.basename(options.build_config),
'path': options.build_config,
'type': options.type,
'deps_configs': direct_deps_config_paths,
@@ -139,16 +148,40 @@
}
deps_info = config['deps_info']
- if options.type in ['android_library', 'android_apk']:
+
+ if options.type == 'java_library':
+ deps_info['requires_android'] = options.requires_android
+ deps_info['supports_android'] = options.supports_android
+
+ deps_require_android = (all_resources_deps +
+ [d['name'] for d in direct_library_deps if d['requires_android']])
+ deps_not_support_android = (
+ [d['name'] for d in direct_library_deps if not d['supports_android']])
+
+ if deps_require_android and not options.requires_android:
+ raise Exception('Some deps require building for the Android platform: ' +
+ str(deps_require_android))
+
+ if deps_not_support_android and options.supports_android:
+ raise Exception('Not all deps support the Android platform: ' +
+ str(deps_not_support_android))
+
+
+ if options.type in ['java_library', 'android_apk']:
javac_classpath = [c['jar_path'] for c in direct_library_deps]
+ java_full_classpath = [c['jar_path'] for c in all_library_deps]
deps_info['resources_deps'] = [c['path'] for c in all_resources_deps]
deps_info['jar_path'] = options.jar_path
- deps_info['dex_path'] = options.dex_path
+ if options.type == 'android_apk' or options.supports_android:
+ deps_info['dex_path'] = options.dex_path
config['javac'] = {
'classpath': javac_classpath,
}
+ config['java'] = {
+ 'full_classpath': java_full_classpath
+ }
- if options.type == 'android_library':
+ if options.type == 'java_library':
# Only resources might have srcjars (normal srcjar targets are listed in
# srcjar_deps). A resource's srcjar contains the R.java file for those
# resources, and (like Android's default build system) we allow a library to
@@ -157,9 +190,9 @@
c['srcjar'] for c in direct_resources_deps if 'srcjar' in c]
if options.type == 'android_apk':
+ # Apks will get their resources srcjar explicitly passed to the java step.
config['javac']['srcjars'] = []
-
if options.type == 'android_resources':
deps_info['resources_zip'] = options.resources_zip
if options.srcjar:
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index f6bebce..334b74c 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -315,7 +315,7 @@
self.adb.Reboot()
self._cache = {}
- timeout_retry.WaitFor(device_offline, wait_period=1, max_tries=5)
+ timeout_retry.WaitFor(device_offline, wait_period=1)
if block:
self.WaitUntilFullyBooted()
diff --git a/build/android/pylib/gtest/filter/content_browsertests_disabled b/build/android/pylib/gtest/filter/content_browsertests_disabled
index 748f680..0314f5f 100644
--- a/build/android/pylib/gtest/filter/content_browsertests_disabled
+++ b/build/android/pylib/gtest/filter/content_browsertests_disabled
@@ -23,11 +23,6 @@
FileSystemBrowserTestWithLowQuota.QuotaTest
ChildProcessSecurityPolicyInProcessBrowserTest.NoLeak
-# Needs to start the test server before
-# BrowserTestBase::SetUpCommandLine is called, but on Android
-# the test server needs to be started in SetUpOnMainThread().
-SecurityExploitBrowserTest.SetWebUIProperty
-
# Plugins are not supported.
BrowserPluginThreadedCompositorPixelTest.*
BrowserPluginHostTest.*
@@ -108,10 +103,6 @@
# http://crbug.com/338408
TracingControllerTest.EnableCaptureAndDisableMonitoring
-# http://crbug.com/338023
-SecurityExploitBrowserTest.AttemptDuplicateRenderViewHost
-SecurityExploitBrowserTest.AttemptDuplicateRenderWidgetHost
-
# http://crbug.com/338411
FrameTreeBrowserTest.NavigateWithLeftoverFrames
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 56e7449..66feea6 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -79,8 +79,8 @@
# Test case statuses.
re_run = re.compile('\[ RUN \] ?(.*)\r\n')
- re_fail = re.compile('\[ FAILED \] ?(.*)\r\n')
- re_ok = re.compile('\[ OK \] ?(.*?) .*\r\n')
+ re_fail = re.compile('\[ FAILED \] ?(.*?)( \((\d+) ms\))?\r\r\n')
+ re_ok = re.compile('\[ OK \] ?(.*?)( \((\d+) ms\))?\r\r\n')
# Test run statuses.
re_passed = re.compile('\[ PASSED \] ?(.*)\r\n')
@@ -93,6 +93,7 @@
try:
while True:
full_test_name = None
+
found = p.expect([re_run, re_passed, re_runner_fail],
timeout=self._timeout)
if found == 1: # re_passed
@@ -105,17 +106,20 @@
log = p.before.replace('\r', '')
if found == 0: # re_ok
if full_test_name == p.match.group(1).replace('\r', ''):
+ duration_ms = int(p.match.group(3)) if p.match.group(3) else 0
results.AddResult(base_test_result.BaseTestResult(
full_test_name, base_test_result.ResultType.PASS,
- log=log))
+ duration=duration_ms, log=log))
elif found == 2: # re_crash
results.AddResult(base_test_result.BaseTestResult(
full_test_name, base_test_result.ResultType.CRASH,
log=log))
break
else: # re_fail
+ duration_ms = int(p.match.group(3)) if p.match.group(3) else 0
results.AddResult(base_test_result.BaseTestResult(
- full_test_name, base_test_result.ResultType.FAIL, log=log))
+ full_test_name, base_test_result.ResultType.FAIL,
+ duration=duration_ms, log=log))
except pexpect.EOF:
logging.error('Test terminated - EOF')
# We're here because either the device went offline, or the test harness
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py
index d83d00a..a3d8849 100644
--- a/build/android/pylib/instrumentation/test_jar.py
+++ b/build/android/pylib/instrumentation/test_jar.py
@@ -10,11 +10,11 @@
import pickle
import re
import sys
-import tempfile
from pylib import cmd_helper
from pylib import constants
from pylib.device import device_utils
+from pylib.utils import proguard
sys.path.insert(0,
os.path.join(constants.DIR_SOURCE_ROOT,
@@ -23,7 +23,7 @@
import unittest_util # pylint: disable=F0401
# If you change the cached output of proguard, increment this number
-PICKLE_FORMAT_VERSION = 3
+PICKLE_FORMAT_VERSION = 4
class TestJar(object):
@@ -86,111 +86,30 @@
def _GetProguardData(self):
logging.info('Retrieving test methods via proguard.')
- with tempfile.NamedTemporaryFile() as proguard_output:
- cmd_helper.RunCmd(['java', '-jar',
- self._PROGUARD_PATH,
- '-injars', self._jar_path,
- '-dontshrink',
- '-dontoptimize',
- '-dontobfuscate',
- '-dontpreverify',
- '-dump', proguard_output.name])
+ p = proguard.Dump(self._jar_path)
- clazzez = {}
+ class_lookup = dict((c['class'], c) for c in p['classes'])
+ def recursive_get_annotations(c):
+ s = c['superclass']
+ if s in class_lookup:
+ a = recursive_get_annotations(class_lookup[s])
+ else:
+ a = {}
+ a.update(c['annotations'])
+ return a
- annotation = None
- annotation_has_value = False
- clazz = None
- method = None
-
- for line in proguard_output:
- if len(line) == 0:
- annotation = None
- annotation_has_value = False
- method = None
- continue
-
- m = self._PROGUARD_CLASS_RE.match(line)
- if m:
- clazz = m.group(1).replace('/', '.')
- clazzez[clazz] = {
- 'methods': {},
- 'annotations': {}
- }
- annotation = None
- annotation_has_value = False
- method = None
- continue
-
- if not clazz:
- continue
-
- m = self._PROGUARD_SUPERCLASS_RE.match(line)
- if m:
- clazzez[clazz]['superclass'] = m.group(1).replace('/', '.')
- continue
-
- if clazz.endswith('Test'):
- m = self._PROGUARD_METHOD_RE.match(line)
- if m:
- method = m.group(1)
- clazzez[clazz]['methods'][method] = {'annotations': {}}
- annotation = None
- annotation_has_value = False
- continue
-
- m = self._PROGUARD_ANNOTATION_RE.match(line)
- if m:
- # Ignore the annotation package.
- annotation = m.group(1).split('/')[-1]
- if method:
- clazzez[clazz]['methods'][method]['annotations'][annotation] = None
- else:
- clazzez[clazz]['annotations'][annotation] = None
- continue
-
- if annotation:
- if not annotation_has_value:
- m = self._PROGUARD_ANNOTATION_CONST_RE.match(line)
- annotation_has_value = bool(m)
- else:
- m = self._PROGUARD_ANNOTATION_VALUE_RE.match(line)
- if m:
- if method:
- clazzez[clazz]['methods'][method]['annotations'][annotation] = (
- m.group(1))
- else:
- clazzez[clazz]['annotations'][annotation] = m.group(1)
- annotation_has_value = None
-
- test_clazzez = ((n, i) for n, i in clazzez.items() if n.endswith('Test'))
- for clazz_name, clazz_info in test_clazzez:
- logging.info('Processing %s' % clazz_name)
- c = clazz_name
- min_sdk_level = None
-
- while c in clazzez:
- c_info = clazzez[c]
- if not min_sdk_level:
- min_sdk_level = c_info['annotations'].get('MinAndroidSdkLevel', None)
- c = c_info.get('superclass', None)
-
- for method_name, method_info in clazz_info['methods'].items():
- if method_name.startswith('test'):
- qualified_method = '%s#%s' % (clazz_name, method_name)
- method_annotations = []
- for annotation_name, annotation_value in (
- method_info['annotations'].items()):
- method_annotations.append(annotation_name)
- if annotation_value:
- method_annotations.append(
- annotation_name + ':' + annotation_value)
- self._test_methods[qualified_method] = {
- 'annotations': method_annotations
- }
- if min_sdk_level is not None:
- self._test_methods[qualified_method]['min_sdk_level'] = (
- int(min_sdk_level))
+ test_classes = (c for c in p['classes']
+ if c['class'].endswith('Test'))
+ for c in test_classes:
+ class_annotations = recursive_get_annotations(c)
+ test_methods = (m for m in c['methods']
+ if m['method'].startswith('test'))
+ for m in test_methods:
+ qualified_method = '%s#%s' % (c['class'], m['method'])
+ annotations = dict(class_annotations)
+ annotations.update(m['annotations'])
+ self._test_methods[qualified_method] = m
+ self._test_methods[qualified_method]['annotations'] = annotations
logging.info('Storing proguard output to %s', self._pickled_proguard_name)
d = {'VERSION': PICKLE_FORMAT_VERSION,
@@ -199,7 +118,6 @@
with open(self._pickled_proguard_name, 'w') as f:
f.write(pickle.dumps(d))
-
@staticmethod
def _IsTestMethod(test):
class_name, method = test.split('#')
@@ -222,7 +140,7 @@
key = filters[0]
value_list = filters[1].split(',')
for value in value_list:
- if key + ':' + value in annotations:
+ if key in annotations and value == annotations['key']:
return True
elif annotation_filter in annotations:
return True
@@ -230,9 +148,9 @@
def GetAnnotatedTests(self, annotation_filter_list):
"""Returns a list of all tests that match the given annotation filters."""
- return [test for test, attr in self.GetTestMethods().iteritems()
+ return [test for test in self.GetTestMethods()
if self._IsTestMethod(test) and self._AnnotationsMatchFilters(
- annotation_filter_list, attr['annotations'])]
+ annotation_filter_list, self.GetTestAnnotations(test))]
def GetTestMethods(self):
"""Returns a dict of all test methods and relevant attributes.
@@ -245,15 +163,15 @@
"""Get a list of test methods with no known annotations."""
tests_missing_annotations = []
for test_method in self.GetTestMethods().iterkeys():
- annotations_ = frozenset(self.GetTestAnnotations(test_method))
+ annotations_ = frozenset(self.GetTestAnnotations(test_method).iterkeys())
if (annotations_.isdisjoint(self._ANNOTATIONS) and
not self.IsHostDrivenTest(test_method)):
tests_missing_annotations.append(test_method)
return sorted(tests_missing_annotations)
def _IsTestValidForSdkRange(self, test_name, attached_min_sdk_level):
- required_min_sdk_level = self.GetTestMethods()[test_name].get(
- 'min_sdk_level', None)
+ required_min_sdk_level = int(
+ self.GetTestAnnotations(test_name).get('MinAndroidSdkLevel', 0))
return (required_min_sdk_level is None or
attached_min_sdk_level >= required_min_sdk_level)
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 60e00f3..f2808da 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -208,8 +208,8 @@
Returns:
Whether the feature being tested is FirstRunExperience.
"""
- freFeature = 'Feature:FirstRunExperience'
- return freFeature in self.test_pkg.GetTestAnnotations(test)
+ annotations = self.test_pkg.GetTestAnnotations(test)
+ return ('FirstRunExperience' == annotations.get('Feature', None))
def _IsPerfTest(self, test):
"""Determines whether a test is a performance test.
@@ -329,10 +329,11 @@
annotations = self.test_pkg.GetTestAnnotations(test)
timeout_scale = 1
if 'TimeoutScale' in annotations:
- for annotation in annotations:
- scale_match = re.match('TimeoutScale:([0-9]+)', annotation)
- if scale_match:
- timeout_scale = int(scale_match.group(1))
+ try:
+ timeout_scale = int(annotations['TimeoutScale'])
+ except ValueError:
+ logging.warning('Non-integer value of TimeoutScale ignored. (%s)'
+ % annotations['TimeoutScale'])
if self.options.wait_for_debugger:
timeout_scale *= 100
return timeout_scale
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
index f4e5730..c7239b4 100644
--- a/build/android/pylib/uiautomator/test_runner.py
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -63,7 +63,8 @@
def _RunTest(self, test, timeout):
self.device.ClearApplicationState(self._package)
if self.flags:
- if 'Feature:FirstRunExperience' in self.test_pkg.GetTestAnnotations(test):
+ annotations = self.test_pkg.GetTestAnnotations(test)
+ if ('FirstRunExperience' == annotations(test).get('Feature', None)):
self.flags.RemoveFlags(['--disable-fre'])
else:
self.flags.AddFlags(['--disable-fre'])
diff --git a/build/android/pylib/utils/proguard.py b/build/android/pylib/utils/proguard.py
new file mode 100644
index 0000000..02db03e
--- /dev/null
+++ b/build/android/pylib/utils/proguard.py
@@ -0,0 +1,144 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import re
+import tempfile
+
+from pylib import constants
+from pylib import cmd_helper
+
+
+_PROGUARD_CLASS_RE = re.compile(r'\s*?- Program class:\s*([\S]+)$')
+_PROGUARD_SUPERCLASS_RE = re.compile(r'\s*? Superclass:\s*([\S]+)$')
+_PROGUARD_METHOD_RE = re.compile(r'\s*?- Method:\s*(\S*)[(].*$')
+_PROGUARD_ANNOTATION_RE = re.compile(r'\s*?- Annotation \[L(\S*);\]:$')
+_PROGUARD_ANNOTATION_CONST_RE = (
+ re.compile(r'\s*?- Constant element value.*$'))
+_PROGUARD_ANNOTATION_VALUE_RE = re.compile(r'\s*?- \S+? \[(.*)\]$')
+
+_PROGUARD_PATH_SDK = os.path.join(
+ constants.ANDROID_SDK_ROOT, 'tools', 'proguard', 'lib', 'proguard.jar')
+_PROGUARD_PATH_BUILT = (
+ os.path.join(os.environ['ANDROID_BUILD_TOP'], 'external', 'proguard',
+ 'lib', 'proguard.jar')
+ if 'ANDROID_BUILD_TOP' in os.environ else None)
+_PROGUARD_PATH = (
+ _PROGUARD_PATH_SDK if os.path.exists(_PROGUARD_PATH_SDK)
+ else _PROGUARD_PATH_BUILT)
+
+
+def Dump(jar_path):
+ """Dumps class and method information from a JAR into a dict via proguard.
+
+ Args:
+ jar_path: An absolute path to the JAR file to dump.
+ Returns:
+ A dict in the following format:
+ {
+ 'classes': [
+ {
+ 'class': '',
+ 'superclass': '',
+ 'annotations': {},
+ 'methods': [
+ {
+ 'method': '',
+ 'annotations': {},
+ },
+ ...
+ ],
+ },
+ ...
+ ],
+ }
+ """
+
+ with tempfile.NamedTemporaryFile() as proguard_output:
+ cmd_helper.RunCmd(['java', '-jar',
+ _PROGUARD_PATH,
+ '-injars', jar_path,
+ '-dontshrink',
+ '-dontoptimize',
+ '-dontobfuscate',
+ '-dontpreverify',
+ '-dump', proguard_output.name])
+
+
+ results = {
+ 'classes': [],
+ }
+
+ annotation = None
+ annotation_has_value = False
+ class_result = None
+ method_result = None
+
+ for line in proguard_output:
+ line = line.strip('\r\n')
+
+ if len(line) == 0:
+ annotation = None
+ annotation_has_value = False
+ method_result = None
+ continue
+
+ m = _PROGUARD_CLASS_RE.match(line)
+ if m:
+ class_result = {
+ 'class': m.group(1).replace('/', '.'),
+ 'superclass': '',
+ 'annotations': {},
+ 'methods': [],
+ }
+ results['classes'].append(class_result)
+ annotation = None
+ annotation_has_value = False
+ method_result = None
+ continue
+
+ if not class_result:
+ continue
+
+ m = _PROGUARD_SUPERCLASS_RE.match(line)
+ if m:
+ class_result['superclass'] = m.group(1).replace('/', '.')
+ continue
+
+ m = _PROGUARD_METHOD_RE.match(line)
+ if m:
+ method_result = {
+ 'method': m.group(1),
+ 'annotations': {},
+ }
+ class_result['methods'].append(method_result)
+ annotation = None
+ annotation_has_value = False
+ continue
+
+ m = _PROGUARD_ANNOTATION_RE.match(line)
+ if m:
+ # Ignore the annotation package.
+ annotation = m.group(1).split('/')[-1]
+ if method_result:
+ method_result['annotations'][annotation] = None
+ else:
+ class_result['annotations'][annotation] = None
+ continue
+
+ if annotation:
+ if not annotation_has_value:
+ m = _PROGUARD_ANNOTATION_CONST_RE.match(line)
+ annotation_has_value = bool(m)
+ else:
+ m = _PROGUARD_ANNOTATION_VALUE_RE.match(line)
+ if m:
+ if method_result:
+ method_result['annotations'][annotation] = m.group(1)
+ else:
+ class_result['annotations'][annotation] = m.group(1)
+ annotation_has_value = None
+
+ return results
+
diff --git a/build/common.gypi b/build/common.gypi
index 3ddb01a..7fa5d83 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -1292,6 +1292,11 @@
# Experimental setting to optimize Chrome's DLLs with PGO.
'chrome_pgo_phase%': '0',
+ # Whether the VS xtree header has been patched to disable warning 4702. If
+ # it has, then we don't need to disable 4702 (unreachable code warning).
+ # The patch is preapplied to the internal toolchain and hence all bots.
+ 'msvs_xtree_patched%': '<!pymod_do_main(win_is_xtree_patched)',
+
# Clang stuff.
'clang%': '<(clang)',
'host_clang%': '<(host_clang)',
@@ -1565,7 +1570,7 @@
['OS=="win" and "<!pymod_do_main(dir_exists <(windows_sdk_default_path))"=="True"', {
'windows_sdk_path%': '<(windows_sdk_default_path)',
}, {
- 'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.0',
+ 'windows_sdk_path%': 'C:/Program Files (x86)/Windows Kits/8.1',
}],
['OS=="win" and "<!pymod_do_main(dir_exists <(directx_sdk_default_path))"=="True"', {
'directx_sdk_path%': '<(directx_sdk_default_path)',
@@ -1944,13 +1949,6 @@
},{
'msvs_large_module_debug_link_mode%': '2', # Yes
}],
- ['MSVS_VERSION=="2013e"', {
- 'msvs_express%': 1,
- 'secure_atl%': 0,
- },{
- 'msvs_express%': 0,
- 'secure_atl%': 1,
- }],
],
'nacl_win64_defines': [
# This flag is used to minimize dependencies when building
@@ -2785,7 +2783,7 @@
'_SCL_SECURE_NO_DEPRECATE',
# This define is required to pull in the new Win8 interfaces from
# system headers like ShObjIdl.h.
- 'NTDDI_VERSION=0x06020000',
+ 'NTDDI_VERSION=0x06030000',
# This is required for ATL to use XP-safe versions of its functions.
'_USING_V110_SDK71_',
],
@@ -5259,8 +5257,8 @@
['OS=="win"', {
'target_defaults': {
'defines': [
- '_WIN32_WINNT=0x0602',
- 'WINVER=0x0602',
+ '_WIN32_WINNT=0x0603',
+ 'WINVER=0x0603',
'WIN32',
'_WINDOWS',
'NOMINMAX',
@@ -5269,8 +5267,12 @@
'CERT_CHAIN_PARA_HAS_EXTRA_FIELDS',
'WIN32_LEAN_AND_MEAN',
'_ATL_NO_OPENGL',
+ '_SECURE_ATL',
# _HAS_EXCEPTIONS must match ExceptionHandling in msvs_settings.
'_HAS_EXCEPTIONS=0',
+ # Silence some warnings; we can't switch the the 'recommended'
+ # versions as they're not available on old OSs.
+ '_WINSOCK_DEPRECATED_NO_WARNINGS',
],
'conditions': [
['buildtype=="Official"', {
@@ -5338,66 +5340,12 @@
],
},
],
- ['secure_atl', {
- 'defines': [
- '_SECURE_ATL',
- ],
- }],
- ['msvs_express', {
- 'configurations': {
- 'x86_Base': {
- 'msvs_settings': {
- 'VCLinkerTool': {
- 'AdditionalLibraryDirectories':
- ['<(windows_driver_kit_path)/lib/ATL/i386'],
- },
- 'VCLibrarianTool': {
- 'AdditionalLibraryDirectories':
- ['<(windows_driver_kit_path)/lib/ATL/i386'],
- },
- },
- },
- 'x64_Base': {
- 'msvs_settings': {
- 'VCLibrarianTool': {
- 'AdditionalLibraryDirectories':
- ['<(windows_driver_kit_path)/lib/ATL/amd64'],
- },
- 'VCLinkerTool': {
- 'AdditionalLibraryDirectories':
- ['<(windows_driver_kit_path)/lib/ATL/amd64'],
- },
- },
- },
- },
- # https://code.google.com/p/chromium/issues/detail?id=372451#c20
- # Warning 4702 ("Unreachable code") should be re-enabled once
- # Express users are updated to VS2013 Update 2.
+ ['msvs_xtree_patched!=1', {
+ # If xtree hasn't been patched, then we disable C4702. Otherwise,
+ # it's enabled. This will generally only be true for system-level
+ # installed Express users.
'msvs_disabled_warnings': [
- 4702
- ],
- 'msvs_settings': {
- 'VCCLCompilerTool': {
- 'AdditionalOptions!': [
- '/Zc:inline', # Not supported on non-updated Express.
- ],
- },
- 'VCLinkerTool': {
- # Explicitly required when using the ATL with express
- 'AdditionalDependencies': ['atlthunk.lib'],
-
- # ATL 8.0 included in WDK 7.1 makes the linker to generate
- # almost eight hundred LNK4254 and LNK4078 warnings:
- # - warning LNK4254: section 'ATL' (50000040) merged into
- # '.rdata' (40000040) with different attributes
- # - warning LNK4078: multiple 'ATL' sections found with
- # different attributes
- 'AdditionalOptions': ['/ignore:4254', '/ignore:4078'],
- },
- },
- 'msvs_system_include_dirs': [
- '<(windows_driver_kit_path)/inc/atl71',
- '<(windows_driver_kit_path)/inc/mfc42',
+ 4702,
],
}],
],
@@ -5463,6 +5411,7 @@
4510, # Default constructor could not be generated
4512, # Assignment operator could not be generated
4610, # Object can never be instantiated
+ 4996, # 'X': was declared deprecated (for GetVersionEx).
],
'msvs_settings': {
'VCCLCompilerTool': {
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index c9ec4a2..0d65c44 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -34,15 +34,6 @@
# to configure warnings.
is_clang = (os == "mac" || os == "ios" || os == "linux" || os == "chromeos")
- # Forces a 64-bit build on Windows. Does nothing on other platforms. Normally
- # we build 32-bit on Windows regardless of the current host OS bit depth.
- # Setting this flag will override this logic and generate 64-bit toolchains.
- #
- # Normally this would get set automatically when you specify a target using
- # the 64-bit toolchain. You can also set this on the command line to convert
- # the default toolchain to 64-bit.
- force_win64 = false
-
# Selects the desired build flavor. Official builds get additional
# processing to prepare for release. Normally you will want to develop and
# test with this flag off.
@@ -174,16 +165,6 @@
# CPU ARCHITECTURE
# =============================================================================
-if (is_win) {
- # Always use 32-bit on Windows, even when compiling on a 64-bit host OS,
- # unless the override flag is specified.
- if (force_win64) {
- cpu_arch = "x64"
- } else {
- cpu_arch = "x86"
- }
-}
-
if (is_android) {
# TODO(cjhopman): enable this assert once bots are updated to not set
# cpu_arch.
@@ -495,19 +476,14 @@
# default toolchain.
if (is_win) {
- # TODO(brettw) name the toolchains the same as cpu_arch as with Linux below
- # to eliminate these conditionals.
- if (build_cpu_arch == "x64") {
+ # On windows we use the same toolchain for host and target by default.
+ # TODO(dpranke): rename the toolchains to x64 and x86 to match cpu_arch.
+ if (cpu_arch == "x64") {
host_toolchain = "//build/toolchain/win:64"
- } else if (build_cpu_arch == "x86") {
+ } else if (cpu_arch == "x86") {
host_toolchain = "//build/toolchain/win:32"
}
-
- if (cpu_arch == "x64") {
- set_default_toolchain("//build/toolchain/win:64")
- } else if (cpu_arch == "x86") {
- set_default_toolchain("//build/toolchain/win:32")
- }
+ set_default_toolchain("$host_toolchain")
} else if (is_android) {
# Use clang for the x86/64 Linux host builds.
if (build_cpu_arch == "x86" || build_cpu_arch == "x64") {
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index d6711b8..7120bac 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -55,134 +55,6 @@
}
-# Write the target's .build_config file. This is a json file that contains a
-# dictionary of information about how to build this target (things that
-# require knowledge about this target's dependencies and cannot be calculated
-# at gn-time). There is a special syntax to add a value in that dictionary to
-# an action/action_foreachs args:
-# --python-arg=@FileArg($rebased_build_config_path:key0:key1)
-# At runtime, such an arg will be replaced by the value in the build_config.
-# See build/android/gyp/write_build_config.py and
-# build/android/gyp/util/build_utils.py:ExpandFileArgs
-template("write_build_config") {
- if (defined(invoker.testonly)) { testonly = invoker.testonly }
-
- assert(defined(invoker.type))
- assert(defined(invoker.build_config))
-
- type = invoker.type
- build_config = invoker.build_config
-
- assert(type == "android_apk" || type == "android_library" || type == "android_resources")
-
- action(target_name) {
- script = "//build/android/gyp/write_build_config.py"
- depfile = "$target_gen_dir/$target_name.d"
- inputs = []
-
- deps = []
- if (defined(invoker.deps)) {
- deps += invoker.deps
- }
-
- possible_deps_configs = []
- foreach(d, deps) {
- dep_gen_dir = get_label_info(d, "target_gen_dir")
- dep_name = get_label_info(d, "name")
- possible_deps_configs += [ "$dep_gen_dir/$dep_name.build_config" ]
- }
- rebase_possible_deps_configs = rebase_path(possible_deps_configs)
-
- outputs = [
- depfile,
- build_config
- ]
-
- args = [
- "--type", type,
- "--depfile", rebase_path(depfile, root_build_dir),
- "--possible-deps-configs=$rebase_possible_deps_configs",
- "--build-config", rebase_path(build_config, root_build_dir),
- ]
-
- if (type == "android_library" || type == "android_apk") {
- args += [
- "--jar-path", rebase_path(invoker.jar_path, root_build_dir),
- "--dex-path", rebase_path(invoker.dex_path, root_build_dir),
- ]
- }
-
- if (type == "android_resources" || type == "android_apk") {
- assert(defined(invoker.resources_zip))
- args += [
- "--resources-zip", rebase_path(invoker.resources_zip, root_build_dir),
- ]
- if (defined(invoker.android_manifest)) {
- inputs += [
- invoker.android_manifest
- ]
- args += [
- "--android-manifest", rebase_path(invoker.android_manifest, root_build_dir),
- ]
- }
- if (defined(invoker.custom_package)) {
- args += [
- "--package-name", invoker.custom_package
- ]
- }
- }
-
- if (type == "android_apk") {
- if (defined(invoker.native_libs)) {
- rebased_native_libs = rebase_path(invoker.native_libs, root_build_dir)
- rebased_android_readelf = rebase_path(android_readelf, root_build_dir)
- args += [
- "--native-libs=$rebased_native_libs",
- "--readelf-path=$rebased_android_readelf",
- ]
- }
- }
-
- if (defined(invoker.srcjar)) {
- args += [
- "--srcjar", rebase_path(invoker.srcjar, root_build_dir)
- ]
- }
- }
-}
-
-
-# Creates a zip archive of the inputs.
-# If base_dir is provided, the archive paths will be relative to it.
-template("zip") {
- if (defined(invoker.testonly)) { testonly = invoker.testonly }
-
- assert(defined(invoker.inputs))
- assert(defined(invoker.output))
-
- rebase_inputs = rebase_path(invoker.inputs, root_build_dir)
- rebase_output = rebase_path(invoker.output, root_build_dir)
- action(target_name) {
- script = "//build/android/gn/zip.py"
- depfile = "$target_gen_dir/$target_name.d"
- inputs = invoker.inputs
- outputs = [
- depfile,
- invoker.output
- ]
- args = [
- "--depfile", rebase_path(depfile, root_build_dir),
- "--inputs=$rebase_inputs",
- "--output=$rebase_output",
- ]
- if (defined(invoker.base_dir)) {
- args += [
- "--base-dir", rebase_path(invoker.base_dir, root_build_dir)
- ]
- }
- }
-}
-
template("dex") {
if (defined(invoker.testonly)) { testonly = invoker.testonly }
@@ -223,6 +95,234 @@
}
}
+
+# Creates a zip archive of the inputs.
+# If base_dir is provided, the archive paths will be relative to it.
+template("zip") {
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+
+ assert(defined(invoker.inputs))
+ assert(defined(invoker.output))
+
+ rebase_inputs = rebase_path(invoker.inputs, root_build_dir)
+ rebase_output = rebase_path(invoker.output, root_build_dir)
+ action(target_name) {
+ script = "//build/android/gn/zip.py"
+ depfile = "$target_gen_dir/$target_name.d"
+ inputs = invoker.inputs
+ outputs = [
+ depfile,
+ invoker.output
+ ]
+ args = [
+ "--depfile", rebase_path(depfile, root_build_dir),
+ "--inputs=$rebase_inputs",
+ "--output=$rebase_output",
+ ]
+ if (defined(invoker.base_dir)) {
+ args += [
+ "--base-dir", rebase_path(invoker.base_dir, root_build_dir)
+ ]
+ }
+ }
+}
+
+
+# Write the target's .build_config file. This is a json file that contains a
+# dictionary of information about how to build this target (things that
+# require knowledge about this target's dependencies and cannot be calculated
+# at gn-time). There is a special syntax to add a value in that dictionary to
+# an action/action_foreachs args:
+# --python-arg=@FileArg($rebased_build_config_path:key0:key1)
+# At runtime, such an arg will be replaced by the value in the build_config.
+# See build/android/gyp/write_build_config.py and
+# build/android/gyp/util/build_utils.py:ExpandFileArgs
+template("write_build_config") {
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+
+ assert(defined(invoker.type))
+ assert(defined(invoker.build_config))
+
+ type = invoker.type
+ build_config = invoker.build_config
+
+ assert(type == "android_apk" || type == "java_library" || type == "android_resources")
+
+ action(target_name) {
+ script = "//build/android/gyp/write_build_config.py"
+ depfile = "$target_gen_dir/$target_name.d"
+ inputs = []
+
+ deps = []
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
+ }
+
+ possible_deps_configs = []
+ foreach(d, deps) {
+ dep_gen_dir = get_label_info(d, "target_gen_dir")
+ dep_name = get_label_info(d, "name")
+ possible_deps_configs += [ "$dep_gen_dir/$dep_name.build_config" ]
+ }
+ rebase_possible_deps_configs = rebase_path(possible_deps_configs)
+
+ outputs = [
+ depfile,
+ build_config
+ ]
+
+ args = [
+ "--type", type,
+ "--depfile", rebase_path(depfile, root_build_dir),
+ "--possible-deps-configs=$rebase_possible_deps_configs",
+ "--build-config", rebase_path(build_config, root_build_dir),
+ ]
+
+ is_java_library = type == "java_library"
+ is_apk = type == "android_apk"
+ is_android_resources = type == "android_resources"
+
+ supports_android = (is_apk || is_android_resources ||
+ (is_java_library && defined(invoker.supports_android) &&
+ invoker.supports_android))
+ requires_android = (is_apk || is_android_resources ||
+ (is_java_library && defined(invoker.requires_android) &&
+ invoker.requires_android))
+
+ assert(!requires_android || supports_android, "requires_android requires" +
+ " supports_android")
+ # Mark these variables as used.
+ assert(is_java_library || true)
+ assert(is_apk || true)
+ assert(is_android_resources || true)
+
+ if (is_java_library || is_apk) {
+ args += [
+ "--jar-path", rebase_path(invoker.jar_path, root_build_dir),
+ ]
+ }
+
+ if (is_apk || (is_java_library && supports_android)) {
+ args += [
+ "--dex-path", rebase_path(invoker.dex_path, root_build_dir),
+ ]
+ }
+ if (supports_android) {
+ args += [ "--supports-android" ]
+ }
+ if (requires_android) {
+ args += [ "--requires-android" ]
+ }
+
+ if (is_android_resources || is_apk) {
+ assert(defined(invoker.resources_zip))
+ args += [
+ "--resources-zip", rebase_path(invoker.resources_zip, root_build_dir),
+ ]
+ if (defined(invoker.android_manifest)) {
+ inputs += [
+ invoker.android_manifest
+ ]
+ args += [
+ "--android-manifest", rebase_path(invoker.android_manifest, root_build_dir),
+ ]
+ }
+ if (defined(invoker.custom_package)) {
+ args += [
+ "--package-name", invoker.custom_package
+ ]
+ }
+ }
+
+ if (is_apk) {
+ if (defined(invoker.native_libs)) {
+ rebased_native_libs = rebase_path(invoker.native_libs, root_build_dir)
+ rebased_android_readelf = rebase_path(android_readelf, root_build_dir)
+ args += [
+ "--native-libs=$rebased_native_libs",
+ "--readelf-path=$rebased_android_readelf",
+ ]
+ }
+ }
+
+ if (defined(invoker.srcjar)) {
+ args += [
+ "--srcjar", rebase_path(invoker.srcjar, root_build_dir)
+ ]
+ }
+ }
+}
+
+
+template("process_java_prebuilt") {
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+
+ _input_jar_path = invoker.input_jar_path
+ _output_jar_path = invoker.output_jar_path
+ _jar_toc_path = _output_jar_path + ".TOC"
+
+ assert(invoker.build_config != "")
+
+ if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
+ _proguard_jar_path = "$android_sdk_root/tools/proguard/lib/proguard.jar"
+ _proguard_config_path = invoker.proguard_config
+ _build_config = invoker.build_config
+ _rebased_build_config = rebase_path(_build_config, root_build_dir)
+ action("${target_name}__proguard_process") {
+ script = "//build/android/gyp/proguard.py"
+ inputs = [
+ android_sdk_jar,
+ _proguard_jar_path,
+ _build_config,
+ _input_jar_path,
+ _proguard_config_path,
+ ]
+ depfile = "${target_gen_dir}/${target_name}.d"
+ outputs = [
+ depfile,
+ _output_jar_path,
+ ]
+ args = [
+ "--depfile", rebase_path(depfile, root_build_dir),
+ "--proguard-path", rebase_path(_proguard_jar_path, root_build_dir),
+ "--input-path", rebase_path(_input_jar_path, root_build_dir),
+ "--output-path", rebase_path(_output_jar_path, root_build_dir),
+ "--proguard-config", rebase_path(_proguard_config_path, root_build_dir),
+ "--classpath", rebased_android_sdk_jar,
+ "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
+ ]
+ }
+ } else {
+ copy("${target_name}__copy_jar") {
+ sources = [_input_jar_path]
+ outputs = [_output_jar_path]
+ }
+ }
+
+ action("${target_name}__jar_toc") {
+ script = "//build/android/gyp/jar_toc.py"
+ depfile = "$target_gen_dir/$target_name.d"
+ outputs = [
+ depfile,
+ _jar_toc_path,
+ _jar_toc_path + ".md5.stamp"
+ ]
+ inputs = [ _output_jar_path ]
+ args = [
+ "--depfile", rebase_path(depfile, root_build_dir),
+ "--jar-path", rebase_path(_output_jar_path, root_build_dir),
+ "--toc-path", rebase_path(_jar_toc_path, root_build_dir),
+ ]
+ }
+
+ group(target_name) {
+ deps = [
+ ":${target_name}__jar_toc"
+ ]
+ }
+}
+
+
# Packages resources, assets, dex, and native libraries into an apk. Signs and
# zipaligns the apk.
template("create_apk") {
@@ -379,74 +479,68 @@
}
}
-template("java_prebuilt") {
+template("java_prebuilt_impl") {
if (defined(invoker.testonly)) { testonly = invoker.testonly }
+ _supports_android = (
+ defined(invoker.supports_android) && invoker.supports_android)
- _input_jar_path = invoker.input_jar_path
- _output_jar_path = invoker.output_jar_path
- _jar_toc_path = _output_jar_path + ".TOC"
+ assert(defined(invoker.jar_path))
+ _base_path = "${target_gen_dir}/$target_name"
+ _jar_path = _base_path + ".jar"
+ _build_config = _base_path + ".build_config"
- assert(invoker.build_config != "")
+ if (_supports_android) {
+ _dex_path = _base_path + ".dex.jar"
+ }
- if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
- _proguard_jar_path = "$android_sdk_root/tools/proguard/lib/proguard.jar"
- _proguard_config_path = invoker.proguard_config
- _build_config = invoker.build_config
- _rebased_build_config = rebase_path(_build_config, root_build_dir)
- action("${target_name}__proguard_process") {
- script = "//build/android/gyp/proguard.py"
- inputs = [
- android_sdk_jar,
- _proguard_jar_path,
- _build_config,
- _input_jar_path,
- _proguard_config_path,
- ]
- depfile = "${target_gen_dir}/${target_name}.d"
- outputs = [
- depfile,
- _output_jar_path,
- ]
- args = [
- "--depfile", rebase_path(depfile, root_build_dir),
- "--proguard-path", rebase_path(_proguard_jar_path, root_build_dir),
- "--input-path", rebase_path(_input_jar_path, root_build_dir),
- "--output-path", rebase_path(_output_jar_path, root_build_dir),
- "--proguard-config", rebase_path(_proguard_config_path, root_build_dir),
- "--classpath", rebased_android_sdk_jar,
- "--classpath=@FileArg($_rebased_build_config:javac:classpath)",
- ]
+ _final_deps = []
+ _template_name = target_name
+
+
+ _final_deps += [ ":${_template_name}__build_config" ]
+ write_build_config("${_template_name}__build_config") {
+ type = "java_library"
+ supports_android = _supports_android
+ requires_android = (defined(invoker.requires_android) &&
+ invoker.requires_android)
+
+ deps = []
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
}
- } else {
- copy("${target_name}__copy_jar") {
- sources = [_input_jar_path]
- outputs = [_output_jar_path]
+ build_config = _build_config
+ jar_path = _jar_path
+ if (_supports_android) {
+ dex_path = _dex_path
}
}
- action("${target_name}__jar_toc") {
- script = "//build/android/gyp/jar_toc.py"
- depfile = "$target_gen_dir/$target_name.d"
- outputs = [
- depfile,
- _jar_toc_path,
- _jar_toc_path + ".md5.stamp"
- ]
- inputs = [ _output_jar_path ]
- args = [
- "--depfile", rebase_path(depfile, root_build_dir),
- "--jar-path", rebase_path(_output_jar_path, root_build_dir),
- "--toc-path", rebase_path(_jar_toc_path, root_build_dir),
- ]
+ _final_deps += [ ":${_template_name}__process_jar" ]
+ process_java_prebuilt("${_template_name}__process_jar") {
+ if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
+ proguard_preprocess = true
+ proguard_config = invoker.proguard_config
+ }
+
+ build_config = _build_config
+ input_jar_path = invoker.jar_path
+ output_jar_path = _jar_path
+ }
+
+ if (_supports_android) {
+ _final_deps += [ ":${_template_name}__dex" ]
+ dex("${_template_name}__dex") {
+ sources = [_jar_path]
+ output = _dex_path
+ }
}
group(target_name) {
- deps = [
- ":${target_name}__jar_toc"
- ]
+ deps = _final_deps
}
}
+
# Compiles and jars a set of java files.
#
# Outputs:
@@ -502,10 +596,20 @@
# Mark srcjar_deps as used.
assert(_srcjar_deps == [] || true)
- _system_jars = [ android_sdk_jar ]
- action("${target_name}__javac") {
+ _system_jars = []
+ if (defined(invoker.android) && invoker.android) {
+ _system_jars += [ android_sdk_jar ]
+ }
+
+ _rebased_build_config = rebase_path(_build_config, root_build_dir)
+ _rebased_jar_path = rebase_path(_intermediate_jar_path, root_build_dir)
+
+ _template_name = target_name
+ _final_deps = [ ":${_template_name}__javac" ]
+ action("${_template_name}__javac") {
script = "//build/android/gyp/javac.py"
depfile = "$target_gen_dir/$target_name.d"
+ deps = []
outputs = [
depfile,
_intermediate_jar_path,
@@ -516,9 +620,7 @@
_rebased_system_jars = rebase_path(_system_jars, root_build_dir)
_rebased_java_srcjars = rebase_path(_java_srcjars, root_build_dir)
- _rebased_build_config = rebase_path(_build_config, root_build_dir)
_rebased_depfile = rebase_path(depfile, root_build_dir)
- _rebased_jar_path = rebase_path(_intermediate_jar_path, root_build_dir)
args = [
"--depfile=$_rebased_depfile",
"--classpath=$_rebased_system_jars",
@@ -529,13 +631,20 @@
"--jar-excluded-classes=$_jar_excluded_patterns",
]
if (_chromium_code) {
- args += [ "--chromium-code" ]
+ args += [ "--chromium-code=1" ]
+ }
+
+ if (defined(invoker.main_class)) {
+ args += [
+ "--main-class", invoker.main_class
+ ]
}
args += rebase_path(_java_files, root_build_dir)
}
- java_prebuilt("${target_name}__finish") {
+ _final_deps += [ ":${_template_name}__finish" ]
+ process_java_prebuilt("${_template_name}__finish") {
build_config = _build_config
input_jar_path = _intermediate_jar_path
output_jar_path = _final_jar_path
@@ -546,26 +655,68 @@
}
group(target_name) {
- deps = [
- ":${target_name}__javac",
- ":${target_name}__finish",
- ]
+ deps = _final_deps
}
}
-# This adds Android-specific parts to the java_library template.
-#
-# Runs Android lint against the compiled java files.
-# Dexes the output jar for inclusion in an APK.
-template("android_java_library") {
+template("java_library_impl") {
if (defined(invoker.testonly)) { testonly = invoker.testonly }
assert(defined(invoker.java_files) || defined(invoker.DEPRECATED_java_in_dir)
|| defined(invoker.srcjars) || defined(invoker.srcjar_deps))
- assert(defined(invoker.build_config))
- assert(defined(invoker.jar_path))
- assert(defined(invoker.dex_path))
+ _base_path = "$target_gen_dir/$target_name"
+ _jar_path = _base_path + ".jar"
+ if (defined(invoker.jar_path)) {
+ _jar_path = invoker.jar_path
+ }
+ _template_name = target_name
+
+ _final_deps = []
+ _final_datadeps = []
+ if (defined(invoker.datadeps)) {
+ _final_datadeps = invoker.datadeps
+ }
+
+ _supports_android = (defined(invoker.supports_android) &&
+ invoker.supports_android)
+ _requires_android = (defined(invoker.requires_android) &&
+ invoker.requires_android)
+
+ if (_supports_android) {
+ _dex_path = _base_path + ".dex.jar"
+ if (defined(invoker.dex_path)) {
+ _dex_path = invoker.dex_path
+ }
+ }
+
+ if (defined(invoker.override_build_config)) {
+ _build_config = invoker.override_build_config
+ } else {
+ _build_config = _base_path + ".build_config"
+ _final_deps += [ ":${_template_name}__build_config" ]
+ write_build_config("${_template_name}__build_config") {
+ type = "java_library"
+ supports_android = _supports_android
+ requires_android = _requires_android
+
+ deps = []
+ if (defined(invoker.deps)) {
+ deps += invoker.deps
+ }
+
+ build_config = _build_config
+ jar_path = _jar_path
+ if (_supports_android) {
+ dex_path = _dex_path
+ }
+ }
+ }
+
+ _chromium_code = true
+ if (defined(invoker.chromium_code)) {
+ _chromium_code = invoker.chromium_code
+ }
_srcjar_deps = []
if (defined(invoker.srcjar_deps)) {
@@ -602,60 +753,74 @@
}
assert(_java_files != [] || _srcjar_deps != [] || _srcjars != [])
- _jar_path = invoker.jar_path
- _dex_path = invoker.dex_path
-
- _android_manifest = "//build/android/AndroidManifest.xml"
- if (defined(invoker.android_manifest)) {
- _android_manifest = invoker.android_manifest
- }
- assert(_android_manifest != "")
-
- _final_deps = []
- _final_datadeps = []
-
- compile_java("${target_name}__compile_java") {
+ _final_deps += [ ":${_template_name}__compile_java" ]
+ compile_java("${_template_name}__compile_java") {
jar_path = _jar_path
- if (defined(invoker.jar_excluded_patterns)) {
- jar_excluded_patterns = invoker.jar_excluded_patterns
- }
- build_config = invoker.build_config
+ build_config = _build_config
java_files = _java_files
srcjar_deps = _srcjar_deps
srcjars = _srcjars
+ chromium_code = _chromium_code
+ android = _requires_android
- if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
- proguard_preprocess = invoker.proguard_preprocess
- proguard_config = invoker.proguard_config
- }
+ if (defined(invoker.jar_excluded_patterns)) { jar_excluded_patterns = invoker.jar_excluded_patterns }
+ if (defined(invoker.main_class)) { main_class = invoker.main_class }
+ if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess }
+ if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config }
+ if (defined(invoker.dist_jar_path)) { dist_jar_path = invoker.dist_jar_path }
+ }
- if (defined(invoker.dist_jar_path)) {
- dist_jar_path = invoker.dist_jar_path
+ if (defined(invoker.main_class)) {
+ _final_deps += [ ":${_template_name}__binary_script" ]
+ action("${_template_name}__binary_script") {
+ script = "//build/android/gyp/create_java_binary_script.py"
+ depfile = "$target_gen_dir/$target_name.d"
+ java_script = "$root_build_dir/bin/$_template_name"
+ inputs = [ _build_config ]
+ outputs = [
+ depfile,
+ java_script,
+ ]
+ _rebased_build_config = rebase_path(_build_config, root_build_dir)
+ args = [
+ "--depfile", rebase_path(depfile, root_build_dir),
+ "--output", rebase_path(java_script, root_build_dir),
+ "--classpath=@FileArg($_rebased_build_config:java:full_classpath)",
+ "--jar-path", rebase_path(_jar_path, root_build_dir),
+ "--main-class", invoker.main_class,
+ ]
}
}
- if (defined(invoker.chromium_code) && invoker.chromium_code) {
- _final_datadeps += [ ":${target_name}__lint" ]
- android_lint("${target_name}__lint") {
- android_manifest = _android_manifest
- jar_path = _jar_path
- java_files = _java_files
- }
- }
+ if (_supports_android) {
+ if (defined(invoker.chromium_code) && invoker.chromium_code) {
+ _android_manifest = "//build/android/AndroidManifest.xml"
+ if (defined(invoker.android_manifest)) {
+ _android_manifest = invoker.android_manifest
+ }
- dex("${target_name}__dex") {
- sources = [_jar_path]
- output = _dex_path
+ _final_datadeps += [ ":${_template_name}__lint" ]
+ android_lint("${_template_name}__lint") {
+ android_manifest = _android_manifest
+ jar_path = _jar_path
+ java_files = _java_files
+ }
+ }
+
+ _final_deps += [ ":${_template_name}__dex" ]
+ dex("${_template_name}__dex") {
+ sources = [_jar_path]
+ output = _dex_path
+ }
}
group(target_name) {
- deps = [
- ":${target_name}__compile_java",
- ":${target_name}__dex",
- ] + _final_deps + _final_datadeps
+ deps = _final_deps
+ datadeps = _final_datadeps
}
}
+
# Runs process_resources.py
template("process_resources") {
if (defined(invoker.testonly)) { testonly = invoker.testonly }
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index d28c481..3f54c43 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -640,6 +640,153 @@
}
}
+# Declare a Java executable target
+#
+# This target creates an executable from java code and libraries. The executable
+# will be in the output folder's /bin/ directory.
+#
+# Variables
+# deps: Specifies the dependencies of this target. Java targets in this list
+# will be included in the executable (and the javac classpath).
+#
+# java_files: List of .java files included in this library.
+# srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
+# will be added to java_files and be included in this library.
+# srcjars: List of srcjars to be included in this library, together with the
+# ones obtained from srcjar_deps.
+#
+# chromium_code: If true, extra analysis warning/errors will be enabled.
+#
+# datadeps, testonly
+#
+# Example
+# java_library("foo") {
+# java_files = [ "org/chromium/foo/FooMain.java" ]
+# deps = [ ":bar_java" ]
+# main_class = "org.chromium.foo.FooMain"
+# }
+template("java_binary") {
+ # TODO(cjhopman): This should not act like a java_library for dependents (i.e.
+ # dependents shouldn't get the jar in their classpath, etc.).
+ java_library_impl(target_name) {
+ if (defined(invoker.DEPRECATED_java_in_dir)) { DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir }
+ if (defined(invoker.chromium_code)) { chromium_code = invoker.chromium_code }
+ if (defined(invoker.datadeps)) { deps = invoker.datadeps }
+ if (defined(invoker.deps)) { deps = invoker.deps }
+ if (defined(invoker.java_files)) { java_files = invoker.java_files }
+ if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps }
+ if (defined(invoker.srcjars)) { srcjars = invoker.srcjars }
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+
+ main_class = invoker.main_class
+ }
+}
+
+
+# Declare an java library target
+#
+# Variables
+# deps: Specifies the dependencies of this target. Java targets in this list
+# will be added to the javac classpath.
+#
+# java_files: List of .java files included in this library.
+# srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
+# will be added to java_files and be included in this library.
+# srcjars: List of srcjars to be included in this library, together with the
+# ones obtained from srcjar_deps.
+# DEPRECATED_java_in_dir: Directory containing java files. All .java files in
+# this directory will be included in the library. This is only supported to
+# ease the gyp->gn conversion and will be removed in the future.
+#
+# chromium_code: If true, extra analysis warning/errors will be enabled.
+# jar_excluded_patterns: List of patterns of .class files to exclude from the
+# final jar.
+#
+# proguard_preprocess: If true, proguard preprocessing will be run. This can
+# be used to remove unwanted parts of the library.
+# proguard_config: Path to the proguard config for preprocessing.
+#
+# supports_android: If true, Android targets (android_library, android_apk)
+# may depend on this target. Note: if true, this target must only use the
+# subset of Java available on Android.
+# requires_android_platform: If true, this library may depend on
+# android-specific targets. If this is the case, there should be some
+# android-platform-like implementation available at runtime (Android,
+# robolectric, etc).
+#
+# datadeps, testonly
+#
+# Example
+# java_library("foo_java") {
+# java_files = [
+# "org/chromium/foo/Foo.java",
+# "org/chromium/foo/FooInterface.java",
+# "org/chromium/foo/FooService.java",
+# ]
+# deps = [
+# ":bar_java"
+# ]
+# srcjar_deps = [
+# ":foo_generated_enum"
+# ]
+# jar_excluded_patterns = [
+# "*/FooService.class", "*/FooService##*.class"
+# ]
+# }
+template("java_library") {
+ java_library_impl(target_name) {
+ if (defined(invoker.DEPRECATED_java_in_dir)) { DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir }
+ if (defined(invoker.chromium_code)) { chromium_code = invoker.chromium_code }
+ if (defined(invoker.datadeps)) { deps = invoker.datadeps }
+ if (defined(invoker.deps)) { deps = invoker.deps }
+ if (defined(invoker.jar_excluded_patterns)) { jar_excluded_patterns = invoker.jar_excluded_patterns }
+ if (defined(invoker.java_files)) { java_files = invoker.java_files }
+ if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config }
+ if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess }
+ if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps }
+ if (defined(invoker.srcjars)) { srcjars = invoker.srcjars }
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+ if (defined(invoker.jar_path)) { jar_path = invoker.jar_path }
+
+ if (defined(invoker.supports_android) && invoker.supports_android) {
+ supports_android = true
+ }
+ if (defined(invoker.requires_android_platform)
+ && invoker.requires_android_platform) {
+ supports_android = true
+ requires_android = true
+ }
+ }
+}
+
+
+# Declare an java library target for a prebuilt jar
+#
+# Variables
+# deps: Specifies the dependencies of this target. Java targets in this list
+# will be added to the javac classpath.
+# jar_path: Path to the prebuilt jar.
+# proguard_preprocess: If true, proguard preprocessing will be run. This can
+# be used to remove unwanted parts of the library.
+# proguard_config: Path to the proguard config for preprocessing.
+#
+# Example
+# java_prebuilt("foo_java") {
+# jar_path = "foo.jar"
+# deps = [
+# ":foo_resources",
+# ":bar_java"
+# ]
+# }
+template("java_prebuilt") {
+ java_prebuilt_impl(target_name) {
+ jar_path = invoker.jar_path
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+ if (defined(invoker.deps)) { deps = invoker.deps }
+ if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config }
+ if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess }
+ }
+}
# Declare an Android library target
#
@@ -650,21 +797,24 @@
# deps: Specifies the dependencies of this target. Java targets in this list
# will be added to the javac classpath. Android resources in dependencies
# will be used when building this library.
+#
# java_files: List of .java files included in this library.
# srcjar_deps: List of srcjar dependencies. The .java files in the srcjars
# will be added to java_files and be included in this library.
# srcjars: List of srcjars to be included in this library, together with the
# ones obtained from srcjar_deps.
+# DEPRECATED_java_in_dir: Directory containing java files. All .java files in
+# this directory will be included in the library. This is only supported to
+# ease the gyp->gn conversion and will be removed in the future.
+#
# chromium_code: If true, extra analysis warning/errors will be enabled.
# jar_excluded_patterns: List of patterns of .class files to exclude from the
# final jar.
+#
# proguard_preprocess: If true, proguard preprocessing will be run. This can
# be used to remove unwanted parts of the library.
# proguard_config: Path to the proguard config for preprocessing.
#
-# DEPRECATED_java_in_dir: Directory containing java files. All .java files in
-# this directory will be included in the library. This is only supported to
-# ease the gyp->gn conversion and will be removed in the future.
#
# Example
# android_library("foo_java") {
@@ -684,133 +834,33 @@
# ]
# }
template("android_library") {
- if (defined(invoker.testonly)) { testonly = invoker.testonly }
+ assert(!defined(invoker.jar_path),
+ "android_library does not support a custom jar path")
+ java_library_impl(target_name) {
+ if (defined(invoker.DEPRECATED_java_in_dir)) { DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir }
+ if (defined(invoker.chromium_code)) { chromium_code = invoker.chromium_code }
+ if (defined(invoker.datadeps)) { deps = invoker.datadeps }
+ if (defined(invoker.deps)) { deps = invoker.deps }
+ if (defined(invoker.jar_excluded_patterns)) { jar_excluded_patterns = invoker.jar_excluded_patterns }
+ if (defined(invoker.java_files)) { java_files = invoker.java_files }
+ if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config }
+ if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess }
+ if (defined(invoker.srcjar_deps)) { srcjar_deps = invoker.srcjar_deps }
+ if (defined(invoker.srcjars)) { srcjars = invoker.srcjars }
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+ if (defined(invoker.dex_path)) { dex_path = invoker.dex_path }
- assert(defined(invoker.java_files) || defined(invoker.DEPRECATED_java_in_dir)
- || defined(invoker.srcjars) || defined(invoker.srcjar_deps))
- _base_path = "$target_gen_dir/$target_name"
- _build_config = _base_path + ".build_config"
- _jar_path = _base_path + ".jar"
- if (defined(invoker.dex_path)) {
- _dex_path = invoker.dex_path
- } else {
- _dex_path = _base_path + ".dex.jar"
- }
+ supports_android = true
+ requires_android = true
- write_build_config("${target_name}__build_config") {
- type = "android_library"
-
- deps = []
- if (defined(invoker.deps)) {
- deps += invoker.deps
- }
-
- build_config = _build_config
- jar_path = _jar_path
- dex_path = _dex_path
- }
-
- _chromium_code = true
- if (defined(invoker.chromium_code)) {
- _chromium_code = invoker.chromium_code
- }
-
- android_java_library(target_name) {
- chromium_code = _chromium_code
- if (defined(invoker.java_files)) {
- java_files = invoker.java_files
- } else if (defined(invoker.DEPRECATED_java_in_dir)) {
- DEPRECATED_java_in_dir = invoker.DEPRECATED_java_in_dir
- }
- build_config = _build_config
- jar_path = _jar_path
- dex_path = _dex_path
-
- if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
- proguard_preprocess = true
- proguard_config = invoker.proguard_config
- }
-
- jar_excluded_patterns = [
+ if (!defined(jar_excluded_patterns)) { jar_excluded_patterns = [] }
+ jar_excluded_patterns += [
"*/R.class", "*/R##*.class",
"*/Manifest.class", "*/Manifest##*.class",
]
- if (defined(invoker.jar_excluded_patterns)) {
- jar_excluded_patterns += invoker.jar_excluded_patterns
- }
-
- if (defined(invoker.srcjar_deps)) {
- srcjar_deps = invoker.srcjar_deps
- }
- if (defined(invoker.srcjars)) {
- srcjars = invoker.srcjars
- }
}
}
-template("java_library") {
- if (defined(invoker.testonly)) { testonly = invoker.testonly }
-
- assert(defined(invoker.java_files) || defined(invoker.DEPRECATED_java_in_dir)
- || defined(invoker.srcjars))
-
- _srcjar_deps = []
- if (defined(invoker.srcjar_deps)) {
- _srcjar_deps = invoker.srcjar_deps
- }
-
- _srcjars = []
- if (defined(invoker.srcjars)) {
- _srcjars = invoker.srcjars
- }
-
- _java_files = []
- if (defined(invoker.java_files)) {
- _java_files = invoker.java_files
- } else if (defined(invoker.DEPRECATED_java_in_dir)) {
- _src_dir = invoker.DEPRECATED_java_in_dir + "/src"
- _src_dir_exists = exec_script("//build/dir_exists.py",
- [ rebase_path(_src_dir, root_build_dir) ],
- "string")
- assert(_src_dir_exists == "False",
- "In GN, java_in_dir should be the fully specified java directory " +
- "(i.e. including the trailing \"/src\")")
-
- _java_files_build_rel = exec_script(
- "//build/android/gyp/find.py",
- [
- "--pattern",
- "*.java",
- rebase_path(invoker.DEPRECATED_java_in_dir, root_build_dir)
- ],
- "list lines"
- )
- _java_files = rebase_path(_java_files_build_rel, ".", root_build_dir)
- }
- assert(_java_files != [] || _srcjar_deps != [] || _srcjars != [])
-
- # TODO(cjhopman): Write a proper build config so that java library
- # dependencies work correctly.
- _build_config = "$target_gen_dir/$target_name.build_config"
- write_file(
- _build_config,
- "{ \"javac\": { \"classpath\": [], \"srcjars\": [] } }")
-
- _jar_path = "$root_build_dir/lib.java/$target_name.jar"
- if (defined(invoker.jar_path)) {
- _jar_path = invoker.jar_path
- }
-
- compile_java(target_name) {
- build_config = _build_config
- jar_path = _jar_path
- java_files = _java_files
- srcjar_deps = _srcjar_deps
- srcjars = _srcjars
- }
-}
-
-
# Declare an Android library target for a prebuilt jar
#
# This target creates an Android library containing java code and Android
@@ -834,47 +884,14 @@
# ]
# }
template("android_java_prebuilt") {
- if (defined(invoker.testonly)) { testonly = invoker.testonly }
-
- assert(defined(invoker.jar_path))
- _base_path = "${target_gen_dir}/$target_name"
- _jar_path = _base_path + ".jar"
- _dex_path = _base_path + ".dex.jar"
- _build_config = _base_path + ".build_config"
-
- write_build_config("${target_name}__build_config") {
- type = "android_library"
-
- deps = []
- if (defined(invoker.deps)) {
- deps += invoker.deps
- }
- build_config = _build_config
- jar_path = _jar_path
- dex_path = _dex_path
- }
-
- java_prebuilt("${target_name}__process_jar") {
- if (defined(invoker.proguard_preprocess) && invoker.proguard_preprocess) {
- proguard_preprocess = true
- proguard_config = invoker.proguard_config
- }
-
- build_config = _build_config
- input_jar_path = invoker.jar_path
- output_jar_path = _jar_path
- }
-
- dex("${target_name}__dex") {
- sources = [_jar_path]
- output = _dex_path
- }
-
- group(target_name) {
- deps = [
- ":${target_name}__build_config",
- ":${target_name}__dex",
- ]
+ java_prebuilt_impl(target_name) {
+ jar_path = invoker.jar_path
+ supports_android = true
+ requires_android = true
+ if (defined(invoker.testonly)) { testonly = invoker.testonly }
+ if (defined(invoker.deps)) { deps = invoker.deps }
+ if (defined(invoker.proguard_config)) { proguard_config = invoker.proguard_config }
+ if (defined(invoker.proguard_preprocess)) { proguard_preprocess = invoker.proguard_preprocess }
}
}
@@ -934,7 +951,7 @@
assert(defined(invoker.final_apk_path) || defined(invoker.apk_name))
gen_dir = "$target_gen_dir/$target_name"
base_path = "$gen_dir/$target_name"
- build_config = "$base_path.build_config"
+ _build_config = "$base_path.build_config"
resources_zip_path = "$base_path.resources.zip"
all_resources_zip_path = "$base_path.resources.all.zip"
jar_path = "$base_path.jar"
@@ -993,7 +1010,10 @@
" Chromium linker.")
}
- _native_libs = invoker.native_libs
+ _native_libs = process_file_template(
+ invoker.native_libs,
+ "$root_build_dir/lib.stripped/{{source_file_part}}")
+
_native_libs_dir = base_path + "/libs"
if (_use_chromium_linker) {
@@ -1009,12 +1029,13 @@
}
}
- _rebased_build_config = rebase_path(build_config, root_build_dir)
+ _rebased_build_config = rebase_path(_build_config, root_build_dir)
write_build_config("${_template_name}__build_config") {
type = "android_apk"
dex_path = final_dex_path
resources_zip = resources_zip_path
+ build_config = _build_config
if (defined(invoker.deps)) {
deps = invoker.deps
@@ -1032,6 +1053,7 @@
resource_dirs = ["//build/android/ant/empty/res"]
zip_path = resources_zip_path
generate_constant_ids = true
+ build_config = _build_config
}
_srcjar_deps += [":${_template_name}__process_resources"]
@@ -1049,7 +1071,7 @@
"//base/android/java/templates/NativeLibraries.template",
]
inputs = [
- build_config,
+ _build_config,
]
defines = [
@@ -1071,8 +1093,12 @@
}
final_deps += [ ":${_template_name}__java" ]
- android_java_library("${_template_name}__java") {
+ java_library_impl("${_template_name}__java") {
+ supports_android = true
+ requires_android = true
+ override_build_config = _build_config
android_manifest = invoker.android_manifest
+ chromium_code = true
if (defined(invoker.java_files)) {
java_files = invoker.java_files
} else if (defined(invoker.DEPRECATED_java_in_dir)) {
@@ -1092,7 +1118,7 @@
action("${_template_name}__create_dist_jar") {
script = "//build/android/gyp/create_dist_jar.py"
depfile = "$target_gen_dir/$target_name.d"
- inputs = [ build_config ]
+ inputs = [ _build_config ]
outputs = [
depfile,
_dist_jar_path,
@@ -1114,7 +1140,7 @@
dex("${_template_name}__final_dex") {
deps = [ ":${_template_name}__java" ]
sources = [ jar_path ]
- inputs = [ build_config ]
+ inputs = [ _build_config ]
output = final_dex_path
dex_arg_key = "${_rebased_build_config}:apk_dex:dependency_dex_files"
args = [ "--inputs=@FileArg($dex_arg_key)" ]
@@ -1129,7 +1155,7 @@
depfile
]
inputs = [
- build_config
+ _build_config
]
deps = []
skip_packing_list = [
@@ -1220,10 +1246,9 @@
# resource dependencies of the apk.
# unittests_dep: This should be the label of the gtest native target. This
# target must be defined previously in the same file.
-# unittests_binary: The name of the binary produced by the unittests_dep
-# target, relative to the root build directory. If unspecified, it assumes
-# the name of the unittests_dep target (which will be correct unless that
-# target specifies an "output_name".
+# unittests_binary: The basename of the library produced by the unittests_dep
+# target. If unspecified, it assumes the name of the unittests_dep target
+# (which will be correct unless that target specifies an "output_name".
# TODO(brettw) make this automatic by allowing get_target_outputs to
# support executables.
#
@@ -1240,9 +1265,9 @@
test_suite_name = get_label_info(invoker.unittests_dep, "name")
if (defined(invoker.unittests_binary)) {
- unittests_binary = root_out_dir + "/" + invoker.unittests_binary
+ unittests_binary = invoker.unittests_binary
} else {
- unittests_binary = root_out_dir + "/lib.stripped/lib" + test_suite_name + ".so"
+ unittests_binary = "lib" + test_suite_name + ".so"
}
android_apk(target_name) {
@@ -1252,8 +1277,7 @@
"//testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java"
]
android_manifest = "//testing/android/java/AndroidManifest.xml"
- unittests_outputs = [ unittests_binary ]
- native_libs = [unittests_outputs[0]]
+ native_libs = [ unittests_binary ]
deps = [ "//base:base_java" ]
if (defined(invoker.deps)) {
deps += invoker.deps
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 8487338..0d9e501 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -690,6 +690,7 @@
# Warnings to evaluate and possibly fix/reenable later:
"/wd4100", # Unreferenced formal function parameter.
+ "/wd4121", # Alignment of a member was sensitive to packing.
"/wd4189", # A variable was declared and initialized but never used.
"/wd4244", # Conversion: possible loss of data.
"/wd4481", # Nonstandard extension: override specifier.
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index c3aa915..58e310f 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -13,7 +13,7 @@
"_ATL_NO_OPENGL",
"_WINDOWS",
"CERT_CHAIN_PARA_HAS_EXTRA_FIELDS",
- "NTDDI_VERSION=0x06020000",
+ "NTDDI_VERSION=0x06030000",
"PSAPI_VERSION=1",
"WIN32",
]
@@ -35,8 +35,8 @@
# targets need to manually override it for their compiles.
config("winver") {
defines = [
- "_WIN32_WINNT=0x0602",
- "WINVER=0x0602",
+ "_WIN32_WINNT=0x0603",
+ "WINVER=0x0603",
]
}
diff --git a/build/get_landmines.py b/build/get_landmines.py
index 1eec5ee..2c3b3d7 100755
--- a/build/get_landmines.py
+++ b/build/get_landmines.py
@@ -48,6 +48,7 @@
gyp_msvs_version().startswith('2013')):
print "Switched win from VS2010 to VS2013."
print "Update to VS2013 Update 2."
+ print "Update to VS2013 Update 4."
print 'Need to clobber everything due to an IDL change in r154579 (blink)'
print 'Need to clobber everything due to gen file moves in r175513 (Blink)'
if (platform() != 'ios'):
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 1775f86..8ee6083 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -307,6 +307,9 @@
// http://crbug.com/425057
"deadlock:webrtc::ViEChannelManagerScoped::ViEChannelManagerScoped\n"
+// https://crbug.com/433993
+"deadlock:content::WebRtcAudioDeviceImpl\n"
+
// End of suppressions.
; // Please keep this semicolon.
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index a9fab7c..988683d 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -24,7 +24,6 @@
# Parameters:
# cpu_arch: cpu_arch to pass as a build arg
# environment: File name of environment file.
-# force_win64 (optional): value for this build arg.
template("msvc_toolchain") {
if (defined(invoker.concurrent_links)) {
concurrent_links = invoker.concurrent_links
@@ -32,6 +31,16 @@
env = invoker.environment
+ if (is_debug) {
+ configuration = "Debug"
+ } else {
+ configuration = "Release"
+ }
+ exec_script("../../vs_toolchain.py", ["copy_dlls",
+ rebase_path(root_build_dir),
+ configuration,
+ invoker.cpu_arch])
+
toolchain(target_name) {
# Make these apply to all tools below.
lib_switch = ""
@@ -154,23 +163,24 @@
# passed to the build. They are ignored when this is the default toolchain.
toolchain_args() {
cpu_arch = invoker.cpu_arch
-
- # Normally the build config resets the CPU architecture to 32-bits. Setting
- # this flag overrides that behavior.
- if (defined(invoker.force_win64)) {
- force_win64 = invoker.force_win64
- }
}
}
}
-msvc_toolchain("32") {
- environment = "environment.x86"
- cpu_arch = "x64"
+# TODO(dpranke): Declare both toolchains all of the time when we
+# get it sorted out how we want to support them both in a single build.
+# Right now only one of these can be enabled at a time because the
+# runtime libraries get copied to root_build_dir and would collide.
+if (cpu_arch == "x86") {
+ msvc_toolchain("32") {
+ environment = "environment.x86"
+ cpu_arch = "x86"
+ }
}
-msvc_toolchain("64") {
- environment = "environment.x64"
- cpu_arch = "x64"
- force_win64 = true
+if (cpu_arch == "x64") {
+ msvc_toolchain("64") {
+ environment = "environment.x64"
+ cpu_arch = "x64"
+ }
}
diff --git a/build/toolchain_vs2013.hash b/build/toolchain_vs2013.hash
index 9a81029..4ed8816 100644
--- a/build/toolchain_vs2013.hash
+++ b/build/toolchain_vs2013.hash
@@ -1 +1 @@
-ee7d718ec60c2dc5d255bbe325909c2021a7efef
\ No newline at end of file
+ee7d718ec60c2dc5d255bbe325909c2021a7efef
diff --git a/build/util/lastchange.py b/build/util/lastchange.py
index 28a266d..d1c33e8 100755
--- a/build/util/lastchange.py
+++ b/build/util/lastchange.py
@@ -108,7 +108,7 @@
if not hsh:
return None
pos = ''
- proc = RunGitCommand(directory, ['show', '-s', '--format=%B', 'HEAD'])
+ proc = RunGitCommand(directory, ['cat-file', 'commit', 'HEAD'])
if proc:
output = proc.communicate()[0]
if proc.returncode == 0 and output:
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index f68ba52..a490a2c 100644
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -63,6 +63,29 @@
return vs2013_runtime_dll_dirs
+def _CopyRuntimeImpl(target, source):
+ """Copy |source| to |target| if it doesn't already exist or if it
+ needs to be updated.
+ """
+ if (os.path.isdir(os.path.dirname(target)) and
+ (not os.path.isfile(target) or
+ os.stat(target).st_mtime != os.stat(source).st_mtime)):
+ print 'Copying %s to %s...' % (source, target)
+ if os.path.exists(target):
+ os.unlink(target)
+ shutil.copy2(source, target)
+
+
+def _CopyRuntime(target_dir, source_dir, dll_pattern):
+ """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
+ exist, but the target directory does exist."""
+ for which in ('p', 'r'):
+ dll = dll_pattern % which
+ target = os.path.join(target_dir, dll)
+ source = os.path.join(source_dir, dll)
+ _CopyRuntimeImpl(target, source)
+
+
def CopyVsRuntimeDlls(output_dir, runtime_dirs):
"""Copies the VS runtime DLLs from the given |runtime_dirs| to the output
directory so that even if not system-installed, built binaries are likely to
@@ -73,27 +96,6 @@
"""
assert sys.platform.startswith(('win32', 'cygwin'))
- def copy_runtime_impl(target, source):
- """Copy |source| to |target| if it doesn't already exist or if it need to be
- updated.
- """
- if (os.path.isdir(os.path.dirname(target)) and
- (not os.path.isfile(target) or
- os.stat(target).st_mtime != os.stat(source).st_mtime)):
- print 'Copying %s to %s...' % (source, target)
- if os.path.exists(target):
- os.unlink(target)
- shutil.copy2(source, target)
-
- def copy_runtime(target_dir, source_dir, dll_pattern):
- """Copy both the msvcr and msvcp runtime DLLs, only if the target doesn't
- exist, but the target directory does exist."""
- for which in ('p', 'r'):
- dll = dll_pattern % which
- target = os.path.join(target_dir, dll)
- source = os.path.join(source_dir, dll)
- copy_runtime_impl(target, source)
-
x86, x64 = runtime_dirs
out_debug = os.path.join(output_dir, 'Debug')
out_debug_nacl64 = os.path.join(output_dir, 'Debug', 'x64')
@@ -106,12 +108,12 @@
os.makedirs(out_debug_nacl64)
if os.path.exists(out_release) and not os.path.exists(out_release_nacl64):
os.makedirs(out_release_nacl64)
- copy_runtime(out_debug, x86, 'msvc%s120d.dll')
- copy_runtime(out_release, x86, 'msvc%s120.dll')
- copy_runtime(out_debug_x64, x64, 'msvc%s120d.dll')
- copy_runtime(out_release_x64, x64, 'msvc%s120.dll')
- copy_runtime(out_debug_nacl64, x64, 'msvc%s120d.dll')
- copy_runtime(out_release_nacl64, x64, 'msvc%s120.dll')
+ _CopyRuntime(out_debug, x86, 'msvc%s120d.dll')
+ _CopyRuntime(out_release, x86, 'msvc%s120.dll')
+ _CopyRuntime(out_debug_x64, x64, 'msvc%s120d.dll')
+ _CopyRuntime(out_release_x64, x64, 'msvc%s120.dll')
+ _CopyRuntime(out_debug_nacl64, x64, 'msvc%s120d.dll')
+ _CopyRuntime(out_release_nacl64, x64, 'msvc%s120.dll')
# Copy the PGO runtime library to the release directories.
if os.environ.get('GYP_MSVS_OVERRIDE_PATH'):
@@ -121,11 +123,31 @@
pgo_runtime_dll = 'pgort120.dll'
source_x86 = os.path.join(pgo_x86_runtime_dir, pgo_runtime_dll)
if os.path.exists(source_x86):
- copy_runtime_impl(os.path.join(out_release, pgo_runtime_dll), source_x86)
+ _CopyRuntimeImpl(os.path.join(out_release, pgo_runtime_dll), source_x86)
source_x64 = os.path.join(pgo_x64_runtime_dir, pgo_runtime_dll)
if os.path.exists(source_x64):
- copy_runtime_impl(os.path.join(out_release_x64, pgo_runtime_dll),
- source_x64)
+ _CopyRuntimeImpl(os.path.join(out_release_x64, pgo_runtime_dll),
+ source_x64)
+
+
+def CopyDlls(target_dir, configuration, cpu_arch):
+ """Copy the VS runtime DLLs into the requested directory as needed.
+
+ configuration is one of 'Debug' or 'Release'.
+ cpu_arch is one of 'x86' or 'x64'.
+
+ The debug configuration gets both the debug and release DLLs; the
+ release config only the latter.
+ """
+ vs2013_runtime_dll_dirs = SetEnvironmentAndGetRuntimeDllDirs()
+ if not vs2013_runtime_dll_dirs:
+ return
+
+ x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
+ runtime_dir = x64_runtime if cpu_arch == 'x64' else x86_runtime
+ _CopyRuntime(target_dir, runtime_dir, 'msvc%s120.dll')
+ if configuration == 'Debug':
+ _CopyRuntime(target_dir, runtime_dir, 'msvc%s120d.dll')
def _GetDesiredVsToolchainHashes():
@@ -187,13 +209,12 @@
commands = {
'update': Update,
'get_toolchain_dir': GetToolchainDir,
- # TODO(scottmg): Add copy_dlls for GN builds (gyp_chromium calls
- # CopyVsRuntimeDlls via import, currently).
+ 'copy_dlls': CopyDlls,
}
if len(sys.argv) < 2 or sys.argv[1] not in commands:
print >>sys.stderr, 'Expected one of: %s' % ', '.join(commands)
return 1
- return commands[sys.argv[1]]()
+ return commands[sys.argv[1]](*sys.argv[2:])
if __name__ == '__main__':
diff --git a/build/win_is_xtree_patched.py b/build/win_is_xtree_patched.py
new file mode 100755
index 0000000..5717322
--- /dev/null
+++ b/build/win_is_xtree_patched.py
@@ -0,0 +1,26 @@
+#!/usr/bin/env python
+# 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.
+
+"""Determines if the VS xtree header has been patched to disable C4702."""
+
+import os
+
+
+def IsPatched():
+ # TODO(scottmg): For now, just return if we're using the packaged toolchain
+ # script (because we know it's patched). Another case could be added here to
+ # query the active VS installation and actually check the contents of xtree.
+ # http://crbug.com/346399.
+ return os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1) == 0
+
+
+def DoMain(_):
+ """Hook to be called from gyp without starting a separate python
+ interpreter."""
+ return IsPatched()
+
+
+if __name__ == '__main__':
+ print DoMain([])
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 3b3ed6d..ab3aab4 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -534,6 +534,7 @@
"test/fake_picture_layer_impl.h",
"test/fake_picture_layer_tiling_client.cc",
"test/fake_picture_layer_tiling_client.h",
+ "test/fake_picture_pile.cc",
"test/fake_picture_pile.h",
"test/fake_picture_pile_impl.cc",
"test/fake_picture_pile_impl.h",
diff --git a/cc/PRESUBMIT.py b/cc/PRESUBMIT.py
index 46c3a54..71c4ea1 100644
--- a/cc/PRESUBMIT.py
+++ b/cc/PRESUBMIT.py
@@ -11,7 +11,7 @@
import re
import string
-CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$',)
+CC_SOURCE_FILES=(r'^cc/.*\.(cc|h)$', r'^cc\\.*\.(cc|h)$')
def CheckChangeLintsClean(input_api, output_api):
input_api.cpplint._cpplint_state.ResetErrorCounts() # reset global state
@@ -21,10 +21,6 @@
input_api.AffectedSourceFiles(source_filter)]
level = 1 # strict, but just warn
- # TODO(danakj): Temporary, while the OVERRIDE and FINAL fixup is in progress.
- # crbug.com/422353
- input_api.cpplint._SetFilters('-readability/inheritance')
-
for file_name in files:
input_api.cpplint.ProcessFile(file_name, level)
diff --git a/cc/base/delayed_unique_notifier_unittest.cc b/cc/base/delayed_unique_notifier_unittest.cc
index 3e41d32..f30834e 100644
--- a/cc/base/delayed_unique_notifier_unittest.cc
+++ b/cc/base/delayed_unique_notifier_unittest.cc
@@ -35,7 +35,7 @@
public:
DelayedUniqueNotifierTest() : notification_count_(0) {}
- virtual void SetUp() override {
+ void SetUp() override {
notification_count_ = 0;
task_runner_ = make_scoped_refptr(new base::TestSimpleTaskRunner);
}
diff --git a/cc/base/unique_notifier_unittest.cc b/cc/base/unique_notifier_unittest.cc
index 0ba9892..dfab85e 100644
--- a/cc/base/unique_notifier_unittest.cc
+++ b/cc/base/unique_notifier_unittest.cc
@@ -17,7 +17,7 @@
public:
UniqueNotifierTest() : notification_count_(0) {}
- virtual void SetUp() override { ResetNotificationCount(); }
+ void SetUp() override { ResetNotificationCount(); }
void Notify() { ++notification_count_; }
diff --git a/cc/blink/web_external_bitmap_impl.h b/cc/blink/web_external_bitmap_impl.h
index 7dbfab3..2d2d8ce 100644
--- a/cc/blink/web_external_bitmap_impl.h
+++ b/cc/blink/web_external_bitmap_impl.h
@@ -28,9 +28,9 @@
virtual ~WebExternalBitmapImpl();
// blink::WebExternalBitmap implementation.
- virtual blink::WebSize size() override;
- virtual void setSize(blink::WebSize size) override;
- virtual uint8* pixels() override;
+ blink::WebSize size() override;
+ void setSize(blink::WebSize size) override;
+ uint8* pixels() override;
base::SharedMemory* shared_memory() { return shared_memory_.get(); }
diff --git a/cc/blink/web_layer_impl_fixed_bounds.h b/cc/blink/web_layer_impl_fixed_bounds.h
index 099feaf..edfd4bb 100644
--- a/cc/blink/web_layer_impl_fixed_bounds.h
+++ b/cc/blink/web_layer_impl_fixed_bounds.h
@@ -24,13 +24,13 @@
virtual ~WebLayerImplFixedBounds();
// WebLayerImpl overrides.
- virtual void invalidateRect(const blink::WebRect& rect) override;
- virtual void setTransformOrigin(
+ void invalidateRect(const blink::WebRect& rect) override;
+ void setTransformOrigin(
const blink::WebFloatPoint3D& transform_origin) override;
- virtual void setBounds(const blink::WebSize& bounds) override;
- virtual blink::WebSize bounds() const override;
- virtual void setTransform(const SkMatrix44& transform) override;
- virtual SkMatrix44 transform() const override;
+ void setBounds(const blink::WebSize& bounds) override;
+ blink::WebSize bounds() const override;
+ void setTransform(const SkMatrix44& transform) override;
+ SkMatrix44 transform() const override;
CC_BLINK_EXPORT void SetFixedBounds(gfx::Size bounds);
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index db58318..d4a031f 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -170,6 +170,7 @@
'test/fake_picture_layer_impl.h',
'test/fake_picture_layer_tiling_client.cc',
'test/fake_picture_layer_tiling_client.h',
+ 'test/fake_picture_pile.cc',
'test/fake_picture_pile.h',
'test/fake_picture_pile_impl.cc',
'test/fake_picture_pile_impl.h',
diff --git a/cc/debug/micro_benchmark_controller_unittest.cc b/cc/debug/micro_benchmark_controller_unittest.cc
index a5683c4..31494ac 100644
--- a/cc/debug/micro_benchmark_controller_unittest.cc
+++ b/cc/debug/micro_benchmark_controller_unittest.cc
@@ -21,7 +21,7 @@
MicroBenchmarkControllerTest()
: layer_tree_host_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
- virtual void SetUp() override {
+ void SetUp() override {
impl_proxy_ = make_scoped_ptr(new FakeImplProxy);
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
layer_tree_host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(
@@ -32,7 +32,7 @@
layer_tree_host_->InitializeForTesting(scoped_ptr<Proxy>(new FakeProxy));
}
- virtual void TearDown() override {
+ void TearDown() override {
layer_tree_host_impl_ = nullptr;
layer_tree_host_ = nullptr;
impl_proxy_ = nullptr;
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index 07058d0..7009c4a 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -99,10 +99,6 @@
return base_client_->CreateTile(tiling, content_rect);
}
- RasterSource* GetRasterSource() override {
- return base_client_->GetRasterSource();
- }
-
gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override {
return base_client_->CalculateTileSize(content_bounds);
}
@@ -217,10 +213,10 @@
FixedInvalidationPictureLayerTilingClient client(
layer, gfx::Rect(layer->content_bounds()));
- PictureLayerTilingSet tiling_set(&client);
+ auto tiling_set = PictureLayerTilingSet::Create(&client);
PictureLayerTiling* tiling =
- tiling_set.AddTiling(layer->contents_scale_x(), layer->bounds());
+ tiling_set->AddTiling(layer->contents_scale_x(), layer->bounds());
tiling->CreateAllTilesForTesting();
for (PictureLayerTiling::CoverageIterator it(
tiling, layer->contents_scale_x(), layer->visible_content_rect());
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index 193454c..17ec668 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -6,6 +6,7 @@
#define CC_DEBUG_RENDERING_STATS_H_
#include <list>
+#include <vector>
#include "base/basictypes.h"
#include "base/debug/trace_event_argument.h"
diff --git a/cc/debug/ring_buffer.h b/cc/debug/ring_buffer.h
index 94d8459..f9a6749 100644
--- a/cc/debug/ring_buffer.h
+++ b/cc/debug/ring_buffer.h
@@ -12,9 +12,7 @@
template<typename T, size_t kSize>
class RingBuffer {
public:
- explicit RingBuffer()
- : current_index_(0) {
- }
+ RingBuffer() : current_index_(0) {}
size_t BufferSize() const {
return kSize;
diff --git a/cc/layers/delegated_frame_provider_unittest.cc b/cc/layers/delegated_frame_provider_unittest.cc
index 5ba92bf..454bf7d 100644
--- a/cc/layers/delegated_frame_provider_unittest.cc
+++ b/cc/layers/delegated_frame_provider_unittest.cc
@@ -62,12 +62,12 @@
false);
}
- virtual void SetUp() override {
+ void SetUp() override {
resource_collection_ = new DelegatedFrameResourceCollection;
resource_collection_->SetClient(this);
}
- virtual void TearDown() override { resource_collection_->SetClient(nullptr); }
+ void TearDown() override { resource_collection_->SetClient(nullptr); }
void UnusedResourcesAreAvailable() override {
resources_available_ = true;
diff --git a/cc/layers/delegated_frame_resource_collection_unittest.cc b/cc/layers/delegated_frame_resource_collection_unittest.cc
index 3e95823..f91fe63 100644
--- a/cc/layers/delegated_frame_resource_collection_unittest.cc
+++ b/cc/layers/delegated_frame_resource_collection_unittest.cc
@@ -21,9 +21,9 @@
protected:
DelegatedFrameResourceCollectionTest() : resources_available_(false) {}
- virtual void SetUp() override { CreateResourceCollection(); }
+ void SetUp() override { CreateResourceCollection(); }
- virtual void TearDown() override { DestroyResourceCollection(); }
+ void TearDown() override { DestroyResourceCollection(); }
void CreateResourceCollection() {
DCHECK(!resource_collection_.get());
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc
index c61f2c2..7745d90 100644
--- a/cc/layers/layer_impl_unittest.cc
+++ b/cc/layers/layer_impl_unittest.cc
@@ -5,6 +5,7 @@
#include "cc/layers/layer_impl.h"
#include "cc/layers/painted_scrollbar_layer_impl.h"
+#include "cc/layers/solid_color_scrollbar_layer_impl.h"
#include "cc/output/filter_operation.h"
#include "cc/output/filter_operations.h"
#include "cc/test/fake_impl_proxy.h"
@@ -14,6 +15,7 @@
#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
+#include "cc/trees/tree_synchronizer.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
@@ -736,5 +738,131 @@
EXPECT_EQ(scroll_offset.x(), horizontal_scrollbar->current_pos());
}
+class LayerImplScrollbarSyncTest : public testing::Test {
+ public:
+ enum {
+ ROOT = 1,
+ IV_CLIP = 2,
+ PAGE = 3,
+ IV_SCROLL = 4,
+ SCROLLBAR = 5,
+ OLD_ROOT = 6,
+ OV_CLIP = 7,
+ OV_SCROLL = 8,
+ };
+ enum TreeID {
+ PENDING,
+ ACTIVE
+ };
+
+ LayerImplScrollbarSyncTest()
+ : host_impl_(settings(), &proxy_, &shared_bitmap_manager_) {
+ host_impl_.CreatePendingTree();
+
+ CreateLayers(host_impl_.pending_tree());
+ CreateLayers(host_impl_.active_tree());
+ }
+
+ void CreateLayers(LayerTreeImpl * tree) {
+ tree->SetRootLayer(LayerImpl::Create(tree, ROOT));
+ LayerImpl * root = tree->root_layer();
+ ASSERT_TRUE(root != nullptr);
+
+ int hierarchy[] = {IV_CLIP, PAGE, IV_SCROLL, OLD_ROOT, OV_CLIP, OV_SCROLL};
+ LayerImpl * parent = root;
+ for (int child_id : hierarchy) {
+ parent->AddChild(LayerImpl::Create(tree, child_id));
+ parent = tree->LayerById(child_id);
+ ASSERT_TRUE(parent != nullptr);
+ }
+
+ root->AddChild(
+ SolidColorScrollbarLayerImpl::Create(tree, SCROLLBAR, HORIZONTAL,
+ 5, 5, false, true));
+ }
+
+ LayerImpl* layer(int id, TreeID tree_id) {
+ LayerTreeImpl* tree =
+ ((tree_id == PENDING) ?
+ host_impl_.pending_tree() : host_impl_.active_tree());
+
+ assert(tree);
+ return tree->LayerById(id);
+ }
+
+ bool LayerHasScrollbar(int id, TreeID tree_id) {
+ return layer(id, tree_id)->HasScrollbar(HORIZONTAL);
+ }
+
+ ScrollbarLayerImplBase* pending_scrollbar() {
+ LayerImpl* layer_impl = layer(SCROLLBAR, PENDING);
+ assert(layer_impl);
+ return layer_impl->ToScrollbarLayer();
+ }
+
+ LayerImpl* pending_root() {
+ LayerImpl * result = layer(ROOT, PENDING);
+ assert(result);
+ return result;
+ }
+
+ LayerImpl* active_root() {
+ LayerImpl * result = layer(ROOT, ACTIVE);
+ assert(result);
+ return result;
+ }
+
+ LayerTreeSettings settings() {
+ LayerTreeSettings settings;
+ settings.use_pinch_virtual_viewport = true;
+ return settings;
+ }
+
+ private:
+ FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
+ FakeLayerTreeHostImpl host_impl_;
+};
+
+TEST_F(LayerImplScrollbarSyncTest, LayerImplBecomesScrollable) {
+ // In the beginning IV_SCROLL layer is not scrollable.
+ ASSERT_FALSE(layer(IV_SCROLL, PENDING)->scrollable());
+
+ // For pinch virtual viewport the clip layer is the inner viewport
+ // clip layer (IV_CLIP) and the scroll one is the outer viewport
+ // scroll layer (OV_SCROLL).
+ pending_scrollbar()->SetScrollLayerAndClipLayerByIds(OV_SCROLL, IV_CLIP);
+
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, PENDING));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, PENDING));
+
+ // Synchronize with the active tree.
+ TreeSynchronizer::PushProperties(pending_root(), active_root());
+
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, ACTIVE));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, ACTIVE));
+
+ // Make IV_SCROLL layer scrollable.
+ layer(IV_SCROLL, PENDING)->SetScrollClipLayer(IV_CLIP);
+ layer(IV_SCROLL, PENDING)->SetNeedsPushProperties();
+ ASSERT_TRUE(layer(IV_SCROLL, PENDING)->scrollable());
+
+ pending_scrollbar()->SetScrollLayerAndClipLayerByIds(OV_SCROLL, IV_CLIP);
+
+ // Now IV_CLIP layer should also receive the scrollbar.
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, PENDING));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, PENDING));
+ ASSERT_TRUE(LayerHasScrollbar(IV_SCROLL, PENDING));
+
+ // Synchronize with the active tree.
+ TreeSynchronizer::PushProperties(pending_root(), active_root());
+
+ ASSERT_TRUE(layer(IV_SCROLL, ACTIVE)->scrollable());
+
+ ASSERT_TRUE(LayerHasScrollbar(OV_SCROLL, ACTIVE));
+ ASSERT_TRUE(LayerHasScrollbar(IV_CLIP, ACTIVE));
+ ASSERT_TRUE(LayerHasScrollbar(IV_SCROLL, ACTIVE));
+}
+
} // namespace
} // namespace cc
diff --git a/cc/layers/layer_perftest.cc b/cc/layers/layer_perftest.cc
index f42e228..0b4c852 100644
--- a/cc/layers/layer_perftest.cc
+++ b/cc/layers/layer_perftest.cc
@@ -37,13 +37,13 @@
kTimeCheckInterval) {}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
layer_tree_host_->InitializeSingleThreaded(
&fake_client_, base::MessageLoopProxy::current(), nullptr);
}
- virtual void TearDown() override {
+ void TearDown() override {
layer_tree_host_->SetRootLayer(nullptr);
layer_tree_host_ = nullptr;
}
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 246a658..4dfe86a 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -64,11 +64,11 @@
fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
protected:
- virtual void SetUp() override {
+ void SetUp() override {
layer_tree_host_.reset(new StrictMock<MockLayerTreeHost>(&fake_client_));
}
- virtual void TearDown() override {
+ void TearDown() override {
Mock::VerifyAndClearExpectations(layer_tree_host_.get());
EXPECT_CALL(*layer_tree_host_, SetNeedsFullTreeSync()).Times(AnyNumber());
parent_ = nullptr;
diff --git a/cc/layers/layer_utils.h b/cc/layers/layer_utils.h
index 396f070..bef37f4 100644
--- a/cc/layers/layer_utils.h
+++ b/cc/layers/layer_utils.h
@@ -8,21 +8,21 @@
#include "cc/base/cc_export.h"
namespace gfx {
- class BoxF;
+class BoxF;
} // namespace gfx
namespace cc {
- class LayerImpl;
+class LayerImpl;
- class CC_EXPORT LayerUtils {
- public:
- // Computes a box in screen space that should entirely contain the layer's
- // bounds through the entirety of the layer's current animation. Returns
- // true and sets |out| to the inflation if there are animations that can
- // inflate bounds in the path to the root layer and that it was able to
- // inflate correctly. Returns false otherwise.
- static bool GetAnimationBounds(const LayerImpl& layer, gfx::BoxF* out);
- };
+class CC_EXPORT LayerUtils {
+ public:
+ // Computes a box in screen space that should entirely contain the layer's
+ // bounds through the entirety of the layer's current animation. Returns
+ // true and sets |out| to the inflation if there are animations that can
+ // inflate bounds in the path to the root layer and that it was able to
+ // inflate correctly. Returns false otherwise.
+ static bool GetAnimationBounds(const LayerImpl& layer, gfx::BoxF* out);
+};
} // namespace cc
diff --git a/cc/layers/layer_utils_unittest.cc b/cc/layers/layer_utils_unittest.cc
index 1eb1986..5764bc6 100644
--- a/cc/layers/layer_utils_unittest.cc
+++ b/cc/layers/layer_utils_unittest.cc
@@ -25,7 +25,7 @@
public:
LayerUtilsGetAnimationBoundsTest()
: host_impl_(&proxy_, &shared_bitmap_manager_),
- root_(CreateThreeNodeTree(host_impl_)),
+ root_(CreateThreeNodeTree(&host_impl_)),
parent_(root_->children()[0]),
child_(parent_->children()[0]) {}
@@ -35,11 +35,11 @@
private:
static scoped_ptr<LayerImpl> CreateThreeNodeTree(
- LayerTreeHostImpl& host_impl) {
- scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
- root->AddChild(LayerImpl::Create(host_impl.active_tree(), 2));
- root->children()[0]
- ->AddChild(LayerImpl::Create(host_impl.active_tree(), 3));
+ LayerTreeHostImpl* host_impl) {
+ scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl->active_tree(), 1);
+ root->AddChild(LayerImpl::Create(host_impl->active_tree(), 2));
+ root->children()[0]->AddChild(
+ LayerImpl::Create(host_impl->active_tree(), 3));
return root.Pass();
}
diff --git a/cc/layers/nine_patch_layer_impl.cc b/cc/layers/nine_patch_layer_impl.cc
index 1c76d11..0dd2b6f 100644
--- a/cc/layers/nine_patch_layer_impl.cc
+++ b/cc/layers/nine_patch_layer_impl.cc
@@ -207,14 +207,14 @@
uv_top.width(),
uv_left.height());
- // Nothing is opaque here.
- // TODO(danakj): Should we look at the SkBitmaps to determine opaqueness?
gfx::Rect opaque_rect;
gfx::Rect visible_rect;
const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const bool opaque = layer_tree_impl()->IsUIResourceOpaque(ui_resource_id_);
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_top_left);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -233,6 +233,7 @@
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_top_right);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -251,6 +252,7 @@
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_left);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -269,6 +271,7 @@
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom_right);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -286,6 +289,7 @@
}
visible_rect = occlusion_in_content_space.GetUnoccludedContentRect(layer_top);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -304,6 +308,7 @@
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_left);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -322,6 +327,7 @@
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_right);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -340,6 +346,7 @@
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_bottom);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -359,6 +366,7 @@
if (fill_center_) {
visible_rect =
occlusion_in_content_space.GetUnoccludedContentRect(layer_center);
+ opaque_rect = opaque ? visible_rect : gfx::Rect();
if (!visible_rect.IsEmpty()) {
TextureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
diff --git a/cc/layers/nine_patch_layer_impl_unittest.cc b/cc/layers/nine_patch_layer_impl_unittest.cc
index 695d827..f6262d3 100644
--- a/cc/layers/nine_patch_layer_impl_unittest.cc
+++ b/cc/layers/nine_patch_layer_impl_unittest.cc
@@ -271,5 +271,70 @@
}
}
+TEST(NinePatchLayerImplTest, OpaqueRect) {
+ gfx::Size layer_size(1000, 1000);
+ gfx::Size viewport_size(1000, 1000);
+
+ LayerTestCommon::LayerImplTest impl;
+
+ SkBitmap sk_bitmap_opaque;
+ sk_bitmap_opaque.allocN32Pixels(10, 10);
+ sk_bitmap_opaque.setImmutable();
+ sk_bitmap_opaque.setAlphaType(kOpaque_SkAlphaType);
+
+ UIResourceId uid_opaque = 6;
+ UIResourceBitmap bitmap_opaque(sk_bitmap_opaque);
+ impl.host_impl()->CreateUIResource(uid_opaque, bitmap_opaque);
+
+ SkBitmap sk_bitmap_alpha;
+ sk_bitmap_alpha.allocN32Pixels(10, 10);
+ sk_bitmap_alpha.setImmutable();
+ sk_bitmap_alpha.setAlphaType(kUnpremul_SkAlphaType);
+
+ UIResourceId uid_alpha = 7;
+ UIResourceBitmap bitmap_alpha(sk_bitmap_alpha);
+
+ impl.host_impl()->CreateUIResource(uid_alpha, bitmap_alpha);
+
+ NinePatchLayerImpl *nine_patch_layer_impl =
+ impl.AddChildToRoot<NinePatchLayerImpl>();
+ nine_patch_layer_impl->SetBounds(layer_size);
+ nine_patch_layer_impl->SetContentBounds(layer_size);
+ nine_patch_layer_impl->SetDrawsContent(true);
+
+ impl.CalcDrawProps(viewport_size);
+
+ {
+ SCOPED_TRACE("Use opaque image");
+
+ nine_patch_layer_impl->SetUIResourceId(uid_opaque);
+ nine_patch_layer_impl->SetImageBounds(gfx::Size(10, 10));
+
+ gfx::Rect aperture = gfx::Rect(3, 3, 4, 4);
+ gfx::Rect border = gfx::Rect(300, 300, 400, 400);
+ nine_patch_layer_impl->SetLayout(aperture, border, true);
+
+ impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
+
+ const QuadList &quad_list = impl.quad_list();
+ for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
+ it != quad_list.BackToFrontEnd(); ++it)
+ EXPECT_FALSE(it->ShouldDrawWithBlending());
+ }
+
+ {
+ SCOPED_TRACE("Use tranparent image");
+
+ nine_patch_layer_impl->SetUIResourceId(uid_alpha);
+
+ impl.AppendQuadsWithOcclusion(nine_patch_layer_impl, gfx::Rect());
+
+ const QuadList &quad_list = impl.quad_list();
+ for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
+ it != quad_list.BackToFrontEnd(); ++it)
+ EXPECT_TRUE(it->ShouldDrawWithBlending());
+ }
+}
+
} // namespace
} // namespace cc
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 5d45cae..029e99d 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -23,7 +23,14 @@
recording_source_(new PicturePile),
instrumentation_object_tracker_(id()),
update_source_frame_number_(-1),
- can_use_lcd_text_last_frame_(can_use_lcd_text()) {
+ can_use_lcd_text_last_frame_(can_use_lcd_text()),
+ is_mask_(false) {
+}
+
+PictureLayer::PictureLayer(ContentLayerClient* client,
+ scoped_ptr<RecordingSource> source)
+ : PictureLayer(client) {
+ recording_source_ = source.Pass();
}
PictureLayer::~PictureLayer() {
@@ -60,13 +67,18 @@
// See PictureLayerImpl::PushPropertiesTo for more details.
layer_impl->invalidation_.Clear();
layer_impl->invalidation_.Swap(&recording_invalidation_);
- layer_impl->UpdateRasterSource(recording_source_->CreateRasterSource());
+ layer_impl->set_is_mask(is_mask_);
+ scoped_refptr<RasterSource> raster_source =
+ recording_source_->CreateRasterSource();
+ raster_source->SetBackgoundColor(SafeOpaqueBackgroundColor());
+ raster_source->SetRequiresClear(!contents_opaque() &&
+ !client_->FillsBoundsCompletely());
+ layer_impl->UpdateRasterSource(raster_source);
}
void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
Layer::SetLayerTreeHost(host);
if (host) {
- // TODO(hendrikw): Perhaps use and initialization function to do this work.
recording_source_->SetMinContentsScale(
host->settings().minimum_contents_scale);
recording_source_->SetTileGridSize(host->settings().default_tile_grid_size);
@@ -129,10 +141,8 @@
// for them.
DCHECK(client_);
updated |= recording_source_->UpdateAndExpandInvalidation(
- client_, &recording_invalidation_, SafeOpaqueBackgroundColor(),
- contents_opaque(), client_->FillsBoundsCompletely(), layer_size,
- visible_layer_rect, update_source_frame_number_,
- Picture::RECORD_NORMALLY);
+ client_, &recording_invalidation_, layer_size, visible_layer_rect,
+ update_source_frame_number_, Picture::RECORD_NORMALLY);
last_updated_visible_content_rect_ = visible_content_rect();
if (updated) {
@@ -147,7 +157,7 @@
}
void PictureLayer::SetIsMask(bool is_mask) {
- recording_source_->SetIsMask(is_mask);
+ is_mask_ = is_mask;
}
bool PictureLayer::SupportsLCDText() const {
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 2969ee1..e4acb1f 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -45,6 +45,8 @@
protected:
explicit PictureLayer(ContentLayerClient* client);
+ // Allow tests to inject a recording source.
+ PictureLayer(ContentLayerClient* client, scoped_ptr<RecordingSource> source);
~PictureLayer() override;
bool HasDrawableContent() const override;
@@ -63,6 +65,7 @@
int update_source_frame_number_;
bool can_use_lcd_text_last_frame_;
+ bool is_mask_;
DISALLOW_COPY_AND_ASSIGN(PictureLayer);
};
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 6d89140..111a0e7 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -31,6 +31,8 @@
#include "ui/gfx/geometry/size_conversions.h"
namespace {
+// This must be > 1 as we multiply or divide by this to find a new raster
+// scale during pinch.
const float kMaxScaleRatioDuringPinch = 2.0f;
// When creating a new tiling during pinch, snap to an existing
@@ -85,7 +87,8 @@
was_screen_space_transform_animating_(false),
needs_post_commit_initialization_(true),
should_update_tile_priorities_(false),
- only_used_low_res_last_append_quads_(false) {
+ only_used_low_res_last_append_quads_(false),
+ is_mask_(false) {
layer_tree_impl()->RegisterPictureLayerImpl(this);
}
@@ -124,7 +127,7 @@
layer_impl->UpdateRasterSource(raster_source_);
- DCHECK(!raster_source_->IsSolidColor() || !tilings_->num_tilings());
+ DCHECK_IMPLIES(raster_source_->IsSolidColor(), tilings_->num_tilings() == 0);
// Tilings would be expensive to push, so we swap.
layer_impl->tilings_.swap(tilings_);
layer_impl->tilings_->SetClient(layer_impl);
@@ -472,7 +475,7 @@
UpdateIdealScales();
- DCHECK(tilings_->num_tilings() > 0 || raster_contents_scale_ == 0.f)
+ DCHECK_IMPLIES(tilings_->num_tilings() == 0, raster_contents_scale_ == 0.f)
<< "A layer with no tilings shouldn't have valid raster scales";
if (!raster_contents_scale_ || ShouldAdjustRasterScale()) {
RecalculateRasterScales();
@@ -498,47 +501,40 @@
void PictureLayerImpl::UpdateTilePriorities(
const Occlusion& occlusion_in_content_space) {
- DCHECK(!raster_source_->IsSolidColor() || !tilings_->num_tilings());
+ DCHECK_IMPLIES(raster_source_->IsSolidColor(), tilings_->num_tilings() == 0);
+
double current_frame_time_in_seconds =
(layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
base::TimeTicks()).InSecondsF();
-
gfx::Rect viewport_rect_in_layer_space =
GetViewportForTilePriorityInContentSpace();
- bool tiling_needs_update = false;
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- if (tilings_->tiling_at(i)->NeedsUpdateForFrameAtTimeAndViewport(
- current_frame_time_in_seconds, viewport_rect_in_layer_space)) {
- tiling_needs_update = true;
- break;
- }
- }
- if (!tiling_needs_update)
- return;
- WhichTree tree =
- layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+ // The tiling set can require tiles for activation any of the following
+ // conditions are true:
+ // - This layer produced a high-res or non-ideal-res tile last frame.
+ // - We're in requires high res to draw mode.
+ // - We're not in smoothness takes priority mode.
+ // To put different, the tiling set can't require tiles for activation if
+ // we're in smoothness mode and only used low-res or checkerboard to draw last
+ // frame and we don't need high res to draw.
+ //
+ // The reason for this is that we should be able to activate sooner and get a
+ // more up to date recording, so we don't run out of recording on the active
+ // tree.
bool can_require_tiles_for_activation =
!only_used_low_res_last_append_quads_ || RequiresHighResToDraw() ||
!layer_tree_impl()->SmoothnessTakesPriority();
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = tilings_->tiling_at(i);
- tiling->set_can_require_tiles_for_activation(
- can_require_tiles_for_activation);
+ // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
+ // they are the same space in picture layer, as contents scale is always 1.
+ bool updated = tilings_->UpdateTilePriorities(
+ viewport_rect_in_layer_space, ideal_contents_scale_,
+ current_frame_time_in_seconds, occlusion_in_content_space,
+ can_require_tiles_for_activation);
- // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
- // they are the same space in picture layer, as contents scale is always 1.
- tiling->ComputeTilePriorityRects(tree,
- viewport_rect_in_layer_space,
- ideal_contents_scale_,
- current_frame_time_in_seconds,
- occlusion_in_content_space);
- }
-
- // Tile priorities were modified.
// TODO(vmpstr): See if this can be removed in favour of calling it from LTHI
- layer_tree_impl()->DidModifyTilePriorities();
+ if (updated)
+ layer_tree_impl()->DidModifyTilePriorities();
}
gfx::Rect PictureLayerImpl::GetViewportForTilePriorityInContentSpace() const {
@@ -623,7 +619,7 @@
// memory savings that we can get. Note that we don't handle solid color
// masks, so we shouldn't bother analyzing those.
// Bugs: crbug.com/397198, crbug.com/396908
- if (!raster_source_->IsMask())
+ if (!is_mask_)
flags = Tile::USE_PICTURE_ANALYSIS;
return layer_tree_impl()->tile_manager()->CreateTile(
@@ -632,10 +628,6 @@
flags);
}
-RasterSource* PictureLayerImpl::GetRasterSource() {
- return raster_source_.get();
-}
-
const Region* PictureLayerImpl::GetPendingInvalidation() {
if (layer_tree_impl()->IsPendingTree())
return &invalidation_;
@@ -699,7 +691,7 @@
int max_texture_size =
layer_tree_impl()->resource_provider()->max_texture_size();
- if (raster_source_->IsMask()) {
+ if (is_mask_) {
// Masks are not tiled, so if we can't cover the whole mask with one tile,
// don't make any tiles at all. Returning an empty size signals this.
if (content_bounds.width() > max_texture_size ||
@@ -788,9 +780,9 @@
bool synced_high_res_tiling = false;
if (CanHaveTilings()) {
- synced_high_res_tiling =
- tilings_->SyncTilings(*other->tilings_, raster_source_->GetSize(),
- invalidation_, MinimumContentsScale());
+ synced_high_res_tiling = tilings_->SyncTilings(
+ *other->tilings_, raster_source_->GetSize(), invalidation_,
+ MinimumContentsScale(), raster_source_.get());
} else {
RemoveAllTilings();
}
@@ -865,7 +857,7 @@
DCHECK(layer_tree_impl()->IsPendingTree());
if (!tilings_)
- tilings_ = make_scoped_ptr(new PictureLayerTilingSet(this));
+ tilings_ = PictureLayerTilingSet::Create(this);
PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer();
if (twin_layer) {
@@ -1052,16 +1044,20 @@
// During pinch we completely ignore the current ideal scale, and just use
// a multiple of the previous scale.
- // TODO(danakj): This seems crazy, we should use the current ideal, no?
bool is_pinching = layer_tree_impl()->PinchGestureActive();
if (is_pinching && old_raster_contents_scale) {
// See ShouldAdjustRasterScale:
// - When zooming out, preemptively create new tiling at lower resolution.
// - When zooming in, approximate ideal using multiple of kMaxScaleRatio.
bool zooming_out = old_raster_page_scale > ideal_page_scale_;
- float desired_contents_scale =
- zooming_out ? old_raster_contents_scale / kMaxScaleRatioDuringPinch
- : old_raster_contents_scale * kMaxScaleRatioDuringPinch;
+ float desired_contents_scale = old_raster_contents_scale;
+ if (zooming_out) {
+ while (desired_contents_scale > ideal_contents_scale_)
+ desired_contents_scale /= kMaxScaleRatioDuringPinch;
+ } else {
+ while (desired_contents_scale < ideal_contents_scale_)
+ desired_contents_scale *= kMaxScaleRatioDuringPinch;
+ }
raster_contents_scale_ = SnappedContentsScale(desired_contents_scale);
raster_page_scale_ =
raster_contents_scale_ / raster_device_scale_ / raster_source_scale_;
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index b341bde..78b13fc 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -119,7 +119,6 @@
// PictureLayerTilingClient overrides.
scoped_refptr<Tile> CreateTile(PictureLayerTiling* tiling,
const gfx::Rect& content_rect) override;
- RasterSource* GetRasterSource() override;
gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override;
const Region* GetPendingInvalidation() override;
const PictureLayerTiling* GetPendingOrActiveTwinTiling(
@@ -139,6 +138,7 @@
// Mask-related functions.
void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
gfx::Size* resource_size) const override;
+ void set_is_mask(bool is_mask) { is_mask_ = is_mask; }
size_t GPUMemoryUsageInBytes() const override;
@@ -222,6 +222,7 @@
// after a CalculateContentsScale/ManageTilings.
bool should_update_tile_priorities_;
bool only_used_low_res_last_append_quads_;
+ bool is_mask_;
// Any draw properties derived from |transform|, |viewport|, and |clip|
// parameters in LayerTreeHostImpl::SetExternalDrawConstraints are not valid
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index 7f1ce85..1f98a68 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -45,7 +45,7 @@
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
- virtual void SetUp() override {
+ void SetUp() override {
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
}
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index a75feb0..1d7e2ee 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -71,9 +71,7 @@
virtual ~PictureLayerImplTest() {
}
- virtual void SetUp() override {
- InitializeRenderer();
- }
+ void SetUp() override { InitializeRenderer(); }
virtual void InitializeRenderer() {
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
@@ -883,18 +881,13 @@
// Zoom out further, close to our low-res scale factor. We should
// use that tiling as high-res, and not create a new tiling.
- SetContentsScaleOnBothLayers(
- low_res_factor, 1.0f, low_res_factor / 2.0f, 1.0f, false);
+ SetContentsScaleOnBothLayers(low_res_factor * 2.1f, 1.0f,
+ low_res_factor * 2.1f, 1.0f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
// Zoom in a lot now. Since we increase by increments of
- // kMaxScaleRatioDuringPinch, this will first use 1.0, then 2.0
- // and then finally create a new tiling at 4.0.
- SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
- EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
- EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
+ // kMaxScaleRatioDuringPinch, this will create a new tiling at 4.0.
+ SetContentsScaleOnBothLayers(3.8f, 1.0f, 2.1f, 1.f, false);
EXPECT_EQ(4u, active_layer_->tilings()->num_tilings());
EXPECT_FLOAT_EQ(4.0f,
active_layer_->tilings()->tiling_at(0)->contents_scale());
@@ -938,10 +931,17 @@
SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f, 1.0f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
- // Zoom in. 0.125(desired_scale) should be snapped to 0.12 during zoom-in
- // because 0.125(desired_scale) is within the ratio(1.2)
- SetContentsScaleOnBothLayers(0.5f, 1.0f, 0.5f, 1.0f, false);
+ // Zoom in. 0.25(desired_scale) should be snapped to 0.24 during zoom-in
+ // because 0.25(desired_scale) is within the ratio(1.2).
+ SetContentsScaleOnBothLayers(0.25f, 1.0f, 0.25f, 1.0f, false);
EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
+
+ // Zoom in a lot. Since we move in factors of two, we should get a scale that
+ // is a power of 2 times 0.24.
+ SetContentsScaleOnBothLayers(1.f, 1.0f, 1.f, 1.0f, false);
+ EXPECT_EQ(4u, active_layer_->tilings()->num_tilings());
+ EXPECT_FLOAT_EQ(1.92f,
+ active_layer_->tilings()->tiling_at(0)->contents_scale());
}
TEST_F(PictureLayerImplTest, CleanUpTilings) {
@@ -1188,8 +1188,8 @@
ResetTilingsAndRasterScales();
// Mask layers dont create low res since they always fit on one tile.
- pending_pile->SetIsMask(true);
- active_pile->SetIsMask(true);
+ pending_layer_->set_is_mask(true);
+ active_layer_->set_is_mask(true);
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
@@ -1204,8 +1204,8 @@
scoped_refptr<FakePicturePileImpl> valid_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
- valid_pile->SetIsMask(true);
SetupPendingTree(valid_pile);
+ pending_layer_->set_is_mask(true);
SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
@@ -1231,8 +1231,8 @@
scoped_refptr<FakePicturePileImpl> huge_pile =
FakePicturePileImpl::CreateFilledPile(
tile_size, gfx::Size(max_texture_size + 1, 10));
- huge_pile->SetIsMask(true);
SetupPendingTree(huge_pile);
+ pending_layer_->set_is_mask(true);
SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
@@ -1256,8 +1256,8 @@
scoped_refptr<FakePicturePileImpl> valid_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
- valid_pile->SetIsMask(true);
SetupPendingTree(valid_pile);
+ pending_layer_->set_is_mask(true);
float ideal_contents_scale = 1.3f;
SetupDrawPropertiesAndUpdateTiles(
@@ -2027,7 +2027,7 @@
// TODO(vmpstr): This is confusing. Rework the test to create different bounds
// on different trees instead of fudging tilings.
pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, gfx::Rect(pending_layer_bounds), 1.f, 1.f, Occlusion());
+ gfx::Rect(pending_layer_bounds), 1.f, 1.f, Occlusion());
pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
active_layer_->SetAllTilesReady();
@@ -2117,8 +2117,7 @@
// Drop the tiles on the active tree and recreate them. The same tiles
// should be shared or not.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(), 1.f, 1.0, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(), 1.f, 1.0, Occlusion());
EXPECT_TRUE(active_tiling->AllTilesForTesting().empty());
active_tiling->CreateAllTilesForTesting();
@@ -2459,7 +2458,8 @@
EXPECT_LT(page_scale * contents_scale,
pending_layer_->MinimumContentsScale());
- SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, 1.f, false);
+ SetContentsScaleOnBothLayers(contents_scale * page_scale, 1.f, page_scale,
+ 1.f, false);
ASSERT_GE(pending_layer_->num_tilings(), 0u);
EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
pending_layer_->HighResTiling()->contents_scale());
@@ -2474,7 +2474,7 @@
delegated_rendering));
}
- virtual void SetUp() override {
+ void SetUp() override {
PictureLayerImplTest::SetUp();
// Create some default active and pending trees.
@@ -3716,10 +3716,10 @@
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
- pending_pile->SetIsMask(true);
scoped_ptr<FakePictureLayerImpl> mask =
FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 3,
pending_pile);
+ mask->set_is_mask(true);
mask->SetBounds(bounds);
mask->SetContentBounds(bounds);
@@ -4504,8 +4504,8 @@
Region invalidation(layer_rect);
recording_source->UpdateAndExpandInvalidation(
- &client, &invalidation, SK_ColorWHITE, false, false, layer_bounds,
- layer_rect, frame_number++, Picture::RECORD_NORMALLY);
+ &client, &invalidation, layer_bounds, layer_rect, frame_number++,
+ Picture::RECORD_NORMALLY);
scoped_refptr<RasterSource> pending_raster_source =
recording_source->CreateRasterSource();
@@ -4571,8 +4571,8 @@
Region invalidation1(layer_rect);
recording_source->UpdateAndExpandInvalidation(
- &client, &invalidation1, SK_ColorWHITE, false, false, layer_bounds,
- layer_rect, frame_number++, Picture::RECORD_NORMALLY);
+ &client, &invalidation1, layer_bounds, layer_rect, frame_number++,
+ Picture::RECORD_NORMALLY);
scoped_refptr<RasterSource> raster_source1 =
recording_source->CreateRasterSource();
@@ -4589,8 +4589,8 @@
Region invalidation2(layer_rect);
recording_source->UpdateAndExpandInvalidation(
- &client, &invalidation2, SK_ColorWHITE, false, false, layer_bounds,
- layer_rect, frame_number++, Picture::RECORD_NORMALLY);
+ &client, &invalidation2, layer_bounds, layer_rect, frame_number++,
+ Picture::RECORD_NORMALLY);
scoped_refptr<RasterSource> raster_source2 =
recording_source->CreateRasterSource();
diff --git a/cc/layers/scrollbar_layer_impl_base.cc b/cc/layers/scrollbar_layer_impl_base.cc
index 4248617..beac79f 100644
--- a/cc/layers/scrollbar_layer_impl_base.cc
+++ b/cc/layers/scrollbar_layer_impl_base.cc
@@ -69,11 +69,7 @@
for (LayerImpl* current_layer = scroll_layer;
current_layer && current_layer != container_layer->parent();
current_layer = current_layer->parent()) {
- // TODO(wjmaclean) We shouldn't need to exempt the scroll_layer from the
- // scrollable() test below. https://crbug.com/367858.
- if (current_layer->scrollable() || current_layer == container_layer ||
- current_layer == scroll_layer)
- (current_layer->*operation)(scrollbar);
+ (current_layer->*operation)(scrollbar);
}
}
} // namespace
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 73415c0..436eadc 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -2,6 +2,9 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <set>
+#include <vector>
+
#include "base/message_loop/message_loop_proxy.h"
#include "cc/layers/solid_color_layer.h"
#include "cc/layers/surface_layer.h"
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 7433a14..908d428 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -103,7 +103,7 @@
settings_.layer_transforms_should_scale_layer_contents = true;
}
- virtual void SetUp() {
+ void SetUp() override {
impl_thread_.Start();
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
layer_tree_host_ = SynchronousOutputSurfaceLayerTreeHost::Create(
diff --git a/cc/output/geometry_binding.cc b/cc/output/geometry_binding.cc
index b8c9759..054a962 100644
--- a/cc/output/geometry_binding.cc
+++ b/cc/output/geometry_binding.cc
@@ -26,11 +26,9 @@
uint16 data[6];
};
- COMPILE_ASSERT(sizeof(Quad) == 24 * sizeof(float), // NOLINT(runtime/sizeof)
+ COMPILE_ASSERT(sizeof(Quad) == 24 * sizeof(float), struct_is_densely_packed);
+ COMPILE_ASSERT(sizeof(QuadIndex) == 6 * sizeof(uint16_t),
struct_is_densely_packed);
- COMPILE_ASSERT(
- sizeof(QuadIndex) == 6 * sizeof(uint16_t), // NOLINT(runtime/sizeof)
- struct_is_densely_packed);
Quad quad_list[8];
QuadIndex quad_index_list[8];
@@ -79,33 +77,17 @@
// "const GLvoid*" even though it is actually an offset into the buffer
// object's data store and not a pointer to the client's address space.
const void* offsets[3] = {
- 0, reinterpret_cast<const void*>(
- 3 * sizeof(float)), // NOLINT(runtime/sizeof)
- reinterpret_cast<const void*>(5 *
- sizeof(float)), // NOLINT(runtime/sizeof)
+ 0,
+ reinterpret_cast<const void*>(3 * sizeof(float)),
+ reinterpret_cast<const void*>(5 * sizeof(float)),
};
- GLC(gl_,
- gl_->VertexAttribPointer(PositionAttribLocation(),
- 3,
- GL_FLOAT,
- false,
- 6 * sizeof(float), // NOLINT(runtime/sizeof)
- offsets[0]));
- GLC(gl_,
- gl_->VertexAttribPointer(TexCoordAttribLocation(),
- 2,
- GL_FLOAT,
- false,
- 6 * sizeof(float), // NOLINT(runtime/sizeof)
- offsets[1]));
- GLC(gl_,
- gl_->VertexAttribPointer(TriangleIndexAttribLocation(),
- 1,
- GL_FLOAT,
- false,
- 6 * sizeof(float), // NOLINT(runtime/sizeof)
- offsets[2]));
+ GLC(gl_, gl_->VertexAttribPointer(PositionAttribLocation(), 3, GL_FLOAT,
+ false, 6 * sizeof(float), offsets[0]));
+ GLC(gl_, gl_->VertexAttribPointer(TexCoordAttribLocation(), 2, GL_FLOAT,
+ false, 6 * sizeof(float), offsets[1]));
+ GLC(gl_, gl_->VertexAttribPointer(TriangleIndexAttribLocation(), 1, GL_FLOAT,
+ false, 6 * sizeof(float), offsets[2]));
GLC(gl_, gl_->EnableVertexAttribArray(PositionAttribLocation()));
GLC(gl_, gl_->EnableVertexAttribArray(TexCoordAttribLocation()));
GLC(gl_, gl_->EnableVertexAttribArray(TriangleIndexAttribLocation()));
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 99192c8..a3a297b 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -539,7 +539,7 @@
using GLRenderer::BeginDrawingFrame;
- virtual void FinishDrawingFrame(DrawingFrame* frame) override {
+ void FinishDrawingFrame(DrawingFrame* frame) override {
GLRenderer::FinishDrawingFrame(frame);
if (!expect_overlays_) {
diff --git a/cc/quads/list_container_unittest.cc b/cc/quads/list_container_unittest.cc
index 3ef677c..d41d8bd 100644
--- a/cc/quads/list_container_unittest.cc
+++ b/cc/quads/list_container_unittest.cc
@@ -56,10 +56,9 @@
class MockDrawQuad : public DrawQuad {
public:
- virtual ~MockDrawQuad() { Destruct(); }
- virtual void IterateResources(
- const ResourceIteratorCallback& callback) override {}
- virtual void ExtendValue(base::debug::TracedValue* value) const override {}
+ ~MockDrawQuad() override { Destruct(); }
+ void IterateResources(const ResourceIteratorCallback& callback) override {}
+ void ExtendValue(base::debug::TracedValue* value) const override {}
MOCK_METHOD0(Destruct, void());
};
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 04b18c3..9d8ea84 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -168,6 +168,7 @@
}
void PictureLayerTiling::UpdateTilesToCurrentRasterSource(
+ RasterSource* raster_source,
const Region& layer_invalidation,
const gfx::Size& new_layer_bounds) {
DCHECK(!new_layer_bounds.IsEmpty());
@@ -249,7 +250,6 @@
Invalidate(layer_invalidation);
}
- RasterSource* raster_source = client_->GetRasterSource();
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
it->second->set_raster_source(raster_source);
VerifyLiveTilesRect();
@@ -537,7 +537,6 @@
}
void PictureLayerTiling::ComputeTilePriorityRects(
- WhichTree tree,
const gfx::Rect& viewport_in_layer_space,
float ideal_contents_scale,
double current_frame_time_in_seconds,
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index eb47b60..e1ccde4 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -38,7 +38,6 @@
virtual scoped_refptr<Tile> CreateTile(
PictureLayerTiling* tiling,
const gfx::Rect& content_rect) = 0;
- virtual RasterSource* GetRasterSource() = 0;
virtual gfx::Size CalculateTileSize(
const gfx::Size& content_bounds) const = 0;
// This invalidation region defines the area (if any, it can by null) that
@@ -145,7 +144,8 @@
const gfx::Size& layer_bounds,
PictureLayerTilingClient* client);
gfx::Size layer_bounds() const { return layer_bounds_; }
- void UpdateTilesToCurrentRasterSource(const Region& layer_invalidation,
+ void UpdateTilesToCurrentRasterSource(RasterSource* raster_source,
+ const Region& layer_invalidation,
const gfx::Size& new_layer_bounds);
void CreateMissingTilesInLiveTilesRect();
void RemoveTilesInRegion(const Region& layer_region);
@@ -260,8 +260,7 @@
void Reset();
- void ComputeTilePriorityRects(WhichTree tree,
- const gfx::Rect& viewport_in_layer_space,
+ void ComputeTilePriorityRects(const gfx::Rect& viewport_in_layer_space,
float ideal_contents_scale,
double current_frame_time_in_seconds,
const Occlusion& occlusion_in_layer_space);
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 0d1443e..55d495b 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -43,7 +43,7 @@
1).Pass();
}
- virtual void SetUp() override {
+ void SetUp() override {
picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256));
picture_layer_tiling_client_.set_max_tiles_for_interest_area(250);
picture_layer_tiling_client_.set_tree(PENDING_TREE);
@@ -52,15 +52,14 @@
picture_layer_tiling_->CreateAllTilesForTesting();
}
- virtual void TearDown() override {
- picture_layer_tiling_.reset(NULL);
- }
+ void TearDown() override { picture_layer_tiling_.reset(NULL); }
void RunInvalidateTest(const std::string& test_name, const Region& region) {
timer_.Reset();
do {
picture_layer_tiling_->UpdateTilesToCurrentRasterSource(
- region, picture_layer_tiling_->tiling_size());
+ picture_layer_tiling_client_.raster_source(), region,
+ picture_layer_tiling_->tiling_size());
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
@@ -76,7 +75,7 @@
timer_.Reset();
do {
picture_layer_tiling_->ComputeTilePriorityRects(
- PENDING_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
+ viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
@@ -102,7 +101,7 @@
timer_.Reset();
do {
picture_layer_tiling_->ComputeTilePriorityRects(
- PENDING_TREE, viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
+ viewport_rect, 1.f, timer_.NumLaps() + 1, Occlusion());
viewport_rect = gfx::Rect(viewport_rect.x() + xoffsets[offsetIndex],
viewport_rect.y() + yoffsets[offsetIndex],
@@ -130,8 +129,8 @@
picture_layer_tiling_ =
PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
timer_.Reset();
do {
@@ -155,8 +154,8 @@
picture_layer_tiling_ =
PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
timer_.Reset();
do {
@@ -185,8 +184,8 @@
picture_layer_tiling_ =
PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
timer_.Reset();
TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
@@ -217,8 +216,8 @@
picture_layer_tiling_ =
PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
picture_layer_tiling_client_.set_tree(ACTIVE_TREE);
- picture_layer_tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ picture_layer_tiling_->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
SMOOTHNESS_TAKES_PRIORITY,
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index a0000b6..060bd27 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -19,6 +19,12 @@
} // namespace
+// static
+scoped_ptr<PictureLayerTilingSet> PictureLayerTilingSet::Create(
+ PictureLayerTilingClient* client) {
+ return make_scoped_ptr(new PictureLayerTilingSet(client));
+}
+
PictureLayerTilingSet::PictureLayerTilingSet(PictureLayerTilingClient* client)
: client_(client) {
}
@@ -40,7 +46,8 @@
bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other,
const gfx::Size& new_layer_bounds,
const Region& layer_invalidation,
- float minimum_contents_scale) {
+ float minimum_contents_scale,
+ RasterSource* raster_source) {
if (new_layer_bounds.IsEmpty()) {
RemoveAllTilings();
return false;
@@ -69,8 +76,8 @@
if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
this_tiling->set_resolution(other.tilings_[i]->resolution());
- this_tiling->UpdateTilesToCurrentRasterSource(layer_invalidation,
- new_layer_bounds);
+ this_tiling->UpdateTilesToCurrentRasterSource(
+ raster_source, layer_invalidation, new_layer_bounds);
this_tiling->CreateMissingTilesInLiveTilesRect();
if (this_tiling->resolution() == HIGH_RESOLUTION)
have_high_res_tiling = true;
@@ -145,6 +152,35 @@
tilings_[i]->Reset();
}
+bool PictureLayerTilingSet::UpdateTilePriorities(
+ const gfx::Rect& required_rect_in_layer_space,
+ float ideal_contents_scale,
+ double current_frame_time_in_seconds,
+ const Occlusion& occlusion_in_layer_space,
+ bool can_require_tiles_for_activation) {
+ bool tiling_needs_update = false;
+ // TODO(vmpstr): Check if we have to early out here, or if we can just do it
+ // as part of computing tile priority rects for tilings.
+ for (auto* tiling : tilings_) {
+ if (tiling->NeedsUpdateForFrameAtTimeAndViewport(
+ current_frame_time_in_seconds, required_rect_in_layer_space)) {
+ tiling_needs_update = true;
+ break;
+ }
+ }
+ if (!tiling_needs_update)
+ return false;
+
+ for (auto* tiling : tilings_) {
+ tiling->set_can_require_tiles_for_activation(
+ can_require_tiles_for_activation);
+ tiling->ComputeTilePriorityRects(
+ required_rect_in_layer_space, ideal_contents_scale,
+ current_frame_time_in_seconds, occlusion_in_layer_space);
+ }
+ return true;
+}
+
PictureLayerTilingSet::CoverageIterator::CoverageIterator(
const PictureLayerTilingSet* set,
float contents_scale,
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h
index ddde1d7..489bc0c 100644
--- a/cc/resources/picture_layer_tiling_set.h
+++ b/cc/resources/picture_layer_tiling_set.h
@@ -34,7 +34,9 @@
size_t end;
};
- explicit PictureLayerTilingSet(PictureLayerTilingClient* client);
+ static scoped_ptr<PictureLayerTilingSet> Create(
+ PictureLayerTilingClient* client);
+
~PictureLayerTilingSet();
void SetClient(PictureLayerTilingClient* client);
@@ -50,7 +52,8 @@
bool SyncTilings(const PictureLayerTilingSet& other,
const gfx::Size& new_layer_bounds,
const Region& layer_invalidation,
- float minimum_contents_scale);
+ float minimum_contents_scale,
+ RasterSource* raster_source);
PictureLayerTiling* AddTiling(float contents_scale,
const gfx::Size& layer_bounds);
@@ -72,6 +75,13 @@
// Remove all tiles; keep all tilings.
void RemoveAllTiles();
+ // Update the rects and priorities for tiles based on the given information.
+ bool UpdateTilePriorities(const gfx::Rect& required_rect_in_layer_space,
+ float ideal_contents_scale,
+ double current_frame_time_in_seconds,
+ const Occlusion& occlusion_in_layer_space,
+ bool can_require_tiles_for_activation);
+
// For a given rect, iterates through tiles that can fill it. If no
// set of tiles with resources can fill the rect, then it will iterate
// through null tiles with valid geometry_rect() until the rect is full.
@@ -123,6 +133,8 @@
TilingRange GetTilingRange(TilingRangeType type) const;
private:
+ explicit PictureLayerTilingSet(PictureLayerTilingClient* client);
+
PictureLayerTilingClient* client_;
ScopedPtrVector<PictureLayerTiling> tilings_;
diff --git a/cc/resources/picture_layer_tiling_set_unittest.cc b/cc/resources/picture_layer_tiling_set_unittest.cc
index 0fe8b3c..2a215a8 100644
--- a/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -21,12 +21,12 @@
TEST(PictureLayerTilingSetTest, NoResources) {
FakePictureLayerTilingClient client;
gfx::Size layer_bounds(1000, 800);
- PictureLayerTilingSet set(&client);
+ auto set = PictureLayerTilingSet::Create(&client);
client.SetTileSize(gfx::Size(256, 256));
- set.AddTiling(1.0, layer_bounds);
- set.AddTiling(1.5, layer_bounds);
- set.AddTiling(2.0, layer_bounds);
+ set->AddTiling(1.0, layer_bounds);
+ set->AddTiling(1.5, layer_bounds);
+ set->AddTiling(2.0, layer_bounds);
float contents_scale = 2.0;
gfx::Size content_bounds(
@@ -34,11 +34,8 @@
gfx::Rect content_rect(content_bounds);
Region remaining(content_rect);
- PictureLayerTilingSet::CoverageIterator iter(
- &set,
- contents_scale,
- content_rect,
- contents_scale);
+ PictureLayerTilingSet::CoverageIterator iter(set.get(), contents_scale,
+ content_rect, contents_scale);
for (; iter; ++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
EXPECT_TRUE(content_rect.Contains(geometry_rect));
@@ -62,125 +59,124 @@
PictureLayerTiling* high_res_tiling;
PictureLayerTiling* low_res_tiling;
- PictureLayerTilingSet set(&client);
- set.AddTiling(2.0, layer_bounds);
- high_res_tiling = set.AddTiling(1.0, layer_bounds);
+ auto set = PictureLayerTilingSet::Create(&client);
+ set->AddTiling(2.0, layer_bounds);
+ high_res_tiling = set->AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
- set.AddTiling(0.5, layer_bounds);
- low_res_tiling = set.AddTiling(0.25, layer_bounds);
+ set->AddTiling(0.5, layer_bounds);
+ low_res_tiling = set->AddTiling(0.25, layer_bounds);
low_res_tiling->set_resolution(LOW_RESOLUTION);
- set.AddTiling(0.125, layer_bounds);
+ set->AddTiling(0.125, layer_bounds);
higher_than_high_res_range =
- set.GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
+ set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u, higher_than_high_res_range.start);
EXPECT_EQ(1u, higher_than_high_res_range.end);
- high_res_range = set.GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+ high_res_range = set->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(1u, high_res_range.start);
EXPECT_EQ(2u, high_res_range.end);
between_high_and_low_res_range =
- set.GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
+ set->GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
EXPECT_EQ(2u, between_high_and_low_res_range.start);
EXPECT_EQ(3u, between_high_and_low_res_range.end);
- low_res_range = set.GetTilingRange(PictureLayerTilingSet::LOW_RES);
+ low_res_range = set->GetTilingRange(PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(3u, low_res_range.start);
EXPECT_EQ(4u, low_res_range.end);
lower_than_low_res_range =
- set.GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
+ set->GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(4u, lower_than_low_res_range.start);
EXPECT_EQ(5u, lower_than_low_res_range.end);
- PictureLayerTilingSet set_without_low_res(&client);
- set_without_low_res.AddTiling(2.0, layer_bounds);
- high_res_tiling = set_without_low_res.AddTiling(1.0, layer_bounds);
+ auto set_without_low_res = PictureLayerTilingSet::Create(&client);
+ set_without_low_res->AddTiling(2.0, layer_bounds);
+ high_res_tiling = set_without_low_res->AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
- set_without_low_res.AddTiling(0.5, layer_bounds);
- set_without_low_res.AddTiling(0.25, layer_bounds);
+ set_without_low_res->AddTiling(0.5, layer_bounds);
+ set_without_low_res->AddTiling(0.25, layer_bounds);
- higher_than_high_res_range = set_without_low_res.GetTilingRange(
+ higher_than_high_res_range = set_without_low_res->GetTilingRange(
PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u, higher_than_high_res_range.start);
EXPECT_EQ(1u, higher_than_high_res_range.end);
high_res_range =
- set_without_low_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+ set_without_low_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(1u, high_res_range.start);
EXPECT_EQ(2u, high_res_range.end);
- between_high_and_low_res_range = set_without_low_res.GetTilingRange(
+ between_high_and_low_res_range = set_without_low_res->GetTilingRange(
PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
EXPECT_EQ(2u, between_high_and_low_res_range.start);
EXPECT_EQ(4u, between_high_and_low_res_range.end);
low_res_range =
- set_without_low_res.GetTilingRange(PictureLayerTilingSet::LOW_RES);
+ set_without_low_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
- lower_than_low_res_range = set_without_low_res.GetTilingRange(
+ lower_than_low_res_range = set_without_low_res->GetTilingRange(
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
- PictureLayerTilingSet set_with_only_high_and_low_res(&client);
- high_res_tiling = set_with_only_high_and_low_res.AddTiling(1.0, layer_bounds);
+ auto set_with_only_high_and_low_res = PictureLayerTilingSet::Create(&client);
+ high_res_tiling =
+ set_with_only_high_and_low_res->AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
- low_res_tiling = set_with_only_high_and_low_res.AddTiling(0.5, layer_bounds);
+ low_res_tiling = set_with_only_high_and_low_res->AddTiling(0.5, layer_bounds);
low_res_tiling->set_resolution(LOW_RESOLUTION);
- higher_than_high_res_range = set_with_only_high_and_low_res.GetTilingRange(
+ higher_than_high_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u,
higher_than_high_res_range.end - higher_than_high_res_range.start);
- high_res_range = set_with_only_high_and_low_res.GetTilingRange(
+ high_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(0u, high_res_range.start);
EXPECT_EQ(1u, high_res_range.end);
between_high_and_low_res_range =
- set_with_only_high_and_low_res.GetTilingRange(
+ set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
- EXPECT_EQ(0u,
- between_high_and_low_res_range.end -
- between_high_and_low_res_range.start);
+ EXPECT_EQ(0u, between_high_and_low_res_range.end -
+ between_high_and_low_res_range.start);
- low_res_range = set_with_only_high_and_low_res.GetTilingRange(
+ low_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(1u, low_res_range.start);
EXPECT_EQ(2u, low_res_range.end);
- lower_than_low_res_range = set_with_only_high_and_low_res.GetTilingRange(
+ lower_than_low_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
- PictureLayerTilingSet set_with_only_high_res(&client);
- high_res_tiling = set_with_only_high_res.AddTiling(1.0, layer_bounds);
+ auto set_with_only_high_res = PictureLayerTilingSet::Create(&client);
+ high_res_tiling = set_with_only_high_res->AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
- higher_than_high_res_range = set_with_only_high_res.GetTilingRange(
+ higher_than_high_res_range = set_with_only_high_res->GetTilingRange(
PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u,
higher_than_high_res_range.end - higher_than_high_res_range.start);
high_res_range =
- set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::HIGH_RES);
+ set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(0u, high_res_range.start);
EXPECT_EQ(1u, high_res_range.end);
- between_high_and_low_res_range = set_with_only_high_res.GetTilingRange(
+ between_high_and_low_res_range = set_with_only_high_res->GetTilingRange(
PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
- EXPECT_EQ(0u,
- between_high_and_low_res_range.end -
- between_high_and_low_res_range.start);
+ EXPECT_EQ(0u, between_high_and_low_res_range.end -
+ between_high_and_low_res_range.start);
low_res_range =
- set_with_only_high_res.GetTilingRange(PictureLayerTilingSet::LOW_RES);
+ set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
- lower_than_low_res_range = set_with_only_high_res.GetTilingRange(
+ lower_than_low_res_range = set_with_only_high_res->GetTilingRange(
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
}
@@ -213,11 +209,11 @@
client.SetTileSize(gfx::Size(256, 256));
client.set_tree(PENDING_TREE);
gfx::Size layer_bounds(1000, 800);
- PictureLayerTilingSet set(&client);
+ auto set = PictureLayerTilingSet::Create(&client);
float scale = min_scale;
for (int i = 0; i < num_tilings; ++i, scale += scale_increment) {
- PictureLayerTiling* tiling = set.AddTiling(scale, layer_bounds);
+ PictureLayerTiling* tiling = set->AddTiling(scale, layer_bounds);
tiling->CreateAllTilesForTesting();
std::vector<Tile*> tiles = tiling->AllTilesForTesting();
client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
@@ -230,10 +226,7 @@
Region remaining(content_rect);
PictureLayerTilingSet::CoverageIterator iter(
- &set,
- max_contents_scale,
- content_rect,
- ideal_contents_scale);
+ set.get(), max_contents_scale, content_rect, ideal_contents_scale);
for (; iter; ++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
EXPECT_TRUE(content_rect.Contains(geometry_rect));
@@ -295,8 +288,8 @@
source_client_.set_tree(PENDING_TREE);
target_client_.SetTileSize(tile_size_);
target_client_.set_tree(PENDING_TREE);
- source_.reset(new PictureLayerTilingSet(&source_client_));
- target_.reset(new PictureLayerTilingSet(&target_client_));
+ source_ = PictureLayerTilingSet::Create(&source_client_);
+ target_ = PictureLayerTilingSet::Create(&target_client_);
}
// Sync from source to target.
@@ -308,8 +301,8 @@
for (size_t i = 0; i < target_->num_tilings(); ++i)
target_->tiling_at(i)->CreateAllTilesForTesting();
- target_->SyncTilings(
- *source_.get(), new_bounds, invalidation, minimum_scale);
+ target_->SyncTilings(*source_.get(), new_bounds, invalidation,
+ minimum_scale, target_client_.raster_source());
}
void SyncTilings(const gfx::Size& new_bounds) {
Region invalidation;
@@ -354,7 +347,7 @@
}
for (size_t i = 0; i < target_->num_tilings(); ++i)
- ValidateTiling(target_->tiling_at(i), target_client_.GetRasterSource());
+ ValidateTiling(target_->tiling_at(i), target_client_.raster_source());
}
void ValidateTiling(const PictureLayerTiling* tiling,
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index 786f943..b982dc1 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -36,16 +36,13 @@
}
static void UpdateAllTilePriorities(PictureLayerTilingSet* set,
- WhichTree tree,
const gfx::Rect& visible_layer_rect,
float layer_contents_scale,
double current_frame_time_in_seconds) {
for (size_t i = 0; i < set->num_tilings(); ++i) {
- set->tiling_at(i)->ComputeTilePriorityRects(tree,
- visible_layer_rect,
- layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ set->tiling_at(i)
+ ->ComputeTilePriorityRects(visible_layer_rect, layer_contents_scale,
+ current_frame_time_in_seconds, Occlusion());
}
}
@@ -211,7 +208,8 @@
Region invalidation =
SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
- tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(200, 200));
+ tiling_->UpdateTilesToCurrentRasterSource(client_.raster_source(),
+ invalidation, gfx::Size(200, 200));
EXPECT_FALSE(tiling_->TileAt(0, 0));
}
@@ -266,8 +264,8 @@
// Shrink the tiling so that the last tile row/column is entirely in the
// border pixels of the interior tiles. That row/column is removed.
Region invalidation;
- tiling_->UpdateTilesToCurrentRasterSource(invalidation,
- gfx::Size(right + 1, bottom + 1));
+ tiling_->UpdateTilesToCurrentRasterSource(
+ client_.raster_source(), invalidation, gfx::Size(right + 1, bottom + 1));
EXPECT_EQ(2, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_y());
@@ -284,8 +282,8 @@
// Growing outside the current right/bottom tiles border pixels should create
// the tiles again, even though the live rect has not changed size.
- tiling_->UpdateTilesToCurrentRasterSource(invalidation,
- gfx::Size(right + 2, bottom + 2));
+ tiling_->UpdateTilesToCurrentRasterSource(
+ client_.raster_source(), invalidation, gfx::Size(right + 2, bottom + 2));
EXPECT_EQ(3, tiling_->TilingDataForTesting().num_tiles_x());
EXPECT_EQ(4, tiling_->TilingDataForTesting().num_tiles_y());
@@ -421,7 +419,8 @@
Region invalidation =
SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
- tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(200, 200));
+ tiling_->UpdateTilesToCurrentRasterSource(client_.raster_source(),
+ invalidation, gfx::Size(200, 200));
EXPECT_FALSE(tiling_->TileAt(0, 0));
// The original tile was the same size after resize, but it would include new
@@ -543,8 +542,7 @@
client.SetTileSize(gfx::Size(100, 100));
tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
// Move viewport down 50 pixels in 0.5 seconds.
gfx::Rect down_skewport =
@@ -610,8 +608,7 @@
client.set_tree(ACTIVE_TREE);
tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
// Move viewport down 50 pixels in 0.5 seconds.
gfx::Rect down_skewport =
@@ -678,8 +675,7 @@
gfx::Rect viewport_in_content_space =
gfx::ToEnclosedRect(gfx::ScaleRect(viewport, 0.25f));
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 1.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
gfx::Rect soon_rect = viewport;
@@ -764,8 +760,7 @@
EXPECT_EQ(25, skewport.width());
EXPECT_EQ(35, skewport.height());
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.f, 2.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 2.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
have_now = false;
@@ -817,8 +812,7 @@
EXPECT_FLOAT_EQ(4.f, priority.distance_to_visible);
// Change the underlying layer scale.
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 2.0f, 3.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 2.0f, 3.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
@@ -832,8 +826,7 @@
// Test additional scales.
tiling = TestablePictureLayerTiling::Create(0.2f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 4.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.0f, 4.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
@@ -845,8 +838,7 @@
priority = tiling->TileAt(3, 4)->priority(ACTIVE_TREE);
EXPECT_FLOAT_EQ(60.f, priority.distance_to_visible);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 0.5f, 5.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 0.5f, 5.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
priority = tiling->TileAt(5, 1)->priority(ACTIVE_TREE);
@@ -1095,8 +1087,7 @@
client.set_tree(ACTIVE_TREE);
tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.0f, 1.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
PictureLayerTiling::TilingRasterTileIterator empty_iterator;
@@ -1201,10 +1192,8 @@
client.set_tree(ACTIVE_TREE);
tiling = TestablePictureLayerTiling::Create(1.f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, moved_viewport, 1.0f, 2.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.0f, 1.0, Occlusion());
+ tiling->ComputeTilePriorityRects(moved_viewport, 1.0f, 2.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
gfx::Rect soon_rect = moved_viewport;
@@ -1276,8 +1265,7 @@
client.set_tree(ACTIVE_TREE);
tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
- tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ tiling->ComputeTilePriorityRects(viewport, 1.0f, 1.0, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
PictureLayerTiling::TilingRasterTileIterator empty_iterator;
@@ -1363,7 +1351,6 @@
client_.set_tree(ACTIVE_TREE);
tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE,
gfx::Rect(layer_bounds), // visible content rect
1.f, // current contents scale
1.0, // current frame time
@@ -1371,8 +1358,7 @@
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
// Make the viewport rect empty. All tiles are killed and become zombies.
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- gfx::Rect(), // visible content rect
+ tiling_->ComputeTilePriorityRects(gfx::Rect(), // visible content rect
1.f, // current contents scale
2.0, // current frame time
Occlusion());
@@ -1389,7 +1375,6 @@
client_.set_tree(ACTIVE_TREE);
tiling_->ComputeTilePriorityRects(
- ACTIVE_TREE,
gfx::Rect(layer_bounds), // visible content rect
1.f, // current contents scale
1.0, // current frame time
@@ -1397,8 +1382,7 @@
VerifyTiles(1.f, gfx::Rect(layer_bounds), base::Bind(&TileExists, true));
// If the visible content rect is empty, it should still have live tiles.
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- giant_rect, // visible content rect
+ tiling_->ComputeTilePriorityRects(giant_rect, // visible content rect
1.f, // current contents scale
2.0, // current frame time
Occlusion());
@@ -1417,8 +1401,7 @@
EXPECT_FALSE(viewport_rect.Intersects(gfx::Rect(layer_bounds)));
client_.set_tree(ACTIVE_TREE);
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_rect, // visible content rect
+ tiling_->ComputeTilePriorityRects(viewport_rect, // visible content rect
1.f, // current contents scale
1.0, // current frame time
Occlusion());
@@ -1447,8 +1430,7 @@
client_.set_tree(ACTIVE_TREE);
set_max_tiles_for_interest_area(1);
- tiling_->ComputeTilePriorityRects(ACTIVE_TREE,
- visible_rect, // visible content rect
+ tiling_->ComputeTilePriorityRects(visible_rect, // visible content rect
1.f, // current contents scale
1.0, // current frame time
Occlusion());
@@ -1464,49 +1446,40 @@
client_.SetTileSize(tile_size);
client_.set_tree(PENDING_TREE);
- PictureLayerTilingSet active_set(&client_);
+ auto active_set = PictureLayerTilingSet::Create(&client_);
- active_set.AddTiling(1.f, layer_bounds);
+ active_set->AddTiling(1.f, layer_bounds);
- VerifyTiles(active_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
+ VerifyTiles(active_set->tiling_at(0), 1.f, gfx::Rect(layer_bounds),
base::Bind(&TileExists, false));
- UpdateAllTilePriorities(&active_set,
- PENDING_TREE,
+ UpdateAllTilePriorities(active_set.get(),
gfx::Rect(layer_bounds), // visible content rect
1.f, // current contents scale
1.0); // current frame time
// The active tiling has tiles now.
- VerifyTiles(active_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
+ VerifyTiles(active_set->tiling_at(0), 1.f, gfx::Rect(layer_bounds),
base::Bind(&TileExists, true));
// Add the same tilings to the pending set.
- PictureLayerTilingSet pending_set(&client_);
+ auto pending_set = PictureLayerTilingSet::Create(&client_);
Region invalidation;
- pending_set.SyncTilings(active_set, layer_bounds, invalidation, 0.f);
+ pending_set->SyncTilings(*active_set, layer_bounds, invalidation, 0.f,
+ client_.raster_source());
// The pending tiling starts with no tiles.
- VerifyTiles(pending_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
+ VerifyTiles(pending_set->tiling_at(0), 1.f, gfx::Rect(layer_bounds),
base::Bind(&TileExists, false));
// ComputeTilePriorityRects on the pending tiling at the same frame time. The
// pending tiling should get tiles.
- UpdateAllTilePriorities(&pending_set,
- PENDING_TREE,
+ UpdateAllTilePriorities(pending_set.get(),
gfx::Rect(layer_bounds), // visible content rect
1.f, // current contents scale
1.0); // current frame time
- VerifyTiles(pending_set.tiling_at(0),
- 1.f,
- gfx::Rect(layer_bounds),
+ VerifyTiles(pending_set->tiling_at(0), 1.f, gfx::Rect(layer_bounds),
base::Bind(&TileExists, true));
}
@@ -1533,11 +1506,9 @@
current_layer_bounds,
&client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -1589,11 +1560,9 @@
current_layer_bounds,
&client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -1655,11 +1624,9 @@
current_layer_bounds,
&client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -1715,11 +1682,9 @@
current_layer_bounds,
&client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -1799,11 +1764,9 @@
current_layer_bounds,
&client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -1893,11 +1856,9 @@
current_layer_bounds,
&client);
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -1958,18 +1919,14 @@
&client);
// previous ("last") frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
last_layer_contents_scale,
- last_frame_time_in_seconds,
- Occlusion());
+ last_frame_time_in_seconds, Occlusion());
// current frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -2037,18 +1994,14 @@
&client);
// previous ("last") frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
last_layer_contents_scale,
- last_frame_time_in_seconds,
- Occlusion());
+ last_frame_time_in_seconds, Occlusion());
// current frame
- tiling->ComputeTilePriorityRects(ACTIVE_TREE,
- viewport_in_layer_space,
+ tiling->ComputeTilePriorityRects(viewport_in_layer_space,
current_layer_contents_scale,
- current_frame_time_in_seconds,
- Occlusion());
+ current_frame_time_in_seconds, Occlusion());
tiling->UpdateAllTilePrioritiesForTesting();
ASSERT_TRUE(tiling->TileAt(0, 0));
@@ -2090,8 +2043,8 @@
gfx::Size(10000, 10000),
&active_client);
// Create all tiles on this tiling.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f,
+ Occlusion());
FakePictureLayerTilingClient recycle_client;
recycle_client.SetTileSize(gfx::Size(100, 100));
@@ -2105,8 +2058,8 @@
&recycle_client);
// Create all tiles on the second tiling. All tiles should be shared.
- recycle_tiling->ComputeTilePriorityRects(
- PENDING_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f,
+ 1.0f, Occlusion());
// Set the second tiling as recycled.
active_client.set_twin_tiling(NULL);
@@ -2119,15 +2072,15 @@
EXPECT_EQ(active_tiling->TileAt(0, 0), recycle_tiling->TileAt(0, 0));
// Move the viewport far away from the (0, 0) tile.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(9000, 9000, 100, 100), 1.0f, 2.0, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(9000, 9000, 100, 100), 1.0f,
+ 2.0, Occlusion());
// Ensure the tile was deleted on both tilings.
EXPECT_FALSE(active_tiling->TileAt(0, 0));
EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
// Move the viewport back to (0, 0) tile.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 3.0, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 3.0,
+ Occlusion());
// Ensure that we now have a tile here, but the recycle tiling does not.
EXPECT_TRUE(active_tiling->TileAt(0, 0));
@@ -2144,8 +2097,8 @@
gfx::Size(100, 100),
&active_client);
// Create all tiles on this tiling.
- active_tiling->ComputeTilePriorityRects(
- ACTIVE_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ active_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f,
+ Occlusion());
FakePictureLayerTilingClient recycle_client;
recycle_client.SetTileSize(gfx::Size(100, 100));
@@ -2159,8 +2112,8 @@
&recycle_client);
// Create all tiles on the recycle tiling. All tiles should be shared.
- recycle_tiling->ComputeTilePriorityRects(
- PENDING_TREE, gfx::Rect(0, 0, 100, 100), 1.0f, 1.0f, Occlusion());
+ recycle_tiling->ComputeTilePriorityRects(gfx::Rect(0, 0, 100, 100), 1.0f,
+ 1.0f, Occlusion());
// Set the second tiling as recycled.
active_client.set_twin_tiling(NULL);
@@ -2194,7 +2147,8 @@
EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
Region invalidation;
- tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(250, 150));
+ tiling_->UpdateTilesToCurrentRasterSource(client_.raster_source(),
+ invalidation, gfx::Size(250, 150));
// Tile size in the tiling should be resized to 250x200.
EXPECT_EQ(250, tiling_->TilingDataForTesting().max_texture_size().width());
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index ab138ca..eed12ea 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -26,11 +26,6 @@
// the base picture in each tile.
const int kBasePictureSize = 512;
const int kTileGridBorderPixels = 1;
-#ifdef NDEBUG
-const bool kDefaultClearCanvasSetting = false;
-#else
-const bool kDefaultClearCanvasSetting = true;
-#endif
// Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
// between 0 and 1 meaning invalidation frequency between 0% and 100% that
@@ -169,11 +164,7 @@
PicturePile::PicturePile()
: min_contents_scale_(0),
slow_down_raster_scale_factor_for_debug_(0),
- contents_opaque_(false),
- contents_fill_bounds_completely_(false),
- clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
has_any_recordings_(false),
- is_mask_(false),
is_solid_color_(false),
solid_color_(SK_ColorTRANSPARENT),
pixel_record_distance_(kPixelDistanceToRecord),
@@ -190,17 +181,10 @@
bool PicturePile::UpdateAndExpandInvalidation(
ContentLayerClient* painter,
Region* invalidation,
- SkColor background_color,
- bool contents_opaque,
- bool contents_fill_bounds_completely,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
Picture::RecordingMode recording_mode) {
- background_color_ = background_color;
- contents_opaque_ = contents_opaque;
- contents_fill_bounds_completely_ = contents_fill_bounds_completely;
-
bool updated = false;
Region resize_invalidation;
@@ -569,6 +553,11 @@
return true;
}
+scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const {
+ return scoped_refptr<RasterSource>(
+ PicturePileImpl::CreateFromPicturePile(this));
+}
+
gfx::Size PicturePile::GetSize() const {
return tiling_.tiling_size();
}
@@ -599,6 +588,14 @@
min_contents_scale_ = min_contents_scale;
}
+void PicturePile::SetSlowdownRasterScaleFactor(int factor) {
+ slow_down_raster_scale_factor_for_debug_ = factor;
+}
+
+bool PicturePile::IsSuitableForGpuRasterization() const {
+ return is_suitable_for_gpu_rasterization_;
+}
+
// static
void PicturePile::ComputeTileGridInfo(const gfx::Size& tile_grid_size,
SkTileGridFactory::TileGridInfo* info) {
@@ -618,27 +615,10 @@
ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
}
-void PicturePile::SetSlowdownRasterScaleFactor(int factor) {
- slow_down_raster_scale_factor_for_debug_ = factor;
-}
-
-void PicturePile::SetIsMask(bool is_mask) {
- is_mask_ = is_mask;
-}
-
void PicturePile::SetUnsuitableForGpuRasterizationForTesting() {
is_suitable_for_gpu_rasterization_ = false;
}
-bool PicturePile::IsSuitableForGpuRasterization() const {
- return is_suitable_for_gpu_rasterization_;
-}
-
-scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const {
- return scoped_refptr<RasterSource>(
- PicturePileImpl::CreateFromPicturePile(this));
-}
-
SkTileGridFactory::TileGridInfo PicturePile::GetTileGridInfoForTesting() const {
return tile_grid_info_;
}
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index ffd9b52..e252e97 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -6,7 +6,9 @@
#define CC_RESOURCES_PICTURE_PILE_H_
#include <bitset>
+#include <utility>
+#include "base/containers/hash_tables.h"
#include "base/memory/ref_counted.h"
#include "cc/base/tiling_data.h"
#include "cc/resources/recording_source.h"
@@ -23,21 +25,17 @@
bool UpdateAndExpandInvalidation(
ContentLayerClient* painter,
Region* invalidation,
- SkColor background_color,
- bool contents_opaque,
- bool contents_fill_bounds_completely,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
Picture::RecordingMode recording_mode) override;
+ scoped_refptr<RasterSource> CreateRasterSource() const override;
gfx::Size GetSize() const final;
void SetEmptyBounds() override;
void SetMinContentsScale(float min_contents_scale) override;
- void SetTileGridSize(const gfx::Size& tile_grid_size) override;
void SetSlowdownRasterScaleFactor(int factor) override;
- void SetIsMask(bool is_mask) override;
bool IsSuitableForGpuRasterization() const override;
- scoped_refptr<RasterSource> CreateRasterSource() const override;
+ void SetTileGridSize(const gfx::Size& tile_grid_size) override;
void SetUnsuitableForGpuRasterizationForTesting() override;
SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const override;
@@ -95,15 +93,10 @@
gfx::Rect recorded_viewport_;
float min_contents_scale_;
SkTileGridFactory::TileGridInfo tile_grid_info_;
- SkColor background_color_;
int slow_down_raster_scale_factor_for_debug_;
- bool contents_opaque_;
- bool contents_fill_bounds_completely_;
- bool clear_canvas_with_debug_color_;
// A hint about whether there are any recordings. This may be a false
// positive.
bool has_any_recordings_;
- bool is_mask_;
bool is_solid_color_;
SkColor solid_color_;
int pixel_record_distance_;
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index 7ec9252..7416538 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -14,6 +14,16 @@
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "ui/gfx/geometry/rect_conversions.h"
+namespace {
+
+#ifdef NDEBUG
+const bool kDefaultClearCanvasSetting = false;
+#else
+const bool kDefaultClearCanvasSetting = true;
+#endif
+
+} // namespace
+
namespace cc {
scoped_refptr<PicturePileImpl> PicturePileImpl::Create() {
@@ -27,13 +37,11 @@
PicturePileImpl::PicturePileImpl()
: background_color_(SK_ColorTRANSPARENT),
- contents_opaque_(false),
- contents_fill_bounds_completely_(false),
+ requires_clear_(true),
is_solid_color_(false),
solid_color_(SK_ColorTRANSPARENT),
has_any_recordings_(false),
- is_mask_(false),
- clear_canvas_with_debug_color_(false),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
min_contents_scale_(0.f),
slow_down_raster_scale_factor_for_debug_(0),
should_attempt_to_use_distance_field_text_(false) {
@@ -42,15 +50,13 @@
PicturePileImpl::PicturePileImpl(const PicturePile* other)
: picture_map_(other->picture_map_),
tiling_(other->tiling_),
- background_color_(other->background_color_),
- contents_opaque_(other->contents_opaque_),
- contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
+ background_color_(SK_ColorTRANSPARENT),
+ requires_clear_(true),
is_solid_color_(other->is_solid_color_),
solid_color_(other->solid_color_),
recorded_viewport_(other->recorded_viewport_),
has_any_recordings_(other->has_any_recordings_),
- is_mask_(other->is_mask_),
- clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
min_contents_scale_(other->min_contents_scale_),
slow_down_raster_scale_factor_for_debug_(
other->slow_down_raster_scale_factor_for_debug_),
@@ -88,7 +94,12 @@
// If this picture has opaque contents, it is guaranteeing that it will
// draw an opaque rect the size of the layer. If it is not, then we must
// clear this canvas ourselves.
- if (contents_opaque_ || contents_fill_bounds_completely_) {
+ if (requires_clear_) {
+ TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
+ // Clearing is about ~4x faster than drawing a rect even if the content
+ // isn't covering a majority of the canvas.
+ canvas->clear(SK_ColorTRANSPARENT);
+ } else {
// Even if completely covered, for rasterizations that touch the edge of the
// layer, we also need to raster the background color underneath the last
// texel (since the recording won't cover it) and outside the last texel
@@ -129,11 +140,6 @@
canvas->drawColor(background_color_, SkXfermode::kSrc_Mode);
canvas->restore();
}
- } else {
- TRACE_EVENT_INSTANT0("cc", "SkCanvas::clear", TRACE_EVENT_SCOPE_THREAD);
- // Clearing is about ~4x faster than drawing a rect even if the content
- // isn't covering a majority of the canvas.
- canvas->clear(SK_ColorTRANSPARENT);
}
RasterCommon(canvas,
@@ -401,6 +407,14 @@
should_attempt_to_use_distance_field_text_ = true;
}
+void PicturePileImpl::SetBackgoundColor(SkColor background_color) {
+ background_color_ = background_color;
+}
+
+void PicturePileImpl::SetRequiresClear(bool requires_clear) {
+ requires_clear_ = requires_clear;
+}
+
bool PicturePileImpl::ShouldAttemptToUseDistanceFieldText() const {
return should_attempt_to_use_distance_field_text_;
}
@@ -423,10 +437,6 @@
}
}
-bool PicturePileImpl::IsMask() const {
- return is_mask_;
-}
-
PicturePileImpl::PixelRefIterator::PixelRefIterator(
const gfx::Rect& content_rect,
float contents_scale,
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index 6986db4..b4209e3 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -17,7 +17,14 @@
#include "cc/resources/raster_source.h"
#include "skia/ext/analysis_canvas.h"
#include "skia/ext/refptr.h"
-#include "third_party/skia/include/core/SkPicture.h"
+
+class SkCanvas;
+class SkPicture;
+class SkPixelRef;
+
+namespace gfx {
+class Rect;
+}
namespace cc {
@@ -47,12 +54,13 @@
bool CoversRect(const gfx::Rect& content_rect,
float contents_scale) const override;
void SetShouldAttemptToUseDistanceFieldText() override;
+ void SetBackgoundColor(SkColor background_color) override;
+ void SetRequiresClear(bool requires_clear) override;
bool ShouldAttemptToUseDistanceFieldText() const override;
gfx::Size GetSize() const override;
bool IsSolidColor() const override;
SkColor GetSolidColor() const override;
bool HasRecordings() const override;
- bool IsMask() const override;
// Tracing functionality.
void DidBeginTracing() override;
@@ -101,13 +109,11 @@
PictureMap picture_map_;
TilingData tiling_;
SkColor background_color_;
- bool contents_opaque_;
- bool contents_fill_bounds_completely_;
+ bool requires_clear_;
bool is_solid_color_;
SkColor solid_color_;
gfx::Rect recorded_viewport_;
bool has_any_recordings_;
- bool is_mask_;
bool clear_canvas_with_debug_color_;
float min_contents_scale_;
int slow_down_raster_scale_factor_for_debug_;
diff --git a/cc/resources/picture_pile_impl_unittest.cc b/cc/resources/picture_pile_impl_unittest.cc
index 6dcf740..6e9afc7 100644
--- a/cc/resources/picture_pile_impl_unittest.cc
+++ b/cc/resources/picture_pile_impl_unittest.cc
@@ -634,17 +634,11 @@
}
}
-class FullContentsTest : public ::testing::TestWithParam<bool> {};
-
-TEST_P(FullContentsTest, RasterFullContents) {
+TEST(PicturePileImplTest, RasterFullContents) {
gfx::Size tile_size(1000, 1000);
gfx::Size layer_bounds(3, 5);
float contents_scale = 1.5f;
float raster_divisions = 2.f;
- // Param in this case is whether the content is fully opaque
- // or just filled completely. For this test they should behave the same.
- bool contents_opaque = GetParam();
- bool fills_content = !GetParam();
scoped_refptr<FakePicturePileImpl> pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
@@ -656,8 +650,7 @@
pile->SetMinContentsScale(contents_scale);
pile->set_background_color(SK_ColorBLACK);
- pile->set_contents_opaque(contents_opaque);
- pile->set_contents_fill_bounds_completely(fills_content);
+ pile->SetRequiresClear(false);
pile->set_clear_canvas_with_debug_color(false);
pile->RerecordPile();
@@ -705,10 +698,6 @@
}
}
-INSTANTIATE_TEST_CASE_P(PicturePileImpl,
- FullContentsTest,
- ::testing::Values(false, true));
-
TEST(PicturePileImpl, RasterContentsTransparent) {
gfx::Size tile_size(1000, 1000);
gfx::Size layer_bounds(5, 3);
@@ -717,7 +706,7 @@
scoped_refptr<FakePicturePileImpl> pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
pile->set_background_color(SK_ColorTRANSPARENT);
- pile->set_contents_opaque(false);
+ pile->SetRequiresClear(true);
pile->SetMinContentsScale(contents_scale);
pile->set_clear_canvas_with_debug_color(false);
pile->RerecordPile();
@@ -757,7 +746,7 @@
scoped_refptr<FakePicturePileImpl> pile =
FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
pile->set_background_color(SK_ColorTRANSPARENT);
- pile->set_contents_opaque(false);
+ pile->SetRequiresClear(true);
pile->SetMinContentsScale(MinContentsScale());
pile->set_clear_canvas_with_debug_color(true);
SkPaint color_paint;
diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc
index 25e0d12..0a9a907 100644
--- a/cc/resources/picture_pile_unittest.cc
+++ b/cc/resources/picture_pile_unittest.cc
@@ -17,11 +17,7 @@
class PicturePileTestBase {
public:
- PicturePileTestBase()
- : background_color_(SK_ColorBLUE),
- min_scale_(0.125),
- frame_number_(0),
- contents_opaque_(false) {}
+ PicturePileTestBase() : min_scale_(0.125), frame_number_(0) {}
void InitializeData() {
pile_.SetTileGridSize(gfx::Size(1000, 1000));
@@ -43,10 +39,9 @@
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect) {
frame_number_++;
- return pile_.UpdateAndExpandInvalidation(
- &client_, invalidation, background_color_, contents_opaque_, false,
- layer_size, visible_layer_rect, frame_number_,
- Picture::RECORD_NORMALLY);
+ return pile_.UpdateAndExpandInvalidation(&client_, invalidation, layer_size,
+ visible_layer_rect, frame_number_,
+ Picture::RECORD_NORMALLY);
}
bool UpdateWholePile() {
@@ -59,15 +54,13 @@
FakeContentLayerClient client_;
FakePicturePile pile_;
- SkColor background_color_;
float min_scale_;
int frame_number_;
- bool contents_opaque_;
};
class PicturePileTest : public PicturePileTestBase, public testing::Test {
public:
- virtual void SetUp() override { InitializeData(); }
+ void SetUp() override { InitializeData(); }
};
TEST_F(PicturePileTest, InvalidationOnTileBorderOutsideInterestRect) {
@@ -531,7 +524,7 @@
class PicturePileResizeCornerTest : public PicturePileTestBase,
public testing::TestWithParam<Corner> {
protected:
- virtual void SetUp() override { InitializeData(); }
+ void SetUp() override { InitializeData(); }
static gfx::Rect CornerSinglePixelRect(Corner corner, const gfx::Size& s) {
switch (corner) {
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index f7ea271..5f200db 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -81,6 +81,9 @@
// during rasterization.
virtual void SetShouldAttemptToUseDistanceFieldText() = 0;
+ virtual void SetBackgoundColor(SkColor background_color) = 0;
+ virtual void SetRequiresClear(bool requires_clear) = 0;
+
// Return true iff this raster source would benefit from using distance
// field text.
virtual bool ShouldAttemptToUseDistanceFieldText() const = 0;
@@ -90,9 +93,6 @@
virtual void AsValueInto(base::debug::TracedValue* array) const = 0;
virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0;
- // TODO(vmpstr): This should be a layer property.
- virtual bool IsMask() const = 0;
-
protected:
friend class base::RefCountedThreadSafe<RasterSource>;
diff --git a/cc/resources/raster_worker_pool_perftest.cc b/cc/resources/raster_worker_pool_perftest.cc
index fdec054..d86155a 100644
--- a/cc/resources/raster_worker_pool_perftest.cc
+++ b/cc/resources/raster_worker_pool_perftest.cc
@@ -228,7 +228,7 @@
public RasterizerClient {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
switch (GetParam()) {
case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
Create3dOutputSurfaceAndResourceProvider();
@@ -277,7 +277,7 @@
DCHECK(raster_worker_pool_);
raster_worker_pool_->AsRasterizer()->SetClient(this);
}
- virtual void TearDown() override {
+ void TearDown() override {
raster_worker_pool_->AsRasterizer()->Shutdown();
raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
}
@@ -485,7 +485,7 @@
public testing::Test {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
output_surface_ = FakeOutputSurface::Create3d(context_provider_).Pass();
CHECK(output_surface_->BindToClient(&output_surface_client_));
resource_provider_ =
diff --git a/cc/resources/raster_worker_pool_unittest.cc b/cc/resources/raster_worker_pool_unittest.cc
index 775acda..0518f64 100644
--- a/cc/resources/raster_worker_pool_unittest.cc
+++ b/cc/resources/raster_worker_pool_unittest.cc
@@ -129,7 +129,7 @@
timed_out_(false) {}
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
switch (GetParam()) {
case RASTER_WORKER_POOL_TYPE_PIXEL_BUFFER:
Create3dOutputSurfaceAndResourceProvider();
@@ -179,7 +179,7 @@
raster_worker_pool_->AsRasterizer()->SetClient(this);
}
- virtual void TearDown() override {
+ void TearDown() override {
raster_worker_pool_->AsRasterizer()->Shutdown();
raster_worker_pool_->AsRasterizer()->CheckForCompletedTasks();
}
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
index cbbeb70..19eea72 100644
--- a/cc/resources/recording_source.h
+++ b/cc/resources/recording_source.h
@@ -28,28 +28,27 @@
virtual bool UpdateAndExpandInvalidation(
ContentLayerClient* painter,
Region* invalidation,
- SkColor background_color,
- bool contents_opaque,
- bool contents_fill_bounds_completely,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
Picture::RecordingMode recording_mode) = 0;
+ virtual scoped_refptr<RasterSource> CreateRasterSource() const = 0;
+
virtual gfx::Size GetSize() const = 0;
virtual void SetEmptyBounds() = 0;
virtual void SetMinContentsScale(float min_contents_scale) = 0;
- virtual void SetTileGridSize(const gfx::Size& tile_grid_size) = 0;
virtual void SetSlowdownRasterScaleFactor(int factor) = 0;
- virtual void SetIsMask(bool is_mask) = 0;
virtual bool IsSuitableForGpuRasterization() const = 0;
- virtual scoped_refptr<RasterSource> CreateRasterSource() const = 0;
+ // TODO(hendrikw): This is an implementation detail, remove it when possible.
+ virtual void SetTileGridSize(const gfx::Size& tile_grid_size) = 0;
// TODO(hendrikw): Figure out how to remove this.
virtual void SetUnsuitableForGpuRasterizationForTesting() = 0;
virtual SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const = 0;
};
-}
+
+} // namespace cc
#endif // CC_RESOURCES_RECORDING_SOURCE_H_
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 023a1cd..2518972 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -9,6 +9,7 @@
#include "base/containers/hash_tables.h"
#include "base/debug/trace_event.h"
+#include "base/metrics/histogram.h"
#include "base/stl_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
@@ -198,11 +199,11 @@
DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator);
};
-// Generic fence implementation for query objects. Fence has passed when query
-// result is available.
-class QueryFence : public ResourceProvider::Fence {
+// Query object based fence implementation used to detect completion of copy
+// texture operations. Fence has passed when query result is available.
+class CopyTextureFence : public ResourceProvider::Fence {
public:
- QueryFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
+ CopyTextureFence(gpu::gles2::GLES2Interface* gl, unsigned query_id)
: gl_(gl), query_id_(query_id) {}
// Overridden from ResourceProvider::Fence:
@@ -211,20 +212,31 @@
unsigned available = 1;
gl_->GetQueryObjectuivEXT(
query_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
- return !!available;
+ if (!available)
+ return false;
+
+ ProcessResult();
+ return true;
}
void Wait() override {
- unsigned result = 0;
- gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &result);
+ // ProcessResult() will wait for result to become available.
+ ProcessResult();
}
private:
- ~QueryFence() override {}
+ ~CopyTextureFence() override {}
+
+ void ProcessResult() {
+ unsigned time_elapsed_us = 0;
+ gl_->GetQueryObjectuivEXT(query_id_, GL_QUERY_RESULT_EXT, &time_elapsed_us);
+ UMA_HISTOGRAM_CUSTOM_COUNTS("Renderer4.CopyTextureLatency", time_elapsed_us,
+ 0, 256000, 50);
+ }
gpu::gles2::GLES2Interface* gl_;
unsigned query_id_;
- DISALLOW_COPY_AND_ASSIGN(QueryFence);
+ DISALLOW_COPY_AND_ASSIGN(CopyTextureFence);
};
} // namespace
@@ -2077,7 +2089,7 @@
// source resource until CopyTextureCHROMIUM command has completed.
gl->EndQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM);
source_resource->read_lock_fence = make_scoped_refptr(
- new QueryFence(gl, source_resource->gl_read_lock_query_id));
+ new CopyTextureFence(gl, source_resource->gl_read_lock_query_id));
} else {
// Create a SynchronousFence when CHROMIUM_sync_query extension is missing.
// Try to use one synchronous fence for as many CopyResource operations as
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index e507ad6..d8bfe4c 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -103,11 +103,11 @@
// Force all textures to be consecutive numbers starting at "1",
// so we easily can test for them.
- virtual GLuint NextTextureId() override {
+ GLuint NextTextureId() override {
base::AutoLock lock(namespace_->lock);
return namespace_->next_texture_id++;
}
- virtual void RetireTextureId(GLuint) override {}
+ void RetireTextureId(GLuint) override {}
};
// Shared data between multiple ResourceProviderContext. This contains mailbox
diff --git a/cc/resources/scoped_gpu_raster.h b/cc/resources/scoped_gpu_raster.h
index a322ccb..e70ebd0 100644
--- a/cc/resources/scoped_gpu_raster.h
+++ b/cc/resources/scoped_gpu_raster.h
@@ -17,7 +17,7 @@
// GL resources while an instance of this class is alive.
class CC_EXPORT ScopedGpuRaster {
public:
- ScopedGpuRaster(ContextProvider* context_provider);
+ explicit ScopedGpuRaster(ContextProvider* context_provider);
~ScopedGpuRaster();
private:
diff --git a/cc/resources/task_graph_runner_perftest.cc b/cc/resources/task_graph_runner_perftest.cc
index 7809e58..51dad74 100644
--- a/cc/resources/task_graph_runner_perftest.cc
+++ b/cc/resources/task_graph_runner_perftest.cc
@@ -45,11 +45,11 @@
kTimeCheckInterval) {}
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
task_graph_runner_ = make_scoped_ptr(new TaskGraphRunner);
namespace_token_ = task_graph_runner_->GetNamespaceToken();
}
- virtual void TearDown() override { task_graph_runner_ = nullptr; }
+ void TearDown() override { task_graph_runner_ = nullptr; }
void AfterTest(const std::string& test_name) {
// Format matches chrome/test/perf/perf_test.h:PrintResult
diff --git a/cc/resources/task_graph_runner_unittest.cc b/cc/resources/task_graph_runner_unittest.cc
index ad23b66..afc369d 100644
--- a/cc/resources/task_graph_runner_unittest.cc
+++ b/cc/resources/task_graph_runner_unittest.cc
@@ -167,7 +167,7 @@
public base::DelegateSimpleThread::Delegate {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
const size_t num_threads = GetParam();
while (workers_.size() < num_threads) {
scoped_ptr<base::DelegateSimpleThread> worker =
@@ -179,7 +179,7 @@
for (int i = 0; i < kNamespaceCount; ++i)
namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
}
- virtual void TearDown() override {
+ void TearDown() override {
task_graph_runner_->Shutdown();
while (workers_.size()) {
scoped_ptr<base::DelegateSimpleThread> worker = workers_.take_front();
@@ -285,14 +285,14 @@
public base::DelegateSimpleThread::Delegate {
public:
// Overridden from testing::Test:
- virtual void SetUp() override {
+ void SetUp() override {
worker_.reset(new base::DelegateSimpleThread(this, "TestWorker"));
worker_->Start();
for (int i = 0; i < kNamespaceCount; ++i)
namespace_token_[i] = task_graph_runner_->GetNamespaceToken();
}
- virtual void TearDown() override {
+ void TearDown() override {
task_graph_runner_->Shutdown();
worker_->Join();
}
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 1c7d4ca..d83b824 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -233,7 +233,6 @@
scheduled_raster_task_limit_(scheduled_raster_task_limit),
all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
- did_initialize_visible_tile_(false),
did_check_for_completed_tasks_since_last_schedule_tasks_(true),
did_oom_on_last_assign_(false),
ready_to_activate_check_notifier_(
@@ -433,7 +432,7 @@
resource_pool_->acquired_memory_usage_bytes());
}
-bool TileManager::UpdateVisibleTiles() {
+void TileManager::UpdateVisibleTiles() {
TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
rasterizer_->CheckForCompletedTasks();
@@ -446,10 +445,6 @@
"stats",
RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
update_visible_tiles_stats_ = RasterTaskCompletionStats();
-
- bool did_initialize_visible_tile = did_initialize_visible_tile_;
- did_initialize_visible_tile_ = false;
- return did_initialize_visible_tile;
}
scoped_refptr<base::debug::ConvertableToTraceFormat>
@@ -828,9 +823,6 @@
mts.draw_info.resource_ = resource.Pass();
}
- if (tile->priority(ACTIVE_TREE).distance_to_visible == 0.f)
- did_initialize_visible_tile_ = true;
-
client_->NotifyTileStateChanged(tile);
}
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 92821e0..e94fb7c 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -108,8 +108,7 @@
void ManageTiles(const GlobalStateThatImpactsTilePriority& state);
- // Returns true when visible tiles have been initialized.
- bool UpdateVisibleTiles();
+ void UpdateVisibleTiles();
scoped_refptr<Tile> CreateTile(RasterSource* raster_source,
const gfx::Size& tile_size,
@@ -254,7 +253,6 @@
RenderingStatsInstrumentation* rendering_stats_instrumentation_;
- bool did_initialize_visible_tile_;
bool did_check_for_completed_tasks_since_last_schedule_tasks_;
bool did_oom_on_last_assign_;
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 7262926..7b096bd 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -111,7 +111,7 @@
host_impl_.tile_manager()->SetGlobalStateForTesting(state);
}
- virtual void SetUp() override {
+ void SetUp() override {
InitializeRenderer();
SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
}
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index a253672..49a93d3 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -55,7 +55,7 @@
host_impl_.tile_manager()->SetGlobalStateForTesting(state);
}
- virtual void SetUp() override {
+ void SetUp() override {
InitializeRenderer();
SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
}
@@ -194,23 +194,23 @@
// Invalidate the pending tree.
pending_layer_->set_invalidation(invalidation);
pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
- invalidation, gfx::Size(1000, 1000));
+ pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
- invalidation, gfx::Size(1000, 1000));
+ pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
active_layer_->ResetAllTilesPriorities();
pending_layer_->ResetAllTilesPriorities();
// Renew all of the tile priorities.
gfx::Rect viewport(50, 50, 100, 100);
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_layer_->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->HighResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->LowResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
// Populate all tiles directly from the tilings.
all_tiles.clear();
@@ -442,23 +442,23 @@
// Invalidate the pending tree.
pending_layer_->set_invalidation(invalidation);
pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
- invalidation, gfx::Size(1000, 1000));
+ pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
- invalidation, gfx::Size(1000, 1000));
+ pending_layer_->raster_source(), invalidation, gfx::Size(1000, 1000));
active_layer_->ResetAllTilesPriorities();
pending_layer_->ResetAllTilesPriorities();
// Renew all of the tile priorities.
gfx::Rect viewport(50, 50, 100, 100);
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_layer_->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->HighResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
- active_layer_->LowResTiling()->ComputeTilePriorityRects(
- ACTIVE_TREE, viewport, 1.0f, 1.0, Occlusion());
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ active_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
// Populate all tiles directly from the tilings.
all_tiles.clear();
@@ -593,14 +593,14 @@
// Renew all of the tile priorities.
gfx::Rect viewport(layer_bounds);
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_layer_->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
pending_child_layer->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+ viewport, 1.0f, 1.0, Occlusion());
pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+ viewport, 1.0f, 1.0, Occlusion());
// Populate all tiles directly from the tilings.
all_tiles.clear();
@@ -696,14 +696,14 @@
// Renew all of the tile priorities.
gfx::Rect viewport(layer_bounds);
- pending_layer_->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
- pending_layer_->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+ pending_layer_->HighResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
+ pending_layer_->LowResTiling()->ComputeTilePriorityRects(viewport, 1.0f, 1.0,
+ Occlusion());
pending_child_layer->HighResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+ viewport, 1.0f, 1.0, Occlusion());
pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
- PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+ viewport, 1.0f, 1.0, Occlusion());
// Populate all tiles directly from the tilings.
std::set<Tile*> all_pending_tiles;
diff --git a/cc/scheduler/begin_frame_source_unittest.cc b/cc/scheduler/begin_frame_source_unittest.cc
index b741e35..a4b3d6e 100644
--- a/cc/scheduler/begin_frame_source_unittest.cc
+++ b/cc/scheduler/begin_frame_source_unittest.cc
@@ -312,7 +312,7 @@
scoped_ptr<TestBackToBackBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
- virtual void SetUp() override {
+ void SetUp() override {
now_src_ = TestNowSource::Create(1000);
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -323,7 +323,7 @@
source_->AddObserver(obs_.get());
}
- virtual void TearDown() override { obs_.reset(); }
+ void TearDown() override { obs_.reset(); }
};
const int64_t BackToBackBeginFrameSourceTest::kDeadline =
@@ -478,7 +478,7 @@
scoped_ptr<TestSyntheticBeginFrameSource> source_;
scoped_ptr<MockBeginFrameObserver> obs_;
- virtual void SetUp() override {
+ void SetUp() override {
now_src_ = TestNowSource::Create(1000);
task_runner_ =
make_scoped_refptr(new OrderedSimpleTaskRunner(now_src_, false));
@@ -488,7 +488,7 @@
source_->AddObserver(obs_.get());
}
- virtual void TearDown() override { obs_.reset(); }
+ void TearDown() override { obs_.reset(); }
};
TEST_F(SyntheticBeginFrameSourceTest,
@@ -547,7 +547,7 @@
// BeginFrameSourceMultiplexer testing -----------------------------------
class BeginFrameSourceMultiplexerTest : public ::testing::Test {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
mux_ = BeginFrameSourceMultiplexer::Create();
source1_store_ = make_scoped_ptr(new FakeBeginFrameSource());
@@ -559,7 +559,7 @@
source3_ = source3_store_.get();
}
- virtual void TearDown() override {
+ void TearDown() override {
// Make sure the mux is torn down before the sources.
mux_.reset();
}
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 5c515b2..b190988 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -244,11 +244,6 @@
}
}
-void Scheduler::SetSwapUsedIncompleteTile(bool used_incomplete_tile) {
- state_machine_.SetSwapUsedIncompleteTile(used_incomplete_tile);
- ProcessScheduledActions();
-}
-
void Scheduler::DidSwapBuffersComplete() {
state_machine_.DidSwapBuffersComplete();
ProcessScheduledActions();
@@ -477,8 +472,9 @@
"Scheduler::BeginRetroFrames all expired",
TRACE_EVENT_SCOPE_THREAD);
} else {
- BeginImplFrame(begin_retro_frame_args_.front());
+ BeginFrameArgs front = begin_retro_frame_args_.front();
begin_retro_frame_args_.pop_front();
+ BeginImplFrame(front);
}
}
@@ -669,9 +665,6 @@
case SchedulerStateMachine::ACTION_COMMIT:
client_->ScheduledActionCommit();
break;
- case SchedulerStateMachine::ACTION_UPDATE_VISIBLE_TILES:
- client_->ScheduledActionUpdateVisibleTiles();
- break;
case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
client_->ScheduledActionActivateSyncTree();
break;
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 523c246..2a924f1 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -40,7 +40,6 @@
virtual DrawResult ScheduledActionDrawAndSwapForced() = 0;
virtual void ScheduledActionAnimate() = 0;
virtual void ScheduledActionCommit() = 0;
- virtual void ScheduledActionUpdateVisibleTiles() = 0;
virtual void ScheduledActionActivateSyncTree() = 0;
virtual void ScheduledActionBeginOutputSurfaceCreation() = 0;
virtual void ScheduledActionManageTiles() = 0;
@@ -120,7 +119,6 @@
void SetMaxSwapsPending(int max);
void DidSwapBuffers();
- void SetSwapUsedIncompleteTile(bool used_incomplete_tile);
void DidSwapBuffersComplete();
void SetImplLatencyTakesPriority(bool impl_latency_takes_priority);
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 94016f3..82b13d7 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -26,7 +26,6 @@
last_frame_number_swap_performed_(-1),
last_frame_number_swap_requested_(-1),
last_frame_number_begin_main_frame_sent_(-1),
- last_frame_number_update_visible_tiles_was_called_(-1),
manage_tiles_funnel_(0),
consecutive_checkerboard_animations_(0),
max_pending_swaps_(1),
@@ -34,7 +33,6 @@
needs_redraw_(false),
needs_animate_(false),
needs_manage_tiles_(false),
- swap_used_incomplete_tile_(false),
needs_commit_(false),
inside_poll_for_anticipated_draw_triggers_(false),
visible_(false),
@@ -129,8 +127,6 @@
return "ACTION_SEND_BEGIN_MAIN_FRAME";
case ACTION_COMMIT:
return "ACTION_COMMIT";
- case ACTION_UPDATE_VISIBLE_TILES:
- return "ACTION_UPDATE_VISIBLE_TILES";
case ACTION_ACTIVATE_SYNC_TREE:
return "ACTION_ACTIVATE_SYNC_TREE";
case ACTION_DRAW_AND_SWAP_IF_POSSIBLE:
@@ -206,8 +202,6 @@
last_frame_number_swap_requested_);
state->SetInteger("last_frame_number_begin_main_frame_sent",
last_frame_number_begin_main_frame_sent_);
- state->SetInteger("last_frame_number_update_visible_tiles_was_called",
- last_frame_number_update_visible_tiles_was_called_);
state->SetInteger("manage_tiles_funnel", manage_tiles_funnel_);
state->SetInteger("consecutive_checkerboard_animations",
@@ -217,7 +211,6 @@
state->SetBoolean("needs_redraw", needs_redraw_);
state->SetBoolean("needs_animate_", needs_animate_);
state->SetBoolean("needs_manage_tiles", needs_manage_tiles_);
- state->SetBoolean("swap_used_incomplete_tile", swap_used_incomplete_tile_);
state->SetBoolean("needs_commit", needs_commit_);
state->SetBoolean("visible", visible_);
state->SetBoolean("can_start", can_start_);
@@ -265,11 +258,6 @@
last_frame_number_begin_main_frame_sent_;
}
-bool SchedulerStateMachine::HasUpdatedVisibleTilesThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_update_visible_tiles_was_called_;
-}
-
bool SchedulerStateMachine::HasSwappedThisFrame() const {
return current_frame_number_ == last_frame_number_swap_performed_;
}
@@ -394,34 +382,6 @@
return pending_tree_is_ready_for_activation_;
}
-bool SchedulerStateMachine::ShouldUpdateVisibleTiles() const {
- if (!settings_.impl_side_painting)
- return false;
- if (HasUpdatedVisibleTilesThisFrame())
- return false;
-
- // We don't want to update visible tiles right after drawing.
- if (HasRequestedSwapThisFrame())
- return false;
-
- // There's no reason to check for tiles if we don't have an output surface.
- if (!HasInitializedOutputSurface())
- return false;
-
- // We should not check for visible tiles until we've entered the deadline so
- // we check as late as possible and give the tiles more time to initialize.
- if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
- return false;
-
- // If the last swap drew with checkerboard or missing tiles, we should
- // poll for any new visible tiles so we can be notified to draw again
- // when there are.
- if (swap_used_incomplete_tile_)
- return true;
-
- return false;
-}
-
bool SchedulerStateMachine::ShouldAnimate() const {
// If a commit occurred after our last call, we need to do animation again.
if (HasAnimatedThisFrame() && !did_commit_after_animating_)
@@ -534,8 +494,6 @@
}
SchedulerStateMachine::Action SchedulerStateMachine::NextAction() const {
- if (ShouldUpdateVisibleTiles())
- return ACTION_UPDATE_VISIBLE_TILES;
if (ShouldActivatePendingTree())
return ACTION_ACTIVATE_SYNC_TREE;
if (ShouldCommit())
@@ -564,11 +522,6 @@
case ACTION_NONE:
return;
- case ACTION_UPDATE_VISIBLE_TILES:
- last_frame_number_update_visible_tiles_was_called_ =
- current_frame_number_;
- return;
-
case ACTION_ACTIVATE_SYNC_TREE:
UpdateStateOnActivation();
return;
@@ -767,12 +720,6 @@
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return true;
- // We need to draw a more complete frame than we did the last BeginImplFrame,
- // so request another BeginImplFrame in anticipation that we will have
- // additional visible tiles.
- if (swap_used_incomplete_tile_)
- return true;
-
return needs_animate_ || needs_redraw_;
}
@@ -963,11 +910,6 @@
last_frame_number_swap_performed_ = current_frame_number_;
}
-void SchedulerStateMachine::SetSwapUsedIncompleteTile(
- bool used_incomplete_tile) {
- swap_used_incomplete_tile_ = used_incomplete_tile;
-}
-
void SchedulerStateMachine::DidSwapBuffersComplete() {
DCHECK_GT(pending_swaps_, 0);
pending_swaps_--;
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index a63a683..489ece6 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -95,7 +95,6 @@
ACTION_ANIMATE,
ACTION_SEND_BEGIN_MAIN_FRAME,
ACTION_COMMIT,
- ACTION_UPDATE_VISIBLE_TILES,
ACTION_ACTIVATE_SYNC_TREE,
ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
ACTION_DRAW_AND_SWAP_FORCED,
@@ -260,7 +259,6 @@
bool ShouldDrawForced() const;
bool ShouldDraw() const;
bool ShouldActivatePendingTree() const;
- bool ShouldUpdateVisibleTiles() const;
bool ShouldSendBeginMainFrame() const;
bool ShouldCommit() const;
bool ShouldManageTiles() const;
@@ -268,7 +266,6 @@
void AdvanceCurrentFrameNumber();
bool HasAnimatedThisFrame() const;
bool HasSentBeginMainFrameThisFrame() const;
- bool HasUpdatedVisibleTilesThisFrame() const;
bool HasRequestedSwapThisFrame() const;
bool HasSwappedThisFrame() const;
@@ -292,7 +289,6 @@
int last_frame_number_swap_performed_;
int last_frame_number_swap_requested_;
int last_frame_number_begin_main_frame_sent_;
- int last_frame_number_update_visible_tiles_was_called_;
// manage_tiles_funnel_ is "filled" each time ManageTiles is called
// and "drained" on each BeginImplFrame. If the funnel gets too full,
@@ -305,7 +301,6 @@
bool needs_redraw_;
bool needs_animate_;
bool needs_manage_tiles_;
- bool swap_used_incomplete_tile_;
bool needs_commit_;
bool inside_poll_for_anticipated_draw_triggers_;
bool visible_;
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 91900a2..7d61df3 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -88,8 +88,6 @@
FakeSchedulerClient()
: automatic_swap_ack_(true),
- swap_contains_incomplete_tile_(false),
- redraw_will_happen_if_update_visible_tiles_happens_(false),
now_src_(TestNowSource::Create()),
task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
fake_external_begin_frame_source_(nullptr),
@@ -191,10 +189,6 @@
return -1;
}
- void SetSwapContainsIncompleteTile(bool contain) {
- swap_contains_incomplete_tile_ = contain;
- }
-
bool HasAction(const char* action) const {
return ActionIndex(action) >= 0;
}
@@ -208,9 +202,6 @@
void SetAutomaticSwapAck(bool automatic_swap_ack) {
automatic_swap_ack_ = automatic_swap_ack;
}
- void SetRedrawWillHappenIfUpdateVisibleTilesHappens(bool redraw) {
- redraw_will_happen_if_update_visible_tiles_happens_ = redraw;
- }
// SchedulerClient implementation.
void WillBeginImplFrame(const BeginFrameArgs& args) override {
actions_.push_back("WillBeginImplFrame");
@@ -234,12 +225,6 @@
draw_will_happen_ && swap_will_happen_if_draw_happens_;
if (swap_will_happen) {
scheduler_->DidSwapBuffers();
- if (swap_contains_incomplete_tile_) {
- scheduler_->SetSwapUsedIncompleteTile(true);
- swap_contains_incomplete_tile_ = false;
- } else {
- scheduler_->SetSwapUsedIncompleteTile(false);
- }
if (automatic_swap_ack_)
scheduler_->DidSwapBuffersComplete();
@@ -255,12 +240,6 @@
actions_.push_back("ScheduledActionCommit");
states_.push_back(scheduler_->AsValue());
}
- void ScheduledActionUpdateVisibleTiles() override {
- actions_.push_back("ScheduledActionUpdateVisibleTiles");
- states_.push_back(scheduler_->AsValue());
- if (redraw_will_happen_if_update_visible_tiles_happens_)
- scheduler_->SetNeedsRedraw();
- }
void ScheduledActionActivateSyncTree() override {
actions_.push_back("ScheduledActionActivateSyncTree");
states_.push_back(scheduler_->AsValue());
@@ -303,8 +282,6 @@
bool automatic_swap_ack_;
int num_draws_;
bool log_anticipated_draw_time_change_;
- bool swap_contains_incomplete_tile_;
- bool redraw_will_happen_if_update_visible_tiles_happens_;
base::TimeTicks posted_begin_impl_frame_deadline_;
std::vector<const char*> actions_;
std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_;
@@ -1012,68 +989,6 @@
scheduler->DidManageTiles(); // Corresponds to ScheduledActionManageTiles
}
-TEST(SchedulerTest, ShouldUpdateVisibleTiles) {
- FakeSchedulerClient client;
- SchedulerSettings scheduler_settings;
- scheduler_settings.impl_side_painting = true;
- scheduler_settings.use_external_begin_frame_source = true;
- TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
- scheduler->SetCanStart();
- scheduler->SetVisible(true);
- scheduler->SetCanDraw(true);
- InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
-
- client.SetRedrawWillHappenIfUpdateVisibleTilesHappens(true);
-
- // SetNeedsCommit should begin the frame.
- client.Reset();
- scheduler->SetNeedsCommit();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client);
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
- EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- scheduler->NotifyBeginMainFrameStarted();
- scheduler->NotifyReadyToCommit();
- EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
-
- client.Reset();
- scheduler->NotifyReadyToActivate();
- EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client);
-
- client.Reset();
- client.SetSwapContainsIncompleteTile(true);
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
- EXPECT_FALSE(scheduler->RedrawPending());
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionUpdateVisibleTiles", client, 0, 3);
- EXPECT_ACTION("ScheduledActionAnimate", client, 1, 3);
- EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 2, 3);
-
- client.Reset();
- client.AdvanceFrame();
- EXPECT_SINGLE_ACTION("WillBeginImplFrame", client);
- EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
-
- // No more UpdateVisibleTiles().
- client.Reset();
- client.task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
-}
-
TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
SchedulerClientNeedsManageTilesInDraw client;
SchedulerSettings scheduler_settings;
diff --git a/cc/surfaces/display_client.h b/cc/surfaces/display_client.h
index b0f8f79..71ee434 100644
--- a/cc/surfaces/display_client.h
+++ b/cc/surfaces/display_client.h
@@ -25,6 +25,7 @@
protected:
virtual ~DisplayClient() {}
};
-}
+
+} // namespace cc
#endif // CC_SURFACES_DISPLAY_CLIENT_H_
diff --git a/cc/surfaces/surface_aggregator.cc b/cc/surfaces/surface_aggregator.cc
index 44afaff..588d624 100644
--- a/cc/surfaces/surface_aggregator.cc
+++ b/cc/surfaces/surface_aggregator.cc
@@ -381,6 +381,19 @@
}
}
+void SurfaceAggregator::RemoveUnreferencedChildren() {
+ for (const auto& surface : previous_contained_surfaces_) {
+ if (!contained_surfaces_.count(surface.first)) {
+ SurfaceToResourceChildIdMap::iterator it =
+ surface_id_to_resource_child_id_.find(surface.first);
+ if (it != surface_id_to_resource_child_id_.end()) {
+ provider_->DestroyChild(it->second);
+ surface_id_to_resource_child_id_.erase(it);
+ }
+ }
+ }
+}
+
scoped_ptr<CompositorFrame> SurfaceAggregator::Aggregate(SurfaceId surface_id) {
Surface* surface = manager_->GetSurfaceForId(surface_id);
DCHECK(surface);
@@ -406,6 +419,7 @@
DCHECK(referenced_surfaces_.empty());
dest_pass_list_ = NULL;
+ RemoveUnreferencedChildren();
contained_surfaces_.swap(previous_contained_surfaces_);
contained_surfaces_.clear();
diff --git a/cc/surfaces/surface_aggregator.h b/cc/surfaces/surface_aggregator.h
index 31d35dd..aeeb590 100644
--- a/cc/surfaces/surface_aggregator.h
+++ b/cc/surfaces/surface_aggregator.h
@@ -52,6 +52,10 @@
SurfaceId surface_id);
void CopyPasses(const DelegatedFrameData* frame_data, Surface* surface);
+ // Remove Surfaces that were referenced before but aren't currently
+ // referenced from the ResourceProvider.
+ void RemoveUnreferencedChildren();
+
bool TakeResources(Surface* surface,
const DelegatedFrameData* frame_data,
RenderPassList* render_pass_list);
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index 4771c82..5213327 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -1242,6 +1242,41 @@
factory.Destroy(surface_id);
}
+TEST_F(SurfaceAggregatorWithResourcesTest, TwoSurfaces) {
+ ResourceTrackingSurfaceFactoryClient client;
+ SurfaceFactory factory(&manager_, &client);
+ SurfaceId surface_id(7u);
+ factory.Create(surface_id, SurfaceSize());
+ SurfaceId surface_id2(8u);
+ factory.Create(surface_id2, SurfaceSize());
+
+ ResourceProvider::ResourceId ids[] = {11, 12, 13};
+ SubmitFrameWithResources(ids, arraysize(ids), &factory, surface_id);
+ ResourceProvider::ResourceId ids2[] = {14, 15, 16};
+ SubmitFrameWithResources(ids2, arraysize(ids2), &factory, surface_id2);
+
+ scoped_ptr<CompositorFrame> frame = aggregator_->Aggregate(surface_id);
+
+ SubmitFrameWithResources(NULL, 0, &factory, surface_id);
+
+ // Nothing should be available to be returned yet.
+ EXPECT_TRUE(client.returned_resources().empty());
+
+ frame = aggregator_->Aggregate(surface_id2);
+
+ // surface_id wasn't referenced, so its resources should be returned.
+ ASSERT_EQ(3u, client.returned_resources().size());
+ ResourceProvider::ResourceId returned_ids[3];
+ for (size_t i = 0; i < 3; ++i) {
+ returned_ids[i] = client.returned_resources()[i].id;
+ }
+ EXPECT_THAT(returned_ids,
+ testing::WhenSorted(testing::ElementsAreArray(ids)));
+ EXPECT_EQ(3u, resource_provider_->num_resources());
+ factory.Destroy(surface_id);
+ factory.Destroy(surface_id2);
+}
+
} // namespace
} // namespace cc
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index 3c44994..ced02a6 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -27,7 +27,6 @@
void SetNeedsRedrawOnImplThread() override {}
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {}
void SetNeedsAnimateOnImplThread() override {}
- void DidInitializeVisibleTileOnImplThread() override {}
void SetNeedsCommitOnImplThread() override {}
void SetNeedsManageTilesOnImplThread() override {}
void PostAnimationEventsToMainThreadOnImplThread(
diff --git a/cc/test/fake_picture_layer.cc b/cc/test/fake_picture_layer.cc
index bd169ba..1a19bc7 100644
--- a/cc/test/fake_picture_layer.cc
+++ b/cc/test/fake_picture_layer.cc
@@ -12,8 +12,19 @@
: PictureLayer(client),
update_count_(0),
push_properties_count_(0),
- always_update_resources_(false),
- output_surface_created_count_(0) {
+ output_surface_created_count_(0),
+ always_update_resources_(false) {
+ SetBounds(gfx::Size(1, 1));
+ SetIsDrawable(true);
+}
+
+FakePictureLayer::FakePictureLayer(ContentLayerClient* client,
+ scoped_ptr<RecordingSource> source)
+ : PictureLayer(client, source.Pass()),
+ update_count_(0),
+ push_properties_count_(0),
+ output_surface_created_count_(0),
+ always_update_resources_(false) {
SetBounds(gfx::Size(1, 1));
SetIsDrawable(true);
}
diff --git a/cc/test/fake_picture_layer.h b/cc/test/fake_picture_layer.h
index 7aa155e..f42a14d 100644
--- a/cc/test/fake_picture_layer.h
+++ b/cc/test/fake_picture_layer.h
@@ -8,15 +8,21 @@
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "cc/layers/picture_layer.h"
+#include "cc/resources/recording_source.h"
namespace cc {
-
class FakePictureLayer : public PictureLayer {
public:
static scoped_refptr<FakePictureLayer> Create(ContentLayerClient* client) {
return make_scoped_refptr(new FakePictureLayer(client));
}
+ static scoped_refptr<FakePictureLayer> CreateWithRecordingSource(
+ ContentLayerClient* client,
+ scoped_ptr<RecordingSource> source) {
+ return make_scoped_refptr(new FakePictureLayer(client, source.Pass()));
+ }
+
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
size_t update_count() const { return update_count_; }
@@ -41,12 +47,14 @@
private:
explicit FakePictureLayer(ContentLayerClient* client);
+ FakePictureLayer(ContentLayerClient* client,
+ scoped_ptr<RecordingSource> source);
~FakePictureLayer() override;
size_t update_count_;
size_t push_properties_count_;
- bool always_update_resources_;
size_t output_surface_created_count_;
+ bool always_update_resources_;
};
} // namespace cc
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index bf55ebf..13b20ad 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -105,7 +105,7 @@
if (tilings()) {
for (size_t i = 0; i < num_tilings(); ++i) {
tilings()->tiling_at(i)->UpdateTilesToCurrentRasterSource(
- Region(), raster_source_->GetSize());
+ raster_source_.get(), Region(), raster_source_->GetSize());
}
}
}
diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc
index a218a21..b21e011 100644
--- a/cc/test/fake_picture_layer_tiling_client.cc
+++ b/cc/test/fake_picture_layer_tiling_client.cc
@@ -49,10 +49,6 @@
return tile_manager_->CreateTile(pile_.get(), tile_size_, rect, 1, 0, 0, 0);
}
-RasterSource* FakePictureLayerTilingClient::GetRasterSource() {
- return pile_.get();
-}
-
void FakePictureLayerTilingClient::SetTileSize(const gfx::Size& tile_size) {
tile_size_ = tile_size;
}
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h
index c8cc4e2..acf26d0 100644
--- a/cc/test/fake_picture_layer_tiling_client.h
+++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -23,7 +23,6 @@
// PictureLayerTilingClient implementation.
scoped_refptr<Tile> CreateTile(PictureLayerTiling* tiling,
const gfx::Rect& rect) override;
- RasterSource* GetRasterSource() override;
gfx::Size CalculateTileSize(const gfx::Size& content_bounds) const override;
TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
size_t GetMaxTilesForInterestArea() const override;
@@ -61,6 +60,7 @@
skewport_extrapolation_limit_in_content_pixels_ = limit;
}
void set_tree(WhichTree tree) { tree_ = tree; }
+ RasterSource* raster_source() { return pile_.get(); }
TileManager* tile_manager() const {
return tile_manager_.get();
diff --git a/cc/test/fake_picture_pile.cc b/cc/test/fake_picture_pile.cc
new file mode 100644
index 0000000..912ec06
--- /dev/null
+++ b/cc/test/fake_picture_pile.cc
@@ -0,0 +1,15 @@
+// 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/test/fake_picture_pile.h"
+
+#include "cc/test/fake_picture_pile_impl.h"
+
+namespace cc {
+
+scoped_refptr<RasterSource> FakePicturePile::CreateRasterSource() const {
+ return FakePicturePileImpl::CreateFromPile(this, playback_allowed_event_);
+}
+
+} // namespace cc
diff --git a/cc/test/fake_picture_pile.h b/cc/test/fake_picture_pile.h
index e486e3b..4a7b65b 100644
--- a/cc/test/fake_picture_pile.h
+++ b/cc/test/fake_picture_pile.h
@@ -7,15 +7,29 @@
#include "cc/resources/picture_pile.h"
+namespace base {
+class WaitableEvent;
+}
+
namespace cc {
class FakePicturePile : public PicturePile {
public:
+ using PictureInfo = PicturePile::PictureInfo;
+ using PictureMapKey = PicturePile::PictureMapKey;
+ using PictureMap = PicturePile::PictureMap;
+
+ FakePicturePile() : playback_allowed_event_(nullptr) {}
~FakePicturePile() override {}
+ // PicturePile overrides.
+ scoped_refptr<RasterSource> CreateRasterSource() const override;
+
using PicturePile::buffer_pixels;
using PicturePile::CanRasterSlowTileCheck;
using PicturePile::Clear;
+ using PicturePile::SetMinContentsScale;
+ using PicturePile::SetTileGridSize;
PictureMap& picture_map() { return picture_map_; }
const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
@@ -37,6 +51,10 @@
has_any_recordings_ = has_recordings;
}
+ void SetPlaybackAllowedEvent(base::WaitableEvent* event) {
+ playback_allowed_event_ = event;
+ }
+
TilingData& tiling() { return tiling_; }
bool is_solid_color() const { return is_solid_color_; }
@@ -44,10 +62,10 @@
void SetPixelRecordDistance(int d) { pixel_record_distance_ = d; }
- typedef PicturePile::PictureInfo PictureInfo;
- typedef PicturePile::PictureMapKey PictureMapKey;
- typedef PicturePile::PictureMap PictureMap;
+ private:
+ base::WaitableEvent* playback_allowed_event_;
};
+
} // namespace cc
#endif // CC_TEST_FAKE_PICTURE_PILE_H_
diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc
index 3d31c12..cb68e87 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -8,6 +8,7 @@
#include <limits>
#include <utility>
+#include "base/synchronization/waitable_event.h"
#include "cc/resources/picture_pile.h"
#include "cc/test/fake_picture_pile.h"
#include "cc/test/impl_side_painting_settings.h"
@@ -15,10 +16,14 @@
namespace cc {
-FakePicturePileImpl::FakePicturePileImpl() {}
+FakePicturePileImpl::FakePicturePileImpl() : playback_allowed_event_(nullptr) {
+}
-FakePicturePileImpl::FakePicturePileImpl(const PicturePile* other)
+FakePicturePileImpl::FakePicturePileImpl(
+ const PicturePile* other,
+ base::WaitableEvent* playback_allowed_event)
: PicturePileImpl(other),
+ playback_allowed_event_(playback_allowed_event),
tile_grid_info_(other->GetTileGridInfoForTesting()) {
}
@@ -34,7 +39,7 @@
pile.SetRecordedViewport(gfx::Rect(layer_bounds));
pile.SetHasAnyRecordings(true);
- auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+ auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
for (int x = 0; x < pile_impl->tiling().num_tiles_x(); ++x) {
for (int y = 0; y < pile_impl->tiling().num_tiles_y(); ++y)
pile_impl->AddRecordingAt(x, y);
@@ -51,7 +56,7 @@
pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
pile.SetRecordedViewport(gfx::Rect());
pile.SetHasAnyRecordings(false);
- return make_scoped_refptr(new FakePicturePileImpl(&pile));
+ return make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
}
scoped_refptr<FakePicturePileImpl>
@@ -65,7 +70,7 @@
// This simulates a false positive for this flag.
pile.SetRecordedViewport(gfx::Rect());
pile.SetHasAnyRecordings(true);
- return make_scoped_refptr(new FakePicturePileImpl(&pile));
+ return make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
}
scoped_refptr<FakePicturePileImpl>
@@ -79,11 +84,26 @@
pile.SetRecordedViewport(gfx::Rect(size));
pile.SetHasAnyRecordings(true);
- auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+ auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile, nullptr));
pile_impl->AddRecordingAt(0, 0);
return pile_impl;
}
+scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateFromPile(
+ const PicturePile* other,
+ base::WaitableEvent* playback_allowed_event) {
+ return make_scoped_refptr(
+ new FakePicturePileImpl(other, playback_allowed_event));
+}
+
+void FakePicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
+ if (playback_allowed_event_)
+ playback_allowed_event_->Wait();
+ PicturePileImpl::PlaybackToCanvas(canvas, canvas_rect, contents_scale);
+}
+
void FakePicturePileImpl::AddRecordingAt(int x, int y) {
EXPECT_GE(x, 0);
EXPECT_GE(y, 0);
diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h
index f1a9d31..5769d37 100644
--- a/cc/test/fake_picture_pile_impl.h
+++ b/cc/test/fake_picture_pile_impl.h
@@ -9,6 +9,10 @@
#include "cc/resources/picture_pile_impl.h"
#include "cc/test/fake_content_layer_client.h"
+namespace base {
+class WaitableEvent;
+}
+
namespace cc {
class FakePicturePileImpl : public PicturePileImpl {
@@ -23,6 +27,14 @@
CreateEmptyPileThatThinksItHasRecordings(const gfx::Size& tile_size,
const gfx::Size& layer_bounds);
static scoped_refptr<FakePicturePileImpl> CreateInfiniteFilledPile();
+ static scoped_refptr<FakePicturePileImpl> CreateFromPile(
+ const PicturePile* other,
+ base::WaitableEvent* playback_allowed_event);
+
+ // Hi-jack the PlaybackToCanvas method to delay its completion.
+ void PlaybackToCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const override;
TilingData& tiling() { return tiling_; }
@@ -56,14 +68,6 @@
background_color_ = color;
}
- void set_contents_opaque(bool contents_opaque) {
- contents_opaque_ = contents_opaque;
- }
-
- void set_contents_fill_bounds_completely(bool fills) {
- contents_fill_bounds_completely_ = fills;
- }
-
void set_clear_canvas_with_debug_color(bool clear) {
clear_canvas_with_debug_color_ = clear;
}
@@ -73,7 +77,6 @@
}
bool HasRecordingAt(int x, int y) const;
- void SetIsMask(bool mask) { is_mask_ = mask; }
int num_tiles_x() const { return tiling_.num_tiles_x(); }
int num_tiles_y() const { return tiling_.num_tiles_y(); }
@@ -84,11 +87,13 @@
protected:
FakePicturePileImpl();
- explicit FakePicturePileImpl(const PicturePile* other);
+ FakePicturePileImpl(const PicturePile* other,
+ base::WaitableEvent* playback_allowed_event);
~FakePicturePileImpl() override;
FakeContentLayerClient client_;
SkPaint default_paint_;
+ base::WaitableEvent* playback_allowed_event_;
SkTileGridFactory::TileGridInfo tile_grid_info_;
};
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 373959d..89cc554 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -69,7 +69,7 @@
DCHECK(CalledOnValidThread());
}
- virtual void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
+ void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
DCHECK(CalledOnValidThread());
if (needs_begin_frames) {
base::MessageLoop::current()->PostDelayedTask(
@@ -80,7 +80,7 @@
}
}
- virtual void SetClientReady() override {
+ void SetClientReady() override {
DCHECK(CalledOnValidThread());
is_ready_ = true;
}
@@ -259,22 +259,17 @@
LayerTreeHostImpl::ReclaimResources(ack);
}
- void UpdateVisibleTiles() override {
- LayerTreeHostImpl::UpdateVisibleTiles();
- test_hooks_->UpdateVisibleTilesOnThread(this);
- }
-
void NotifyReadyToActivate() override {
if (block_notify_ready_to_activate_for_testing_) {
notify_ready_to_activate_was_blocked_ = true;
} else {
- client_->NotifyReadyToActivate();
+ LayerTreeHostImpl::NotifyReadyToActivate();
test_hooks_->NotifyReadyToActivateOnThread(this);
}
}
void NotifyReadyToDraw() override {
- client_->NotifyReadyToDraw();
+ LayerTreeHostImpl::NotifyReadyToDraw();
test_hooks_->NotifyReadyToDrawOnThread(this);
}
@@ -327,6 +322,11 @@
test_hooks_->UpdateAnimationState(this, has_unfinished_animation);
}
+ void NotifyTileStateChanged(const Tile* tile) override {
+ LayerTreeHostImpl::NotifyTileStateChanged(tile);
+ test_hooks_->NotifyTileStateChangedOnThread(this, tile);
+ }
+
private:
TestHooks* test_hooks_;
bool block_notify_ready_to_activate_for_testing_;
@@ -513,7 +513,7 @@
}
}
-void LayerTreeTest::EndTestAfterDelay(int delay_milliseconds) {
+void LayerTreeTest::EndTestAfterDelayMs(int delay_milliseconds) {
main_task_runner_->PostDelayedTask(
FROM_HERE,
base::Bind(&LayerTreeTest::EndTest, main_thread_weak_ptr_),
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 531e28d..b801d94 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -57,9 +57,10 @@
virtual void DrawLayersOnThread(LayerTreeHostImpl* host_impl) {}
virtual void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) {}
virtual void SwapBuffersCompleteOnThread(LayerTreeHostImpl* host_impl) {}
- virtual void UpdateVisibleTilesOnThread(LayerTreeHostImpl* host_impl) {}
virtual void NotifyReadyToActivateOnThread(LayerTreeHostImpl* host_impl) {}
virtual void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) {}
+ virtual void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+ const Tile* tile) {}
virtual void AnimateLayers(LayerTreeHostImpl* host_impl,
base::TimeTicks monotonic_time) {}
virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
@@ -130,7 +131,7 @@
virtual ~LayerTreeTest();
virtual void EndTest();
- void EndTestAfterDelay(int delay_milliseconds);
+ void EndTestAfterDelayMs(int delay_milliseconds);
void PostAddAnimationToMainThread(Layer* layer_to_receive_animation);
void PostAddInstantAnimationToMainThread(Layer* layer_to_receive_animation);
diff --git a/cc/test/pixel_test.h b/cc/test/pixel_test.h
index dff2790..46cdcba 100644
--- a/cc/test/pixel_test.h
+++ b/cc/test/pixel_test.h
@@ -93,7 +93,7 @@
bool ExpandedViewport() const;
protected:
- virtual void SetUp() override;
+ void SetUp() override;
};
// Wrappers to differentiate renderers where the the output surface and viewport
diff --git a/cc/test/pixel_test_utils.h b/cc/test/pixel_test_utils.h
index d8ff7fd..81d20ce 100644
--- a/cc/test/pixel_test_utils.h
+++ b/cc/test/pixel_test_utils.h
@@ -5,6 +5,8 @@
#ifndef CC_TEST_PIXEL_TEST_UTILS_H_
#define CC_TEST_PIXEL_TEST_UTILS_H_
+#include <string>
+
#include "base/files/file_path.h"
#include "cc/test/pixel_comparator.h"
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 696da7a..ffe2ddb 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -174,8 +174,8 @@
} // namespace
-LayerTreeHostImpl::FrameData::FrameData()
- : contains_incomplete_tile(false), has_no_damage(false) {}
+LayerTreeHostImpl::FrameData::FrameData() : has_no_damage(false) {
+}
LayerTreeHostImpl::FrameData::~FrameData() {}
@@ -239,11 +239,11 @@
animation_registrar_(AnimationRegistrar::Create()),
rendering_stats_instrumentation_(rendering_stats_instrumentation),
micro_benchmark_controller_(this),
- need_to_update_visible_tiles_before_draw_(false),
shared_bitmap_manager_(shared_bitmap_manager),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
id_(id),
- requires_high_res_to_draw_(false) {
+ requires_high_res_to_draw_(false),
+ required_for_draw_tile_is_top_of_raster_queue_(false) {
DCHECK(proxy_->IsImplThread());
DidVisibilityChange(this, visible_);
animation_registrar_->set_supports_scroll_animations(
@@ -489,7 +489,6 @@
void LayerTreeHostImpl::FrameData::AsValueInto(
base::debug::TracedValue* value) const {
- value->SetBoolean("contains_incomplete_tile", contains_incomplete_tile);
value->SetBoolean("has_no_damage", has_no_damage);
// Quad data can be quite large, so only dump render passes if we select
@@ -839,7 +838,6 @@
if (append_quads_data.num_incomplete_tiles ||
append_quads_data.num_missing_tiles) {
- frame->contains_incomplete_tile = true;
if (RequiresHighResToDraw())
draw_result = DRAW_ABORTED_MISSING_HIGH_RES_CONTENT;
}
@@ -1034,12 +1032,11 @@
"LayerTreeHostImpl::PrepareToDraw",
"SourceFrameNumber",
active_tree_->source_frame_number());
-
- if (need_to_update_visible_tiles_before_draw_ &&
- tile_manager_ && tile_manager_->UpdateVisibleTiles()) {
- DidInitializeVisibleTile();
- }
- need_to_update_visible_tiles_before_draw_ = true;
+ // This will cause NotifyTileStateChanged() to be called for any visible tiles
+ // that completed, which will add damage to the frame for them so they appear
+ // as part of the current frame being drawn.
+ if (settings().impl_side_painting)
+ tile_manager_->UpdateVisibleTiles();
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Compositing.NumActiveLayers", active_tree_->NumLayers(), 1, 400, 20);
@@ -1051,7 +1048,6 @@
frame->render_passes.clear();
frame->render_passes_by_id.clear();
frame->will_draw_layers.clear();
- frame->contains_incomplete_tile = false;
frame->has_no_damage = false;
if (active_tree_->root_layer()) {
@@ -1082,13 +1078,6 @@
NOTREACHED();
}
-void LayerTreeHostImpl::DidInitializeVisibleTileForTesting() {
- // Add arbitrary damage, to trigger prepare-to-draws.
- // Here, setting damage as viewport size, used only for testing.
- SetFullRootLayerDamage();
- DidInitializeVisibleTile();
-}
-
void LayerTreeHostImpl::ResetTreesForTesting() {
if (active_tree_)
active_tree_->DetachLayerTree();
@@ -1180,11 +1169,6 @@
client_->SetNeedsManageTilesOnImplThread();
}
-void LayerTreeHostImpl::DidInitializeVisibleTile() {
- if (client_ && !client_->IsInsideDraw())
- client_->DidInitializeVisibleTileOnImplThread();
-}
-
void LayerTreeHostImpl::GetPictureLayerImplPairs(
std::vector<PictureLayerImpl::Pair>* layer_pairs,
bool need_valid_tile_priorities) const {
@@ -1225,6 +1209,20 @@
picture_layer_pairs_.clear();
GetPictureLayerImplPairs(&picture_layer_pairs_, true);
queue->Build(picture_layer_pairs_, tree_priority);
+
+ if (!queue->IsEmpty()) {
+ // Only checking the Top() tile here isn't a definite answer that there is
+ // or isn't something required for draw in this raster queue. It's just a
+ // heuristic to let us hit the common case and proactively tell the
+ // scheduler that we expect to draw within each vsync until we get all the
+ // tiles ready to draw. If we happen to miss a required for draw tile here,
+ // then we will miss telling the scheduler each frame that we intend to draw
+ // so it may make worse scheduling decisions.
+ required_for_draw_tile_is_top_of_raster_queue_ =
+ queue->Top()->required_for_draw();
+ } else {
+ required_for_draw_tile_is_top_of_raster_queue_ = false;
+ }
}
void LayerTreeHostImpl::BuildEvictionQueue(EvictionTilePriorityQueue* queue,
@@ -1245,6 +1243,11 @@
}
void LayerTreeHostImpl::NotifyReadyToDraw() {
+ // Tiles that are ready will cause NotifyTileStateChanged() to be called so we
+ // don't need to schedule a draw here. Just stop WillBeginImplFrame() from
+ // causing optimistic requests to draw a frame.
+ required_for_draw_tile_is_top_of_raster_queue_ = false;
+
client_->NotifyReadyToDraw();
}
@@ -1264,6 +1267,13 @@
if (layer_impl)
layer_impl->NotifyTileStateChanged(tile);
}
+
+ // Check for a non-null active tree to avoid doing this during shutdown.
+ if (active_tree_ && !client_->IsInsideDraw() && tile->required_for_draw()) {
+ // The LayerImpl::NotifyTileStateChanged() should damage the layer, so this
+ // redraw will make those tiles be displayed.
+ SetNeedsRedraw();
+ }
}
void LayerTreeHostImpl::SetMemoryPolicy(const ManagedMemoryPolicy& policy) {
@@ -1602,6 +1612,13 @@
UpdateCurrentBeginFrameArgs(args);
// Cache the begin impl frame interval
begin_impl_frame_interval_ = args.interval;
+
+ if (required_for_draw_tile_is_top_of_raster_queue_) {
+ // Optimistically schedule a draw, as a tile required for draw is at the top
+ // of the current raster queue. This will let us expect the tile to complete
+ // and draw it within the impl frame we are beginning now.
+ SetNeedsRedraw();
+ }
}
void LayerTreeHostImpl::UpdateViewportContainerSizes() {
@@ -1729,15 +1746,7 @@
TRACE_EVENT_ASYNC_BEGIN0("cc", "PendingTree:waiting", pending_tree_.get());
}
-void LayerTreeHostImpl::UpdateVisibleTiles() {
- if (tile_manager_ && tile_manager_->UpdateVisibleTiles())
- DidInitializeVisibleTile();
- need_to_update_visible_tiles_before_draw_ = false;
-}
-
void LayerTreeHostImpl::ActivateSyncTree() {
- need_to_update_visible_tiles_before_draw_ = true;
-
if (pending_tree_) {
TRACE_EVENT_ASYNC_END0("cc", "PendingTree:waiting", pending_tree_.get());
@@ -1940,7 +1949,6 @@
scheduled_raster_task_limit);
UpdateTileManagerMemoryPolicy(ActualManagedMemoryPolicy());
- need_to_update_visible_tiles_before_draw_ = false;
}
void LayerTreeHostImpl::CreateResourceAndRasterWorkerPool(
@@ -2940,9 +2948,6 @@
// scales that we want when we're not inside a pinch.
active_tree_->set_needs_update_draw_properties();
SetNeedsRedraw();
- // TODO(danakj): Don't set root damage. Just updating draw properties and
- // getting new tiles rastered should be enough! crbug.com/427423
- SetFullRootLayerDamage();
}
static void CollectScrollDeltas(ScrollAndScaleSet* scroll_info,
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 24cb730..ba4fabf 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -82,7 +82,6 @@
virtual void SetNeedsRedrawOnImplThread() = 0;
virtual void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) = 0;
virtual void SetNeedsAnimateOnImplThread() = 0;
- virtual void DidInitializeVisibleTileOnImplThread() = 0;
virtual void SetNeedsCommitOnImplThread() = 0;
virtual void SetNeedsManageTilesOnImplThread() = 0;
virtual void PostAnimationEventsToMainThreadOnImplThread(
@@ -172,7 +171,6 @@
RenderPassIdHashMap render_passes_by_id;
const LayerImplList* render_surface_layer_list;
LayerImplList will_draw_layers;
- bool contains_incomplete_tile;
bool has_no_damage;
// RenderPassSink implementation.
@@ -210,9 +208,6 @@
// immediately if any notifications had been blocked while blocking.
virtual void BlockNotifyReadyToActivateForTesting(bool block);
- // This allows us to inject DidInitializeVisibleTile events for testing.
- void DidInitializeVisibleTileForTesting();
-
// Resets all of the trees to an empty state.
void ResetTreesForTesting();
@@ -302,7 +297,6 @@
return pending_tree_ ? pending_tree_.get() : active_tree_.get();
}
virtual void CreatePendingTree();
- virtual void UpdateVisibleTiles();
virtual void ActivateSyncTree();
// Shortcuts to layers on the active tree.
@@ -574,8 +568,6 @@
bool zero_budget);
void EnforceManagedMemoryPolicy(const ManagedMemoryPolicy& policy);
- void DidInitializeVisibleTile();
-
void MarkUIResourceNotEvicted(UIResourceId uid);
void NotifySwapPromiseMonitorsOfSetNeedsRedraw();
@@ -699,8 +691,6 @@
MicroBenchmarkControllerImpl micro_benchmark_controller_;
scoped_ptr<TaskGraphRunner> single_thread_synchronous_task_graph_runner_;
- bool need_to_update_visible_tiles_before_draw_;
-
// Optional callback to notify of new tree activations.
base::Closure tree_activation_callback_;
@@ -714,6 +704,7 @@
std::vector<PictureLayerImpl::Pair> picture_layer_pairs_;
bool requires_high_res_to_draw_;
+ bool required_for_draw_tile_is_top_of_raster_queue_;
DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImpl);
};
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 17179cd..0b9d976 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -87,7 +87,6 @@
did_request_redraw_(false),
did_request_animate_(false),
did_request_manage_tiles_(false),
- did_upload_visible_tile_(false),
reduce_memory_result_(true),
current_limit_bytes_(0),
current_priority_cutoff_value_(0) {
@@ -103,11 +102,11 @@
return settings;
}
- virtual void SetUp() override {
+ void SetUp() override {
CreateHostImpl(DefaultSettings(), CreateOutputSurface());
}
- virtual void TearDown() override {}
+ void TearDown() override {}
void UpdateRendererCapabilitiesOnImplThread() override {}
void DidLoseOutputSurfaceOnImplThread() override {}
@@ -133,9 +132,6 @@
void SetNeedsManageTilesOnImplThread() override {
did_request_manage_tiles_ = true;
}
- void DidInitializeVisibleTileOnImplThread() override {
- did_upload_visible_tile_ = true;
- }
void SetNeedsCommitOnImplThread() override { did_request_commit_ = true; }
void PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> events) override {}
@@ -394,7 +390,6 @@
bool did_request_redraw_;
bool did_request_animate_;
bool did_request_manage_tiles_;
- bool did_upload_visible_tile_;
bool reduce_memory_result_;
base::Closure scrollbar_fade_start_;
base::TimeDelta requested_scrollbar_animation_delay_;
@@ -6224,7 +6219,7 @@
class LayerTreeHostImplTestDeferredInitialize : public LayerTreeHostImplTest {
protected:
- virtual void SetUp() override {
+ void SetUp() override {
LayerTreeHostImplTest::SetUp();
set_reduce_memory_result(false);
@@ -6413,7 +6408,7 @@
class LayerTreeHostImplTestManageTiles : public LayerTreeHostImplTest {
public:
- virtual void SetUp() override {
+ void SetUp() override {
LayerTreeSettings settings;
settings.impl_side_painting = true;
@@ -7071,7 +7066,7 @@
class LayerTreeHostImplWithTopControlsTest : public LayerTreeHostImplTest {
public:
- virtual void SetUp() override {
+ void SetUp() override {
LayerTreeSettings settings = DefaultSettings();
settings.calculate_top_controls_position = true;
settings.top_controls_height = top_controls_height_;
@@ -7459,7 +7454,7 @@
class LayerTreeHostImplWithImplicitLimitsTest : public LayerTreeHostImplTest {
public:
- virtual void SetUp() override {
+ void SetUp() override {
LayerTreeSettings settings = DefaultSettings();
settings.max_memory_for_prepaint_percentage = 50;
CreateHostImpl(settings, CreateOutputSurface());
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index 148769e..14029b5 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -61,7 +61,7 @@
pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
}
- virtual void InitializeSettings(LayerTreeSettings* settings) override {
+ void InitializeSettings(LayerTreeSettings* settings) override {
settings->force_antialiasing = force_antialiasing_;
settings->force_blending_with_shaders = force_blending_with_shaders_;
}
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 5c66790..e39a76d 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -25,6 +25,7 @@
#include "cc/output/output_surface.h"
#include "cc/quads/draw_quad.h"
#include "cc/quads/io_surface_draw_quad.h"
+#include "cc/quads/tile_draw_quad.h"
#include "cc/resources/prioritized_resource.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/resource_update_queue.h"
@@ -36,6 +37,7 @@
#include "cc/test/fake_painted_scrollbar_layer.h"
#include "cc/test/fake_picture_layer.h"
#include "cc/test/fake_picture_layer_impl.h"
+#include "cc/test/fake_picture_pile.h"
#include "cc/test/fake_proxy.h"
#include "cc/test/fake_scoped_ui_resource.h"
#include "cc/test/geometry_test_utils.h"
@@ -415,12 +417,13 @@
class LayerTreeHostTestSetNeedsRedrawRect : public LayerTreeHostTest {
public:
LayerTreeHostTestSetNeedsRedrawRect()
- : num_draws_(0),
- bounds_(50, 50),
- invalid_rect_(10, 10, 20, 20),
- root_layer_(ContentLayer::Create(&client_)) {}
+ : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {}
void BeginTest() override {
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_layer_ = FakePictureLayer::Create(&client_);
+ else
+ root_layer_ = ContentLayer::Create(&client_);
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(bounds_);
layer_tree_host()->SetRootLayer(root_layer_);
@@ -464,7 +467,7 @@
const gfx::Size bounds_;
const gfx::Rect invalid_rect_;
FakeContentLayerClient client_;
- scoped_refptr<ContentLayer> root_layer_;
+ scoped_refptr<Layer> root_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsRedrawRect);
@@ -479,7 +482,10 @@
root_layer_ = Layer::Create();
root_layer_->SetBounds(gfx::Size(10, 20));
- scaled_layer_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ scaled_layer_ = FakePictureLayer::Create(&client_);
+ else
+ scaled_layer_ = FakeContentLayer::Create(&client_);
scaled_layer_->SetBounds(gfx::Size(1, 1));
root_layer_->AddChild(scaled_layer_);
@@ -497,10 +503,15 @@
void DidCommit() override {
switch (layer_tree_host()->source_frame_number()) {
case 1:
- // Changing the device scale factor causes a commit. It also changes
- // the content bounds of |scaled_layer_|, which should not generate
- // a second commit as a result.
- layer_tree_host()->SetDeviceScaleFactor(4.f);
+ // SetBounds grows the layer and exposes new content.
+ if (layer_tree_host()->settings().impl_side_painting) {
+ scaled_layer_->SetBounds(gfx::Size(4, 4));
+ } else {
+ // Changing the device scale factor causes a commit. It also changes
+ // the content bounds of |scaled_layer_|, which should not generate
+ // a second commit as a result.
+ layer_tree_host()->SetDeviceScaleFactor(4.f);
+ }
break;
default:
// No extra commits.
@@ -516,7 +527,7 @@
private:
FakeContentLayerClient client_;
scoped_refptr<Layer> root_layer_;
- scoped_refptr<FakeContentLayer> scaled_layer_;
+ scoped_refptr<Layer> scaled_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoExtraCommitFromInvalidate);
@@ -583,12 +594,13 @@
class LayerTreeHostTestSetNextCommitForcesRedraw : public LayerTreeHostTest {
public:
LayerTreeHostTestSetNextCommitForcesRedraw()
- : num_draws_(0),
- bounds_(50, 50),
- invalid_rect_(10, 10, 20, 20),
- root_layer_(ContentLayer::Create(&client_)) {}
+ : num_draws_(0), bounds_(50, 50), invalid_rect_(10, 10, 20, 20) {}
void BeginTest() override {
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_layer_ = FakePictureLayer::Create(&client_);
+ else
+ root_layer_ = ContentLayer::Create(&client_);
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(bounds_);
layer_tree_host()->SetRootLayer(root_layer_);
@@ -665,7 +677,7 @@
const gfx::Size bounds_;
const gfx::Rect invalid_rect_;
FakeContentLayerClient client_;
- scoped_refptr<ContentLayer> root_layer_;
+ scoped_refptr<Layer> root_layer_;
};
SINGLE_AND_MULTI_THREAD_BLOCKNOTIFY_TEST_F(
@@ -675,22 +687,31 @@
// its damage is preserved until the next time it is drawn.
class LayerTreeHostTestUndrawnLayersDamageLater : public LayerTreeHostTest {
public:
- LayerTreeHostTestUndrawnLayersDamageLater()
- : root_layer_(ContentLayer::Create(&client_)) {}
+ LayerTreeHostTestUndrawnLayersDamageLater() {}
void SetupTree() override {
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_layer_ = FakePictureLayer::Create(&client_);
+ else
+ root_layer_ = ContentLayer::Create(&client_);
root_layer_->SetIsDrawable(true);
root_layer_->SetBounds(gfx::Size(50, 50));
layer_tree_host()->SetRootLayer(root_layer_);
// The initially transparent layer has a larger child layer, which is
// not initially drawn because of the this (parent) layer.
- parent_layer_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ parent_layer_ = FakePictureLayer::Create(&client_);
+ else
+ parent_layer_ = FakeContentLayer::Create(&client_);
parent_layer_->SetBounds(gfx::Size(15, 15));
parent_layer_->SetOpacity(0.0f);
root_layer_->AddChild(parent_layer_);
- child_layer_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ child_layer_ = FakePictureLayer::Create(&client_);
+ else
+ child_layer_ = FakeContentLayer::Create(&client_);
child_layer_->SetBounds(gfx::Size(25, 25));
parent_layer_->AddChild(child_layer_);
@@ -755,9 +776,9 @@
private:
FakeContentLayerClient client_;
- scoped_refptr<ContentLayer> root_layer_;
- scoped_refptr<FakeContentLayer> parent_layer_;
- scoped_refptr<FakeContentLayer> child_layer_;
+ scoped_refptr<Layer> root_layer_;
+ scoped_refptr<Layer> parent_layer_;
+ scoped_refptr<Layer> child_layer_;
};
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
@@ -1130,16 +1151,27 @@
// from being updated during commit.
class LayerTreeHostTestOpacityChange : public LayerTreeHostTest {
public:
- LayerTreeHostTestOpacityChange()
- : test_opacity_change_delegate_(),
- update_check_layer_(ContentLayerWithUpdateTracking::Create(
- &test_opacity_change_delegate_)) {
- test_opacity_change_delegate_.SetTestLayer(update_check_layer_.get());
- }
+ LayerTreeHostTestOpacityChange() : test_opacity_change_delegate_() {}
void BeginTest() override {
+ if (layer_tree_host()->settings().impl_side_painting) {
+ update_check_picture_layer_ =
+ FakePictureLayer::Create(&test_opacity_change_delegate_);
+ test_opacity_change_delegate_.SetTestLayer(
+ update_check_picture_layer_.get());
+ is_impl_paint_ = true;
+ } else {
+ update_check_content_layer_ = ContentLayerWithUpdateTracking::Create(
+ &test_opacity_change_delegate_);
+ test_opacity_change_delegate_.SetTestLayer(
+ update_check_content_layer_.get());
+ is_impl_paint_ = false;
+ }
layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
- layer_tree_host()->root_layer()->AddChild(update_check_layer_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ layer_tree_host()->root_layer()->AddChild(update_check_picture_layer_);
+ else
+ layer_tree_host()->root_layer()->AddChild(update_check_content_layer_);
PostSetNeedsCommitToMainThread();
}
@@ -1148,47 +1180,36 @@
void AfterTest() override {
// Update() should have been called once.
- EXPECT_EQ(1, update_check_layer_->PaintContentsCount());
+ if (is_impl_paint_)
+ EXPECT_EQ(1u, update_check_picture_layer_->update_count());
+ else
+ EXPECT_EQ(1, update_check_content_layer_->PaintContentsCount());
}
private:
TestOpacityChangeLayerDelegate test_opacity_change_delegate_;
- scoped_refptr<ContentLayerWithUpdateTracking> update_check_layer_;
+ scoped_refptr<ContentLayerWithUpdateTracking> update_check_content_layer_;
+ scoped_refptr<FakePictureLayer> update_check_picture_layer_;
+ bool is_impl_paint_;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestOpacityChange);
-class NoScaleContentLayer : public ContentLayer {
- public:
- static scoped_refptr<NoScaleContentLayer> Create(ContentLayerClient* client) {
- return make_scoped_refptr(new NoScaleContentLayer(client));
- }
-
- void CalculateContentsScale(float ideal_contents_scale,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* contentBounds) override {
- // Skip over the ContentLayer's method to the base Layer class.
- Layer::CalculateContentsScale(ideal_contents_scale,
- contents_scale_x,
- contents_scale_y,
- contentBounds);
- }
-
- private:
- explicit NoScaleContentLayer(ContentLayerClient* client)
- : ContentLayer(client) {}
- ~NoScaleContentLayer() override {}
-};
-
class LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers
: public LayerTreeHostTest {
public:
- LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers()
- : root_layer_(NoScaleContentLayer::Create(&client_)),
- child_layer_(ContentLayer::Create(&client_)) {}
+ LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers() {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ // PictureLayer can only be used with impl side painting enabled.
+ settings->impl_side_painting = true;
+ }
void BeginTest() override {
+ client_.set_fill_with_nonsolid_color(true);
+ root_layer_ = FakePictureLayer::Create(&client_);
+ child_layer_ = FakePictureLayer::Create(&client_);
+
layer_tree_host()->SetViewportSize(gfx::Size(60, 60));
layer_tree_host()->SetDeviceScaleFactor(1.5);
EXPECT_EQ(gfx::Size(60, 60), layer_tree_host()->device_viewport_size());
@@ -1219,8 +1240,10 @@
// Device viewport is scaled.
EXPECT_EQ(gfx::Size(60, 60), impl->DrawViewportSize());
- LayerImpl* root = impl->active_tree()->root_layer();
- LayerImpl* child = impl->active_tree()->root_layer()->children()[0];
+ FakePictureLayerImpl* root =
+ static_cast<FakePictureLayerImpl*>(impl->active_tree()->root_layer());
+ FakePictureLayerImpl* child = static_cast<FakePictureLayerImpl*>(
+ impl->active_tree()->root_layer()->children()[0]);
// Positions remain in layout pixels.
EXPECT_EQ(gfx::Point(0, 0), root->position());
@@ -1244,10 +1267,8 @@
EXPECT_RECT_EQ(gfx::Rect(0, 0, 60, 60),
root->render_surface()->content_rect());
- // The content bounds of the child should be scaled.
- gfx::Size child_bounds_scaled =
- gfx::ToCeiledSize(gfx::ScaleSize(child->bounds(), 1.5));
- EXPECT_EQ(child_bounds_scaled, child->content_bounds());
+ // The max tiling scale of the child should be scaled.
+ EXPECT_FLOAT_EQ(1.5f, child->MaximumTilingContentsScale());
gfx::Transform scale_transform;
scale_transform.Scale(impl->device_scale_factor(),
@@ -1261,13 +1282,13 @@
EXPECT_EQ(root_screen_space_transform, root->screen_space_transform());
// The child is at position 2,2, which is transformed to 3,3 after the scale
- gfx::Transform child_screen_space_transform;
- child_screen_space_transform.Translate(3.f, 3.f);
- gfx::Transform child_draw_transform = child_screen_space_transform;
+ gfx::Transform child_transform;
+ child_transform.Translate(3.f, 3.f);
+ child_transform.Scale(child->MaximumTilingContentsScale(),
+ child->MaximumTilingContentsScale());
- EXPECT_TRANSFORMATION_MATRIX_EQ(child_draw_transform,
- child->draw_transform());
- EXPECT_TRANSFORMATION_MATRIX_EQ(child_screen_space_transform,
+ EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform, child->draw_transform());
+ EXPECT_TRANSFORMATION_MATRIX_EQ(child_transform,
child->screen_space_transform());
EndTest();
@@ -1277,12 +1298,13 @@
private:
FakeContentLayerClient client_;
- scoped_refptr<NoScaleContentLayer> root_layer_;
- scoped_refptr<ContentLayer> child_layer_;
+ scoped_refptr<FakePictureLayer> root_layer_;
+ scoped_refptr<FakePictureLayer> child_layer_;
};
MULTI_THREAD_TEST_F(LayerTreeHostTestDeviceScaleFactorScalesViewportAndLayers);
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
// Verify atomicity of commits and reuse of textures.
class LayerTreeHostTestDirectRendererAtomicCommit : public LayerTreeHostTest {
public:
@@ -1391,6 +1413,7 @@
MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(
LayerTreeHostTestDirectRendererAtomicCommit);
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
class LayerTreeHostTestDelegatingRendererAtomicCommit
: public LayerTreeHostTestDirectRendererAtomicCommit {
public:
@@ -1458,6 +1481,7 @@
layer->SetContentsOpaque(opaque);
}
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
class LayerTreeHostTestAtomicCommitWithPartialUpdate
: public LayerTreeHostTest {
public:
@@ -1631,6 +1655,7 @@
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(
LayerTreeHostTestAtomicCommitWithPartialUpdate);
+// TODO(sohanjg) : Make it work with impl-side painting.
class LayerTreeHostTestSurfaceNotAllocatedForLayersOutsideMemoryLimit
: public LayerTreeHostTest {
protected:
@@ -1951,11 +1976,15 @@
layer_tree_host()->SetViewportSize(gfx::Size(10, 10));
layer_tree_host()->root_layer()->SetBounds(gfx::Size(10, 10));
- content_layer_ = ContentLayer::Create(&client_);
- content_layer_->SetBounds(gfx::Size(10, 10));
- content_layer_->SetPosition(gfx::PointF(0.f, 0.f));
- content_layer_->SetIsDrawable(true);
- layer_tree_host()->root_layer()->AddChild(content_layer_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ layer_ = FakePictureLayer::Create(&client_);
+ else
+ layer_ = FakeContentLayer::Create(&client_);
+
+ layer_->SetBounds(gfx::Size(10, 10));
+ layer_->SetPosition(gfx::PointF(0.f, 0.f));
+ layer_->SetIsDrawable(true);
+ layer_tree_host()->root_layer()->AddChild(layer_);
PostSetNeedsCommitToMainThread();
}
@@ -1963,7 +1992,7 @@
void DidCommitAndDrawFrame() override {
if (num_draw_layers_ == 2)
return;
- content_layer_->SetNeedsDisplay();
+ layer_->SetNeedsDisplay();
}
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
@@ -1984,12 +2013,12 @@
private:
FakeContentLayerClient client_;
- scoped_refptr<Layer> content_layer_;
+ scoped_refptr<Layer> layer_;
int num_commit_complete_;
int num_draw_layers_;
};
-MULTI_THREAD_NOIMPL_TEST_F(LayerTreeHostTestContinuousInvalidate);
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousInvalidate);
class LayerTreeHostTestDeferCommits : public LayerTreeHostTest {
public:
@@ -2192,6 +2221,7 @@
EXPECT_EQ(0u, host->MaxPartialTextureUpdates());
}
+// TODO(sohanjg) : Remove it once impl-side painting ships everywhere.
class LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted
: public LayerTreeHostTest {
public:
@@ -2596,9 +2626,7 @@
test_capabilities_.gpu.texture_rectangle = true;
}
- virtual GLuint createTexture() override {
- return 1;
- }
+ GLuint createTexture() override { return 1; }
MOCK_METHOD1(activeTexture, void(GLenum texture));
MOCK_METHOD2(bindTexture, void(GLenum target,
GLuint texture_id));
@@ -4482,7 +4510,10 @@
}
void SetupTree() override {
- root_ = FakeContentLayer::Create(&client_);
+ if (layer_tree_host()->settings().impl_side_painting)
+ root_ = FakePictureLayer::Create(&client_);
+ else
+ root_ = FakeContentLayer::Create(&client_);
root_->SetBounds(gfx::Size(20, 20));
layer_tree_host()->SetRootLayer(root_);
LayerTreeHostTest::SetupTree();
@@ -4524,10 +4555,9 @@
size_t first_output_surface_memory_limit_;
size_t second_output_surface_memory_limit_;
FakeContentLayerClient client_;
- scoped_refptr<FakeContentLayer> root_;
+ scoped_refptr<Layer> root_;
};
-// No output to copy for delegated renderers.
SINGLE_AND_MULTI_THREAD_TEST_F(
LayerTreeHostTestSetMemoryPolicyOnLostOutputSurface);
@@ -5000,7 +5030,8 @@
void SetupTree() override {
LayerTreeHostTest::SetupTree();
- scoped_refptr<PictureLayer> layer = PictureLayer::Create(&layer_client_);
+ scoped_refptr<FakePictureLayer> layer =
+ FakePictureLayer::Create(&layer_client_);
layer->SetBounds(gfx::Size(10, 10));
layer->SetIsDrawable(true);
layer_tree_host()->root_layer()->AddChild(layer);
@@ -5330,4 +5361,388 @@
};
MULTI_THREAD_TEST_F(LayerTreeHostAcceptsDeltasFromImplWithoutRootLayer);
+
+class LayerTreeHostTestCrispUpAfterPinchEnds : public LayerTreeHostTest {
+ protected:
+ LayerTreeHostTestCrispUpAfterPinchEnds()
+ : playback_allowed_event_(true, true) {}
+
+ void SetupTree() override {
+ frame_ = 1;
+ posted_ = false;
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(500, 500));
+
+ scoped_refptr<Layer> pinch = Layer::Create();
+ pinch->SetBounds(gfx::Size(500, 500));
+ pinch->SetScrollClipLayerId(root->id());
+ pinch->SetIsContainerForFixedPositionLayers(true);
+ root->AddChild(pinch);
+
+ scoped_ptr<FakePicturePile> pile(new FakePicturePile);
+ pile->SetPlaybackAllowedEvent(&playback_allowed_event_);
+ scoped_refptr<FakePictureLayer> layer =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ layer->SetBounds(gfx::Size(500, 500));
+ layer->SetContentsOpaque(true);
+ pinch->AddChild(layer);
+
+ layer_tree_host()->RegisterViewportLayers(root, pinch, pinch);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ // Returns the delta scale of all quads in the frame's root pass from their
+ // ideal, or 0 if they are not all the same.
+ float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) {
+ if (frame_data->has_no_damage)
+ return 0.f;
+ float frame_scale = 0.f;
+ RenderPass* root_pass = frame_data->render_passes.back();
+ for (const auto& draw_quad : root_pass->quad_list) {
+ // Checkerboards mean an incomplete frame.
+ if (draw_quad->material != DrawQuad::TILED_CONTENT)
+ return 0.f;
+ const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
+ float quad_scale =
+ quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
+ float transform_scale =
+ SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+ float scale = quad_scale / transform_scale;
+ if (frame_scale != 0.f && frame_scale != scale)
+ return 0.f;
+ frame_scale = scale;
+ }
+ return frame_scale;
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data);
+ switch (frame_) {
+ case 1:
+ // Drew at page scale 1 before any pinching.
+ EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ PostNextAfterDraw(host_impl);
+ break;
+ case 2:
+ // Wait for any activations that need to occur due to starting a pinch,
+ // and drawing with a non-identity transform (for eg. LCD text being
+ // disabled).
+ if (host_impl->pending_tree())
+ break;
+ if (quad_scale_delta != 1.f)
+ break;
+ // Drew at page scale 1.5 after pinching in.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ PostNextAfterDraw(host_impl);
+ break;
+ case 3:
+ // By pinching out, we will create a new tiling and raster it. This may
+ // cause some additional draws, though we should still be drawing with
+ // the old 1.5 tiling.
+ if (frame_data->has_no_damage)
+ break;
+ // Drew at page scale 1 with the 1.5 tiling while pinching out.
+ EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(1.5f, quad_scale_delta);
+ // We don't PostNextAfterDraw here, instead we wait for the new tiling
+ // to finish rastering so we don't get any noise in further steps.
+ break;
+ case 4:
+ // Drew at page scale 1 with the 1.5 tiling after pinching out completed
+ // while waiting for texture uploads to complete.
+ EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+ // This frame will not have any damage, since it's actually the same as
+ // the last frame, and should contain no incomplete tiles. We just want
+ // to make sure we drew here at least once after the pinch ended to be
+ // sure that drawing after pinch doesn't leave us at the wrong scale
+ EXPECT_TRUE(frame_data->has_no_damage);
+ PostNextAfterDraw(host_impl);
+ break;
+ case 5:
+ if (quad_scale_delta != 1.f)
+ break;
+ // Drew at scale 1 after texture uploads are done.
+ EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ EndTest();
+ break;
+ }
+ return draw_result;
+ }
+
+ void PostNextAfterDraw(LayerTreeHostImpl* host_impl) {
+ if (posted_)
+ return;
+ posted_ = true;
+ ImplThreadTaskRunner()->PostDelayedTask(
+ FROM_HERE, base::Bind(&LayerTreeHostTestCrispUpAfterPinchEnds::Next,
+ base::Unretained(this), host_impl),
+ // Use a delay to allow raster/upload to happen in between frames. This
+ // should cause flakiness if we fail to block raster/upload when
+ // desired.
+ base::TimeDelta::FromMilliseconds(16 * 4));
+ }
+
+ void Next(LayerTreeHostImpl* host_impl) {
+ ++frame_;
+ posted_ = false;
+ switch (frame_) {
+ case 2:
+ // Pinch zoom in.
+ host_impl->PinchGestureBegin();
+ host_impl->PinchGestureUpdate(1.5f, gfx::Point(100, 100));
+ host_impl->PinchGestureEnd();
+ break;
+ case 3:
+ // Pinch zoom back to 1.f but don't end it.
+ host_impl->PinchGestureBegin();
+ host_impl->PinchGestureUpdate(1.f / 1.5f, gfx::Point(100, 100));
+ break;
+ case 4:
+ // End the pinch, but delay tile production.
+ playback_allowed_event_.Reset();
+ host_impl->PinchGestureEnd();
+ break;
+ case 5:
+ // Let tiles complete.
+ playback_allowed_event_.Signal();
+ break;
+ }
+ }
+
+ void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+ const Tile* tile) override {
+ if (frame_ == 3) {
+ // On frame 3, we will have a lower res tile complete for the pinch-out
+ // gesture even though it's not displayed. We wait for it here to prevent
+ // flakiness.
+ EXPECT_EQ(0.75f, tile->contents_scale());
+ PostNextAfterDraw(host_impl);
+ }
+ // On frame_ == 4, we are preventing texture uploads from completing,
+ // so this verifies they are not completing before frame_ == 5.
+ // Flaky failures here indicate we're failing to prevent uploads from
+ // completing.
+ EXPECT_NE(4, frame_) << tile->contents_scale();
+ }
+
+ void AfterTest() override {}
+
+ FakeContentLayerClient client_;
+ int frame_;
+ bool posted_;
+ base::WaitableEvent playback_allowed_event_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestCrispUpAfterPinchEnds);
+
+class LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy
+ : public LayerTreeHostTestCrispUpAfterPinchEnds {
+ protected:
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->use_one_copy = true;
+ }
+
+ scoped_ptr<FakeOutputSurface> CreateFakeOutputSurface(
+ bool fallback) override {
+ scoped_ptr<TestWebGraphicsContext3D> context3d =
+ TestWebGraphicsContext3D::Create();
+ context3d->set_support_image(true);
+ context3d->set_support_sync_query(true);
+
+ if (delegating_renderer())
+ return FakeOutputSurface::CreateDelegating3d(context3d.Pass());
+ else
+ return FakeOutputSurface::Create3d(context3d.Pass());
+ }
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestCrispUpAfterPinchEndsWithOneCopy);
+
+class LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles
+ : public LayerTreeHostTest {
+ protected:
+ LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles()
+ : playback_allowed_event_(true, true) {}
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->impl_side_painting = true;
+ }
+
+ void SetupTree() override {
+ step_ = 1;
+ continuous_draws_ = 0;
+ expect_draw_ = false;
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ root->SetBounds(gfx::Size(500, 500));
+
+ scoped_refptr<Layer> pinch = Layer::Create();
+ pinch->SetBounds(gfx::Size(500, 500));
+ pinch->SetScrollClipLayerId(root->id());
+ pinch->SetIsContainerForFixedPositionLayers(true);
+ root->AddChild(pinch);
+
+ scoped_ptr<FakePicturePile> pile(new FakePicturePile);
+ pile->SetPlaybackAllowedEvent(&playback_allowed_event_);
+ scoped_refptr<FakePictureLayer> layer =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ layer->SetBounds(gfx::Size(500, 500));
+ layer->SetContentsOpaque(true);
+ pinch->AddChild(layer);
+
+ layer_tree_host()->RegisterViewportLayers(root, pinch, pinch);
+ layer_tree_host()->SetPageScaleFactorAndLimits(1.f, 1.f, 4.f);
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ // Returns the delta scale of all quads in the frame's root pass from their
+ // ideal, or 0 if they are not all the same.
+ float FrameQuadScaleDeltaFromIdeal(LayerTreeHostImpl::FrameData* frame_data) {
+ if (frame_data->has_no_damage)
+ return 0.f;
+ float frame_scale = 0.f;
+ RenderPass* root_pass = frame_data->render_passes.back();
+ for (const auto& draw_quad : root_pass->quad_list) {
+ const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
+ float quad_scale =
+ quad->tex_coord_rect.width() / static_cast<float>(quad->rect.width());
+ float transform_scale =
+ SkMScalarToFloat(quad->quadTransform().matrix().get(0, 0));
+ float scale = quad_scale / transform_scale;
+ if (frame_scale != 0.f && frame_scale != scale)
+ return 0.f;
+ frame_scale = scale;
+ }
+ return frame_scale;
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ float quad_scale_delta = FrameQuadScaleDeltaFromIdeal(frame_data);
+ switch (step_) {
+ case 1:
+ // Drew at scale 1 before any pinching.
+ EXPECT_EQ(1.f, host_impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ break;
+ case 2:
+ if (quad_scale_delta != 1.f / 1.5f)
+ break;
+ // Drew at scale 1 still though the ideal is 1.5.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(1.f / 1.5f, quad_scale_delta);
+ break;
+ case 3:
+ // Continuous draws are attempted.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->total_page_scale_factor());
+ if (!frame_data->has_no_damage)
+ EXPECT_EQ(1.f / 1.5f, quad_scale_delta);
+ break;
+ case 4:
+ if (quad_scale_delta != 1.f)
+ break;
+ // Drew at scale 1.5 when all the tiles completed.
+ EXPECT_EQ(1.5f, host_impl->active_tree()->total_page_scale_factor());
+ EXPECT_EQ(1.f, quad_scale_delta);
+ break;
+ case 5:
+ // TODO(danakj): We may get one more draw because the NotifyReadyToDraw
+ // is asynchronous from the previous draw and happens late.
+ break;
+ case 6:
+ // We may get another draw if we activate due to the pinch (eg LCD text
+ // gets disabled).
+ if (expect_draw_)
+ break;
+ NOTREACHED() << "No draws should happen once we have a complete frame.";
+ break;
+ }
+ expect_draw_ = false;
+ return draw_result;
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ switch (step_) {
+ case 1:
+ // Delay tile production.
+ playback_allowed_event_.Reset();
+ // Pinch zoom in to cause new tiles to be required.
+ host_impl->PinchGestureBegin();
+ host_impl->PinchGestureUpdate(1.5f, gfx::Point(100, 100));
+ host_impl->PinchGestureEnd();
+ ++step_;
+ break;
+ case 2:
+ ++step_;
+ break;
+ case 3:
+ // We should continue to try draw while there are incomplete visible
+ // tiles.
+ if (++continuous_draws_ > 5) {
+ // Allow the tiles to complete.
+ playback_allowed_event_.Signal();
+ ++step_;
+ }
+ break;
+ case 4:
+ // TODO(danakj): Now we wait for NotifyReadyToDraw to avoid flakiness
+ // since it happens asynchronously.
+ ++step_;
+ break;
+ }
+ }
+
+ void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override {
+ if (step_ == 5) {
+ // We should not continue to draw any more. End the test after a timeout
+ // to watch for any extraneous draws.
+ // TODO(brianderson): We could remove this delay and instead wait until
+ // the BeginFrameSource decides it doesn't need to send frames anymore,
+ // or test that it already doesn't here.
+ EndTestAfterDelayMs(16 * 4);
+ ++step_;
+ expect_draw_ = true;
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ expect_draw_ = true;
+ }
+
+ void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+ const Tile* tile) override {
+ // On step_ == 2, we are preventing texture uploads from completing,
+ // so this verifies they are not completing before step_ == 3.
+ // Flaky failures here indicate we're failing to prevent uploads from
+ // completing.
+ EXPECT_NE(2, step_);
+ }
+
+ void AfterTest() override { EXPECT_GT(continuous_draws_, 5); }
+
+ FakeContentLayerClient client_;
+ int step_;
+ int continuous_draws_;
+ bool expect_draw_;
+ base::WaitableEvent playback_allowed_event_;
+};
+
+MULTI_THREAD_TEST_F(LayerTreeHostTestContinuousDrawWhenCreatingVisibleTiles);
+
} // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index fb05300..dc34d3c 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -133,7 +133,7 @@
void DidFailToInitializeOutputSurface() override { ++times_create_failed_; }
- virtual void TearDown() override {
+ void TearDown() override {
LayerTreeTest::TearDown();
EXPECT_EQ(times_to_expect_create_failed_, times_create_failed_);
}
diff --git a/cc/trees/layer_tree_host_unittest_damage.cc b/cc/trees/layer_tree_host_unittest_damage.cc
index d541751..d34cd4d 100644
--- a/cc/trees/layer_tree_host_unittest_damage.cc
+++ b/cc/trees/layer_tree_host_unittest_damage.cc
@@ -529,98 +529,5 @@
MULTI_THREAD_TEST_F(LayerTreeHostDamageTestScrollbarCommitDoesNoDamage);
-class LayerTreeHostDamageTestVisibleTilesStillTriggerDraws
- : public LayerTreeHostDamageTest {
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->impl_side_painting = true;
- }
-
- void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-
- void SetupTree() override {
- scoped_refptr<FakePictureLayer> root = FakePictureLayer::Create(&client_);
- root->SetBounds(gfx::Size(500, 500));
- layer_tree_host()->SetRootLayer(root);
- LayerTreeHostDamageTest::SetupTree();
-
- swap_count_ = 0;
- prepare_to_draw_count_ = 0;
- update_visible_tile_count_ = 0;
- }
-
- DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
- LayerTreeHostImpl::FrameData* frame_data,
- DrawResult draw_result) override {
- EXPECT_EQ(DRAW_SUCCESS, draw_result);
- prepare_to_draw_count_++;
- switch (prepare_to_draw_count_) {
- case 1:
- // Detect that we have an incomplete tile, during the first frame.
- // The first frame should have damage.
- frame_data->contains_incomplete_tile = true;
- DCHECK(!frame_data->has_no_damage);
- break;
- case 2:
- // Make a no-damage frame. We early out and can't detect
- // incomplete tiles, even if they still exist.
- frame_data->contains_incomplete_tile = false;
- frame_data->has_no_damage = true;
- break;
- case 3:
- // Trigger the last swap for the completed tile.
- frame_data->contains_incomplete_tile = false;
- frame_data->has_no_damage = false;
- EndTest();
- break;
- default:
- NOTREACHED();
- break;
- }
-
- return draw_result;
- }
-
- void UpdateVisibleTilesOnThread(LayerTreeHostImpl* host_impl) override {
- // Simulate creating some visible tiles (that trigger prepare-to-draws).
- // The first we make into a no-damage-frame during prepare-to-draw (see
- // above). This is to ensure we still get UpdateVisibleTiles calls after
- // a no-damage or aborted frame.
- update_visible_tile_count_++;
- switch (update_visible_tile_count_) {
- case 3:
- case 6:
- host_impl->DidInitializeVisibleTileForTesting();
- break;
- case 7:
- NOTREACHED();
- break;
- }
- }
-
- void SwapBuffersOnThread(LayerTreeHostImpl* host_impl,
- bool didSwap) override {
- if (!didSwap)
- return;
- ++swap_count_;
- }
-
- void AfterTest() override {
- // We should keep getting update-visible-tiles calls
- // until we report there are no more incomplete-tiles.
- EXPECT_EQ(update_visible_tile_count_, 6);
- // First frame, plus two triggered by DidInitializeVisibleTile()
- EXPECT_EQ(prepare_to_draw_count_, 3);
- // First swap, plus final swap (contained damage).
- EXPECT_EQ(swap_count_, 2);
- }
-
- FakeContentLayerClient client_;
- int swap_count_;
- int prepare_to_draw_count_;
- int update_visible_tile_count_;
-};
-
-MULTI_THREAD_TEST_F(LayerTreeHostDamageTestVisibleTilesStillTriggerDraws);
-
} // namespace
} // namespace cc
diff --git a/cc/trees/occlusion_tracker_unittest.cc b/cc/trees/occlusion_tracker_unittest.cc
index 75cd243..56d830f 100644
--- a/cc/trees/occlusion_tracker_unittest.cc
+++ b/cc/trees/occlusion_tracker_unittest.cc
@@ -174,7 +174,7 @@
virtual void RunMyTest() = 0;
- virtual void TearDown() { DestroyLayers(); }
+ void TearDown() override { DestroyLayers(); }
typename Types::HostType* GetHost();
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index f15c7ec..4cb0a9e 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -383,12 +383,6 @@
SetNeedsRedrawOnImplThread();
}
-void SingleThreadProxy::DidInitializeVisibleTileOnImplThread() {
- TRACE_EVENT0("cc", "SingleThreadProxy::DidInitializeVisibleTileOnImplThread");
- if (scheduler_on_impl_thread_)
- scheduler_on_impl_thread_->SetNeedsRedraw();
-}
-
void SingleThreadProxy::SetNeedsCommitOnImplThread() {
client_->ScheduleComposite();
if (scheduler_on_impl_thread_)
@@ -753,11 +747,6 @@
DoAnimate();
}
-void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() {
- DebugScopedSetImplThread impl(this);
- layer_tree_host_impl_->UpdateVisibleTiles();
-}
-
void SingleThreadProxy::ScheduledActionActivateSyncTree() {
DebugScopedSetImplThread impl(this);
layer_tree_host_impl_->ActivateSyncTree();
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index fa300de..e4cf793 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -67,7 +67,6 @@
DrawResult ScheduledActionDrawAndSwapForced() override;
void ScheduledActionCommit() override;
void ScheduledActionAnimate() override;
- void ScheduledActionUpdateVisibleTiles() override;
void ScheduledActionActivateSyncTree() override;
void ScheduledActionBeginOutputSurfaceCreation() override;
void ScheduledActionManageTiles() override;
@@ -93,7 +92,6 @@
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
void SetNeedsAnimateOnImplThread() override;
void SetNeedsManageTilesOnImplThread() override;
- void DidInitializeVisibleTileOnImplThread() override;
void SetNeedsCommitOnImplThread() override;
void PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> events) override;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 0f7a2a3..bd85f01 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -479,23 +479,6 @@
SetNeedsRedrawOnImplThread();
}
-void ThreadProxy::SetSwapUsedIncompleteTileOnImplThread(
- bool used_incomplete_tile) {
- DCHECK(IsImplThread());
- if (used_incomplete_tile) {
- TRACE_EVENT_INSTANT0("cc",
- "ThreadProxy::SetSwapUsedIncompleteTileOnImplThread",
- TRACE_EVENT_SCOPE_THREAD);
- }
- impl().scheduler->SetSwapUsedIncompleteTile(used_incomplete_tile);
-}
-
-void ThreadProxy::DidInitializeVisibleTileOnImplThread() {
- TRACE_EVENT0("cc", "ThreadProxy::DidInitializeVisibleTileOnImplThread");
- DCHECK(IsImplThread());
- impl().scheduler->SetNeedsRedraw();
-}
-
void ThreadProxy::MainThreadHasStoppedFlinging() {
DCHECK(IsMainThread());
Proxy::ImplThreadTaskRunner()->PostTask(
@@ -989,12 +972,6 @@
impl().timing_history.DidCommit();
}
-void ThreadProxy::ScheduledActionUpdateVisibleTiles() {
- TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionUpdateVisibleTiles");
- DCHECK(IsImplThread());
- impl().layer_tree_host_impl->UpdateVisibleTiles();
-}
-
void ThreadProxy::ScheduledActionActivateSyncTree() {
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionActivateSyncTree");
DCHECK(IsImplThread());
@@ -1055,15 +1032,8 @@
bool start_ready_animations = draw_frame;
impl().layer_tree_host_impl->UpdateAnimationState(start_ready_animations);
- if (draw_frame) {
- bool did_request_swap = impl().layer_tree_host_impl->SwapBuffers(frame);
-
- // We don't know if we have incomplete tiles if we didn't actually swap.
- if (did_request_swap) {
- DCHECK(!frame.has_no_damage);
- SetSwapUsedIncompleteTileOnImplThread(frame.contains_incomplete_tile);
- }
- }
+ if (draw_frame)
+ impl().layer_tree_host_impl->SwapBuffers(frame);
// Tell the main thread that the the newly-commited frame was drawn.
if (impl().next_frame_is_newly_committed_frame) {
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index adccf72..a1064ab 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -195,7 +195,6 @@
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
void SetNeedsAnimateOnImplThread() override;
void SetNeedsManageTilesOnImplThread() override;
- void DidInitializeVisibleTileOnImplThread() override;
void SetNeedsCommitOnImplThread() override;
void PostAnimationEventsToMainThreadOnImplThread(
scoped_ptr<AnimationEventsVector> queue) override;
@@ -215,7 +214,6 @@
DrawResult ScheduledActionDrawAndSwapForced() override;
void ScheduledActionAnimate() override;
void ScheduledActionCommit() override;
- void ScheduledActionUpdateVisibleTiles() override;
void ScheduledActionActivateSyncTree() override;
void ScheduledActionBeginOutputSurfaceCreation() override;
void ScheduledActionManageTiles() override;
diff --git a/gin/v8.isolate b/gin/v8.isolate
index 14d8a2c..a47dd9e 100644
--- a/gin/v8.isolate
+++ b/gin/v8.isolate
@@ -5,7 +5,7 @@
'conditions': [
['v8_use_external_startup_data==1', {
'variables': {
- 'isolate_dependency_tracked': [
+ 'files': [
'<(PRODUCT_DIR)/natives_blob.bin',
'<(PRODUCT_DIR)/snapshot_blob.bin',
],
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index 990cd02..4fc8145 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -68,6 +68,7 @@
"command_buffer/tests/gl_bind_uniform_location_unittest.cc",
"command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc",
"command_buffer/tests/gl_chromium_path_rendering_unittest.cc",
+ "command_buffer/tests/gl_clear_framebuffer_unittest.cc",
"command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc",
"command_buffer/tests/gl_depth_texture_unittest.cc",
"command_buffer/tests/gl_gpu_memory_buffer_unittest.cc",
diff --git a/gpu/command_buffer/client/fenced_allocator.cc b/gpu/command_buffer/client/fenced_allocator.cc
index 8003857..6db6e50 100644
--- a/gpu/command_buffer/client/fenced_allocator.cc
+++ b/gpu/command_buffer/client/fenced_allocator.cc
@@ -14,23 +14,22 @@
namespace {
-// Allocation alignment, must be a power of two.
-const unsigned int kAllocAlignment = 16;
-
// Round down to the largest multiple of kAllocAlignment no greater than |size|.
unsigned int RoundDown(unsigned int size) {
- return size & ~(kAllocAlignment - 1);
+ return size & ~(FencedAllocator::kAllocAlignment - 1);
}
// Round up to the smallest multiple of kAllocAlignment no smaller than |size|.
unsigned int RoundUp(unsigned int size) {
- return (size + (kAllocAlignment - 1)) & ~(kAllocAlignment - 1);
+ return (size + (FencedAllocator::kAllocAlignment - 1)) &
+ ~(FencedAllocator::kAllocAlignment - 1);
}
} // namespace
#ifndef _MSC_VER
const FencedAllocator::Offset FencedAllocator::kInvalidOffset;
+const unsigned int FencedAllocator::kAllocAlignment;
#endif
FencedAllocator::FencedAllocator(unsigned int size,
diff --git a/gpu/command_buffer/client/fenced_allocator.h b/gpu/command_buffer/client/fenced_allocator.h
index 8e222e1..578870d 100644
--- a/gpu/command_buffer/client/fenced_allocator.h
+++ b/gpu/command_buffer/client/fenced_allocator.h
@@ -35,6 +35,9 @@
// Invalid offset, returned by Alloc in case of failure.
static const Offset kInvalidOffset = 0xffffffffU;
+ // Allocation alignment, must be a power of two.
+ static const unsigned int kAllocAlignment = 16;
+
// Creates a FencedAllocator. Note that the size of the buffer is passed, but
// not its base address: everything is handled as offsets into the buffer.
FencedAllocator(unsigned int size,
diff --git a/gpu/command_buffer/client/mapped_memory.cc b/gpu/command_buffer/client/mapped_memory.cc
index fc6ca5d..1919879 100644
--- a/gpu/command_buffer/client/mapped_memory.cc
+++ b/gpu/command_buffer/client/mapped_memory.cc
@@ -26,7 +26,7 @@
MappedMemoryManager::MappedMemoryManager(CommandBufferHelper* helper,
const base::Closure& poll_callback,
size_t unused_memory_reclaim_limit)
- : chunk_size_multiple_(1),
+ : chunk_size_multiple_(FencedAllocator::kAllocAlignment),
helper_(helper),
poll_callback_(poll_callback),
allocated_memory_(0),
diff --git a/gpu/command_buffer/client/mapped_memory.h b/gpu/command_buffer/client/mapped_memory.h
index 789e69c..10ac639 100644
--- a/gpu/command_buffer/client/mapped_memory.h
+++ b/gpu/command_buffer/client/mapped_memory.h
@@ -135,6 +135,7 @@
}
void set_chunk_size_multiple(unsigned int multiple) {
+ DCHECK(multiple % FencedAllocator::kAllocAlignment == 0);
chunk_size_multiple_ = multiple;
}
@@ -201,4 +202,3 @@
} // namespace gpu
#endif // GPU_COMMAND_BUFFER_CLIENT_MAPPED_MEMORY_H_
-
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 4013c3a..1c43029 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -44,6 +44,8 @@
"feature_info.cc",
"framebuffer_manager.h",
"framebuffer_manager.cc",
+ "gles2_cmd_clear_framebuffer.cc",
+ "gles2_cmd_clear_framebuffer.h",
"gles2_cmd_copy_texture_chromium.cc",
"gles2_cmd_copy_texture_chromium.h",
"gles2_cmd_decoder.h",
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 24e1f92..6dd1f34 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -848,6 +848,9 @@
if (workarounds_.disable_egl_khr_fence_sync) {
gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync = false;
}
+ if (workarounds_.disable_egl_khr_wait_sync) {
+ gfx::g_driver_egl.ext.b_EGL_KHR_wait_sync = false;
+ }
#endif
if (workarounds_.disable_arb_sync)
gfx::g_driver_gl.ext.b_GL_ARB_sync = false;
@@ -855,12 +858,14 @@
UMA_HISTOGRAM_BOOLEAN("GPU.FenceSupport", ui_gl_fence_works);
feature_flags_.map_buffer_range =
- is_es3 || extensions.Contains("GL_ARB_map_buffer_range");
+ 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");
+ 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.
if (has_pixel_buffers && ui_gl_fence_works &&
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index 88a0a37..53dbf6c 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -134,6 +134,7 @@
#undef GPU_OP
EXPECT_EQ(0, info_->workarounds().max_texture_size);
EXPECT_EQ(0, info_->workarounds().max_cube_map_texture_size);
+ EXPECT_FALSE(info_->workarounds().gl_clear_broken);
// Test good types.
{
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
new file mode 100644
index 0000000..765dcb9
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.cc
@@ -0,0 +1,188 @@
+// 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 "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h"
+
+#include "base/basictypes.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
+
+namespace {
+
+#define SHADER(src) \
+ "#ifdef GL_ES\n" \
+ "precision mediump float;\n" \
+ "#endif\n" #src
+
+const char* g_vertex_shader_source = {
+ SHADER(
+ uniform float u_clear_depth;
+ attribute vec4 a_position;
+ void main(void) {
+ gl_Position = vec4(a_position.x, a_position.y, u_clear_depth, 1.0);
+ }
+ ),
+};
+
+const char* g_fragment_shader_source = {
+ SHADER(
+ uniform vec4 u_clear_color;
+ void main(void) {
+ gl_FragColor = u_clear_color;
+ }
+ ),
+};
+
+void CompileShader(GLuint shader, const char* shader_source) {
+ glShaderSource(shader, 1, &shader_source, 0);
+ glCompileShader(shader);
+#if DCHECK_IS_ON
+ GLint compile_status = GL_FALSE;
+ glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status);
+ if (GL_TRUE != compile_status) {
+ char buffer[1024];
+ GLsizei length = 0;
+ glGetShaderInfoLog(shader, sizeof(buffer), &length, buffer);
+ std::string log(buffer, length);
+ DLOG(ERROR) << "Error compiling shader: " << log;
+ DLOG(ERROR) << "Shader compilation failure.";
+ }
+#endif
+}
+
+} // namespace
+
+namespace gpu {
+
+ClearFramebufferResourceManager::ClearFramebufferResourceManager(
+ const gles2::GLES2Decoder* decoder)
+ : initialized_(false), program_(0u), buffer_id_(0u) {
+ Initialize(decoder);
+}
+
+ClearFramebufferResourceManager::~ClearFramebufferResourceManager() {
+ Destroy();
+ DCHECK(!buffer_id_);
+}
+
+void ClearFramebufferResourceManager::Initialize(
+ const gles2::GLES2Decoder* decoder) {
+ COMPILE_ASSERT(
+ kVertexPositionAttrib == 0u,
+ Position_attribs_must_be_0);
+ DCHECK(!buffer_id_);
+
+ glGenBuffersARB(1, &buffer_id_);
+ glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
+ const GLfloat kQuadVertices[] = {-1.0f, -1.0f,
+ 1.0f, -1.0f,
+ 1.0f, 1.0f,
+ -1.0f, 1.0f};
+ glBufferData(
+ GL_ARRAY_BUFFER, sizeof(kQuadVertices), kQuadVertices, GL_STATIC_DRAW);
+ decoder->RestoreBufferBindings();
+ initialized_ = true;
+}
+
+void ClearFramebufferResourceManager::Destroy() {
+ if (!initialized_)
+ return;
+
+ glDeleteProgram(program_);
+ glDeleteBuffersARB(1, &buffer_id_);
+ buffer_id_ = 0;
+}
+
+void ClearFramebufferResourceManager::ClearFramebuffer(
+ const gles2::GLES2Decoder* decoder,
+ const gfx::Size& framebuffer_size,
+ GLbitfield mask,
+ GLfloat clear_color_red,
+ GLfloat clear_color_green,
+ GLfloat clear_color_blue,
+ GLfloat clear_color_alpha,
+ GLfloat clear_depth_value,
+ GLint clear_stencil_value) {
+ if (!initialized_) {
+ DLOG(ERROR) << "Uninitialized manager.";
+ return;
+ }
+
+ if (!program_) {
+ program_ = glCreateProgram();
+ GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
+ CompileShader(vertex_shader, g_vertex_shader_source);
+ glAttachShader(program_, vertex_shader);
+ GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
+ CompileShader(fragment_shader, g_fragment_shader_source);
+ glAttachShader(program_, fragment_shader);
+ glBindAttribLocation(program_, kVertexPositionAttrib, "a_position");
+ glLinkProgram(program_);
+#if DCHECK_IS_ON
+ GLint linked = GL_FALSE;
+ glGetProgramiv(program_, GL_LINK_STATUS, &linked);
+ if (GL_TRUE != linked)
+ DLOG(ERROR) << "Program link failure.";
+#endif
+ depth_handle_ = glGetUniformLocation(program_, "u_clear_depth");
+ color_handle_ = glGetUniformLocation(program_, "u_clear_color");
+ glDeleteShader(fragment_shader);
+ glDeleteShader(vertex_shader);
+ }
+ glUseProgram(program_);
+
+#if DCHECK_IS_ON
+ glValidateProgram(program_);
+ GLint validation_status = GL_FALSE;
+ glGetProgramiv(program_, GL_VALIDATE_STATUS, &validation_status);
+ if (GL_TRUE != validation_status)
+ DLOG(ERROR) << "Invalid shader.";
+#endif
+
+ decoder->ClearAllAttributes();
+ glEnableVertexAttribArray(kVertexPositionAttrib);
+
+ glBindBuffer(GL_ARRAY_BUFFER, buffer_id_);
+ glVertexAttribPointer(kVertexPositionAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
+
+ glUniform1f(depth_handle_, clear_depth_value);
+ glUniform4f(color_handle_, clear_color_red, clear_color_green,
+ clear_color_blue, clear_color_alpha);
+
+ if (!(mask & GL_COLOR_BUFFER_BIT)) {
+ glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
+ }
+
+ if (mask & GL_DEPTH_BUFFER_BIT) {
+ glEnable(GL_DEPTH_TEST);
+ glDepthFunc(GL_ALWAYS);
+ } else {
+ glDisable(GL_DEPTH_TEST);
+ glDepthMask(GL_FALSE);
+ }
+
+ if (mask & GL_STENCIL_BUFFER_BIT) {
+ glEnable(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, clear_stencil_value, 0xFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ } else {
+ glDisable(GL_STENCIL_TEST);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilMask(0);
+ }
+
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDisable(GL_POLYGON_OFFSET_FILL);
+
+ glViewport(0, 0, framebuffer_size.width(), framebuffer_size.height());
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ decoder->RestoreAllAttributes();
+ decoder->RestoreProgramBindings();
+ decoder->RestoreBufferBindings();
+ decoder->RestoreGlobalState();
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
new file mode 100644
index 0000000..6b533f5
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h
@@ -0,0 +1,54 @@
+// 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 GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_CLEAR_FRAMEBUFFER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_CLEAR_FRAMEBUFFER_H_
+
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gfx {
+class Size;
+}
+
+namespace gpu {
+namespace gles2 {
+class GLES2Decoder;
+}
+
+class GPU_EXPORT ClearFramebufferResourceManager {
+ public:
+ ClearFramebufferResourceManager(const gles2::GLES2Decoder* decoder);
+ ~ClearFramebufferResourceManager();
+
+
+ void ClearFramebuffer(const gles2::GLES2Decoder* decoder,
+ const gfx::Size& framebuffer_size,
+ GLbitfield mask,
+ GLfloat clear_color_red,
+ GLfloat clear_color_green,
+ GLfloat clear_color_blue,
+ GLfloat clear_color_alpha,
+ GLfloat clear_depth_value,
+ GLint clear_stencil_value);
+
+ private:
+ void Initialize(const gles2::GLES2Decoder* decoder);
+ void Destroy();
+
+ // The attributes used during invocation of the extension.
+ static const GLuint kVertexPositionAttrib = 0;
+
+ bool initialized_;
+ GLuint program_;
+ GLuint depth_handle_;
+ GLuint color_handle_;
+ GLuint buffer_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(ClearFramebufferResourceManager);
+};
+
+} // namespace gpu.
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_CLEAR_FRAMEBUFFER_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 4d54739..dec594b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -41,6 +41,7 @@
#include "gpu/command_buffer/service/feature_info.h"
#include "gpu/command_buffer/service/framebuffer_manager.h"
#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_clear_framebuffer.h"
#include "gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.h"
#include "gpu/command_buffer/service/gles2_cmd_validation.h"
#include "gpu/command_buffer/service/gpu_state_tracer.h"
@@ -1840,6 +1841,7 @@
#endif
scoped_ptr<CopyTextureCHROMIUMResourceManager> copy_texture_CHROMIUM_;
+ scoped_ptr<ClearFramebufferResourceManager> clear_framebuffer_blit_;
// Cached values of the currently assigned viewport dimensions.
GLsizei viewport_max_width_;
@@ -2764,6 +2766,14 @@
AsyncPixelTransferManager::Create(context.get()));
async_pixel_transfer_manager_->Initialize(texture_manager());
+ if (workarounds().gl_clear_broken) {
+ DCHECK(!clear_framebuffer_blit_.get());
+ LOCAL_COPY_REAL_GL_ERRORS_TO_WRAPPER("glClearWorkaroundInit");
+ clear_framebuffer_blit_.reset(new ClearFramebufferResourceManager(this));
+ if (LOCAL_PEEK_GL_ERROR("glClearWorkaroundInit") != GL_NO_ERROR)
+ return false;
+ }
+
framebuffer_manager()->AddObserver(this);
return true;
@@ -3549,6 +3559,8 @@
copy_texture_CHROMIUM_.reset();
}
+ clear_framebuffer_blit_.reset();
+
if (state_.current_program.get()) {
program_manager()->UnuseProgram(shader_manager(),
state_.current_program.get());
@@ -3614,6 +3626,7 @@
state_.current_program = NULL;
copy_texture_CHROMIUM_.reset();
+ clear_framebuffer_blit_.reset();
if (query_manager_.get()) {
query_manager_->Destroy(have_context);
@@ -5106,6 +5119,19 @@
if (CheckBoundFramebuffersValid("glClear")) {
ApplyDirtyState();
ScopedRenderTo do_render(framebuffer_state_.bound_draw_framebuffer.get());
+ if (workarounds().gl_clear_broken) {
+ ScopedGLErrorSuppressor suppressor("GLES2DecoderImpl::ClearWorkaround",
+ GetErrorState());
+ if (!BoundFramebufferHasDepthAttachment())
+ mask &= ~GL_DEPTH_BUFFER_BIT;
+ if (!BoundFramebufferHasStencilAttachment())
+ mask &= ~GL_STENCIL_BUFFER_BIT;
+ clear_framebuffer_blit_->ClearFramebuffer(
+ this, GetBoundReadFrameBufferSize(), mask, state_.color_clear_red,
+ state_.color_clear_green, state_.color_clear_blue,
+ state_.color_clear_alpha, state_.depth_clear, state_.stencil_clear);
+ return error::kNoError;
+ }
glClear(mask);
}
return error::kNoError;
@@ -7578,6 +7604,11 @@
} else {
data = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY);
}
+ if (!data) {
+ LOCAL_SET_GL_ERROR(GL_OUT_OF_MEMORY, "glMapBuffer",
+ "Unable to map memory for readback.");
+ return;
+ }
memcpy(pixels, data, pixels_size);
// GL_PIXEL_PACK_BUFFER_ARB is currently unused, so we don't
// have to restore the state.
@@ -7779,7 +7810,10 @@
GLuint buffer = 0;
glGenBuffersARB(1, &buffer);
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, buffer);
- glBufferData(GL_PIXEL_PACK_BUFFER_ARB, pixels_size, NULL, GL_STREAM_READ);
+ // For ANGLE client version 2, GL_STREAM_READ is not available.
+ const GLenum usage_hint =
+ features().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) {
glReadPixels(x, y, width, height, format, type, 0);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 0ef9585..ef37c90 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -666,8 +666,6 @@
EXPECT_TRUE(process_success);
EXPECT_FALSE(query->pending());
- QuerySync* sync = static_cast<QuerySync*>(shared_memory_address_);
- EXPECT_EQ(static_cast<GLenum>(0), static_cast<GLenum>(sync->result));
#if DCHECK_IS_ON
EXPECT_CALL(*gl_, IsSync(kGlSync))
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index fdb5fa8..8b75333 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -408,6 +408,7 @@
private:
scoped_ptr<gfx::GLFence> fence_;
+ base::TimeTicks begin_time_;
};
CommandsCompletedQuery::CommandsCompletedQuery(QueryManager* manager,
@@ -416,7 +417,10 @@
uint32 shm_offset)
: Query(manager, target, shm_id, shm_offset) {}
-bool CommandsCompletedQuery::Begin() { return true; }
+bool CommandsCompletedQuery::Begin() {
+ begin_time_ = base::TimeTicks::HighResNow();
+ return true;
+}
bool CommandsCompletedQuery::End(base::subtle::Atomic32 submit_count) {
fence_.reset(gfx::GLFence::Create());
@@ -428,13 +432,11 @@
// Note: |did_finish| guarantees that the GPU has passed the fence but
// we cannot assume that GLFence::HasCompleted() will return true yet as
// that's not guaranteed by all GLFence implementations.
- //
- // TODO(reveman): Add UMA stats to determine how common it is that glFinish()
- // needs to be called for these queries to complete. crbug.com/431845
if (!did_finish && fence_ && !fence_->HasCompleted())
return true;
- return MarkAsCompleted(0);
+ base::TimeDelta elapsed = base::TimeTicks::HighResNow() - begin_time_;
+ return MarkAsCompleted(elapsed.InMicroseconds());
}
void CommandsCompletedQuery::Destroy(bool have_context) {
diff --git a/gpu/command_buffer/tests/gl_clear_framebuffer_unittest.cc b/gpu/command_buffer/tests/gl_clear_framebuffer_unittest.cc
new file mode 100644
index 0000000..8a925c8
--- /dev/null
+++ b/gpu/command_buffer/tests/gl_clear_framebuffer_unittest.cc
@@ -0,0 +1,200 @@
+// 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 GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2extchromium.h>
+
+#include <vector>
+
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/command_buffer/tests/gl_manager.h"
+#include "gpu/command_buffer/tests/gl_test_utils.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+
+// A collection of tests that exercise the glClear workaround.
+class GLClearFramebufferTest : public testing::TestWithParam<bool> {
+ public:
+ GLClearFramebufferTest() : color_handle_(0u), depth_handle_(0u) {}
+
+ protected:
+ void SetUp() override {
+ if (GetParam()) {
+ // Force the glClear() workaround so we can test it here.
+ CommandLine command_line(base::CommandLine::NO_PROGRAM);
+ command_line.AppendSwitchASCII(switches::kGpuDriverBugWorkarounds,
+ base::IntToString(gpu::GL_CLEAR_BROKEN));
+ gl_.InitializeWithCommandLine(GLManager::Options(), &command_line);
+ DCHECK(gl_.workarounds().gl_clear_broken);
+ } else {
+ gl_.Initialize(GLManager::Options());
+ DCHECK(!gl_.workarounds().gl_clear_broken);
+ }
+ }
+
+ void InitDraw();
+ void SetDrawColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
+ void SetDrawDepth(GLfloat depth);
+ void DrawQuad();
+
+ void TearDown() override {
+ GLTestHelper::CheckGLError("no errors", __LINE__);
+ gl_.Destroy();
+ }
+
+ private:
+ GLManager gl_;
+ GLuint color_handle_;
+ GLuint depth_handle_;
+};
+
+void GLClearFramebufferTest::InitDraw() {
+ static const char* v_shader_str =
+ "attribute vec4 a_Position;\n"
+ "uniform float u_depth;\n"
+ "void main()\n"
+ "{\n"
+ " gl_Position = a_Position;\n"
+ " gl_Position.z = u_depth;\n"
+ "}\n";
+ static const char* f_shader_str =
+ "precision mediump float;\n"
+ "uniform vec4 u_draw_color;\n"
+ "void main()\n"
+ "{\n"
+ " gl_FragColor = u_draw_color;\n"
+ "}\n";
+
+ GLuint program = GLTestHelper::LoadProgram(v_shader_str, f_shader_str);
+ DCHECK(program);
+ glUseProgram(program);
+ GLuint position_loc = glGetAttribLocation(program, "a_Position");
+
+ GLTestHelper::SetupUnitQuad(position_loc);
+ color_handle_ = glGetUniformLocation(program, "u_draw_color");
+ DCHECK(color_handle_ != static_cast<GLuint>(-1));
+ depth_handle_ = glGetUniformLocation(program, "u_depth");
+ DCHECK(depth_handle_ != static_cast<GLuint>(-1));
+}
+
+void GLClearFramebufferTest::SetDrawColor(GLfloat r,
+ GLfloat g,
+ GLfloat b,
+ GLfloat a) {
+ glUniform4f(color_handle_, r, g, b, a);
+}
+
+void GLClearFramebufferTest::SetDrawDepth(GLfloat depth) {
+ glUniform1f(depth_handle_, depth);
+}
+
+void GLClearFramebufferTest::DrawQuad() {
+ glDrawArrays(GL_TRIANGLES, 0, 6);
+}
+
+INSTANTIATE_TEST_CASE_P(GLClearFramebufferTestWithParam,
+ GLClearFramebufferTest,
+ ::testing::Values(true, false));
+
+TEST_P(GLClearFramebufferTest, ClearColor) {
+ glClearColor(1.0f, 0.5f, 0.25f, 0.5f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Verify.
+ const uint8 expected[] = {255, 128, 64, 128};
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 1 /* tolerance */, expected));
+}
+
+TEST_P(GLClearFramebufferTest, ClearColorWithMask) {
+ glColorMask(GL_TRUE, GL_FALSE, GL_FALSE, GL_FALSE);
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Verify.
+ const uint8 expected[] = {255, 0, 0, 0};
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
+}
+
+// crbug.com/434094
+#if !defined(OS_MACOSX)
+TEST_P(GLClearFramebufferTest, ClearColorWithScissor) {
+ glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Verify.
+ const uint8 expected[] = {255, 255, 255, 255};
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
+
+ glScissor(0, 0, 0, 0);
+ glEnable(GL_SCISSOR_TEST);
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ // Verify - no changes.
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, expected));
+}
+#endif
+
+TEST_P(GLClearFramebufferTest, ClearDepthStencil) {
+ const GLuint kStencilRef = 1 << 2;
+ InitDraw();
+ SetDrawColor(1.0f, 0.0f, 0.0f, 1.0f);
+ DrawQuad();
+ // Verify.
+ const uint8 kRed[] = {255, 0, 0, 255};
+ const uint8 kGreen[] = {0, 255, 0, 255};
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
+
+ glClearStencil(kStencilRef);
+ glClear(GL_STENCIL_BUFFER_BIT);
+ glEnable(GL_STENCIL_TEST);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc(GL_NOTEQUAL, kStencilRef, 0xFFFFFFFF);
+
+ SetDrawColor(0.0f, 1.0f, 0.0f, 1.0f);
+ DrawQuad();
+ // Verify - stencil should have failed, so still red.
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
+
+ glStencilFunc(GL_EQUAL, kStencilRef, 0xFFFFFFFF);
+ DrawQuad();
+ // Verify - stencil should have passed, so green.
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kGreen));
+
+ glEnable(GL_DEPTH_TEST);
+ glClearDepthf(0.0f);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ SetDrawDepth(0.5f);
+ SetDrawColor(1.0f, 0.0f, 0.0f, 1.0f);
+ DrawQuad();
+ // Verify - depth test should have failed, so still green.
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kGreen));
+
+ glClearDepthf(0.9f);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ DrawQuad();
+ // Verify - depth test should have passed, so red.
+ EXPECT_TRUE(
+ GLTestHelper::CheckPixels(0, 0, 1, 1, 0 /* tolerance */, kRed));
+}
+
+} // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index ebd821c..c09901f 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -139,6 +139,10 @@
}
void GLManager::Initialize(const GLManager::Options& options) {
+ InitializeWithCommandLine(options, nullptr);
+}
+void GLManager::InitializeWithCommandLine(const GLManager::Options& options,
+ base::CommandLine* command_line) {
const int32 kCommandBufferSize = 1024 * 1024;
const size_t kStartTransferBufferSize = 4 * 1024 * 1024;
const size_t kMinTransferBufferSize = 1 * 256 * 1024;
@@ -186,14 +190,19 @@
attrib_helper.blue_size = 8;
attrib_helper.alpha_size = 8;
attrib_helper.depth_size = 16;
+ attrib_helper.stencil_size = 8;
attrib_helper.Serialize(&attribs);
+ DCHECK(!command_line || !context_group);
if (!context_group) {
+ scoped_refptr<gles2::FeatureInfo> feature_info;
+ if (command_line)
+ feature_info = new gles2::FeatureInfo(*command_line);
context_group =
new gles2::ContextGroup(mailbox_manager_.get(),
NULL,
new gpu::gles2::ShaderTranslatorCache,
- NULL,
+ feature_info,
options.bind_generates_resource);
}
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index 03ed6a1..7a3eb2c 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -13,6 +13,10 @@
#include "ui/gfx/gpu_memory_buffer.h"
#include "ui/gfx/size.h"
+namespace base {
+class CommandLine;
+}
+
namespace gfx {
class GLContext;
@@ -66,6 +70,8 @@
gfx::GpuMemoryBuffer::Format format);
void Initialize(const Options& options);
+ void InitializeWithCommandLine(const Options& options,
+ base::CommandLine* command_line);
void Destroy();
void MakeCurrent();
diff --git a/gpu/command_buffer/tests/gl_query_unittest.cc b/gpu/command_buffer/tests/gl_query_unittest.cc
index 0104430..5ea7e8d 100644
--- a/gpu/command_buffer/tests/gl_query_unittest.cc
+++ b/gpu/command_buffer/tests/gl_query_unittest.cc
@@ -63,7 +63,7 @@
glGetQueryObjectuivEXT(commands_issue_query, GL_QUERY_RESULT_EXT, &result);
// Sanity check - the resulting delta is shorter than the time it took to
// run this test.
- EXPECT_LT(result, base::TimeDelta(after - before).InMicroseconds());
+ EXPECT_LE(result, base::TimeDelta(after - before).InMicroseconds());
result = 0;
available = 0;
@@ -152,6 +152,8 @@
return;
}
+ base::TimeTicks before = base::TimeTicks::HighResNow();
+
GLuint query;
glGenQueriesEXT(1, &query);
glBeginQueryEXT(GL_COMMANDS_COMPLETED_CHROMIUM, query);
@@ -161,7 +163,12 @@
glFlush();
GLuint result = 0;
glGetQueryObjectuivEXT(query, GL_QUERY_RESULT_EXT, &result);
- EXPECT_EQ(0u, result);
+
+ base::TimeTicks after = base::TimeTicks::HighResNow();
+ // Sanity check - the resulting delta is shorter than the time it took to
+ // run this test.
+ EXPECT_LE(result, base::TimeDelta(after - before).InMicroseconds());
+
glDeleteQueriesEXT(1, &query);
GLTestHelper::CheckGLError("no errors", __LINE__);
}
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index 13ffe94..c276d43 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -62,6 +62,8 @@
'command_buffer/service/feature_info.cc',
'command_buffer/service/framebuffer_manager.h',
'command_buffer/service/framebuffer_manager.cc',
+ 'command_buffer/service/gles2_cmd_clear_framebuffer.cc',
+ 'command_buffer/service/gles2_cmd_clear_framebuffer.h',
'command_buffer/service/gles2_cmd_copy_texture_chromium.cc',
'command_buffer/service/gles2_cmd_copy_texture_chromium.h',
'command_buffer/service/gles2_cmd_decoder.h',
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index c9b5335..3db1ff9 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
{
"name": "gpu driver bug list",
// Please update the version number whenever you change this file.
- "version": "7.7",
+ "version": "7.9",
"entries": [
{
"id": 1,
@@ -915,17 +915,6 @@
]
},
{
- "id": 79,
- "cr_bugs": [371530],
- "description": "Testing ARB sync fences is broken on MacOSX",
- "os": {
- "type": "macosx"
- },
- "features": [
- "disable_arb_sync"
- ]
- },
- {
"id": 82,
"description": "PBO mappings segfault on certain older Qualcomm drivers",
"cr_bugs": [394510],
@@ -1046,6 +1035,44 @@
"features": [
"disable_async_readpixels"
]
+ },
+ {
+ "id": 94,
+ "description": "Disable EGL_KHR_wait_sync on NVIDIA with GLES 3.1",
+ "cr_bugs": [433057],
+ "os": {
+ "type": "android",
+ "version": {
+ "op": "<=",
+ "value": "5.0.0"
+ }
+ },
+ "gl_vendor": "NVIDIA.*",
+ "gl_type": "gles",
+ "gl_version": {
+ "op": "=",
+ "value": "3.1"
+ },
+ "features": [
+ "disable_egl_khr_wait_sync"
+ ]
+ },
+ {
+ "id": 95,
+ "cr_bugs": [421271],
+ "description": "glClear does not always work on these drivers",
+ "os": {
+ "type": "android"
+ },
+ "gl_type": "gles",
+ "gl_version": {
+ "op": "<",
+ "value": "3.0"
+ },
+ "gl_vendor": "Imagination.*",
+ "features": [
+ "gl_clear_broken"
+ ]
}
]
}
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index 871798e..841a470 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -28,6 +28,8 @@
disable_depth_texture) \
GPU_OP(DISABLE_EGL_KHR_FENCE_SYNC, \
disable_egl_khr_fence_sync) \
+ GPU_OP(DISABLE_EGL_KHR_WAIT_SYNC, \
+ disable_egl_khr_wait_sync) \
GPU_OP(DISABLE_EXT_DISCARD_FRAMEBUFFER, \
disable_ext_discard_framebuffer) \
GPU_OP(DISABLE_EXT_DRAW_BUFFERS, \
@@ -52,6 +54,8 @@
force_gl_finish_after_compositing) \
GPU_OP(FORCE_INTEGRATED_GPU, \
force_integrated_gpu) \
+ GPU_OP(GL_CLEAR_BROKEN, \
+ gl_clear_broken) \
GPU_OP(INIT_GL_POSITION_IN_VERTEX_SHADER, \
init_gl_position_in_vertex_shader) \
GPU_OP(INIT_TEXTURE_MAX_ANISOTROPY, \
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index ddecf45..5a9deb1 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -321,6 +321,7 @@
'command_buffer/tests/gl_bind_uniform_location_unittest.cc',
'command_buffer/tests/gl_chromium_framebuffer_multisample_unittest.cc',
'command_buffer/tests/gl_chromium_path_rendering_unittest.cc',
+ 'command_buffer/tests/gl_clear_framebuffer_unittest.cc',
'command_buffer/tests/gl_copy_texture_CHROMIUM_unittest.cc',
'command_buffer/tests/gl_depth_texture_unittest.cc',
'command_buffer/tests/gl_gpu_memory_buffer_unittest.cc',
diff --git a/mojo/tools/roll/cc_strip_video.patch b/mojo/tools/roll/cc_strip_video.patch
index 07c6fae..90bb220 100644
--- a/mojo/tools/roll/cc_strip_video.patch
+++ b/mojo/tools/roll/cc_strip_video.patch
@@ -1,8 +1,8 @@
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
-index 9b417f0..f753895 100644
+index a296bb0..ab3aab4 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
-@@ -208,13 +208,6 @@ component("cc") {
+@@ -212,13 +212,6 @@ component("cc") {
"layers/ui_resource_layer.h",
"layers/ui_resource_layer_impl.cc",
"layers/ui_resource_layer_impl.h",
@@ -16,7 +16,7 @@
"output/begin_frame_args.cc",
"output/begin_frame_args.h",
"output/bsp_tree.cc",
-@@ -427,8 +420,6 @@ component("cc") {
+@@ -429,8 +422,6 @@ component("cc") {
"resources/ui_resource_client.h",
"resources/ui_resource_request.cc",
"resources/ui_resource_request.h",
@@ -25,7 +25,7 @@
"resources/zero_copy_raster_worker_pool.cc",
"resources/zero_copy_raster_worker_pool.h",
"scheduler/begin_frame_source.cc",
-@@ -490,7 +481,6 @@ component("cc") {
+@@ -492,7 +483,6 @@ component("cc") {
"//gpu",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/command_buffer/client:gpu_memory_buffer_manager",
@@ -33,7 +33,7 @@
"//ui/events:events_base",
"//ui/gfx",
"//ui/gfx/geometry",
-@@ -559,8 +549,6 @@ source_set("test_support") {
+@@ -563,8 +553,6 @@ source_set("test_support") {
"test/fake_tile_manager_client.h",
"test/fake_ui_resource_layer_tree_host_impl.cc",
"test/fake_ui_resource_layer_tree_host_impl.h",
@@ -42,7 +42,7 @@
"test/geometry_test_utils.cc",
"test/geometry_test_utils.h",
"test/test_in_process_context_provider.cc",
-@@ -713,7 +701,6 @@ test("cc_unittests") {
+@@ -717,7 +705,6 @@ test("cc_unittests") {
"layers/tiled_layer_unittest.cc",
"layers/ui_resource_layer_impl_unittest.cc",
"layers/ui_resource_layer_unittest.cc",
@@ -50,7 +50,7 @@
"output/begin_frame_args_unittest.cc",
"output/delegating_renderer_unittest.cc",
"output/filter_operations_unittest.cc",
-@@ -743,7 +730,6 @@ test("cc_unittests") {
+@@ -747,7 +734,6 @@ test("cc_unittests") {
"resources/texture_uploader_unittest.cc",
"resources/tile_manager_unittest.cc",
"resources/tile_priority_unittest.cc",
@@ -58,7 +58,7 @@
"scheduler/begin_frame_source_unittest.cc",
"scheduler/delay_based_time_source_unittest.cc",
"scheduler/scheduler_state_machine_unittest.cc",
-@@ -772,7 +758,6 @@ test("cc_unittests") {
+@@ -776,7 +762,6 @@ test("cc_unittests") {
"trees/layer_tree_host_unittest_picture.cc",
"trees/layer_tree_host_unittest_proxy.cc",
"trees/layer_tree_host_unittest_scroll.cc",
@@ -66,7 +66,7 @@
"trees/layer_tree_impl_unittest.cc",
"trees/occlusion_tracker_unittest.cc",
"trees/occlusion_unittest.cc",
-@@ -799,7 +784,6 @@ test("cc_unittests") {
+@@ -803,7 +788,6 @@ test("cc_unittests") {
"//gpu:test_support",
"//gpu/command_buffer/client:gles2_interface",
"//gpu/command_buffer/common:gles2_utils",
@@ -74,7 +74,7 @@
"//testing/gmock",
"//testing/gtest",
"//ui/events:events_base",
-@@ -831,7 +815,6 @@ test("cc_perftests") {
+@@ -835,7 +819,6 @@ test("cc_perftests") {
"//gpu",
"//gpu:test_support",
"//gpu/command_buffer/common:gles2_utils",
@@ -253,7 +253,7 @@
-
-} // namespace cc
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
-index a472475..4eb1324 100644
+index 75dcfe8..cb6189e 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -13,7 +13,6 @@
@@ -265,7 +265,7 @@
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/context_provider.h"
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
-index c172869..a0ce823 100644
+index 0c2bc3d..d112ed1 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -12,7 +12,6 @@
@@ -421,7 +421,7 @@
- color_space);
- }
-
-- virtual void SetUp() override {
+- void SetUp() override {
- GLRendererPixelTest::SetUp();
- video_resource_updater_.reset(new VideoResourceUpdater(
- output_surface_->context_provider(), resource_provider_.get()));
@@ -636,7 +636,7 @@
namespace cc {
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
-index 9395639..5d2d939 100644
+index e128013..0b9d976 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -27,7 +27,6 @@
@@ -671,7 +671,7 @@
namespace cc {
namespace {
-@@ -95,7 +91,6 @@ class LayerTreeHostImplTest : public testing::Test,
+@@ -94,7 +90,6 @@ class LayerTreeHostImplTest : public testing::Test,
reduce_memory_result_(true),
current_limit_bytes_(0),
current_priority_cutoff_value_(0) {
@@ -679,7 +679,7 @@
}
LayerTreeSettings DefaultSettings() {
-@@ -5066,18 +5061,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
+@@ -5151,18 +5146,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
LayerImpl::Create(host_impl_->active_tree(), 1);
root_layer->SetBounds(gfx::Size(10, 10));
@@ -698,7 +698,7 @@
scoped_ptr<IOSurfaceLayerImpl> io_surface_layer =
IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5);
io_surface_layer->SetBounds(gfx::Size(10, 10));
-@@ -6139,16 +6122,6 @@ TEST_F(LayerTreeHostImplTest,
+@@ -6225,16 +6208,6 @@ TEST_F(LayerTreeHostImplTest,
scoped_ptr<SolidColorLayerImpl> root_layer =
SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
@@ -716,7 +716,7 @@
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
-index aedd0d9..0859d86 100644
+index 2abf6d3..b0ce5a5 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -18,7 +18,6 @@
@@ -727,15 +727,15 @@
#include "cc/output/begin_frame_args.h"
#include "cc/output/compositor_frame_ack.h"
#include "cc/output/copy_output_request.h"
-@@ -39,7 +38,6 @@
- #include "cc/test/fake_picture_layer_impl.h"
+@@ -41,7 +40,6 @@
+ #include "cc/test/fake_picture_pile.h"
#include "cc/test/fake_proxy.h"
#include "cc/test/fake_scoped_ui_resource.h"
-#include "cc/test/fake_video_frame_provider.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/test_shared_bitmap_manager.h"
-@@ -3972,28 +3970,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
+@@ -4149,28 +4147,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
int num_draws_;
};
@@ -765,7 +765,7 @@
// to the compositor thread, even though no resources are updated in
// response to that invalidation.
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
-index b12a8da..fb05300 100644
+index 134d928..dc34d3c 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -15,8 +15,6 @@
diff --git a/net/BUILD.gn b/net/BUILD.gn
index 3bd06bc..be0ac53 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -473,6 +473,8 @@
# doesn't set USE_NSS but needs some of the files.
set_sources_assignment_filter([])
sources += [
+ "base/net_util_mac.cc",
+ "base/net_util_mac.h",
"base/network_change_notifier_mac.cc",
"base/network_config_watcher_mac.cc",
"base/platform_mime_util_mac.mm",
@@ -506,6 +508,8 @@
"base/platform_mime_util_linux.cc",
"base/address_tracker_linux.cc",
"base/address_tracker_linux.h",
+ "base/net_util_linux.cc",
+ "base/net_util_linux.h"
]
set_sources_assignment_filter(sources_assignment_filter)
diff --git a/net/base/host_port_pair.cc b/net/base/host_port_pair.cc
index 6675692..18cf9f5 100644
--- a/net/base/host_port_pair.cc
+++ b/net/base/host_port_pair.cc
@@ -10,6 +10,7 @@
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "net/base/ip_endpoint.h"
+#include "net/base/net_util.h"
#include "url/gurl.h"
namespace net {
@@ -36,7 +37,8 @@
int port;
if (!base::StringToInt(key_port[1], &port))
return HostPortPair();
- DCHECK_LT(port, 1 << 16);
+ if (!IsPortValid(port))
+ return HostPortPair();
HostPortPair host_port_pair;
host_port_pair.set_host(key_port[0]);
host_port_pair.set_port(port);
diff --git a/net/base/host_port_pair_unittest.cc b/net/base/host_port_pair_unittest.cc
index 5b15db9..2c97e94 100644
--- a/net/base/host_port_pair_unittest.cc
+++ b/net/base/host_port_pair_unittest.cc
@@ -37,13 +37,19 @@
}
TEST(HostPortPairTest, BadString) {
- HostPortPair foo = HostPortPair::FromString("foo.com:2:3");
- EXPECT_TRUE(foo.host().empty());
- EXPECT_EQ(0, foo.port());
+ const char* kBadStrings[] = {
+ "foo.com:2:3",
+ "bar.com:two",
+ "www.google.com:-1",
+ "127.0.0.1:65536",
+ "[2001:db8::42]:65536",
+ };
- HostPortPair bar = HostPortPair::FromString("bar.com:two");
- EXPECT_TRUE(bar.host().empty());
- EXPECT_EQ(0, bar.port());
+ for (size_t index = 0; index < arraysize(kBadStrings); ++index) {
+ HostPortPair foo = HostPortPair::FromString(kBadStrings[index]);
+ EXPECT_TRUE(foo.host().empty());
+ EXPECT_EQ(0, foo.port());
+ }
}
TEST(HostPortPairTest, Emptiness) {
diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h
index 6e49bbb..2754326 100644
--- a/net/base/load_flags_list.h
+++ b/net/base/load_flags_list.h
@@ -34,94 +34,90 @@
// impact the HTTP request headers.
LOAD_FLAG(DISABLE_CACHE, 1 << 5)
-// This is a navigation that will not be intercepted by any registered
-// URLRequest::Interceptors.
-LOAD_FLAG(DISABLE_INTERCEPT, 1 << 6)
-
// If present, ignores certificate mismatches with the domain name.
// (The default behavior is to trigger an OnSSLCertificateError callback.)
-LOAD_FLAG(IGNORE_CERT_COMMON_NAME_INVALID, 1 << 7)
+LOAD_FLAG(IGNORE_CERT_COMMON_NAME_INVALID, 1 << 6)
// If present, ignores certificate expiration dates
// (The default behavior is to trigger an OnSSLCertificateError callback).
-LOAD_FLAG(IGNORE_CERT_DATE_INVALID, 1 << 8)
+LOAD_FLAG(IGNORE_CERT_DATE_INVALID, 1 << 7)
// If present, trusts all certificate authorities
// (The default behavior is to trigger an OnSSLCertificateError callback).
-LOAD_FLAG(IGNORE_CERT_AUTHORITY_INVALID, 1 << 9)
+LOAD_FLAG(IGNORE_CERT_AUTHORITY_INVALID, 1 << 8)
// If present, causes certificate revocation checks to be skipped on secure
// connections.
-LOAD_FLAG(DISABLE_CERT_REVOCATION_CHECKING, 1 << 10)
+LOAD_FLAG(DISABLE_CERT_REVOCATION_CHECKING, 1 << 9)
// If present, ignores wrong key usage of the certificate
// (The default behavior is to trigger an OnSSLCertificateError callback).
-LOAD_FLAG(IGNORE_CERT_WRONG_USAGE, 1 << 11)
+LOAD_FLAG(IGNORE_CERT_WRONG_USAGE, 1 << 10)
// This load will not make any changes to cookies, including storing new
// cookies or updating existing ones.
-LOAD_FLAG(DO_NOT_SAVE_COOKIES, 1 << 12)
+LOAD_FLAG(DO_NOT_SAVE_COOKIES, 1 << 11)
// Do not resolve proxies. This override is used when downloading PAC files
// to avoid having a circular dependency.
-LOAD_FLAG(BYPASS_PROXY, 1 << 13)
+LOAD_FLAG(BYPASS_PROXY, 1 << 12)
// Indicate this request is for a download, as opposed to viewing.
-LOAD_FLAG(IS_DOWNLOAD, 1 << 14)
+LOAD_FLAG(IS_DOWNLOAD, 1 << 13)
// Requires EV certificate verification.
-LOAD_FLAG(VERIFY_EV_CERT, 1 << 15)
+LOAD_FLAG(VERIFY_EV_CERT, 1 << 14)
// This load will not send any cookies.
-LOAD_FLAG(DO_NOT_SEND_COOKIES, 1 << 16)
+LOAD_FLAG(DO_NOT_SEND_COOKIES, 1 << 15)
// This load will not send authentication data (user name/password)
// to the server (as opposed to the proxy).
-LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 17)
+LOAD_FLAG(DO_NOT_SEND_AUTH_DATA, 1 << 16)
// This should only be used for testing (set by HttpNetworkTransaction).
-LOAD_FLAG(IGNORE_ALL_CERT_ERRORS, 1 << 18)
+LOAD_FLAG(IGNORE_ALL_CERT_ERRORS, 1 << 17)
// Indicate that this is a top level frame, so that we don't assume it is a
// subresource and speculatively pre-connect or pre-resolve when a referring
// page is loaded.
-LOAD_FLAG(MAIN_FRAME, 1 << 19)
+LOAD_FLAG(MAIN_FRAME, 1 << 18)
// Indicate that this is a sub frame, and hence it might have subresources that
// should be speculatively resolved, or even speculatively preconnected.
-LOAD_FLAG(SUB_FRAME, 1 << 20)
+LOAD_FLAG(SUB_FRAME, 1 << 19)
// If present, intercept actual request/response headers from network stack
// and report them to renderer. This includes cookies, so the flag is only
// respected if renderer has CanReadRawCookies capability in the security
// policy.
-LOAD_FLAG(REPORT_RAW_HEADERS, 1 << 21)
+LOAD_FLAG(REPORT_RAW_HEADERS, 1 << 20)
// Indicates that this load was motivated by the rel=prefetch feature,
// and is (in theory) not intended for the current frame.
-LOAD_FLAG(PREFETCH, 1 << 22)
+LOAD_FLAG(PREFETCH, 1 << 21)
// Indicates that this is a load that ignores limits and should complete
// immediately.
-LOAD_FLAG(IGNORE_LIMITS, 1 << 23)
+LOAD_FLAG(IGNORE_LIMITS, 1 << 22)
// Suppress login prompts for this request. Cached credentials or
// default credentials may still be used for authentication.
-LOAD_FLAG(DO_NOT_PROMPT_FOR_LOGIN, 1 << 24)
+LOAD_FLAG(DO_NOT_PROMPT_FOR_LOGIN, 1 << 23)
// Indicates that the operation is somewhat likely to be due to an
// explicit user action. This can be used as a hint to treat the
// request with higher priority.
-LOAD_FLAG(MAYBE_USER_GESTURE, 1 << 25)
+LOAD_FLAG(MAYBE_USER_GESTURE, 1 << 24)
// Indicates that the username:password portion of the URL should not
// be honored, but that other forms of authority may be used.
-LOAD_FLAG(DO_NOT_USE_EMBEDDED_IDENTITY, 1 << 26)
+LOAD_FLAG(DO_NOT_USE_EMBEDDED_IDENTITY, 1 << 25)
// Send request directly to the origin if the effective proxy is the data
// reduction proxy.
// TODO(rcs): Remove this flag as soon as http://crbug.com/339237 is resolved.
-LOAD_FLAG(BYPASS_DATA_REDUCTION_PROXY, 1 << 27)
+LOAD_FLAG(BYPASS_DATA_REDUCTION_PROXY, 1 << 26)
// Indicates the the request is an asynchronous revalidation.
-LOAD_FLAG(ASYNC_REVALIDATION, 1 << 28)
+LOAD_FLAG(ASYNC_REVALIDATION, 1 << 27)
diff --git a/net/base/net_info_source_list.h b/net/base/net_info_source_list.h
index be3019e..107840b 100644
--- a/net/base/net_info_source_list.h
+++ b/net/base/net_info_source_list.h
@@ -20,3 +20,4 @@
NET_INFO_SOURCE(SPDY_ALT_PROTO_MAPPINGS, "spdyAlternateProtocolMappings",
1 << 7)
NET_INFO_SOURCE(HTTP_CACHE, "httpCacheInfo", 1 << 8)
+NET_INFO_SOURCE(SDCH, "sdchInfo", 1 << 9)
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 6dfe8c6..af7c290 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -2363,3 +2363,38 @@
// This event is created (in a source of the same name) when the internal DNS
// resolver creates a UDP socket to check for global IPv6 connectivity.
EVENT_TYPE(IPV6_REACHABILITY_CHECK)
+
+// ------------------------------------------------------------------------
+// SDCH
+// ------------------------------------------------------------------------
+
+// This event is created when some problem occurs during sdch-encoded resource
+// handling. It contains the following parameters:
+// {
+// "sdch_problem_code": <SDCH problem code>,
+// "net_error": <Always ERR_FAILED, present just to indicate this is a
+// failure>,
+// }
+EVENT_TYPE(SDCH_DECODING_ERROR)
+
+// This event is created when SdchFilter initialization fails due to the
+// response corruption. It contains the following parameters:
+// {
+// "cause": <Response corruption detection cause>,
+// "cached": <True if response was read from cache>,
+// }
+EVENT_TYPE(SDCH_RESPONSE_CORRUPTION_DETECTION)
+
+// This event is created when some problem occurs during sdch dictionary fetch.
+// It contains the following parameters:
+// {
+// "dictionary_url": <Dictionary url>,
+// "sdch_problem_code": <SDCH problem code>,
+// "net_error": <Only present on unexpected errors. Always ERR_FAILED when
+// present. Used to indicate this is a real failure>,
+// }
+EVENT_TYPE(SDCH_DICTIONARY_ERROR)
+
+// This event is created when SdchDictionaryFetcher starts fetch. It contains
+// no parameters.
+EVENT_TYPE(SDCH_DICTIONARY_FETCH)
diff --git a/net/base/net_log_util.cc b/net/base/net_log_util.cc
index b8816ba..a15e899 100644
--- a/net/base/net_log_util.cc
+++ b/net/base/net_log_util.cc
@@ -15,6 +15,7 @@
#include "net/base/load_states.h"
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
+#include "net/base/sdch_manager.h"
#include "net/disk_cache/disk_cache.h"
#include "net/dns/host_cache.h"
#include "net/dns/host_resolver.h"
@@ -66,6 +67,14 @@
#undef NET_ERROR
};
+const StringToConstant kSdchProblems[] = {
+#define SDCH_PROBLEM_CODE(label, value) \
+ { #label, value } \
+ ,
+#include "net/base/sdch_problem_code_list.h"
+#undef SDCH_PROBLEM_CODE
+};
+
const char* NetInfoSourceToString(NetInfoSource source) {
switch (source) {
#define NET_INFO_SOURCE(label, string, value) \
@@ -187,6 +196,17 @@
constants_dict->Set("quicRstStreamError", dict);
}
+ // Add information on the relationship between SDCH problem codes and their
+ // symbolic names.
+ {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+
+ for (size_t i = 0; i < arraysize(kSdchProblems); i++)
+ dict->SetInteger(kSdchProblems[i].name, kSdchProblems[i].constant);
+
+ constants_dict->Set("sdchProblemCode", dict);
+ }
+
// Information about the relationship between event phase enums and their
// symbolic names.
{
@@ -455,6 +475,17 @@
info_dict);
}
+ if (info_sources & NET_INFO_SDCH) {
+ base::Value* info_dict;
+ SdchManager* sdch_manager = context->sdch_manager();
+ if (sdch_manager) {
+ info_dict = sdch_manager->SdchInfoToValue();
+ } else {
+ info_dict = new base::DictionaryValue();
+ }
+ net_info_dict->Set(NetInfoSourceToString(NET_INFO_SDCH), info_dict);
+ }
+
return net_info_dict.Pass();
}
diff --git a/net/base/net_util.cc b/net/base/net_util.cc
index b9cf59f..9dcf9df 100644
--- a/net/base/net_util.cc
+++ b/net/base/net_util.cc
@@ -9,6 +9,7 @@
#include <algorithm>
#include <iterator>
+#include <limits>
#include <set>
#include "build/build_config.h"
@@ -294,6 +295,10 @@
return StripWWW(base::ASCIIToUTF16(url.host()));
}
+bool IsPortValid(int port) {
+ return port >= 0 && port <= std::numeric_limits<uint16>::max();
+}
+
bool IsPortAllowedByDefault(int port) {
int array_size = arraysize(kRestrictedPorts);
for (int i = 0; i < array_size; i++) {
diff --git a/net/base/net_util.h b/net/base/net_util.h
index 72ac169..44b913a 100644
--- a/net/base/net_util.h
+++ b/net/base/net_util.h
@@ -248,6 +248,10 @@
// Runs |url|'s host through StripWWW(). |url| must be valid.
NET_EXPORT base::string16 StripWWWFromHost(const GURL& url);
+// Checks if |port| is in the valid range (0 to 65535, though 0 is technically
+// reserved). Should be used before casting a port to a uint16.
+NET_EXPORT bool IsPortValid(int port);
+
// Checks |port| against a list of ports which are restricted by default.
// Returns true if |port| is allowed, false if it is restricted.
NET_EXPORT bool IsPortAllowedByDefault(int port);
diff --git a/net/base/net_util_linux.cc b/net/base/net_util_linux.cc
new file mode 100644
index 0000000..e4e0f7f
--- /dev/null
+++ b/net/base/net_util_linux.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 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 "net/base/net_util_linux.h"
+
+#include <net/if.h>
+#include <netinet/in.h>
+#include <set>
+#include <sys/types.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/address_tracker_linux.h"
+#include "net/base/escape.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util_posix.h"
+#include "url/gurl.h"
+
+namespace net {
+
+namespace {
+
+// When returning true, the platform native IPv6 address attributes were
+// successfully converted to net IP address attributes. Otherwise, returning
+// false and the caller should drop the IP address which can't be used by the
+// application layer.
+bool TryConvertNativeToNetIPAttributes(int native_attributes,
+ int* net_attributes) {
+ // For Linux/ChromeOS/Android, we disallow addresses with attributes
+ // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
+ // are still progressing through duplicated address detection (DAD)
+ // and shouldn't be used by the application layer until DAD process
+ // is completed.
+ if (native_attributes & (
+#if !defined(OS_ANDROID)
+ IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
+#endif // !OS_ANDROID
+ IFA_F_TENTATIVE)) {
+ return false;
+ }
+
+ if (native_attributes & IFA_F_TEMPORARY) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
+ }
+
+ if (native_attributes & IFA_F_DEPRECATED) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace internal {
+
+inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) {
+#if defined(OS_ANDROID)
+ return ip.begin();
+#else
+ return ip.data();
+#endif
+}
+
+bool GetNetworkListImpl(
+ NetworkInterfaceList* networks,
+ int policy,
+ const base::hash_set<int>& online_links,
+ const internal::AddressTrackerLinux::AddressMap& address_map,
+ GetInterfaceNameFunction get_interface_name) {
+ std::map<int, std::string> ifnames;
+
+ for (internal::AddressTrackerLinux::AddressMap::const_iterator it =
+ address_map.begin();
+ it != address_map.end(); ++it) {
+ // Ignore addresses whose links are not online.
+ if (online_links.find(it->second.ifa_index) == online_links.end())
+ continue;
+
+ sockaddr_storage sock_addr;
+ socklen_t sock_len = sizeof(sockaddr_storage);
+
+ // Convert to sockaddr for next check.
+ if (!IPEndPoint(it->first, 0)
+ .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
+ continue;
+ }
+
+ // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
+ if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
+ continue;
+
+ int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
+
+ if (it->second.ifa_family == AF_INET6) {
+ // Ignore addresses whose attributes are not actionable by
+ // the application layer.
+ if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
+ &ip_attributes))
+ continue;
+ }
+
+ // Find the name of this link.
+ std::map<int, std::string>::const_iterator itname =
+ ifnames.find(it->second.ifa_index);
+ std::string ifname;
+ if (itname == ifnames.end()) {
+ char buffer[IF_NAMESIZE] = {0};
+ if (get_interface_name(it->second.ifa_index, buffer)) {
+ ifname = ifnames[it->second.ifa_index] = buffer;
+ } else {
+ // Ignore addresses whose interface name can't be retrieved.
+ continue;
+ }
+ } else {
+ ifname = itname->second;
+ }
+
+ // Based on the interface name and policy, determine whether we
+ // should ignore it.
+ if (ShouldIgnoreInterface(ifname, policy))
+ continue;
+
+ networks->push_back(
+ NetworkInterface(ifname, ifname, it->second.ifa_index,
+ NetworkChangeNotifier::CONNECTION_UNKNOWN, it->first,
+ it->second.ifa_prefixlen, ip_attributes));
+ }
+
+ return true;
+}
+
+} // namespace internal
+
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
+ if (networks == NULL)
+ return false;
+
+ internal::AddressTrackerLinux tracker;
+ tracker.Init();
+
+ return internal::GetNetworkListImpl(networks, policy,
+ tracker.GetOnlineLinks(),
+ tracker.GetAddressMap(), &if_indextoname);
+}
+
+} // namespace net
diff --git a/net/base/net_util_linux.h b/net/base/net_util_linux.h
new file mode 100644
index 0000000..340c380
--- /dev/null
+++ b/net/base/net_util_linux.h
@@ -0,0 +1,31 @@
+// Copyright (c) 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 NET_BASE_NET_UTIL_LINUX_H_
+#define NET_BASE_NET_UTIL_LINUX_H_
+
+// This file is only used to expose some of the internals
+// of net_util_linux.cc to tests.
+
+#include "base/containers/hash_tables.h"
+#include "net/base/address_tracker_linux.h"
+#include "net/base/net_util.h"
+
+namespace net {
+namespace internal {
+
+typedef char* (*GetInterfaceNameFunction)(unsigned int interface_index,
+ char* ifname);
+
+NET_EXPORT bool GetNetworkListImpl(
+ NetworkInterfaceList* networks,
+ int policy,
+ const base::hash_set<int>& online_links,
+ const internal::AddressTrackerLinux::AddressMap& address_map,
+ GetInterfaceNameFunction get_interface_name);
+
+} // namespace internal
+} // namespace net
+
+#endif // NET_BASE_NET_UTIL_LINUX_H_
diff --git a/net/base/net_util_mac.cc b/net/base/net_util_mac.cc
new file mode 100644
index 0000000..5dd4630
--- /dev/null
+++ b/net/base/net_util_mac.cc
@@ -0,0 +1,246 @@
+// Copyright (c) 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 "net/base/net_util_mac.h"
+
+#include <ifaddrs.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include <set>
+#include <sys/types.h>
+
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_tokenizer.h"
+#include "base/strings/string_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "net/base/escape.h"
+#include "net/base/ip_endpoint.h"
+#include "net/base/net_errors.h"
+#include "net/base/net_util_posix.h"
+#include "url/gurl.h"
+
+#if !defined(OS_IOS)
+#include <net/if_media.h>
+#include <netinet/in_var.h>
+#include <sys/ioctl.h>
+#endif // !OS_IOS
+
+namespace net {
+
+namespace {
+
+#if !defined(OS_IOS)
+
+// MacOSX implementation of IPAttributesGetterMac which calls ioctl on socket to
+// retrieve IP attributes.
+class IPAttributesGetterMacImpl : public internal::IPAttributesGetterMac {
+ public:
+ IPAttributesGetterMacImpl();
+ ~IPAttributesGetterMacImpl() override;
+ bool IsInitialized() const override;
+ bool GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) override;
+
+ private:
+ int ioctl_socket_;
+};
+
+IPAttributesGetterMacImpl::IPAttributesGetterMacImpl()
+ : ioctl_socket_(socket(AF_INET6, SOCK_DGRAM, 0)) {
+ DCHECK_GE(ioctl_socket_, 0);
+}
+
+bool IPAttributesGetterMacImpl::IsInitialized() const {
+ return ioctl_socket_ >= 0;
+}
+
+IPAttributesGetterMacImpl::~IPAttributesGetterMacImpl() {
+ if (ioctl_socket_ >= 0) {
+ close(ioctl_socket_);
+ }
+}
+
+bool IPAttributesGetterMacImpl::GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) {
+ struct in6_ifreq ifr = {};
+ strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+ memcpy(&ifr.ifr_ifru.ifru_addr, sock_addr, sock_addr->sa_len);
+ int rv = ioctl(ioctl_socket_, SIOCGIFAFLAG_IN6, &ifr);
+ if (rv >= 0) {
+ *native_attributes = ifr.ifr_ifru.ifru_flags;
+ }
+ return (rv >= 0);
+}
+
+// When returning true, the platform native IPv6 address attributes were
+// successfully converted to net IP address attributes. Otherwise, returning
+// false and the caller should drop the IP address which can't be used by the
+// application layer.
+bool TryConvertNativeToNetIPAttributes(int native_attributes,
+ int* net_attributes) {
+ // For MacOSX, we disallow addresses with attributes IN6_IFF_ANYCASE,
+ // IN6_IFF_DUPLICATED, IN6_IFF_TENTATIVE, and IN6_IFF_DETACHED as these are
+ // still progressing through duplicated address detection (DAD) or are not
+ // suitable to be used in an one-to-one communication and shouldn't be used
+ // by the application layer.
+ if (native_attributes & (IN6_IFF_ANYCAST | IN6_IFF_DUPLICATED |
+ IN6_IFF_TENTATIVE | IN6_IFF_DETACHED)) {
+ return false;
+ }
+
+ if (native_attributes & IN6_IFF_TEMPORARY) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
+ }
+
+ if (native_attributes & IN6_IFF_DEPRECATED) {
+ *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
+ }
+
+ return true;
+}
+
+NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
+ int addr_family,
+ const std::string& interface_name) {
+ NetworkChangeNotifier::ConnectionType type =
+ NetworkChangeNotifier::CONNECTION_UNKNOWN;
+
+ struct ifmediareq ifmr = {};
+ strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
+
+ int s = socket(addr_family, SOCK_DGRAM, 0);
+ if (s == -1) {
+ return type;
+ }
+
+ if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
+ if (ifmr.ifm_current & IFM_IEEE80211) {
+ type = NetworkChangeNotifier::CONNECTION_WIFI;
+ } else if (ifmr.ifm_current & IFM_ETHER) {
+ type = NetworkChangeNotifier::CONNECTION_ETHERNET;
+ }
+ }
+ close(s);
+ return type;
+}
+
+#endif // !OS_IOS
+} // namespace
+
+namespace internal {
+
+bool GetNetworkListImpl(NetworkInterfaceList* networks,
+ int policy,
+ const ifaddrs* interfaces,
+ IPAttributesGetterMac* ip_attributes_getter) {
+ // Enumerate the addresses assigned to network interfaces which are up.
+ for (const ifaddrs* interface = interfaces; interface != NULL;
+ interface = interface->ifa_next) {
+ // Skip loopback interfaces, and ones which are down.
+ if (!(IFF_RUNNING & interface->ifa_flags))
+ continue;
+ if (IFF_LOOPBACK & interface->ifa_flags)
+ continue;
+ // Skip interfaces with no address configured.
+ struct sockaddr* addr = interface->ifa_addr;
+ if (!addr)
+ continue;
+
+ // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
+ // configured on non-loopback interfaces.
+ if (IsLoopbackOrUnspecifiedAddress(addr))
+ continue;
+
+ const std::string& name = interface->ifa_name;
+ // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
+ if (ShouldIgnoreInterface(name, policy)) {
+ continue;
+ }
+
+ NetworkChangeNotifier::ConnectionType connection_type =
+ NetworkChangeNotifier::CONNECTION_UNKNOWN;
+
+ int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
+
+#if !defined(OS_IOS)
+ // Retrieve native ip attributes and convert to net version if a getter is
+ // given.
+ if (ip_attributes_getter && ip_attributes_getter->IsInitialized()) {
+ int native_attributes = 0;
+ if (addr->sa_family == AF_INET6 &&
+ ip_attributes_getter->GetIPAttributes(
+ interface->ifa_name, interface->ifa_addr, &native_attributes)) {
+ if (!TryConvertNativeToNetIPAttributes(native_attributes,
+ &ip_attributes)) {
+ continue;
+ }
+ }
+ }
+
+ connection_type = GetNetworkInterfaceType(addr->sa_family, name);
+#endif // !OS_IOS
+
+ IPEndPoint address;
+
+ int addr_size = 0;
+ if (addr->sa_family == AF_INET6) {
+ addr_size = sizeof(sockaddr_in6);
+ } else if (addr->sa_family == AF_INET) {
+ addr_size = sizeof(sockaddr_in);
+ }
+
+ if (address.FromSockAddr(addr, addr_size)) {
+ uint8 prefix_length = 0;
+ if (interface->ifa_netmask) {
+ // If not otherwise set, assume the same sa_family as ifa_addr.
+ if (interface->ifa_netmask->sa_family == 0) {
+ interface->ifa_netmask->sa_family = addr->sa_family;
+ }
+ IPEndPoint netmask;
+ if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
+ prefix_length = MaskPrefixLength(netmask.address());
+ }
+ }
+ networks->push_back(NetworkInterface(
+ name, name, if_nametoindex(name.c_str()), connection_type,
+ address.address(), prefix_length, ip_attributes));
+ }
+ }
+
+ return true;
+}
+
+} // namespace internal
+
+bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
+ if (networks == NULL)
+ return false;
+
+ // getifaddrs() may require IO operations.
+ base::ThreadRestrictions::AssertIOAllowed();
+
+ ifaddrs* interfaces;
+ if (getifaddrs(&interfaces) < 0) {
+ PLOG(ERROR) << "getifaddrs";
+ return false;
+ }
+
+ scoped_ptr<internal::IPAttributesGetterMac> ip_attributes_getter;
+
+#if !defined(OS_IOS)
+ ip_attributes_getter.reset(new IPAttributesGetterMacImpl());
+#endif
+
+ bool result = internal::GetNetworkListImpl(networks, policy, interfaces,
+ ip_attributes_getter.get());
+ freeifaddrs(interfaces);
+ return result;
+}
+
+} // namespace net
diff --git a/net/base/net_util_mac.h b/net/base/net_util_mac.h
new file mode 100644
index 0000000..178facc
--- /dev/null
+++ b/net/base/net_util_mac.h
@@ -0,0 +1,42 @@
+// Copyright (c) 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 NET_BASE_NET_UTIL_MAC_H_
+#define NET_BASE_NET_UTIL_MAC_H_
+
+// This file is only used to expose some of the internals
+// of net_util_mac.cc to tests.
+
+#include "base/macros.h"
+#include "net/base/net_export.h"
+#include "net/base/net_util.h"
+
+struct ifaddrs;
+struct sockaddr;
+
+namespace net {
+namespace internal {
+
+class NET_EXPORT IPAttributesGetterMac {
+ public:
+ IPAttributesGetterMac() {}
+ virtual ~IPAttributesGetterMac() {}
+ virtual bool IsInitialized() const = 0;
+ virtual bool GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) = 0;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(IPAttributesGetterMac);
+};
+
+NET_EXPORT bool GetNetworkListImpl(NetworkInterfaceList* networks,
+ int policy,
+ const ifaddrs* interfaces,
+ IPAttributesGetterMac* ip_attributes_getter);
+
+} // namespace internal
+} // namespace net
+
+#endif // NET_BASE_NET_UTIL_MAC_H_
diff --git a/net/base/net_util_posix.cc b/net/base/net_util_posix.cc
index a2fa6cd..b8e7195 100644
--- a/net/base/net_util_posix.cc
+++ b/net/base/net_util_posix.cc
@@ -7,38 +7,18 @@
#include <set>
#include <sys/types.h>
-#include "base/files/file_path.h"
-#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
-#include "base/threading/thread_restrictions.h"
-#include "net/base/escape.h"
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_errors.h"
-#include "url/gurl.h"
#if !defined(OS_NACL)
-#if defined(OS_MACOSX)
-#include <ifaddrs.h>
-#else
-#include "net/base/address_tracker_linux.h"
#include "net/base/net_util_posix.h"
-#endif // OS_MACOSX
#include <net/if.h>
#include <netinet/in.h>
#endif // !defined(OS_NACL)
-#if defined(OS_MACOSX) && !defined(OS_IOS)
-#include <net/if_media.h>
-#include <netinet/in_var.h>
-#include <sys/ioctl.h>
-#endif
-
namespace net {
-namespace {
+#if !defined(OS_NACL)
+namespace internal {
// The application layer can pass |policy| defined in net_util.h to
// request filtering out certain type of interfaces.
@@ -77,330 +57,13 @@
return false;
}
-#if defined(OS_MACOSX)
-
-struct NetworkInterfaceInfo {
- NetworkInterfaceInfo() : permanent(true) { }
-
- bool permanent; // IPv6 has notion of temporary address. If the address is
- // IPv6 and it's temporary this field will be false.
- NetworkInterface interface;
-};
-
-// This method will remove permanent IPv6 addresses if a temporary address
-// is available for same network interface.
-void RemovePermanentIPv6AddressesWhereTemporaryExists(
- std::vector<NetworkInterfaceInfo>* infos) {
- if (!infos || infos->empty())
- return;
-
- // Build a set containing the names of interfaces with a temp IPv6 address
- std::set<std::string> ifaces_with_temp_addrs;
- std::vector<NetworkInterfaceInfo>::iterator i;
- for (i = infos->begin(); i != infos->end(); ++i) {
- if (!i->permanent && i->interface.address.size() == kIPv6AddressSize) {
- ifaces_with_temp_addrs.insert(i->interface.name);
- }
- }
-
- // If there are no such interfaces then there's no further work.
- if (ifaces_with_temp_addrs.empty())
- return;
-
- // Search for permenent addresses belonging to same network interface.
- for (i = infos->begin(); i != infos->end(); ) {
- // If the address is IPv6 and it's permanent and there is temporary
- // address for it, then we can remove this address.
- if ((i->interface.address.size() == kIPv6AddressSize) && i->permanent &&
- (ifaces_with_temp_addrs.find(i->interface.name) !=
- ifaces_with_temp_addrs.end())) {
- i = infos->erase(i);
- } else {
- ++i;
- }
- }
-}
-
-#if !defined(OS_IOS)
-NetworkChangeNotifier::ConnectionType GetNetworkInterfaceType(
- int addr_family, const std::string& interface_name) {
- NetworkChangeNotifier::ConnectionType type =
- NetworkChangeNotifier::CONNECTION_UNKNOWN;
-
- struct ifmediareq ifmr = {};
- strncpy(ifmr.ifm_name, interface_name.c_str(), sizeof(ifmr.ifm_name) - 1);
-
- int s = socket(addr_family, SOCK_DGRAM, 0);
- if (s == -1) {
- return type;
- }
-
- if (ioctl(s, SIOCGIFMEDIA, &ifmr) != -1) {
- if (ifmr.ifm_current & IFM_IEEE80211) {
- type = NetworkChangeNotifier::CONNECTION_WIFI;
- } else if (ifmr.ifm_current & IFM_ETHER) {
- type = NetworkChangeNotifier::CONNECTION_ETHERNET;
- }
- }
- close(s);
- return type;
-}
-
-#endif // !defined(OS_IOS)
-#elif !defined(OS_NACL) // OS_MACOSX
-
-// Convert platform native IPv6 address attributes to net IP address
-// attributes and drop ones that can't be used by the application
-// layer.
-bool TryConvertNativeToNetIPAttributes(int native_attributes,
- int* net_attributes) {
- // For Linux/ChromeOS/Android, we disallow addresses with attributes
- // IFA_F_OPTIMISTIC, IFA_F_DADFAILED, and IFA_F_TENTATIVE as these
- // are still progressing through duplicated address detection (DAD)
- // and shouldn't be used by the application layer until DAD process
- // is completed.
- if (native_attributes & (
-#if !defined(OS_ANDROID)
- IFA_F_OPTIMISTIC | IFA_F_DADFAILED |
-#endif // !OS_ANDROID
- IFA_F_TENTATIVE)) {
- return false;
- }
-
- if (native_attributes & IFA_F_TEMPORARY) {
- *net_attributes |= IP_ADDRESS_ATTRIBUTE_TEMPORARY;
- }
-
- if (native_attributes & IFA_F_DEPRECATED) {
- *net_attributes |= IP_ADDRESS_ATTRIBUTE_DEPRECATED;
- }
-
- return true;
-}
-#endif // OS_MACOSX
-} // namespace
-
-namespace internal {
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
-
-inline const unsigned char* GetIPAddressData(const IPAddressNumber& ip) {
-#if defined(OS_ANDROID)
- return ip.begin();
-#else
- return ip.data();
-#endif
-}
-
-bool GetNetworkListImpl(
- NetworkInterfaceList* networks,
- int policy,
- const base::hash_set<int>& online_links,
- const internal::AddressTrackerLinux::AddressMap& address_map,
- GetInterfaceNameFunction get_interface_name) {
- std::map<int, std::string> ifnames;
-
- for (internal::AddressTrackerLinux::AddressMap::const_iterator it =
- address_map.begin();
- it != address_map.end();
- ++it) {
- // Ignore addresses whose links are not online.
- if (online_links.find(it->second.ifa_index) == online_links.end())
- continue;
-
- sockaddr_storage sock_addr;
- socklen_t sock_len = sizeof(sockaddr_storage);
-
- // Convert to sockaddr for next check.
- if (!IPEndPoint(it->first, 0)
- .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addr), &sock_len)) {
- continue;
- }
-
- // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
- if (IsLoopbackOrUnspecifiedAddress(reinterpret_cast<sockaddr*>(&sock_addr)))
- continue;
-
- int ip_attributes = IP_ADDRESS_ATTRIBUTE_NONE;
-
- if (it->second.ifa_family == AF_INET6) {
- // Ignore addresses whose attributes are not actionable by
- // the application layer.
- if (!TryConvertNativeToNetIPAttributes(it->second.ifa_flags,
- &ip_attributes))
- continue;
- }
-
- // Find the name of this link.
- std::map<int, std::string>::const_iterator itname =
- ifnames.find(it->second.ifa_index);
- std::string ifname;
- if (itname == ifnames.end()) {
- char buffer[IF_NAMESIZE] = {0};
- if (get_interface_name(it->second.ifa_index, buffer)) {
- ifname = ifnames[it->second.ifa_index] = buffer;
- } else {
- // Ignore addresses whose interface name can't be retrieved.
- continue;
- }
- } else {
- ifname = itname->second;
- }
-
- // Based on the interface name and policy, determine whether we
- // should ignore it.
- if (ShouldIgnoreInterface(ifname, policy))
- continue;
-
- networks->push_back(
- NetworkInterface(ifname,
- ifname,
- it->second.ifa_index,
- NetworkChangeNotifier::CONNECTION_UNKNOWN,
- it->first,
- it->second.ifa_prefixlen,
- ip_attributes));
- }
-
- return true;
-}
-#endif
-
} // namespace internal
-
+#else // OS_NACL
bool GetNetworkList(NetworkInterfaceList* networks, int policy) {
- if (networks == NULL)
- return false;
-#if defined(OS_NACL)
NOTIMPLEMENTED();
return false;
-#elif !defined(OS_MACOSX)
-
- internal::AddressTrackerLinux tracker;
- tracker.Init();
-
- return internal::GetNetworkListImpl(networks,
- policy,
- tracker.GetOnlineLinks(),
- tracker.GetAddressMap(),
- &if_indextoname);
-
-#else // Only OS_MACOSX and OS_IOS will run the code below
-
- // getifaddrs() may require IO operations.
- base::ThreadRestrictions::AssertIOAllowed();
-
-#if !defined(OS_IOS)
- int ioctl_socket = -1;
- if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) {
- // we need a socket to query information about temporary address.
- ioctl_socket = socket(AF_INET6, SOCK_DGRAM, 0);
- DCHECK_GT(ioctl_socket, 0);
- }
-#endif
-
- ifaddrs* interfaces;
- if (getifaddrs(&interfaces) < 0) {
- PLOG(ERROR) << "getifaddrs";
- return false;
- }
-
- std::vector<NetworkInterfaceInfo> network_infos;
-
- // Enumerate the addresses assigned to network interfaces which are up.
- for (ifaddrs *interface = interfaces;
- interface != NULL;
- interface = interface->ifa_next) {
- // Skip loopback interfaces, and ones which are down.
- if (!(IFF_UP & interface->ifa_flags))
- continue;
- if (IFF_LOOPBACK & interface->ifa_flags)
- continue;
- // Skip interfaces with no address configured.
- struct sockaddr* addr = interface->ifa_addr;
- if (!addr)
- continue;
-
- // Skip unspecified addresses (i.e. made of zeroes) and loopback addresses
- // configured on non-loopback interfaces.
- if (IsLoopbackOrUnspecifiedAddress(addr))
- continue;
-
- int addr_size = 0;
- if (addr->sa_family == AF_INET6) {
- addr_size = sizeof(sockaddr_in6);
- } else if (addr->sa_family == AF_INET) {
- addr_size = sizeof(sockaddr_in);
- }
-
- const std::string& name = interface->ifa_name;
- // Filter out VMware interfaces, typically named vmnet1 and vmnet8.
- if (ShouldIgnoreInterface(name, policy)) {
- continue;
- }
-
- NetworkInterfaceInfo network_info;
- NetworkChangeNotifier::ConnectionType connection_type =
- NetworkChangeNotifier::CONNECTION_UNKNOWN;
-#if !defined(OS_IOS)
- // Check if this is a temporary address. Currently this is only supported
- // on Mac.
- if ((policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) &&
- ioctl_socket >= 0 && addr->sa_family == AF_INET6) {
- struct in6_ifreq ifr = {};
- strncpy(ifr.ifr_name, interface->ifa_name, sizeof(ifr.ifr_name) - 1);
- memcpy(&ifr.ifr_ifru.ifru_addr, interface->ifa_addr,
- interface->ifa_addr->sa_len);
- int rv = ioctl(ioctl_socket, SIOCGIFAFLAG_IN6, &ifr);
- if (rv >= 0) {
- network_info.permanent = !(ifr.ifr_ifru.ifru_flags & IN6_IFF_TEMPORARY);
- }
- }
-
- connection_type = GetNetworkInterfaceType(addr->sa_family, name);
-#endif
-
- IPEndPoint address;
- if (address.FromSockAddr(addr, addr_size)) {
- uint8 net_mask = 0;
- if (interface->ifa_netmask) {
- // If not otherwise set, assume the same sa_family as ifa_addr.
- if (interface->ifa_netmask->sa_family == 0) {
- interface->ifa_netmask->sa_family = addr->sa_family;
- }
- IPEndPoint netmask;
- if (netmask.FromSockAddr(interface->ifa_netmask, addr_size)) {
- net_mask = MaskPrefixLength(netmask.address());
- }
- }
- network_info.interface = NetworkInterface(name,
- name,
- if_nametoindex(name.c_str()),
- connection_type,
- address.address(),
- net_mask,
- IP_ADDRESS_ATTRIBUTE_NONE);
-
- network_infos.push_back(NetworkInterfaceInfo(network_info));
- }
- }
- freeifaddrs(interfaces);
-#if !defined(OS_IOS)
- if (ioctl_socket >= 0) {
- close(ioctl_socket);
- }
-#endif
-
- if (policy & INCLUDE_ONLY_TEMP_IPV6_ADDRESS_IF_POSSIBLE) {
- RemovePermanentIPv6AddressesWhereTemporaryExists(&network_infos);
- }
-
- for (size_t i = 0; i < network_infos.size(); ++i) {
- networks->push_back(network_infos[i].interface);
- }
- return true;
-#endif
}
+#endif // OS_NACL
WifiPHYLayerProtocol GetWifiPHYLayerProtocol() {
return WIFI_PHY_LAYER_PROTOCOL_UNKNOWN;
diff --git a/net/base/net_util_posix.h b/net/base/net_util_posix.h
index b553d1c..93089c2 100644
--- a/net/base/net_util_posix.h
+++ b/net/base/net_util_posix.h
@@ -5,27 +5,21 @@
#ifndef NET_BASE_NET_UTIL_POSIX_H_
#define NET_BASE_NET_UTIL_POSIX_H_
-// This file is only used to expose some of the internals
-// of net_util_posix.cc to tests.
+// This file is only used to expose some of the internals of
+// net_util_posix.cc to net_util_linux.cc and net_util_mac.cc.
+
+#include <string>
+
+struct sockaddr;
namespace net {
namespace internal {
-
-#if !defined(OS_MACOSX) && !defined(OS_NACL)
-typedef char* (*GetInterfaceNameFunction)(unsigned int interface_index,
- char* ifname);
-
-NET_EXPORT bool GetNetworkListImpl(
- NetworkInterfaceList* networks,
- int policy,
- const base::hash_set<int>& online_links,
- const internal::AddressTrackerLinux::AddressMap& address_map,
- GetInterfaceNameFunction get_interface_name);
-
-#endif // !OS_MACOSX && !OS_NACL
+#if !defined(OS_NACL)
+bool ShouldIgnoreInterface(const std::string& name, int policy);
+bool IsLoopbackOrUnspecifiedAddress(const sockaddr* addr);
+#endif // !OS_NACL
} // namespace internal
-
} // namespace net
#endif // NET_BASE_NET_UTIL_POSIX_H_
diff --git a/net/base/net_util_unittest.cc b/net/base/net_util_unittest.cc
index 45f0857..a25903a 100644
--- a/net/base/net_util_unittest.cc
+++ b/net/base/net_util_unittest.cc
@@ -17,10 +17,17 @@
#include "base/strings/utf_string_conversions.h"
#include "base/sys_byteorder.h"
#include "base/time/time.h"
+#include "net/base/ip_endpoint.h"
#if !defined(OS_NACL) && !defined(OS_WIN)
#include <net/if.h>
#include <netinet/in.h>
+#if defined(OS_MACOSX)
+#include <ifaddrs.h>
+#if !defined(OS_IOS)
+#include <netinet/in_var.h>
+#endif // !OS_IOS
+#endif // OS_MACOSX
#endif // !OS_NACL && !OS_WIN
#include "testing/gtest/include/gtest/gtest.h"
#include "url/gurl.h"
@@ -38,6 +45,11 @@
#if !defined(OS_WIN)
#include "net/base/net_util_posix.h"
+#if defined(OS_MACOSX)
+#include "net/base/net_util_mac.h"
+#else // OS_MACOSX
+#include "net/base/net_util_linux.h"
+#endif
#endif // !OS_WIN
using base::ASCIIToUTF16;
@@ -85,6 +97,58 @@
return out;
}
+#if defined(OS_MACOSX)
+class IPAttributesGetterTest : public internal::IPAttributesGetterMac {
+ public:
+ IPAttributesGetterTest() : native_attributes_(0) {}
+ bool IsInitialized() const override { return true; }
+ bool GetIPAttributes(const char* ifname,
+ const sockaddr* sock_addr,
+ int* native_attributes) override {
+ *native_attributes = native_attributes_;
+ return true;
+ }
+ void set_native_attributes(int native_attributes) {
+ native_attributes_ = native_attributes;
+ }
+
+ private:
+ int native_attributes_;
+};
+
+// Helper function to create a single valid ifaddrs
+bool FillIfaddrs(ifaddrs* interfaces,
+ const char* ifname,
+ uint flags,
+ const IPAddressNumber& ip_address,
+ const IPAddressNumber& ip_netmask,
+ sockaddr_storage sock_addrs[2]) {
+ interfaces->ifa_next = NULL;
+ interfaces->ifa_name = const_cast<char*>(ifname);
+ interfaces->ifa_flags = flags;
+
+ socklen_t sock_len = sizeof(sockaddr_storage);
+
+ // Convert to sockaddr for next check.
+ if (!IPEndPoint(ip_address, 0)
+ .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[0]),
+ &sock_len)) {
+ return false;
+ }
+ interfaces->ifa_addr = reinterpret_cast<sockaddr*>(&sock_addrs[0]);
+
+ sock_len = sizeof(sockaddr_storage);
+ if (!IPEndPoint(ip_netmask, 0)
+ .ToSockAddr(reinterpret_cast<sockaddr*>(&sock_addrs[1]),
+ &sock_len)) {
+ return false;
+ }
+ interfaces->ifa_netmask = reinterpret_cast<sockaddr*>(&sock_addrs[1]);
+
+ return true;
+}
+#endif // OS_MACOSX
+
} // anonymous namespace
TEST(NetUtilTest, GetIdentityFromURL) {
@@ -812,6 +876,18 @@
}
}
+static const char ifname_em1[] = "em1";
+static const char ifname_vm[] = "vmnet";
+
+static const unsigned char kIPv6LocalAddr[] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
+static const unsigned char kIPv6Addr[] =
+ {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
+ 0xfe, 0xe5, 0x00, 0xc3};
+static const unsigned char kIPv6Netmask[] =
+ {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00};
+
#if !defined(OS_MACOSX) && !defined(OS_WIN) && !defined(OS_NACL)
char* CopyInterfaceName(const char* ifname, int ifname_size, char* output) {
@@ -820,30 +896,24 @@
return output;
}
-static const char ifname_em1[] = "em1";
char* GetInterfaceName(unsigned int interface_index, char* ifname) {
return CopyInterfaceName(ifname_em1, arraysize(ifname_em1), ifname);
}
-static const char ifname_vm[] = "vmnet";
char* GetInterfaceNameVM(unsigned int interface_index, char* ifname) {
return CopyInterfaceName(ifname_vm, arraysize(ifname_vm), ifname);
}
TEST(NetUtilTest, GetNetworkListTrimming) {
- NetworkInterfaceList results;
- ::base::hash_set<int> online_links;
- net::internal::AddressTrackerLinux::AddressMap address_map;
-
- const unsigned char kIPv6LocalAddr[] = {
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
- const unsigned char kIPv6Addr[] =
- {0x24, 0x01, 0xfa, 0x00, 0x00, 0x04, 0x10, 0x00, 0xbe, 0x30, 0x5b, 0xff,
- 0xfe, 0xe5, 0x00, 0xc3};
-
IPAddressNumber ipv6_local_address(
kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
+ IPAddressNumber ipv6_netmask(kIPv6Netmask,
+ kIPv6Netmask + arraysize(kIPv6Netmask));
+
+ NetworkInterfaceList results;
+ ::base::hash_set<int> online_links;
+ net::internal::AddressTrackerLinux::AddressMap address_map;
// Interface 1 is offline.
struct ifaddrmsg msg = {
@@ -956,7 +1026,101 @@
results.clear();
}
-#endif
+#elif defined(OS_MACOSX)
+
+TEST(NetUtilTest, GetNetworkListTrimming) {
+ IPAddressNumber ipv6_local_address(
+ kIPv6LocalAddr, kIPv6LocalAddr + arraysize(kIPv6LocalAddr));
+ IPAddressNumber ipv6_address(kIPv6Addr, kIPv6Addr + arraysize(kIPv6Addr));
+ IPAddressNumber ipv6_netmask(kIPv6Netmask,
+ kIPv6Netmask + arraysize(kIPv6Netmask));
+
+ NetworkInterfaceList results;
+ IPAttributesGetterTest ip_attributes_getter;
+ sockaddr_storage addresses[2];
+ ifaddrs interface;
+
+ // Address of offline links should be ignored.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_UP, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+
+ // Local address should be trimmed out.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING,
+ ipv6_local_address, ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+
+ // vmware address should return by default.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_vm, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 1ul);
+ EXPECT_EQ(results[0].name, ifname_vm);
+ EXPECT_EQ(results[0].network_prefix, 1ul);
+ EXPECT_EQ(results[0].address, ipv6_address);
+ results.clear();
+
+ // vmware address should be trimmed out if policy specified so.
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_vm, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, EXCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+ results.clear();
+
+#if !defined(OS_IOS)
+ // Addresses with banned attributes should be ignored.
+ ip_attributes_getter.set_native_attributes(IN6_IFF_ANYCAST);
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 0ul);
+ results.clear();
+
+ // Addresses with allowed attribute IFA_F_TEMPORARY should be returned and
+ // attributes should be translated correctly.
+ ip_attributes_getter.set_native_attributes(IN6_IFF_TEMPORARY);
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 1ul);
+ EXPECT_EQ(results[0].name, ifname_em1);
+ EXPECT_EQ(results[0].network_prefix, 1ul);
+ EXPECT_EQ(results[0].address, ipv6_address);
+ EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_TEMPORARY);
+ results.clear();
+
+ // Addresses with allowed attribute IFA_F_DEPRECATED should be returned and
+ // attributes should be translated correctly.
+ ip_attributes_getter.set_native_attributes(IN6_IFF_DEPRECATED);
+ ASSERT_TRUE(FillIfaddrs(&interface, ifname_em1, IFF_RUNNING, ipv6_address,
+ ipv6_netmask, addresses));
+ EXPECT_TRUE(net::internal::GetNetworkListImpl(
+ &results, INCLUDE_HOST_SCOPE_VIRTUAL_INTERFACES, &interface,
+ &ip_attributes_getter));
+ EXPECT_EQ(results.size(), 1ul);
+ EXPECT_EQ(results[0].name, ifname_em1);
+ EXPECT_EQ(results[0].network_prefix, 1ul);
+ EXPECT_EQ(results[0].address, ipv6_address);
+ EXPECT_EQ(results[0].ip_address_attributes, IP_ADDRESS_ATTRIBUTE_DEPRECATED);
+ results.clear();
+#endif // !OS_IOS
+}
+
+#endif // !OS_MACOSX && !OS_WIN && !OS_NACL
namespace {
diff --git a/net/base/network_activity_monitor.cc b/net/base/network_activity_monitor.cc
new file mode 100644
index 0000000..78da8c8
--- /dev/null
+++ b/net/base/network_activity_monitor.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 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 "net/base/network_activity_monitor.h"
+
+namespace net {
+
+namespace {
+
+base::LazyInstance<NetworkActivityMonitor>::Leaky g_network_activity_monitor =
+ LAZY_INSTANCE_INITIALIZER;
+
+} // namespace
+
+NetworkActivityMonitor::NetworkActivityMonitor()
+ : bytes_received_(0), bytes_sent_(0) {
+}
+
+NetworkActivityMonitor::~NetworkActivityMonitor() {
+}
+
+// static
+NetworkActivityMonitor* NetworkActivityMonitor::GetInstance() {
+ return g_network_activity_monitor.Pointer();
+}
+
+void NetworkActivityMonitor::IncrementBytesReceived(uint64_t bytes_received) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ bytes_received_ += bytes_received;
+ last_received_ticks_ = now;
+}
+
+void NetworkActivityMonitor::IncrementBytesSent(uint64_t bytes_sent) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ bytes_sent_ += bytes_sent;
+ last_sent_ticks_ = now;
+}
+
+uint64_t NetworkActivityMonitor::GetBytesReceived() const {
+ base::AutoLock lock(lock_);
+ return bytes_received_;
+}
+
+uint64_t NetworkActivityMonitor::GetBytesSent() const {
+ base::AutoLock lock(lock_);
+ return bytes_sent_;
+}
+
+base::TimeDelta NetworkActivityMonitor::GetTimeSinceLastReceived() const {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ return now - last_received_ticks_;
+}
+
+base::TimeDelta NetworkActivityMonitor::GetTimeSinceLastSent() const {
+ base::TimeTicks now = base::TimeTicks::Now();
+ base::AutoLock lock(lock_);
+ return now - last_sent_ticks_;
+}
+
+} // namespace net
diff --git a/net/base/network_activity_monitor.h b/net/base/network_activity_monitor.h
new file mode 100644
index 0000000..5319477
--- /dev/null
+++ b/net/base/network_activity_monitor.h
@@ -0,0 +1,68 @@
+// Copyright (c) 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 NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
+#define NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
+
+#include "base/basictypes.h"
+#include "base/lazy_instance.h"
+#include "base/synchronization/lock.h"
+#include "base/time/time.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+namespace test {
+
+class NetworkActivityMonitorPeer;
+
+} // namespace test
+
+// NetworkActivityMonitor tracks network activity across all sockets and
+// provides cumulative statistics about bytes sent to and received from
+// the network. It uses a lock to ensure thread-safety.
+//
+// There are a few caveats:
+// * Bytes "sent" includes all send attempts and may include
+// some bytes which were actually never sent over the network.
+// * Bytes received includes only bytes actually received from the network,
+// and does not include any bytes read from the the cache.
+// * Network activity not initiated directly using chromium sockets won't
+// be reflected here (for instance DNS queries issued by getaddrinfo()).
+class NET_EXPORT_PRIVATE NetworkActivityMonitor {
+ public:
+ // Returns the singleton instance of the monitor.
+ static NetworkActivityMonitor* GetInstance();
+
+ void IncrementBytesReceived(uint64_t bytes_received);
+ void IncrementBytesSent(uint64_t bytes_sent);
+
+ uint64_t GetBytesReceived() const;
+ uint64_t GetBytesSent() const;
+
+ base::TimeDelta GetTimeSinceLastReceived() const;
+ base::TimeDelta GetTimeSinceLastSent() const;
+
+ private:
+ friend class test::NetworkActivityMonitorPeer;
+
+ NetworkActivityMonitor();
+ ~NetworkActivityMonitor();
+ friend struct base::DefaultLazyInstanceTraits<NetworkActivityMonitor>;
+
+ // Protects all the following members.
+ mutable base::Lock lock_;
+
+ uint64_t bytes_received_;
+ uint64_t bytes_sent_;
+
+ base::TimeTicks last_received_ticks_;
+ base::TimeTicks last_sent_ticks_;
+
+ DISALLOW_COPY_AND_ASSIGN(NetworkActivityMonitor);
+};
+
+} // namespace net
+
+#endif // NET_BASE_NETWORK_ACTIVITY_MONITOR_H_
diff --git a/net/base/network_activity_monitor_unittest.cc b/net/base/network_activity_monitor_unittest.cc
new file mode 100644
index 0000000..e625c55
--- /dev/null
+++ b/net/base/network_activity_monitor_unittest.cc
@@ -0,0 +1,131 @@
+// Copyright (c) 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 "net/base/network_activity_monitor.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/port.h"
+#include "base/stl_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+
+namespace test {
+
+class NetworkActivityMonitorPeer {
+ public:
+ static void ResetMonitor() {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+ base::AutoLock lock(monitor->lock_);
+ monitor->bytes_sent_ = 0;
+ monitor->bytes_received_ = 0;
+ monitor->last_received_ticks_ = base::TimeTicks();
+ monitor->last_sent_ticks_ = base::TimeTicks();
+ }
+};
+
+
+class NetworkActivityMontiorTest : public testing::Test {
+ public:
+ NetworkActivityMontiorTest() {
+ NetworkActivityMonitorPeer::ResetMonitor();
+ }
+};
+
+TEST_F(NetworkActivityMontiorTest, GetInstance) {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+ EXPECT_TRUE(monitor != NULL);
+ EXPECT_TRUE(monitor == NetworkActivityMonitor::GetInstance());
+}
+
+TEST_F(NetworkActivityMontiorTest, BytesReceived) {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+
+ EXPECT_EQ(0u, monitor->GetBytesReceived());
+
+ base::TimeTicks start = base::TimeTicks::Now();
+ uint64_t bytes = 12345;
+ monitor->IncrementBytesReceived(bytes);
+ EXPECT_EQ(bytes, monitor->GetBytesReceived());
+ base::TimeDelta delta = monitor->GetTimeSinceLastReceived();
+ EXPECT_LE(base::TimeDelta(), delta);
+ EXPECT_GE(base::TimeTicks::Now() - start, delta);
+}
+
+TEST_F(NetworkActivityMontiorTest, BytesSent) {
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+
+ EXPECT_EQ(0u, monitor->GetBytesSent());
+
+ base::TimeTicks start = base::TimeTicks::Now();
+ uint64_t bytes = 12345;
+ monitor->IncrementBytesSent(bytes);
+ EXPECT_EQ(bytes, monitor->GetBytesSent());
+ base::TimeDelta delta = monitor->GetTimeSinceLastSent();
+ EXPECT_LE(base::TimeDelta(), delta);
+ EXPECT_GE(base::TimeTicks::Now() - start, delta);
+}
+
+namespace {
+
+void VerifyBytesReceivedIsMultipleOf(uint64_t bytes) {
+ EXPECT_EQ(0u,
+ NetworkActivityMonitor::GetInstance()->GetBytesReceived() % bytes);
+}
+
+void VerifyBytesSentIsMultipleOf(uint64_t bytes) {
+ EXPECT_EQ(0u, NetworkActivityMonitor::GetInstance()->GetBytesSent() % bytes);
+}
+
+void IncrementBytesReceived(uint64_t bytes) {
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(bytes);
+}
+
+void IncrementBytesSent(uint64_t bytes) {
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(bytes);
+}
+
+} // namespace
+
+TEST_F(NetworkActivityMontiorTest, Threading) {
+ std::vector<base::Thread*> threads;
+ for (size_t i = 0; i < 3; ++i) {
+ threads.push_back(new base::Thread(base::UintToString(i)));
+ ASSERT_TRUE(threads.back()->Start());
+ }
+
+ size_t num_increments = 157;
+ uint64_t bytes_received = GG_UINT64_C(7294954321);
+ uint64_t bytes_sent = GG_UINT64_C(91294998765);
+ for (size_t i = 0; i < num_increments; ++i) {
+ size_t thread_num = i % threads.size();
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&IncrementBytesReceived, bytes_received));
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&IncrementBytesSent, bytes_sent));
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&VerifyBytesSentIsMultipleOf, bytes_sent));
+ threads[thread_num]->task_runner()->PostTask(
+ FROM_HERE,
+ base::Bind(&VerifyBytesReceivedIsMultipleOf, bytes_received));
+ }
+
+ STLDeleteElements(&threads);
+
+ NetworkActivityMonitor* monitor = NetworkActivityMonitor::GetInstance();
+ EXPECT_EQ(num_increments * bytes_received, monitor->GetBytesReceived());
+ EXPECT_EQ(num_increments * bytes_sent, monitor->GetBytesSent());
+}
+
+} // namespace test
+
+} // namespace net
diff --git a/net/base/sdch_manager.cc b/net/base/sdch_manager.cc
index 1285ad9..af5e6ee 100644
--- a/net/base/sdch_manager.cc
+++ b/net/base/sdch_manager.cc
@@ -9,6 +9,7 @@
#include "base/metrics/histogram.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
+#include "base/values.h"
#include "crypto/sha2.h"
#include "net/base/registry_controlled_domains/registry_controlled_domain.h"
#include "net/base/sdch_observer.h"
@@ -78,7 +79,8 @@
SdchManager::Dictionary::~Dictionary() {
}
-bool SdchManager::Dictionary::CanAdvertise(const GURL& target_url) {
+SdchProblemCode SdchManager::Dictionary::CanAdvertise(
+ const GURL& target_url) const {
/* The specific rules of when a dictionary should be advertised in an
Avail-Dictionary header are modeled after the rules for cookie scoping. The
terms "domain-match" and "pathmatch" are defined in RFC 2965 [6]. A
@@ -95,28 +97,28 @@
url scheme.
*/
if (!DomainMatch(target_url, domain_))
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
if (!ports_.empty() && 0 == ports_.count(target_url.EffectiveIntPort()))
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
if (path_.size() && !PathMatch(target_url.path(), path_))
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
if (!SdchManager::secure_scheme_supported() && target_url.SchemeIsSecure())
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
if (target_url.SchemeIsSecure() != url_.SchemeIsSecure())
- return false;
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
if (base::Time::Now() > expiration_)
- return false;
- return true;
+ return SDCH_DICTIONARY_FOUND_EXPIRED;
+ return SDCH_OK;
}
//------------------------------------------------------------------------------
// Security functions restricting loads and use of dictionaries.
// static
-bool SdchManager::Dictionary::CanSet(const std::string& domain,
- const std::string& path,
- const std::set<int>& ports,
- const GURL& dictionary_url) {
+SdchProblemCode SdchManager::Dictionary::CanSet(const std::string& domain,
+ const std::string& path,
+ const std::set<int>& ports,
+ const GURL& dictionary_url) {
/*
A dictionary is invalid and must not be stored if any of the following are
true:
@@ -135,20 +137,17 @@
// and hence the conservative approach is to not allow any redirects (if there
// were any... then don't allow the dictionary to be set).
- if (domain.empty()) {
- SdchErrorRecovery(DICTIONARY_MISSING_DOMAIN_SPECIFIER);
- return false; // Domain is required.
- }
+ if (domain.empty())
+ return SDCH_DICTIONARY_MISSING_DOMAIN_SPECIFIER; // Domain is required.
+
if (registry_controlled_domains::GetDomainAndRegistry(
- domain,
- registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES).empty()) {
- SdchErrorRecovery(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN);
- return false; // domain was a TLD.
+ domain, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES)
+ .empty()) {
+ return SDCH_DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN; // domain was a TLD.
}
- if (!Dictionary::DomainMatch(dictionary_url, domain)) {
- SdchErrorRecovery(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL);
- return false;
- }
+
+ if (!Dictionary::DomainMatch(dictionary_url, domain))
+ return SDCH_DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL;
std::string referrer_url_host = dictionary_url.host();
size_t postfix_domain_index = referrer_url_host.rfind(domain);
@@ -156,23 +155,20 @@
if (referrer_url_host.size() == postfix_domain_index + domain.size()) {
// It is a postfix... so check to see if there's a dot in the prefix.
size_t end_of_host_index = referrer_url_host.find_first_of('.');
- if (referrer_url_host.npos != end_of_host_index &&
+ if (referrer_url_host.npos != end_of_host_index &&
end_of_host_index < postfix_domain_index) {
- SdchErrorRecovery(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX);
- return false;
+ return SDCH_DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX;
}
}
- if (!ports.empty()
- && 0 == ports.count(dictionary_url.EffectiveIntPort())) {
- SdchErrorRecovery(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL);
- return false;
- }
- return true;
+ if (!ports.empty() && 0 == ports.count(dictionary_url.EffectiveIntPort()))
+ return SDCH_DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL;
+
+ return SDCH_OK;
}
-// static
-bool SdchManager::Dictionary::CanUse(const GURL& referring_url) {
+SdchProblemCode SdchManager::Dictionary::CanUse(
+ const GURL& referring_url) const {
/*
1. The request URL's host name domain-matches the Domain attribute of the
dictionary.
@@ -184,39 +180,30 @@
HTTPS support AND the dictionary acquisition scheme matches the target
url scheme.
*/
- if (!DomainMatch(referring_url, domain_)) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_DOMAIN);
- return false;
- }
- if (!ports_.empty()
- && 0 == ports_.count(referring_url.EffectiveIntPort())) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST);
- return false;
- }
- if (path_.size() && !PathMatch(referring_url.path(), path_)) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_PATH);
- return false;
- }
- if (!SdchManager::secure_scheme_supported() &&
- referring_url.SchemeIsSecure()) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
- return false;
- }
- if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure()) {
- SdchErrorRecovery(DICTIONARY_FOUND_HAS_WRONG_SCHEME);
- return false;
- }
+ if (!DomainMatch(referring_url, domain_))
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_DOMAIN;
+
+ if (!ports_.empty() && 0 == ports_.count(referring_url.EffectiveIntPort()))
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PORT_LIST;
+
+ if (path_.size() && !PathMatch(referring_url.path(), path_))
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_PATH;
+
+ if (!SdchManager::secure_scheme_supported() && referring_url.SchemeIsSecure())
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
+
+ if (referring_url.SchemeIsSecure() != url_.SchemeIsSecure())
+ return SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME;
// TODO(jar): Remove overly restrictive failsafe test (added per security
// review) when we have a need to be more general.
- if (!referring_url.SchemeIsHTTPOrHTTPS()) {
- SdchErrorRecovery(ATTEMPT_TO_DECODE_NON_HTTP_DATA);
- return false;
- }
+ if (!referring_url.SchemeIsHTTPOrHTTPS())
+ return SDCH_ATTEMPT_TO_DECODE_NON_HTTP_DATA;
- return true;
+ return SDCH_OK;
}
+// static
bool SdchManager::Dictionary::PathMatch(const std::string& path,
const std::string& restriction) {
/* Must be either:
@@ -268,8 +255,9 @@
}
// static
-void SdchManager::SdchErrorRecovery(ProblemCodes problem) {
- UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_4", problem, MAX_PROBLEM_CODE);
+void SdchManager::SdchErrorRecovery(SdchProblemCode problem) {
+ UMA_HISTOGRAM_ENUMERATION("Sdch3.ProblemCodes_5", problem,
+ SDCH_MAX_PROBLEM_CODE);
}
// static
@@ -283,7 +271,7 @@
}
void SdchManager::BlacklistDomain(const GURL& url,
- ProblemCodes blacklist_reason) {
+ SdchProblemCode blacklist_reason) {
SetAllowLatencyExperiment(url, false);
BlacklistInfo* blacklist_info =
@@ -304,7 +292,7 @@
}
void SdchManager::BlacklistDomainForever(const GURL& url,
- ProblemCodes blacklist_reason) {
+ SdchProblemCode blacklist_reason) {
SetAllowLatencyExperiment(url, false);
BlacklistInfo* blacklist_info =
@@ -322,7 +310,7 @@
BlacklistInfo* blacklist_info = &blacklisted_domains_[
base::StringToLowerASCII(domain)];
blacklist_info->count = 0;
- blacklist_info->reason = MIN_PROBLEM_CODE;
+ blacklist_info->reason = SDCH_OK;
}
int SdchManager::BlackListDomainCount(const std::string& domain) {
@@ -341,49 +329,53 @@
return blacklisted_domains_[domain_lower].exponential_count;
}
-bool SdchManager::IsInSupportedDomain(const GURL& url) {
+SdchProblemCode SdchManager::IsInSupportedDomain(const GURL& url) {
DCHECK(thread_checker_.CalledOnValidThread());
if (!g_sdch_enabled_ )
- return false;
+ return SDCH_DISABLED;
if (!secure_scheme_supported() && url.SchemeIsSecure())
- return false;
+ return SDCH_SECURE_SCHEME_NOT_SUPPORTED;
if (blacklisted_domains_.empty())
- return true;
+ return SDCH_OK;
DomainBlacklistInfo::iterator it =
blacklisted_domains_.find(base::StringToLowerASCII(url.host()));
if (blacklisted_domains_.end() == it || it->second.count == 0)
- return true;
+ return SDCH_OK;
UMA_HISTOGRAM_ENUMERATION("Sdch3.BlacklistReason", it->second.reason,
- MAX_PROBLEM_CODE);
- SdchErrorRecovery(DOMAIN_BLACKLIST_INCLUDES_TARGET);
+ SDCH_MAX_PROBLEM_CODE);
int count = it->second.count - 1;
if (count > 0) {
it->second.count = count;
} else {
it->second.count = 0;
- it->second.reason = MIN_PROBLEM_CODE;
+ it->second.reason = SDCH_OK;
}
- return false;
+ return SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET;
}
-void SdchManager::OnGetDictionary(const GURL& request_url,
- const GURL& dictionary_url) {
- if (!CanFetchDictionary(request_url, dictionary_url))
- return;
+SdchProblemCode SdchManager::OnGetDictionary(const GURL& request_url,
+ const GURL& dictionary_url) {
+ DCHECK(thread_checker_.CalledOnValidThread());
+ SdchProblemCode rv = CanFetchDictionary(request_url, dictionary_url);
+ if (rv != SDCH_OK)
+ return rv;
FOR_EACH_OBSERVER(SdchObserver,
observers_,
OnGetDictionary(this, request_url, dictionary_url));
+
+ return SDCH_OK;
}
-bool SdchManager::CanFetchDictionary(const GURL& referring_url,
- const GURL& dictionary_url) const {
+SdchProblemCode SdchManager::CanFetchDictionary(
+ const GURL& referring_url,
+ const GURL& dictionary_url) const {
DCHECK(thread_checker_.CalledOnValidThread());
/* The user agent may retrieve a dictionary from the dictionary URL if all of
the following are true:
@@ -397,41 +389,40 @@
// Item (1) above implies item (2). Spec should be updated.
// I take "host name match" to be "is identical to"
if (referring_url.host() != dictionary_url.host() ||
- referring_url.scheme() != dictionary_url.scheme()) {
- SdchErrorRecovery(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST);
- return false;
- }
- if (!secure_scheme_supported() && referring_url.SchemeIsSecure()) {
- SdchErrorRecovery(DICTIONARY_SELECTED_FOR_SSL);
- return false;
- }
+ referring_url.scheme() != dictionary_url.scheme())
+ return SDCH_DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST;
+
+ if (!secure_scheme_supported() && referring_url.SchemeIsSecure())
+ return SDCH_DICTIONARY_SELECTED_FOR_SSL;
// TODO(jar): Remove this failsafe conservative hack which is more restrictive
// than current SDCH spec when needed, and justified by security audit.
- if (!referring_url.SchemeIsHTTPOrHTTPS()) {
- SdchErrorRecovery(DICTIONARY_SELECTED_FROM_NON_HTTP);
- return false;
- }
+ if (!referring_url.SchemeIsHTTPOrHTTPS())
+ return SDCH_DICTIONARY_SELECTED_FROM_NON_HTTP;
- return true;
+ return SDCH_OK;
}
-void SdchManager::GetVcdiffDictionary(
+SdchProblemCode SdchManager::GetVcdiffDictionary(
const std::string& server_hash,
const GURL& referring_url,
scoped_refptr<Dictionary>* dictionary) {
DCHECK(thread_checker_.CalledOnValidThread());
*dictionary = NULL;
DictionaryMap::iterator it = dictionaries_.find(server_hash);
- if (it == dictionaries_.end()) {
- return;
- }
+ if (it == dictionaries_.end())
+ return SDCH_DICTIONARY_HASH_NOT_FOUND;
+
scoped_refptr<Dictionary> matching_dictionary = it->second;
- if (!IsInSupportedDomain(referring_url))
- return;
- if (!matching_dictionary->CanUse(referring_url))
- return;
- *dictionary = matching_dictionary;
+
+ SdchProblemCode rv = IsInSupportedDomain(referring_url);
+ if (rv != SDCH_OK)
+ return rv;
+
+ rv = matching_dictionary->CanUse(referring_url);
+ if (rv == SDCH_OK)
+ *dictionary = matching_dictionary;
+ return rv;
}
// TODO(jar): If we have evictions from the dictionaries_, then we need to
@@ -443,9 +434,11 @@
int count = 0;
for (DictionaryMap::iterator it = dictionaries_.begin();
it != dictionaries_.end(); ++it) {
- if (!IsInSupportedDomain(target_url))
+ SdchProblemCode rv = IsInSupportedDomain(target_url);
+ if (rv != SDCH_OK)
continue;
- if (!it->second->CanAdvertise(target_url))
+
+ if (it->second->CanAdvertise(target_url) != SDCH_OK)
continue;
++count;
if (!list->empty())
@@ -490,7 +483,7 @@
ExperimentSet::iterator it = allow_latency_experiment_.find(url.host());
if (allow_latency_experiment_.end() == it)
return; // It was already erased, or never allowed.
- SdchErrorRecovery(LATENCY_TEST_DISALLOWED);
+ SdchErrorRecovery(SDCH_LATENCY_TEST_DISALLOWED);
allow_latency_experiment_.erase(it);
}
@@ -502,31 +495,27 @@
observers_.RemoveObserver(observer);
}
-void SdchManager::AddSdchDictionary(const std::string& dictionary_text,
+SdchProblemCode SdchManager::AddSdchDictionary(
+ const std::string& dictionary_text,
const GURL& dictionary_url) {
DCHECK(thread_checker_.CalledOnValidThread());
std::string client_hash;
std::string server_hash;
GenerateHash(dictionary_text, &client_hash, &server_hash);
- if (dictionaries_.find(server_hash) != dictionaries_.end()) {
- SdchErrorRecovery(DICTIONARY_ALREADY_LOADED);
- return; // Already loaded.
- }
+ if (dictionaries_.find(server_hash) != dictionaries_.end())
+ return SDCH_DICTIONARY_ALREADY_LOADED; // Already loaded.
std::string domain, path;
std::set<int> ports;
base::Time expiration(base::Time::Now() + base::TimeDelta::FromDays(30));
- if (dictionary_text.empty()) {
- SdchErrorRecovery(DICTIONARY_HAS_NO_TEXT);
- return; // Missing header.
- }
+ if (dictionary_text.empty())
+ return SDCH_DICTIONARY_HAS_NO_TEXT; // Missing header.
size_t header_end = dictionary_text.find("\n\n");
- if (std::string::npos == header_end) {
- SdchErrorRecovery(DICTIONARY_HAS_NO_HEADER);
- return; // Missing header.
- }
+ if (std::string::npos == header_end)
+ return SDCH_DICTIONARY_HAS_NO_HEADER; // Missing header.
+
size_t line_start = 0; // Start of line being parsed.
while (1) {
size_t line_end = dictionary_text.find('\n', line_start);
@@ -534,10 +523,9 @@
DCHECK_LE(line_end, header_end);
size_t colon_index = dictionary_text.find(':', line_start);
- if (std::string::npos == colon_index) {
- SdchErrorRecovery(DICTIONARY_HEADER_LINE_MISSING_COLON);
- return; // Illegal line missing a colon.
- }
+ if (std::string::npos == colon_index)
+ return SDCH_DICTIONARY_HEADER_LINE_MISSING_COLON; // Illegal line missing
+ // a colon.
if (colon_index > line_end)
break;
@@ -556,7 +544,7 @@
path = value;
} else if (name == "format-version") {
if (value != "1.0")
- return;
+ return SDCH_DICTIONARY_UNSUPPORTED_VERSION;
} else if (name == "max-age") {
int64 seconds;
base::StringToInt64(value, &seconds);
@@ -578,24 +566,23 @@
GURL dictionary_url_normalized(dictionary_url);
StripTrailingDot(&dictionary_url_normalized);
- if (!IsInSupportedDomain(dictionary_url_normalized))
- return;
+ SdchProblemCode rv = IsInSupportedDomain(dictionary_url_normalized);
+ if (rv != SDCH_OK)
+ return rv;
- if (!Dictionary::CanSet(domain, path, ports, dictionary_url_normalized))
- return;
+ rv = Dictionary::CanSet(domain, path, ports, dictionary_url_normalized);
+ if (rv != SDCH_OK)
+ return rv;
// TODO(jar): Remove these hacks to preclude a DOS attack involving piles of
// useless dictionaries. We should probably have a cache eviction plan,
// instead of just blocking additions. For now, with the spec in flux, it
// is probably not worth doing eviction handling.
- if (kMaxDictionarySize < dictionary_text.size()) {
- SdchErrorRecovery(DICTIONARY_IS_TOO_LARGE);
- return;
- }
- if (kMaxDictionaryCount <= dictionaries_.size()) {
- SdchErrorRecovery(DICTIONARY_COUNT_EXCEEDED);
- return;
- }
+ if (kMaxDictionarySize < dictionary_text.size())
+ return SDCH_DICTIONARY_IS_TOO_LARGE;
+
+ if (kMaxDictionaryCount <= dictionaries_.size())
+ return SDCH_DICTIONARY_COUNT_EXCEEDED;
UMA_HISTOGRAM_COUNTS("Sdch3.Dictionary size loaded", dictionary_text.size());
DVLOG(1) << "Loaded dictionary with client hash " << client_hash
@@ -605,7 +592,7 @@
dictionary_url_normalized, domain,
path, expiration, ports);
dictionaries_[server_hash] = dictionary;
- return;
+ return SDCH_OK;
}
// static
@@ -618,4 +605,46 @@
std::replace(output->begin(), output->end(), '/', '_');
}
+base::Value* SdchManager::SdchInfoToValue() const {
+ base::DictionaryValue* value = new base::DictionaryValue();
+
+ value->SetBoolean("sdch_enabled", sdch_enabled());
+ value->SetBoolean("secure_scheme_support", secure_scheme_supported());
+
+ base::ListValue* entry_list = new base::ListValue();
+ for (DictionaryMap::const_iterator it = dictionaries_.begin();
+ it != dictionaries_.end(); ++it) {
+ base::DictionaryValue* entry_dict = new base::DictionaryValue();
+ entry_dict->SetString("url", it->second->url().spec());
+ entry_dict->SetString("client_hash", it->second->client_hash());
+ entry_dict->SetString("domain", it->second->domain());
+ entry_dict->SetString("path", it->second->path());
+ base::ListValue* port_list = new base::ListValue();
+ for (std::set<int>::const_iterator port_it = it->second->ports().begin();
+ port_it != it->second->ports().end(); ++port_it) {
+ port_list->AppendInteger(*port_it);
+ }
+ entry_dict->Set("ports", port_list);
+ entry_dict->SetString("server_hash", it->first);
+ entry_list->Append(entry_dict);
+ }
+ value->Set("dictionaries", entry_list);
+
+ entry_list = new base::ListValue();
+ for (DomainBlacklistInfo::const_iterator it = blacklisted_domains_.begin();
+ it != blacklisted_domains_.end(); ++it) {
+ if (it->second.count == 0)
+ continue;
+ base::DictionaryValue* entry_dict = new base::DictionaryValue();
+ entry_dict->SetString("domain", it->first);
+ if (it->second.count != INT_MAX)
+ entry_dict->SetInteger("tries", it->second.count);
+ entry_dict->SetInteger("reason", it->second.reason);
+ entry_list->Append(entry_dict);
+ }
+ value->Set("blacklisted", entry_list);
+
+ return value;
+}
+
} // namespace net
diff --git a/net/base/sdch_manager.h b/net/base/sdch_manager.h
index ff157e5..016978a 100644
--- a/net/base/sdch_manager.h
+++ b/net/base/sdch_manager.h
@@ -16,8 +16,13 @@
#include "base/threading/thread_checker.h"
#include "base/time/time.h"
#include "net/base/net_export.h"
+#include "net/base/sdch_problem_codes.h"
#include "url/gurl.h"
+namespace base {
+class Value;
+}
+
namespace net {
class SdchObserver;
@@ -35,106 +40,6 @@
// module) to decompress data.
class NET_EXPORT SdchManager {
public:
- // A list of errors that appeared and were either resolved, or used to turn
- // off sdch encoding.
- enum ProblemCodes {
- MIN_PROBLEM_CODE,
-
- // Content-encoding correction problems.
- ADDED_CONTENT_ENCODING = 1,
- FIXED_CONTENT_ENCODING = 2,
- FIXED_CONTENT_ENCODINGS = 3,
-
- // Content decoding errors.
- DECODE_HEADER_ERROR = 4,
- DECODE_BODY_ERROR = 5,
-
- // More content-encoding correction problems.
- OPTIONAL_GUNZIP_ENCODING_ADDED = 6,
-
- // Content encoding correction when we're not even tagged as HTML!?!
- BINARY_ADDED_CONTENT_ENCODING = 7,
- BINARY_FIXED_CONTENT_ENCODING = 8,
- BINARY_FIXED_CONTENT_ENCODINGS = 9,
-
- // Dictionary selection for use problems.
- DICTIONARY_FOUND_HAS_WRONG_DOMAIN = 10,
- DICTIONARY_FOUND_HAS_WRONG_PORT_LIST = 11,
- DICTIONARY_FOUND_HAS_WRONG_PATH = 12,
- DICTIONARY_FOUND_HAS_WRONG_SCHEME = 13,
- DICTIONARY_HASH_NOT_FOUND = 14,
- DICTIONARY_HASH_MALFORMED = 15,
-
- // Dictionary saving problems.
- DICTIONARY_HAS_NO_HEADER = 20,
- DICTIONARY_HEADER_LINE_MISSING_COLON = 21,
- DICTIONARY_MISSING_DOMAIN_SPECIFIER = 22,
- DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN = 23,
- DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL = 24,
- DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL = 25,
- DICTIONARY_HAS_NO_TEXT = 26,
- DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX = 27,
-
- // Dictionary loading problems.
- DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST = 30,
- DICTIONARY_SELECTED_FOR_SSL = 31,
- DICTIONARY_ALREADY_LOADED = 32,
- DICTIONARY_SELECTED_FROM_NON_HTTP = 33,
- DICTIONARY_IS_TOO_LARGE= 34,
- DICTIONARY_COUNT_EXCEEDED = 35,
- DICTIONARY_ALREADY_SCHEDULED_TO_DOWNLOAD = 36,
- DICTIONARY_ALREADY_TRIED_TO_DOWNLOAD = 37,
- DICTIONARY_FETCH_READ_FAILED = 38,
-
- // Failsafe hack.
- ATTEMPT_TO_DECODE_NON_HTTP_DATA = 40,
-
-
- // Content-Encoding problems detected, with no action taken.
- MULTIENCODING_FOR_NON_SDCH_REQUEST = 50,
- SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST = 51,
-
- // Dictionary manager issues.
- DOMAIN_BLACKLIST_INCLUDES_TARGET = 61,
-
- // Problematic decode recovery methods.
- META_REFRESH_RECOVERY = 70, // Dictionary not found.
- // defunct = 71, // Almost the same as META_REFRESH_UNSUPPORTED.
- // defunct = 72, // Almost the same as CACHED_META_REFRESH_UNSUPPORTED.
- // defunct = 73, // PASSING_THROUGH_NON_SDCH plus
- // RESPONSE_TENTATIVE_SDCH in ../filter/sdch_filter.cc.
- META_REFRESH_UNSUPPORTED = 74, // Unrecoverable error.
- CACHED_META_REFRESH_UNSUPPORTED = 75, // As above, but pulled from cache.
- PASSING_THROUGH_NON_SDCH = 76, // Tagged sdch but missing dictionary-hash.
- INCOMPLETE_SDCH_CONTENT = 77, // Last window was not completely decoded.
- PASS_THROUGH_404_CODE = 78, // URL not found message passing through.
-
- // This next report is very common, and not really an error scenario, but
- // it exercises the error recovery logic.
- PASS_THROUGH_OLD_CACHED = 79, // Back button got pre-SDCH cached content.
-
- // Common decoded recovery methods.
- META_REFRESH_CACHED_RECOVERY = 80, // Probably startup tab loading.
- // defunct = 81, // Now tracked by ResponseCorruptionDetectionCause histo.
-
- // Non SDCH problems, only accounted for to make stat counting complete
- // (i.e., be able to be sure all dictionary advertisements are accounted
- // for).
-
- UNFLUSHED_CONTENT = 90, // Possible error in filter chaining.
- // defunct = 91, // MISSING_TIME_STATS (Should never happen.)
- CACHE_DECODED = 92, // No timing stats recorded.
- // defunct = 93, // OVER_10_MINUTES (No timing stats recorded.)
- UNINITIALIZED = 94, // Filter never even got initialized.
- PRIOR_TO_DICTIONARY = 95, // We hadn't even parsed a dictionary selector.
- DECODE_ERROR = 96, // Something went wrong during decode.
-
- // Problem during the latency test.
- LATENCY_TEST_DISALLOWED = 100, // SDCH now failing, but it worked before!
-
- MAX_PROBLEM_CODE // Used to bound histogram.
- };
-
// Use the following static limits to block DOS attacks until we implement
// a cached dictionary evicition strategy.
static const size_t kMaxDictionarySize;
@@ -167,19 +72,25 @@
const GURL& url() const { return url_; }
const std::string& client_hash() const { return client_hash_; }
+ const std::string& domain() const { return domain_; }
+ const std::string& path() const { return path_; }
+ const base::Time& expiration() const { return expiration_; }
+ const std::set<int>& ports() const { return ports_; }
// Security method to check if we can advertise this dictionary for use
// if the |target_url| returns SDCH compressed data.
- bool CanAdvertise(const GURL& target_url);
+ SdchProblemCode CanAdvertise(const GURL& target_url) const;
// Security methods to check if we can establish a new dictionary with the
// given data, that arrived in response to get of dictionary_url.
- static bool CanSet(const std::string& domain, const std::string& path,
- const std::set<int>& ports, const GURL& dictionary_url);
+ static SdchProblemCode CanSet(const std::string& domain,
+ const std::string& path,
+ const std::set<int>& ports,
+ const GURL& dictionary_url);
// Security method to check if we can use a dictionary to decompress a
// target that arrived with a reference to this dictionary.
- bool CanUse(const GURL& referring_url);
+ SdchProblemCode CanUse(const GURL& referring_url) const;
// Compare paths to see if they "match" for dictionary use.
static bool PathMatch(const std::string& path,
@@ -188,7 +99,6 @@
// Compare domains to see if the "match" for dictionary use.
static bool DomainMatch(const GURL& url, const std::string& restriction);
-
// The actual text of the dictionary.
std::string text_;
@@ -218,7 +128,7 @@
void ClearData();
// Record stats on various errors.
- static void SdchErrorRecovery(ProblemCodes problem);
+ static void SdchErrorRecovery(SdchProblemCode problem);
// Enables or disables SDCH compression.
static void EnableSdchSupport(bool enabled);
@@ -237,11 +147,12 @@
// Used when filter errors are found from a given domain, but it is plausible
// that the cause is temporary (such as application startup, where cached
// entries are used, but a dictionary is not yet loaded).
- void BlacklistDomain(const GURL& url, ProblemCodes blacklist_reason);
+ void BlacklistDomain(const GURL& url, SdchProblemCode blacklist_reason);
// Used when SEVERE filter errors are found from a given domain, to prevent
// further use of SDCH on that domain.
- void BlacklistDomainForever(const GURL& url, ProblemCodes blacklist_reason);
+ void BlacklistDomainForever(const GURL& url,
+ SdchProblemCode blacklist_reason);
// Unit test only, this function resets enabling of sdch, and clears the
// blacklist.
@@ -260,11 +171,12 @@
// supported domain (i.e., not blacklisted, and either the specific supported
// domain, or all domains were assumed supported). If it is blacklist, reduce
// by 1 the number of times it will be reported as blacklisted.
- bool IsInSupportedDomain(const GURL& url);
+ SdchProblemCode IsInSupportedDomain(const GURL& url);
// Send out appropriate events notifying observers that a Get-Dictionary
// header has been seen.
- void OnGetDictionary(const GURL& request_url, const GURL& dictionary_url);
+ SdchProblemCode OnGetDictionary(const GURL& request_url,
+ const GURL& dictionary_url);
// Find the vcdiff dictionary (the body of the sdch dictionary that appears
// after the meta-data headers like Domain:...) with the given |server_hash|
@@ -272,9 +184,12 @@
// be sure the returned |dictionary| can be used for decoding content supplied
// in response to a request for |referring_url|.
// Return null in |dictionary| if there is no matching legal dictionary.
- void GetVcdiffDictionary(const std::string& server_hash,
- const GURL& referring_url,
- scoped_refptr<Dictionary>* dictionary);
+ // Returns SDCH_OK if dictionary is not found, SDCH(-over-https) is disabled,
+ // or if matching legal dictionary exists. Otherwise returns the
+ // corresponding problem code.
+ SdchProblemCode GetVcdiffDictionary(const std::string& server_hash,
+ const GURL& referring_url,
+ scoped_refptr<Dictionary>* dictionary);
// Get list of available (pre-cached) dictionaries that we have already loaded
// into memory. The list is a comma separated list of (client) hashes per
@@ -295,12 +210,16 @@
void SetAllowLatencyExperiment(const GURL& url, bool enable);
+ base::Value* SdchInfoToValue() const;
+
// Add an SDCH dictionary to our list of availible
// dictionaries. This addition will fail if addition is illegal
// (data in the dictionary is not acceptable from the
// dictionary_url; dictionary already added, etc.).
- void AddSdchDictionary(const std::string& dictionary_text,
- const GURL& dictionary_url);
+ // Returns SDCH_OK if the addition was successfull, and corresponding error
+ // code otherwise.
+ SdchProblemCode AddSdchDictionary(const std::string& dictionary_text,
+ const GURL& dictionary_url);
// Registration for events generated by the SDCH subsystem.
void AddObserver(SdchObserver* observer);
@@ -308,24 +227,20 @@
private:
struct BlacklistInfo {
- BlacklistInfo()
- : count(0),
- exponential_count(0),
- reason(MIN_PROBLEM_CODE) {}
+ BlacklistInfo() : count(0), exponential_count(0), reason(SDCH_OK) {}
- int count; // # of times to refuse SDCH advertisement.
- int exponential_count; // Current exponential backoff ratchet.
- ProblemCodes reason; // Why domain was blacklisted.
-
+ int count; // # of times to refuse SDCH advertisement.
+ int exponential_count; // Current exponential backoff ratchet.
+ SdchProblemCode reason; // Why domain was blacklisted.
};
typedef std::map<std::string, BlacklistInfo> DomainBlacklistInfo;
typedef std::set<std::string> ExperimentSet;
// Determines whether a "Get-Dictionary" header is legal (dictionary
// url has appropriate relationship to referrer url) in the SDCH
- // protocol. Return true if fetch is legal.
- bool CanFetchDictionary(const GURL& referring_url,
- const GURL& dictionary_url) const;
+ // protocol. Return SDCH_OK if fetch is legal.
+ SdchProblemCode CanFetchDictionary(const GURL& referring_url,
+ const GURL& dictionary_url) const;
// A map of dictionaries info indexed by the hash that the server provides.
typedef std::map<std::string, scoped_refptr<Dictionary> > DictionaryMap;
@@ -340,6 +255,7 @@
// A simple implementation of a RFC 3548 "URL safe" base64 encoder.
static void UrlSafeBase64Encode(const std::string& input,
std::string* output);
+
DictionaryMap dictionaries_;
// List domains where decode failures have required disabling sdch.
diff --git a/net/base/sdch_manager_unittest.cc b/net/base/sdch_manager_unittest.cc
index d986879..c20be58 100644
--- a/net/base/sdch_manager_unittest.cc
+++ b/net/base/sdch_manager_unittest.cc
@@ -8,6 +8,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "net/base/net_log.h"
#include "net/base/sdch_manager.h"
#include "net/base/sdch_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -73,14 +74,7 @@
// failure.
bool AddSdchDictionary(const std::string& dictionary_text,
const GURL& gurl) {
- std::string list;
- sdch_manager_->GetAvailDictionaryList(gurl, &list);
- sdch_manager_->AddSdchDictionary(dictionary_text, gurl);
- std::string list2;
- sdch_manager_->GetAvailDictionaryList(gurl, &list2);
-
- // The list of hashes should change iff the addition succeeds.
- return (list != list2);
+ return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
}
private:
@@ -105,31 +99,34 @@
GURL google_url("http://www.google.com");
SdchManager::EnableSdchSupport(false);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
+ EXPECT_EQ(SDCH_DISABLED, sdch_manager()->IsInSupportedDomain(google_url));
SdchManager::EnableSdchSupport(true);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(google_url));
}
TEST_F(SdchManagerTest, DomainBlacklisting) {
GURL test_url("http://www.test.com");
GURL google_url("http://www.google.com");
- sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test_url));
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(google_url));
+ sdch_manager()->BlacklistDomain(test_url, SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(test_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(google_url));
- sdch_manager()->BlacklistDomain(google_url, SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(google_url));
+ sdch_manager()->BlacklistDomain(google_url, SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(google_url));
}
TEST_F(SdchManagerTest, DomainBlacklistingCaseSensitivity) {
GURL test_url("http://www.TesT.com");
GURL test2_url("http://www.tEst.com");
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test_url));
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(test2_url));
- sdch_manager()->BlacklistDomain(test_url, SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(test2_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(test_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(test2_url));
+ sdch_manager()->BlacklistDomain(test_url, SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(test2_url));
}
TEST_F(SdchManagerTest, BlacklistingReset) {
@@ -139,7 +136,7 @@
sdch_manager()->ClearBlacklistings();
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 0);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
}
TEST_F(SdchManagerTest, BlacklistingSingleBlacklist) {
@@ -147,14 +144,15 @@
std::string domain(gurl.host());
sdch_manager()->ClearBlacklistings();
- sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
+ sdch_manager()->BlacklistDomain(gurl, SDCH_OK);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 1);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), 1);
// Check that any domain lookup reduces the blacklist counter.
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(gurl));
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
}
TEST_F(SdchManagerTest, BlacklistingExponential) {
@@ -164,18 +162,19 @@
int exponential = 1;
for (int i = 1; i < 100; ++i) {
- sdch_manager()->BlacklistDomain(gurl, SdchManager::MIN_PROBLEM_CODE);
+ sdch_manager()->BlacklistDomain(gurl, SDCH_OK);
EXPECT_EQ(sdch_manager()->BlacklistDomainExponential(domain), exponential);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(gurl));
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), exponential - 1);
// Simulate a large number of domain checks (which eventually remove the
// blacklisting).
sdch_manager()->ClearDomainBlacklisting(domain);
EXPECT_EQ(sdch_manager()->BlackListDomainCount(domain), 0);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(gurl));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(gurl));
// Predict what exponential backoff will be.
exponential = 1 + 2 * exponential;
@@ -246,7 +245,8 @@
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
- sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+ EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+ server_hash, target_url, &dictionary));
EXPECT_TRUE(dictionary.get() != NULL);
}
@@ -269,7 +269,9 @@
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
- sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+ EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
+ sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
+ &dictionary));
EXPECT_TRUE(dictionary.get() == NULL);
}
@@ -292,7 +294,9 @@
std::string client_hash;
std::string server_hash;
sdch_manager()->GenerateHash(dictionary_text, &client_hash, &server_hash);
- sdch_manager()->GetVcdiffDictionary(server_hash, target_url, &dictionary);
+ EXPECT_EQ(SDCH_DICTIONARY_FOUND_HAS_WRONG_SCHEME,
+ sdch_manager()->GetVcdiffDictionary(server_hash, target_url,
+ &dictionary));
EXPECT_TRUE(dictionary.get() == NULL);
}
@@ -516,10 +520,10 @@
EXPECT_TRUE(AddSdchDictionary(dictionary_text_1,
GURL("http://" + dictionary_domain_1)));
scoped_refptr<SdchManager::Dictionary> dictionary;
- sdch_manager()->GetVcdiffDictionary(
- server_hash_1,
- GURL("http://" + dictionary_domain_1 + "/random_url"),
- &dictionary);
+ EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+ server_hash_1,
+ GURL("http://" + dictionary_domain_1 + "/random_url"),
+ &dictionary));
EXPECT_TRUE(dictionary.get());
second_manager.AddSdchDictionary(
@@ -530,16 +534,18 @@
&dictionary);
EXPECT_TRUE(dictionary.get());
- sdch_manager()->GetVcdiffDictionary(
- server_hash_2,
- GURL("http://" + dictionary_domain_2 + "/random_url"),
- &dictionary);
+ EXPECT_EQ(
+ SDCH_DICTIONARY_HASH_NOT_FOUND,
+ sdch_manager()->GetVcdiffDictionary(
+ server_hash_2, GURL("http://" + dictionary_domain_2 + "/random_url"),
+ &dictionary));
EXPECT_FALSE(dictionary.get());
- second_manager.GetVcdiffDictionary(
- server_hash_1,
- GURL("http://" + dictionary_domain_1 + "/random_url"),
- &dictionary);
+ EXPECT_EQ(
+ SDCH_DICTIONARY_HASH_NOT_FOUND,
+ second_manager.GetVcdiffDictionary(
+ server_hash_1, GURL("http://" + dictionary_domain_1 + "/random_url"),
+ &dictionary));
EXPECT_FALSE(dictionary.get());
}
@@ -549,14 +555,15 @@
bool expect_https_support = true;
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
- EXPECT_EQ(expect_https_support,
- sdch_manager()->IsInSupportedDomain(secure_url));
+ SdchProblemCode expected_code =
+ expect_https_support ? SDCH_OK : SDCH_SECURE_SCHEME_NOT_SUPPORTED;
+
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
+ EXPECT_EQ(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
SdchManager::EnableSecureSchemeSupport(!expect_https_support);
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(url));
- EXPECT_NE(expect_https_support,
- sdch_manager()->IsInSupportedDomain(secure_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(url));
+ EXPECT_NE(expected_code, sdch_manager()->IsInSupportedDomain(secure_url));
}
TEST_F(SdchManagerTest, ClearDictionaryData) {
@@ -572,25 +579,26 @@
EXPECT_TRUE(AddSdchDictionary(dictionary_text,
GURL("http://" + dictionary_domain)));
scoped_refptr<SdchManager::Dictionary> dictionary;
- sdch_manager()->GetVcdiffDictionary(
- server_hash,
- GURL("http://" + dictionary_domain + "/random_url"),
- &dictionary);
+ EXPECT_EQ(SDCH_OK, sdch_manager()->GetVcdiffDictionary(
+ server_hash,
+ GURL("http://" + dictionary_domain + "/random_url"),
+ &dictionary));
EXPECT_TRUE(dictionary.get());
- sdch_manager()->BlacklistDomain(GURL(blacklist_url),
- SdchManager::MIN_PROBLEM_CODE);
- EXPECT_FALSE(sdch_manager()->IsInSupportedDomain(blacklist_url));
+ sdch_manager()->BlacklistDomain(GURL(blacklist_url), SDCH_OK);
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager()->IsInSupportedDomain(blacklist_url));
sdch_manager()->ClearData();
dictionary = NULL;
- sdch_manager()->GetVcdiffDictionary(
- server_hash,
- GURL("http://" + dictionary_domain + "/random_url"),
- &dictionary);
+ EXPECT_EQ(
+ SDCH_DICTIONARY_HASH_NOT_FOUND,
+ sdch_manager()->GetVcdiffDictionary(
+ server_hash, GURL("http://" + dictionary_domain + "/random_url"),
+ &dictionary));
EXPECT_FALSE(dictionary.get());
- EXPECT_TRUE(sdch_manager()->IsInSupportedDomain(blacklist_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager()->IsInSupportedDomain(blacklist_url));
}
TEST_F(SdchManagerTest, GetDictionaryNotification) {
diff --git a/net/base/sdch_net_log_params.cc b/net/base/sdch_net_log_params.cc
new file mode 100644
index 0000000..02e0ad7
--- /dev/null
+++ b/net/base/sdch_net_log_params.cc
@@ -0,0 +1,34 @@
+// 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 "net/base/sdch_net_log_params.h"
+
+#include "base/values.h"
+#include "net/base/net_errors.h"
+#include "url/gurl.h"
+
+namespace net {
+
+base::Value* NetLogSdchResourceProblemCallback(SdchProblemCode problem,
+ NetLog::LogLevel log_level) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("sdch_problem_code", problem);
+ dict->SetInteger("net_error", ERR_FAILED);
+ return dict;
+}
+
+base::Value* NetLogSdchDictionaryFetchProblemCallback(
+ SdchProblemCode problem,
+ const GURL& url,
+ bool is_error,
+ NetLog::LogLevel log_level) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetInteger("sdch_problem_code", problem);
+ dict->SetString("dictionary_url", url.spec());
+ if (is_error)
+ dict->SetInteger("net_error", ERR_FAILED);
+ return dict;
+}
+
+} // namespace net
diff --git a/net/base/sdch_net_log_params.h b/net/base/sdch_net_log_params.h
new file mode 100644
index 0000000..7421a0a
--- /dev/null
+++ b/net/base/sdch_net_log_params.h
@@ -0,0 +1,32 @@
+// 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 NET_BASE_SDCH_NET_LOG_PARAMS_H_
+#define NET_BASE_SDCH_NET_LOG_PARAMS_H_
+
+#include <string>
+
+#include "net/base/net_export.h"
+#include "net/base/net_log.h"
+#include "net/base/sdch_problem_codes.h"
+
+class GURL;
+
+namespace net {
+
+NET_EXPORT base::Value* NetLogSdchResourceProblemCallback(
+ SdchProblemCode problem,
+ NetLog::LogLevel log_level);
+
+// If |is_error| is false, "net_error" field won't be added to the JSON and the
+// event won't be painted red in the netlog.
+NET_EXPORT base::Value* NetLogSdchDictionaryFetchProblemCallback(
+ SdchProblemCode problem,
+ const GURL& url,
+ bool is_error,
+ NetLog::LogLevel log_level);
+
+} // namespace net
+
+#endif // NET_BASE_SDCH_NET_LOG_PARAMS_H_
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h
new file mode 100644
index 0000000..4efc17c
--- /dev/null
+++ b/net/base/sdch_problem_code_list.h
@@ -0,0 +1,127 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file intentionally does not have header guards, it's included
+// inside a macro to generate enum values.
+
+// This file contains list of sdch-related problem codes.
+// No error.
+SDCH_PROBLEM_CODE(OK, 0)
+
+// Content-encoding correction problems.
+SDCH_PROBLEM_CODE(ADDED_CONTENT_ENCODING, 1)
+SDCH_PROBLEM_CODE(FIXED_CONTENT_ENCODING, 2)
+SDCH_PROBLEM_CODE(FIXED_CONTENT_ENCODINGS, 3)
+
+// Content decoding errors.
+SDCH_PROBLEM_CODE(DECODE_HEADER_ERROR, 4)
+SDCH_PROBLEM_CODE(DECODE_BODY_ERROR, 5)
+
+// More content-encoding correction problems.
+SDCH_PROBLEM_CODE(OPTIONAL_GUNZIP_ENCODING_ADDED, 6)
+
+// Content encoding correction when we're not even tagged as HTML!?!
+SDCH_PROBLEM_CODE(BINARY_ADDED_CONTENT_ENCODING, 7)
+SDCH_PROBLEM_CODE(BINARY_FIXED_CONTENT_ENCODING, 8)
+SDCH_PROBLEM_CODE(BINARY_FIXED_CONTENT_ENCODINGS, 9)
+
+// Dictionary selection for use problems.
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_DOMAIN, 10)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_PORT_LIST, 11)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_PATH, 12)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_HAS_WRONG_SCHEME, 13)
+SDCH_PROBLEM_CODE(DICTIONARY_HASH_NOT_FOUND, 14)
+SDCH_PROBLEM_CODE(DICTIONARY_HASH_MALFORMED, 15)
+SDCH_PROBLEM_CODE(DICTIONARY_FOUND_EXPIRED, 16)
+
+// Dictionary saving problems.
+SDCH_PROBLEM_CODE(DICTIONARY_HAS_NO_HEADER, 20)
+SDCH_PROBLEM_CODE(DICTIONARY_HEADER_LINE_MISSING_COLON, 21)
+SDCH_PROBLEM_CODE(DICTIONARY_MISSING_DOMAIN_SPECIFIER, 22)
+SDCH_PROBLEM_CODE(DICTIONARY_SPECIFIES_TOP_LEVEL_DOMAIN, 23)
+SDCH_PROBLEM_CODE(DICTIONARY_DOMAIN_NOT_MATCHING_SOURCE_URL, 24)
+SDCH_PROBLEM_CODE(DICTIONARY_PORT_NOT_MATCHING_SOURCE_URL, 25)
+SDCH_PROBLEM_CODE(DICTIONARY_HAS_NO_TEXT, 26)
+SDCH_PROBLEM_CODE(DICTIONARY_REFERER_URL_HAS_DOT_IN_PREFIX, 27)
+SDCH_PROBLEM_CODE(DICTIONARY_UNSUPPORTED_VERSION, 28)
+
+// Dictionary loading problems.
+SDCH_PROBLEM_CODE(DICTIONARY_LOAD_ATTEMPT_FROM_DIFFERENT_HOST, 30)
+SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FOR_SSL, 31)
+SDCH_PROBLEM_CODE(DICTIONARY_ALREADY_LOADED, 32)
+SDCH_PROBLEM_CODE(DICTIONARY_SELECTED_FROM_NON_HTTP, 33)
+SDCH_PROBLEM_CODE(DICTIONARY_IS_TOO_LARGE, 34)
+SDCH_PROBLEM_CODE(DICTIONARY_COUNT_EXCEEDED, 35)
+// defunct = 36, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
+// defunct = 37, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
+SDCH_PROBLEM_CODE(DICTIONARY_FETCH_READ_FAILED, 38)
+SDCH_PROBLEM_CODE(DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD, 39)
+
+// Failsafe hack.
+SDCH_PROBLEM_CODE(ATTEMPT_TO_DECODE_NON_HTTP_DATA, 40)
+
+// Content-Encoding problems detected, with no action taken.
+SDCH_PROBLEM_CODE(MULTIENCODING_FOR_NON_SDCH_REQUEST, 50)
+SDCH_PROBLEM_CODE(SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST, 51)
+
+// Dictionary manager issues.
+SDCH_PROBLEM_CODE(DOMAIN_BLACKLIST_INCLUDES_TARGET, 61)
+
+// Problematic decode recovery methods.
+// Dictionary not found.
+SDCH_PROBLEM_CODE(META_REFRESH_RECOVERY, 70)
+// defunct = 71, // Almost the same as META_REFRESH_UNSUPPORTED.
+// defunct = 72, // Almost the same as CACHED_META_REFRESH_UNSUPPORTED.
+// defunct = 73, // PASSING_THROUGH_NON_SDCH plus DISCARD_TENTATIVE_SDCH.
+// Unrecoverable error.
+SDCH_PROBLEM_CODE(META_REFRESH_UNSUPPORTED, 74)
+// As above, but pulled from cache.
+SDCH_PROBLEM_CODE(CACHED_META_REFRESH_UNSUPPORTED, 75)
+// Tagged sdch but missing dictionary-hash.
+SDCH_PROBLEM_CODE(PASSING_THROUGH_NON_SDCH, 76)
+// Last window was not completely decoded.
+SDCH_PROBLEM_CODE(INCOMPLETE_SDCH_CONTENT, 77)
+// URL not found message passing through.
+SDCH_PROBLEM_CODE(PASS_THROUGH_404_CODE, 78)
+
+// This next report is very common, and not really an error scenario, but
+// it exercises the error recovery logic.
+// Back button got pre-SDCH cached content.
+SDCH_PROBLEM_CODE(PASS_THROUGH_OLD_CACHED, 79)
+
+// Common decoded recovery methods.
+// Probably startup tab loading.
+SDCH_PROBLEM_CODE(META_REFRESH_CACHED_RECOVERY, 80)
+// defunct = 81, // Now tracked by ResponseCorruptionDetectionCause histo.
+
+// Non SDCH problems, only accounted for to make stat counting complete
+// (i.e., be able to be sure all dictionary advertisements are accounted
+// for).
+// Possible error in filter chaining.
+SDCH_PROBLEM_CODE(UNFLUSHED_CONTENT, 90)
+// defunct = 91, // MISSING_TIME_STATS (Should never happen.)
+// No timing stats recorded.
+SDCH_PROBLEM_CODE(CACHE_DECODED, 92)
+// defunct = 93, // OVER_10_MINUTES (No timing stats recorded.)
+// Filter never even got initialized.
+SDCH_PROBLEM_CODE(UNINITIALIZED, 94)
+// We hadn't even parsed a dictionary selector.
+SDCH_PROBLEM_CODE(PRIOR_TO_DICTIONARY, 95)
+// Something went wrong during decode.
+SDCH_PROBLEM_CODE(DECODE_ERROR, 96)
+
+// Problem during the latency test.
+// SDCH now failing, but it worked before!
+SDCH_PROBLEM_CODE(LATENCY_TEST_DISALLOWED, 100)
+
+// General SDCH problems.
+// SDCH is disabled.
+SDCH_PROBLEM_CODE(DISABLED, 105)
+// SDCH over https is disabled.
+SDCH_PROBLEM_CODE(SECURE_SCHEME_NOT_SUPPORTED, 106)
+
+// Used to bound histogram.
+SDCH_PROBLEM_CODE(MAX_PROBLEM_CODE, 110)
+
+// These values are not used in histograms.
diff --git a/net/base/sdch_problem_codes.h b/net/base/sdch_problem_codes.h
new file mode 100644
index 0000000..da979fc
--- /dev/null
+++ b/net/base/sdch_problem_codes.h
@@ -0,0 +1,20 @@
+// 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 NET_BASE_SDCH_PROBLEM_CODES_H_
+#define NET_BASE_SDCH_PROBLEM_CODES_H_
+
+namespace net {
+
+// A list of errors that appeared and were either resolved, or used to turn
+// off sdch encoding.
+enum SdchProblemCode {
+#define SDCH_PROBLEM_CODE(label, value) SDCH_##label = value,
+#include "net/base/sdch_problem_code_list.h"
+#undef SDCH_PROBLEM_CODE
+};
+
+} // namespace net
+
+#endif // NET_BASE_SDCH_PROBLEM_CODES_H_
diff --git a/net/filter/filter.cc b/net/filter/filter.cc
index c8a4740..c9a56bd 100644
--- a/net/filter/filter.cc
+++ b/net/filter/filter.cc
@@ -28,11 +28,14 @@
#include "net/base/filename_util_unsafe.h"
#include "net/base/io_buffer.h"
#include "net/base/mime_util.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/filter/gzip_filter.h"
#include "net/filter/sdch_filter.h"
#include "net/url_request/url_request_context.h"
#include "url/gurl.h"
+namespace net {
+
namespace {
// Filter types (using canonical lower case only):
@@ -53,9 +56,15 @@
// Buffer size allocated when de-compressing data.
const int kFilterBufSize = 32 * 1024;
-} // namespace
+void LogSdchProblem(const FilterContext& filter_context,
+ SdchProblemCode problem) {
+ SdchManager::SdchErrorRecovery(problem);
+ filter_context.GetNetLog().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, problem));
+}
-namespace net {
+} // namespace
FilterContext::~FilterContext() {
}
@@ -233,13 +242,12 @@
// It was not an SDCH request, so we'll just record stats.
if (1 < encoding_types->size()) {
// Multiple filters were intended to only be used for SDCH (thus far!)
- SdchManager::SdchErrorRecovery(
- SdchManager::MULTIENCODING_FOR_NON_SDCH_REQUEST);
+ LogSdchProblem(filter_context, SDCH_MULTIENCODING_FOR_NON_SDCH_REQUEST);
}
if ((1 == encoding_types->size()) &&
(FILTER_TYPE_SDCH == encoding_types->front())) {
- SdchManager::SdchErrorRecovery(
- SdchManager::SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST);
+ LogSdchProblem(filter_context,
+ SDCH_SDCH_CONTENT_ENCODE_FOR_NON_SDCH_REQUEST);
}
return;
}
@@ -259,8 +267,7 @@
// no-op pass through filter if it doesn't get gzip headers where expected.
if (1 == encoding_types->size()) {
encoding_types->push_back(FILTER_TYPE_GZIP_HELPING_SDCH);
- SdchManager::SdchErrorRecovery(
- SdchManager::OPTIONAL_GUNZIP_ENCODING_ADDED);
+ LogSdchProblem(filter_context, SDCH_OPTIONAL_GUNZIP_ENCODING_ADDED);
}
return;
}
@@ -294,14 +301,11 @@
// Suspicious case: Advertised dictionary, but server didn't use sdch, and
// we're HTML tagged.
if (encoding_types->empty()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::ADDED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_ADDED_CONTENT_ENCODING);
} else if (1 == encoding_types->size()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::FIXED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_FIXED_CONTENT_ENCODING);
} else {
- SdchManager::SdchErrorRecovery(
- SdchManager::FIXED_CONTENT_ENCODINGS);
+ LogSdchProblem(filter_context, SDCH_FIXED_CONTENT_ENCODINGS);
}
} else {
// Remarkable case!?! We advertised an SDCH dictionary, content-encoding
@@ -313,14 +317,11 @@
// start with "text/html" for some other reason?? We'll report this as a
// fixup to a binary file, but it probably really is text/html (some how).
if (encoding_types->empty()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::BINARY_ADDED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_BINARY_ADDED_CONTENT_ENCODING);
} else if (1 == encoding_types->size()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::BINARY_FIXED_CONTENT_ENCODING);
+ LogSdchProblem(filter_context, SDCH_BINARY_FIXED_CONTENT_ENCODING);
} else {
- SdchManager::SdchErrorRecovery(
- SdchManager::BINARY_FIXED_CONTENT_ENCODINGS);
+ LogSdchProblem(filter_context, SDCH_BINARY_FIXED_CONTENT_ENCODINGS);
}
}
diff --git a/net/filter/filter.h b/net/filter/filter.h
index 37f55e2..13489ef 100644
--- a/net/filter/filter.h
+++ b/net/filter/filter.h
@@ -60,8 +60,9 @@
namespace net {
-class URLRequestContext;
+class BoundNetLog;
class IOBuffer;
+class URLRequestContext;
//------------------------------------------------------------------------------
// Define an interface class that allows access to contextual information
@@ -122,6 +123,9 @@
// The following method forces the context to emit a specific set of
// statistics as selected by the argument.
virtual void RecordPacketStats(StatisticSelector statistic) const = 0;
+
+ // The BoundNetLog of the associated request.
+ virtual const BoundNetLog& GetNetLog() const = 0;
};
//------------------------------------------------------------------------------
diff --git a/net/filter/mock_filter_context.cc b/net/filter/mock_filter_context.cc
index e1e4793..35ab9ee 100644
--- a/net/filter/mock_filter_context.cc
+++ b/net/filter/mock_filter_context.cc
@@ -66,4 +66,8 @@
return context_.get();
}
+const BoundNetLog& MockFilterContext::GetNetLog() const {
+ return net_log_;
+}
+
} // namespace net
diff --git a/net/filter/mock_filter_context.h b/net/filter/mock_filter_context.h
index 8150e8b..41c9e9e 100644
--- a/net/filter/mock_filter_context.h
+++ b/net/filter/mock_filter_context.h
@@ -8,6 +8,7 @@
#include <string>
#include "base/memory/scoped_ptr.h"
+#include "net/base/net_log.h"
#include "net/filter/filter.h"
#include "url/gurl.h"
@@ -73,6 +74,8 @@
void RecordPacketStats(StatisticSelector statistic) const override {}
+ const BoundNetLog& GetNetLog() const override;
+
private:
int buffer_size_;
std::string mime_type_;
@@ -85,6 +88,7 @@
bool ok_to_call_get_url_;
int response_code_;
scoped_ptr<URLRequestContext> context_;
+ BoundNetLog net_log_;
DISALLOW_COPY_AND_ASSIGN(MockFilterContext);
};
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc
index df72367..d03ff7f 100644
--- a/net/filter/sdch_filter.cc
+++ b/net/filter/sdch_filter.cc
@@ -11,7 +11,9 @@
#include "base/logging.h"
#include "base/metrics/histogram.h"
+#include "base/values.h"
#include "net/base/sdch_manager.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/url_request/url_request_context.h"
#include "sdch/open-vcdiff/src/google/vcdecoder.h"
@@ -50,6 +52,51 @@
RESPONSE_MAX,
};
+const char* ResponseCorruptionDetectionCauseToString(
+ ResponseCorruptionDetectionCause cause) {
+ const char* cause_string = "<unknown>";
+ switch (cause) {
+ case RESPONSE_NONE:
+ cause_string = "NONE";
+ break;
+ case RESPONSE_404:
+ cause_string = "404";
+ break;
+ case RESPONSE_NOT_200:
+ cause_string = "NOT_200";
+ break;
+ case RESPONSE_OLD_UNENCODED:
+ cause_string = "OLD_UNENCODED";
+ break;
+ case RESPONSE_TENTATIVE_SDCH:
+ cause_string = "TENTATIVE_SDCH";
+ break;
+ case RESPONSE_NO_DICTIONARY:
+ cause_string = "NO_DICTIONARY";
+ break;
+ case RESPONSE_CORRUPT_SDCH:
+ cause_string = "CORRUPT_SDCH";
+ break;
+ case RESPONSE_ENCODING_LIE:
+ cause_string = "ENCODING_LIE";
+ break;
+ case RESPONSE_MAX:
+ cause_string = "<Error: max enum value>";
+ break;
+ }
+ return cause_string;
+}
+
+base::Value* NetLogSdchResponseCorruptionDetectionCallback(
+ ResponseCorruptionDetectionCause cause,
+ bool cached,
+ NetLog::LogLevel log_level) {
+ base::DictionaryValue* dict = new base::DictionaryValue();
+ dict->SetString("cause", ResponseCorruptionDetectionCauseToString(cause));
+ dict->SetBoolean("cached", cached);
+ return dict;
+}
+
} // namespace
SdchFilter::SdchFilter(const FilterContext& filter_context)
@@ -84,12 +131,12 @@
if (vcdiff_streaming_decoder_.get()) {
if (!vcdiff_streaming_decoder_->FinishDecoding()) {
decoding_status_ = DECODING_ERROR;
- SdchManager::SdchErrorRecovery(SdchManager::INCOMPLETE_SDCH_CONTENT);
+ LogSdchProblem(SDCH_INCOMPLETE_SDCH_CONTENT);
// Make it possible for the user to hit reload, and get non-sdch content.
// Note this will "wear off" quickly enough, and is just meant to assure
// in some rare case that the user is not stuck.
url_request_context_->sdch_manager()->BlacklistDomain(
- url_, SdchManager::INCOMPLETE_SDCH_CONTENT);
+ url_, SDCH_INCOMPLETE_SDCH_CONTENT);
UMA_HISTOGRAM_COUNTS("Sdch3.PartialBytesIn",
static_cast<int>(filter_context_.GetByteReadCount()));
UMA_HISTOGRAM_COUNTS("Sdch3.PartialVcdiffIn", source_bytes_);
@@ -99,7 +146,7 @@
if (!dest_buffer_excess_.empty()) {
// Filter chaining error, or premature teardown.
- SdchManager::SdchErrorRecovery(SdchManager::UNFLUSHED_CONTENT);
+ LogSdchProblem(SDCH_UNFLUSHED_CONTENT);
UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBytesIn",
static_cast<int>(filter_context_.GetByteReadCount()));
UMA_HISTOGRAM_COUNTS("Sdch3.UnflushedBufferSize",
@@ -111,7 +158,7 @@
if (filter_context_.IsCachedContent()) {
// Not a real error, but it is useful to have this tally.
// TODO(jar): Remove this stat after SDCH stability is validated.
- SdchManager::SdchErrorRecovery(SdchManager::CACHE_DECODED);
+ LogSdchProblem(SDCH_CACHE_DECODED);
return; // We don't need timing stats, and we aready got ratios.
}
@@ -135,15 +182,15 @@
return;
}
case DECODING_UNINITIALIZED: {
- SdchManager::SdchErrorRecovery(SdchManager::UNINITIALIZED);
+ LogSdchProblem(SDCH_UNINITIALIZED);
return;
}
case WAITING_FOR_DICTIONARY_SELECTION: {
- SdchManager::SdchErrorRecovery(SdchManager::PRIOR_TO_DICTIONARY);
+ LogSdchProblem(SDCH_PRIOR_TO_DICTIONARY);
return;
}
case DECODING_ERROR: {
- SdchManager::SdchErrorRecovery(SdchManager::DECODE_ERROR);
+ LogSdchProblem(SDCH_DECODE_ERROR);
return;
}
case META_REFRESH_RECOVERY: {
@@ -210,7 +257,7 @@
// We could be more generous, but for now, only a "NOT FOUND" code will
// cause a pass through. All other bad codes will fall into a
// meta-refresh.
- SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_404_CODE);
+ LogSdchProblem(SDCH_PASS_THROUGH_404_CODE);
cause = RESPONSE_404;
decoding_status_ = PASS_THROUGH;
} else if (filter_context_.GetResponseCode() != 200) {
@@ -220,7 +267,7 @@
&& !dictionary_hash_is_plausible_) {
// We must have hit the back button, and gotten content that was fetched
// before we *really* advertised SDCH and a dictionary.
- SdchManager::SdchErrorRecovery(SdchManager::PASS_THROUGH_OLD_CACHED);
+ LogSdchProblem(SDCH_PASS_THROUGH_OLD_CACHED);
decoding_status_ = PASS_THROUGH;
cause = RESPONSE_OLD_UNENCODED;
} else if (possible_pass_through_) {
@@ -256,11 +303,11 @@
// though it is not!
// Meta-refresh won't help, as we didn't advertise an SDCH dictionary!!
// Worse yet, meta-refresh could lead to an infinite refresh loop.
- SdchManager::SdchErrorRecovery(SdchManager::PASSING_THROUGH_NON_SDCH);
+ LogSdchProblem(SDCH_PASSING_THROUGH_NON_SDCH);
decoding_status_ = PASS_THROUGH;
// ... but further back-off on advertising SDCH support.
url_request_context_->sdch_manager()->BlacklistDomain(
- url_, SdchManager::PASSING_THROUGH_NON_SDCH);
+ url_, SDCH_PASSING_THROUGH_NON_SDCH);
cause = RESPONSE_ENCODING_LIE;
}
DCHECK_NE(RESPONSE_NONE, cause);
@@ -274,6 +321,10 @@
UMA_HISTOGRAM_ENUMERATION(
"Sdch3.ResponseCorruptionDetection.Uncached", cause, RESPONSE_MAX);
}
+ filter_context_.GetNetLog().AddEvent(
+ NetLog::TYPE_SDCH_RESPONSE_CORRUPTION_DETECTION,
+ base::Bind(&NetLogSdchResponseCorruptionDetectionCallback, cause,
+ filter_context_.IsCachedContent()));
if (decoding_status_ == PASS_THROUGH) {
dest_buffer_excess_ = dictionary_hash_; // Send what we scanned.
@@ -282,13 +333,12 @@
if (std::string::npos == mime_type_.find("text/html")) {
// Since we can't do a meta-refresh (along with an exponential
// backoff), we'll just make sure this NEVER happens again.
- SdchManager::ProblemCodes problem =
- (filter_context_.IsCachedContent() ?
- SdchManager::CACHED_META_REFRESH_UNSUPPORTED :
- SdchManager::META_REFRESH_UNSUPPORTED);
+ SdchProblemCode problem = (filter_context_.IsCachedContent()
+ ? SDCH_CACHED_META_REFRESH_UNSUPPORTED
+ : SDCH_META_REFRESH_UNSUPPORTED);
url_request_context_->sdch_manager()->BlacklistDomainForever(
url_, problem);
- SdchManager::SdchErrorRecovery(problem);
+ LogSdchProblem(problem);
return FILTER_ERROR;
}
// HTML content means we can issue a meta-refresh, and get the content
@@ -296,14 +346,13 @@
if (filter_context_.IsCachedContent()) {
// Cached content is probably a startup tab, so we'll just get fresh
// content and try again, without disabling sdch.
- SdchManager::SdchErrorRecovery(
- SdchManager::META_REFRESH_CACHED_RECOVERY);
+ LogSdchProblem(SDCH_META_REFRESH_CACHED_RECOVERY);
} else {
// Since it wasn't in the cache, we definately need at least some
// period of blacklisting to get the correct content.
url_request_context_->sdch_manager()->BlacklistDomain(
- url_, SdchManager::META_REFRESH_RECOVERY);
- SdchManager::SdchErrorRecovery(SdchManager::META_REFRESH_RECOVERY);
+ url_, SDCH_META_REFRESH_RECOVERY);
+ LogSdchProblem(SDCH_META_REFRESH_RECOVERY);
}
decoding_status_ = META_REFRESH_RECOVERY;
// Issue a meta redirect with SDCH disabled.
@@ -357,7 +406,7 @@
if (!ret) {
vcdiff_streaming_decoder_.reset(NULL); // Don't call it again.
decoding_status_ = DECODING_ERROR;
- SdchManager::SdchErrorRecovery(SdchManager::DECODE_BODY_ERROR);
+ LogSdchProblem(SDCH_DECODE_BODY_ERROR);
return FILTER_ERROR;
}
@@ -394,32 +443,35 @@
DCHECK(!dictionary_.get());
dictionary_hash_is_plausible_ = true; // Assume plausible, but check.
+ SdchProblemCode rv = SDCH_OK;
if ('\0' == dictionary_hash_[kServerIdLength - 1]) {
SdchManager* manager(url_request_context_->sdch_manager());
- manager->GetVcdiffDictionary(
- std::string(dictionary_hash_, 0, kServerIdLength - 1),
- url_, &dictionary_);
- } else {
- dictionary_hash_is_plausible_ = false;
- }
-
- if (!dictionary_.get()) {
- DCHECK(dictionary_hash_.size() == kServerIdLength);
- // Since dictionary was not found, check to see if hash was even plausible.
- for (size_t i = 0; i < kServerIdLength - 1; ++i) {
- char base64_char = dictionary_hash_[i];
- if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
- dictionary_hash_is_plausible_ = false;
- break;
+ rv = manager->GetVcdiffDictionary(
+ std::string(dictionary_hash_, 0, kServerIdLength - 1), url_,
+ &dictionary_);
+ if (rv == SDCH_DICTIONARY_HASH_NOT_FOUND) {
+ DCHECK(dictionary_hash_.size() == kServerIdLength);
+ // Since dictionary was not found, check to see if hash was even
+ // plausible.
+ for (size_t i = 0; i < kServerIdLength - 1; ++i) {
+ char base64_char = dictionary_hash_[i];
+ if (!isalnum(base64_char) && '-' != base64_char && '_' != base64_char) {
+ rv = SDCH_DICTIONARY_HASH_MALFORMED;
+ dictionary_hash_is_plausible_ = false;
+ break;
+ }
}
}
- if (dictionary_hash_is_plausible_)
- SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_NOT_FOUND);
- else
- SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_HASH_MALFORMED);
+ } else {
+ dictionary_hash_is_plausible_ = false;
+ rv = SDCH_DICTIONARY_HASH_MALFORMED;
+ }
+ if (rv != SDCH_OK) {
+ LogSdchProblem(rv);
decoding_status_ = DECODING_ERROR;
return FILTER_ERROR;
}
+ DCHECK(dictionary_.get());
vcdiff_streaming_decoder_.reset(new open_vcdiff::VCDiffStreamingDecoder);
vcdiff_streaming_decoder_->SetAllowVcdTarget(false);
vcdiff_streaming_decoder_->StartDecoding(dictionary_->text().data(),
@@ -446,4 +498,11 @@
return amount;
}
+void SdchFilter::LogSdchProblem(SdchProblemCode problem) {
+ SdchManager::SdchErrorRecovery(problem);
+ filter_context_.GetNetLog().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, problem));
+}
+
} // namespace net
diff --git a/net/filter/sdch_filter.h b/net/filter/sdch_filter.h
index e9648b1..a1a6607 100644
--- a/net/filter/sdch_filter.h
+++ b/net/filter/sdch_filter.h
@@ -64,6 +64,9 @@
// specified dest_buffer.
int OutputBufferExcess(char* const dest_buffer, size_t available_space);
+ // Add SDCH Problem to net-log and record histogram.
+ void LogSdchProblem(SdchProblemCode problem);
+
// Context data from the owner of this filter.
const FilterContext& filter_context_;
diff --git a/net/filter/sdch_filter_unittest.cc b/net/filter/sdch_filter_unittest.cc
index 2263001..79b5673 100644
--- a/net/filter/sdch_filter_unittest.cc
+++ b/net/filter/sdch_filter_unittest.cc
@@ -67,14 +67,7 @@
// the attempt succeeded.
bool AddSdchDictionary(const std::string& dictionary_text,
const GURL& gurl) {
- std::string list;
- sdch_manager_->GetAvailDictionaryList(gurl, &list);
- sdch_manager_->AddSdchDictionary(dictionary_text, gurl);
- std::string list2;
- sdch_manager_->GetAvailDictionaryList(gurl, &list2);
-
- // The list of hashes should change iff the addition succeeds.
- return (list != list2);
+ return sdch_manager_->AddSdchDictionary(dictionary_text, gurl) == SDCH_OK;
}
MockFilterContext* filter_context() { return filter_context_.get(); }
@@ -412,9 +405,10 @@
EXPECT_EQ(0, output_bytes_or_buffer_size);
EXPECT_EQ(Filter::FILTER_ERROR, status);
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(GURL(url_string)));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
}
TEST_F(SdchFilterTest, DictionaryAddOnce) {
@@ -667,10 +661,11 @@
filter.get(), &output));
EXPECT_EQ(output.size(), 0u); // No output written.
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(wrong_domain_url));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(wrong_domain_url));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(wrong_domain_url));
}
TEST_F(SdchFilterTest, DictionaryPathValidation) {
@@ -723,9 +718,10 @@
output_block_size, filter.get(), &output));
EXPECT_EQ(output.size(), 0u); // No output written.
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(GURL(url_string)));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
}
TEST_F(SdchFilterTest, DictionaryPortValidation) {
@@ -789,9 +785,10 @@
output_block_size, filter.get(), &output));
EXPECT_EQ(output.size(), 0u); // No output written.
- EXPECT_FALSE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_DOMAIN_BLACKLIST_INCLUDES_TARGET,
+ sdch_manager_->IsInSupportedDomain(GURL(url_string)));
sdch_manager_->ClearBlacklistings();
- EXPECT_TRUE(sdch_manager_->IsInSupportedDomain(GURL(url_string)));
+ EXPECT_EQ(SDCH_OK, sdch_manager_->IsInSupportedDomain(GURL(url_string)));
}
//------------------------------------------------------------------------------
diff --git a/net/http/transport_security_state_static.certs b/net/http/transport_security_state_static.certs
index 525d05b..04f4ae4 100644
--- a/net/http/transport_security_state_static.certs
+++ b/net/http/transport_security_state_static.certs
@@ -1507,3 +1507,9 @@
FacebookBackup
sha1/1ww8E0AYsR2oX5lndk2hwp2Uosk=
+
+SpiderOak1
+sha1/UPrvFUSrp9aal5v6Rn0Jv3YJ/wU=
+
+SpiderOak2
+sha1/D0fS/hquA6QprluciyO1hlFUAxg=
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index 867cafd..1774a24 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -263,6 +263,7 @@
DOMAIN_YOUTUBE_NOCOOKIE_COM,
DOMAIN_2MDN_NET,
DOMAIN_FACEBOOK_COM,
+ DOMAIN_SPIDEROAK_COM,
// Boundary value for UMA_HISTOGRAM_ENUMERATION.
DOMAIN_NUM_EVENTS,
};
@@ -530,6 +531,14 @@
"\xd7\x0c\x3c\x13\x40\x18\xb1\x1d\xa8\x5f"
"\x99\x67\x76\x4d\xa1\xc2\x9d\x94\xa2\xc9";
+static const char kSPKIHash_SpiderOak1[] =
+ "\x50\xfa\xef\x15\x44\xab\xa7\xd6\x9a\x97"
+ "\x9b\xfa\x46\x7d\x09\xbf\x76\x09\xff\x05";
+
+static const char kSPKIHash_SpiderOak2[] =
+ "\x0f\x47\xd2\xfe\x1a\xae\x03\xa4\x29\xae"
+ "\x5b\x9c\x8b\x23\xb5\x86\x51\x54\x03\x18";
+
// The following is static data describing the hosts that are hardcoded with
// certificate pins or HSTS information.
@@ -668,6 +677,12 @@
kSPKIHash_FacebookBackup,
NULL,
};
+static const char* const kSpideroakAcceptableCerts[] = {
+ kSPKIHash_RapidSSL,
+ kSPKIHash_SpiderOak1,
+ kSPKIHash_SpiderOak2,
+ NULL,
+};
struct Pinset {
const char *const *const accepted_pins;
@@ -685,6 +700,7 @@
{kLavabitAcceptableCerts, kNoRejectedPublicKeys},
{kDropboxAcceptableCerts, kNoRejectedPublicKeys},
{kFacebookAcceptableCerts, kNoRejectedPublicKeys},
+ {kSpideroakAcceptableCerts, kNoRejectedPublicKeys},
};
// kHSTSHuffmanTree describes a Huffman tree. The nodes of the tree are pairs
@@ -1441,805 +1457,805 @@
0x04, 0x27, 0x45, 0x4d, 0xc0, 0x48, 0xa7, 0xea,
0xfa, 0xdd, 0x96, 0x29, 0xc6, 0x86, 0x70, 0x42,
0x12, 0xa7, 0x9f, 0x7c, 0x42, 0x9c, 0x5e, 0x4f,
- 0xb3, 0x6f, 0x02, 0xa7, 0x4b, 0x84, 0xf5, 0xfe,
- 0x5f, 0x3f, 0x7e, 0x9a, 0xb5, 0x97, 0x3a, 0x7f,
- 0xfb, 0xf7, 0x6b, 0x07, 0x39, 0x8b, 0x6f, 0x6c,
- 0x74, 0xfa, 0x8d, 0xdf, 0xb2, 0x93, 0xa7, 0xde,
- 0xaa, 0xd0, 0xc3, 0xe5, 0xfb, 0x3e, 0x5e, 0x10,
- 0x6a, 0x7c, 0xbf, 0x66, 0xe7, 0x9f, 0x2f, 0xd9,
- 0xed, 0x5f, 0x95, 0x3e, 0x5f, 0xb1, 0xb1, 0xe8,
- 0xfc, 0x8a, 0x7c, 0xb9, 0x5c, 0xf9, 0xf2, 0xfd,
- 0x83, 0xe5, 0xfb, 0x37, 0x5c, 0xf9, 0x7e, 0xb0,
- 0xb7, 0x93, 0xfe, 0x7f, 0x5a, 0xa4, 0xcf, 0x66,
- 0xe7, 0x80, 0x7c, 0xbf, 0x60, 0xf9, 0x7e, 0xcc,
- 0x05, 0x3e, 0x5f, 0xb3, 0xfd, 0x80, 0xe1, 0xc6,
- 0xd9, 0xb1, 0xf2, 0xfd, 0x9f, 0xb2, 0xde, 0xae,
- 0xb4, 0x1f, 0x2f, 0xd8, 0x02, 0x28, 0xfe, 0x45,
- 0x54, 0x59, 0xe1, 0xa1, 0x6e, 0x7c, 0xbf, 0x60,
- 0xf9, 0x7e, 0xe1, 0xae, 0x98, 0x21, 0x3e, 0x5f,
- 0xb0, 0xf5, 0x62, 0x3b, 0x1a, 0xe4, 0x21, 0x29,
- 0x84, 0xe8, 0x94, 0xb0, 0xc6, 0xb0, 0xba, 0xba,
- 0xf0, 0x49, 0xa7, 0xb1, 0xeb, 0xa4, 0xb9, 0x7e,
- 0xdc, 0x88, 0xf9, 0xff, 0x62, 0x6d, 0x82, 0x1e,
- 0xb3, 0x47, 0x4c, 0xfa, 0x0a, 0x8a, 0x11, 0x2d,
- 0x4a, 0x17, 0xcf, 0x60, 0x57, 0x25, 0x7a, 0x71,
- 0x8e, 0x7f, 0xfe, 0xa5, 0xe2, 0xad, 0xb9, 0xa5,
- 0xda, 0xca, 0xce, 0x68, 0xe8, 0x55, 0xdc, 0x3c,
- 0x26, 0xf1, 0x7f, 0x4e, 0x72, 0x6a, 0x59, 0x3f,
- 0xed, 0x2b, 0x4f, 0xd6, 0xd6, 0xd5, 0x0e, 0x9f,
- 0xbf, 0xda, 0x6d, 0xcf, 0x3a, 0x70, 0x42, 0x12,
- 0xa7, 0x6f, 0x50, 0x14, 0xe2, 0xf2, 0x7f, 0xdf,
- 0xe7, 0xef, 0x1c, 0x6d, 0xc2, 0x74, 0xff, 0x7f,
- 0x81, 0xa1, 0xea, 0x0a, 0x4e, 0x8d, 0x93, 0x31,
- 0x62, 0x08, 0x12, 0xbe, 0x59, 0x73, 0xf9, 0xff,
- 0x7f, 0xfe, 0xd5, 0xbb, 0xae, 0xe2, 0xdc, 0xe9,
- 0xc1, 0x08, 0x4b, 0x10, 0x82, 0x7c, 0x29, 0xdc,
- 0x85, 0x88, 0x40, 0xe3, 0x55, 0x38, 0x21, 0x09,
- 0x62, 0x0f, 0x41, 0x62, 0x0f, 0x38, 0xd5, 0x4c,
- 0xac, 0xc4, 0x49, 0xa3, 0x5c, 0xfa, 0xeb, 0x75,
- 0x61, 0xd3, 0xdf, 0xf2, 0xe9, 0x3a, 0x76, 0xf5,
- 0x01, 0xd1, 0x41, 0xe0, 0x30, 0x8e, 0x7c, 0x8b,
- 0x65, 0x61, 0x53, 0xef, 0xf7, 0xff, 0x85, 0x4d,
- 0x88, 0x54, 0xc1, 0x09, 0x51, 0x87, 0xeb, 0x52,
- 0x5b, 0x93, 0x04, 0x52, 0x7f, 0x7f, 0x7a, 0x82,
- 0xd8, 0xde, 0x53, 0x8d, 0xdc, 0x2a, 0x70, 0x1e,
- 0x66, 0xe8, 0x69, 0xcf, 0xfe, 0xb2, 0x82, 0xb9,
- 0x9b, 0x77, 0xfb, 0x49, 0xd3, 0xfa, 0xbb, 0xd9,
- 0x50, 0xf5, 0x27, 0x42, 0xab, 0xb1, 0xc4, 0xcf,
- 0x46, 0x0a, 0x31, 0xd6, 0x71, 0xa5, 0x52, 0xa7,
- 0x04, 0x21, 0x2a, 0x7c, 0xf0, 0x77, 0xf6, 0x29,
- 0xc5, 0xe4, 0xff, 0xf7, 0xe9, 0xd1, 0x48, 0x17,
- 0xe9, 0xd4, 0x7f, 0x8e, 0x9f, 0xfe, 0xc5, 0x76,
- 0xdf, 0x5d, 0x53, 0x34, 0xf8, 0x4e, 0x9e, 0x6f,
- 0xb0, 0x1b, 0x1d, 0x0f, 0x3f, 0x7e, 0x50, 0x9f,
- 0xfc, 0xfc, 0x10, 0x33, 0xd5, 0xdf, 0x55, 0xc3,
- 0xa7, 0xbd, 0xb6, 0x30, 0xe8, 0x54, 0xe3, 0x9e,
- 0x6f, 0xd0, 0xca, 0xf9, 0x0e, 0xa9, 0x53, 0xf6,
- 0xee, 0xbe, 0xfd, 0x2f, 0x3a, 0x7f, 0xdc, 0x3b,
- 0x9e, 0xb6, 0x75, 0x20, 0x3a, 0x7f, 0xd5, 0xaa,
- 0x8d, 0xd5, 0xdb, 0x78, 0xe9, 0xff, 0x7f, 0x9a,
- 0xb7, 0x08, 0xfb, 0x63, 0xa3, 0x11, 0xde, 0x86,
- 0x7e, 0x40, 0x61, 0xf4, 0xf3, 0xf7, 0xe3, 0x47,
- 0x4f, 0x87, 0x6c, 0xcf, 0x9d, 0x3f, 0xf6, 0xef,
- 0xd9, 0x65, 0x6d, 0x5b, 0x2d, 0x27, 0x47, 0x1f,
- 0x85, 0x49, 0xa7, 0xff, 0xb2, 0xf5, 0xc6, 0xac,
- 0xad, 0xb2, 0xd6, 0x53, 0xa7, 0xf5, 0xdb, 0xab,
- 0x5f, 0x6e, 0x94, 0x6a, 0x74, 0x6c, 0x8b, 0x4f,
- 0x90, 0xdd, 0x42, 0x7f, 0xfb, 0xd5, 0xcd, 0xaf,
- 0x5f, 0x69, 0xb7, 0x7f, 0xc7, 0x4f, 0xff, 0xef,
- 0xdf, 0x2d, 0xe5, 0xbf, 0x80, 0xaf, 0x70, 0x42,
- 0x12, 0xa7, 0xb6, 0xcc, 0xd2, 0x54, 0xe7, 0xff,
- 0x53, 0x44, 0x33, 0x38, 0x21, 0x09, 0x53, 0xb3,
- 0xe8, 0x53, 0x8b, 0xc9, 0xff, 0x65, 0x19, 0xb7,
- 0x3f, 0xeb, 0x41, 0xd0, 0x03, 0xe8, 0xf9, 0x4c,
- 0xfe, 0x7f, 0xf2, 0xf7, 0xd6, 0x83, 0xa1, 0x53,
- 0x89, 0xa1, 0x86, 0x92, 0x31, 0x85, 0x77, 0x11,
- 0x4f, 0x7a, 0xfe, 0x53, 0xa7, 0xf6, 0xb8, 0x20,
- 0x07, 0xbe, 0x74, 0xff, 0xf9, 0x5f, 0xed, 0xad,
- 0xbe, 0xb8, 0x29, 0xdc, 0x86, 0x88, 0x32, 0x2c,
- 0x89, 0x4b, 0x99, 0xcf, 0xaa, 0x3e, 0x0e, 0xec,
- 0xe9, 0xfd, 0xb9, 0x95, 0xdc, 0xc1, 0x53, 0xa1,
- 0xe9, 0x9c, 0xfa, 0x16, 0xb5, 0x23, 0xb9, 0x5c,
- 0xff, 0xf2, 0xfe, 0x8d, 0x0d, 0x7b, 0xf9, 0xb6,
- 0x7f, 0x49, 0xd3, 0x94, 0x5a, 0x3a, 0x15, 0x77,
- 0x33, 0x63, 0xbc, 0x8d, 0x21, 0x0c, 0x7d, 0x1e,
- 0xe7, 0x47, 0x11, 0xaa, 0x1e, 0xe2, 0xb4, 0xff,
- 0xf2, 0x2d, 0x6a, 0xac, 0xcb, 0xfa, 0xb6, 0xe3,
- 0xa7, 0xf7, 0xfe, 0xaf, 0x62, 0xf8, 0xe9, 0xfd,
- 0x7f, 0x36, 0xf5, 0xde, 0xa5, 0x49, 0x87, 0x4f,
- 0xd9, 0xfd, 0x22, 0xae, 0xf1, 0xe2, 0xef, 0x35,
- 0x8c, 0x4c, 0x2f, 0xc9, 0xb5, 0x77, 0x9e, 0x1d,
- 0x69, 0x79, 0xd3, 0xfb, 0xef, 0xfe, 0x31, 0x50,
- 0xe9, 0xcc, 0xdb, 0x0e, 0x85, 0x3f, 0x0c, 0x23,
- 0xe3, 0x19, 0xd7, 0xf5, 0x07, 0x4f, 0xfb, 0x5b,
- 0xd7, 0x78, 0x81, 0x9e, 0xa9, 0xd3, 0xff, 0x2f,
- 0xfa, 0xca, 0x07, 0x0d, 0x6a, 0x54, 0x6c, 0x88,
- 0x46, 0x21, 0x4f, 0xad, 0xef, 0x53, 0x53, 0xa0,
- 0xa9, 0xfa, 0xbb, 0xd4, 0x55, 0x85, 0x41, 0x50,
- 0x54, 0x15, 0x05, 0x43, 0xcf, 0x7f, 0xc1, 0x40,
- 0x2d, 0xd4, 0x2b, 0x70, 0x29, 0xbc, 0x2a, 0x6b,
- 0x61, 0x53, 0xf7, 0x75, 0xda, 0x56, 0x15, 0xa0,
- 0xb5, 0x93, 0x76, 0x54, 0x15, 0x05, 0x43, 0xcb,
- 0x4f, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05, 0x41,
- 0x50, 0x54, 0x50, 0x6f, 0x36, 0x0a, 0xf0, 0x50,
- 0x02, 0xaa, 0x14, 0xd8, 0x2a, 0x0a, 0x82, 0xa1,
- 0xe5, 0xa5, 0x42, 0xa0, 0xa8, 0x2a, 0x0a, 0x82,
- 0xa1, 0xe6, 0xa0, 0x01, 0x57, 0x0a, 0x6f, 0x0a,
- 0x82, 0xa0, 0xa8, 0x2a, 0x0a, 0x8a, 0x0d, 0x46,
- 0x90, 0xa1, 0x0a, 0xb0, 0x54, 0xb4, 0x95, 0x05,
- 0x41, 0x50, 0x54, 0x15, 0x1b, 0x1a, 0x8a, 0x42,
- 0x80, 0x15, 0xa8, 0x54, 0x15, 0x05, 0x41, 0x53,
- 0xeb, 0x28, 0x2b, 0x85, 0x41, 0x50, 0xf3, 0xce,
- 0x40, 0xab, 0x05, 0x70, 0x50, 0x09, 0xa4, 0x85,
- 0x41, 0x50, 0x54, 0x15, 0x05, 0x43, 0xcd, 0x45,
- 0x21, 0x5e, 0x0a, 0x6c, 0x15, 0x05, 0x41, 0x50,
- 0x54, 0x15, 0x0f, 0x35, 0x1b, 0x05, 0x58, 0x2b,
- 0xe1, 0x52, 0xb1, 0x50, 0x54, 0x15, 0x27, 0x95,
- 0x05, 0x52, 0x58, 0x41, 0x50, 0x54, 0x15, 0x05,
- 0x45, 0x07, 0xcc, 0xf0, 0xad, 0x23, 0x48, 0x34,
- 0xd0, 0x50, 0x02, 0xae, 0x15, 0x2c, 0x2a, 0x0a,
- 0x82, 0xa4, 0xf2, 0xa0, 0xaa, 0x4b, 0x08, 0x2a,
- 0x0a, 0x85, 0x3d, 0x27, 0x85, 0x78, 0x68, 0x46,
- 0x98, 0x15, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05,
- 0x42, 0x9b, 0x2a, 0x42, 0x84, 0x29, 0x81, 0x5f,
- 0x0a, 0x82, 0xa0, 0xa8, 0x2a, 0x04, 0xbe, 0xa8,
- 0x55, 0xc2, 0xa0, 0xa8, 0x2a, 0x0a, 0x86, 0x17,
- 0xdf, 0x0a, 0xb8, 0x54, 0x98, 0x54, 0x15, 0x05,
- 0x40, 0x0b, 0x4d, 0x42, 0xa0, 0xa8, 0x2a, 0x0a,
- 0x82, 0xa1, 0x4d, 0x43, 0x41, 0x56, 0x0a, 0xd4,
- 0x2a, 0x15, 0x7e, 0xb6, 0x87, 0x27, 0x9e, 0xec,
- 0x53, 0x8b, 0x88, 0xdb, 0x4a, 0x47, 0x99, 0xb7,
- 0x67, 0xad, 0x1d, 0x0c, 0x23, 0x18, 0x8f, 0x63,
- 0x7e, 0x66, 0x01, 0xe7, 0xdd, 0xaa, 0xcd, 0x76,
- 0x1d, 0x5e, 0x5b, 0x32, 0x85, 0x2b, 0x70, 0xb7,
- 0x79, 0x23, 0x7a, 0x4c, 0xf9, 0xff, 0x5c, 0xa9,
- 0x4e, 0x4d, 0x5e, 0x77, 0x95, 0x85, 0x4f, 0x79,
- 0x38, 0x4e, 0x9d, 0xed, 0xb0, 0xe9, 0xcb, 0xbd,
- 0xd4, 0xa2, 0x3c, 0x4e, 0x6c, 0x37, 0x71, 0xf9,
- 0xfd, 0x6f, 0x07, 0x61, 0x5a, 0x0e, 0x8a, 0x51,
- 0x08, 0xd2, 0x84, 0xc0, 0x53, 0xa7, 0xe1, 0xef,
- 0xef, 0x50, 0x1d, 0x37, 0x09, 0xd2, 0xf1, 0xc8,
- 0x5a, 0x49, 0x0e, 0x93, 0x0e, 0x9d, 0x9b, 0x8e,
- 0xf2, 0x24, 0xc4, 0x56, 0xc8, 0x3c, 0x3d, 0xbc,
- 0x3e, 0x7f, 0xfd, 0xaa, 0xe8, 0xe1, 0x1e, 0x02,
- 0xb8, 0x21, 0x09, 0xd0, 0xf6, 0x6c, 0xde, 0xd0,
- 0xa0, 0x42, 0xcf, 0x42, 0x85, 0xa2, 0x4e, 0xa5,
- 0x4f, 0xfe, 0x17, 0x17, 0x5e, 0x9f, 0xcb, 0xfb,
- 0xf7, 0xf5, 0xc3, 0xa7, 0xe7, 0xff, 0xcf, 0xb6,
- 0x1d, 0x3e, 0xa3, 0xc2, 0xaf, 0x3a, 0x04, 0xf5,
- 0x3e, 0x5b, 0x3f, 0xeb, 0x28, 0x83, 0xf8, 0x1e,
- 0x01, 0xd3, 0xb3, 0x1a, 0x3a, 0x59, 0x63, 0xd7,
- 0x01, 0xe4, 0xf3, 0x17, 0x28, 0x3a, 0x7d, 0x8d,
- 0xbe, 0xb4, 0x9d, 0x1e, 0x3c, 0xaa, 0x90, 0xcf,
- 0x2f, 0xee, 0x87, 0x49, 0x71, 0x32, 0xbf, 0xbc,
- 0x5d, 0xc7, 0x70, 0x8a, 0x7b, 0x5e, 0x17, 0x9d,
- 0x3c, 0xba, 0xb7, 0x75, 0x2a, 0x7c, 0xf7, 0x04,
- 0x21, 0x3a, 0x3e, 0x79, 0xfa, 0x93, 0xc6, 0xc8,
- 0x93, 0xc7, 0x08, 0x62, 0xaa, 0xc0, 0x47, 0x63,
- 0xac, 0x36, 0x27, 0xe1, 0xd4, 0x19, 0xf4, 0x3a,
- 0x7f, 0xa8, 0xfe, 0x3e, 0xd8, 0x0a, 0x9d, 0x3d,
- 0xb6, 0xca, 0xd8, 0xe9, 0xff, 0xf2, 0xd9, 0x58,
- 0x8b, 0x7c, 0x14, 0xee, 0x43, 0x45, 0xf1, 0x3f,
- 0x83, 0xd7, 0xaa, 0xe5, 0x07, 0x4f, 0xff, 0xd9,
- 0x7d, 0xef, 0x56, 0xde, 0xf8, 0x07, 0xca, 0xcc,
- 0x2a, 0x6b, 0xe1, 0xd3, 0xe1, 0xf5, 0x1c, 0xc3,
- 0x4c, 0x27, 0x3d, 0x7d, 0x57, 0x8d, 0x30, 0x9c,
- 0xc0, 0x53, 0x50, 0x27, 0x3f, 0xbf, 0xda, 0x6e,
- 0xa2, 0x03, 0x50, 0x27, 0x3f, 0xab, 0x96, 0xf5,
- 0x75, 0xa0, 0xd3, 0x09, 0xcd, 0x9b, 0x1a, 0x61,
- 0x39, 0x82, 0x13, 0xcc, 0x27, 0x18, 0x9a, 0x65,
- 0x26, 0x9e, 0x2e, 0x61, 0x15, 0x50, 0x1b, 0x21,
- 0x04, 0x8e, 0x57, 0x2c, 0xc2, 0x67, 0x1f, 0x3c,
- 0xbd, 0x4a, 0x7e, 0xe1, 0x8f, 0x22, 0x2a, 0xaa,
- 0x16, 0xf2, 0x95, 0x21, 0x55, 0xce, 0x6c, 0x72,
- 0x84, 0xb6, 0x5b, 0xbc, 0xab, 0x79, 0xf6, 0xd8,
- 0x3e, 0xd2, 0x74, 0xfb, 0xf9, 0xbf, 0x1a, 0x3a,
- 0x7f, 0xad, 0xcc, 0xb7, 0x96, 0x97, 0x9d, 0x3f,
- 0x6f, 0xfb, 0xf7, 0x3a, 0x83, 0xa3, 0xc7, 0xd8,
- 0x03, 0x98, 0xfa, 0x2d, 0xef, 0x09, 0x58, 0x55,
- 0xd2, 0x2c, 0x97, 0x91, 0xe5, 0x2e, 0x87, 0x04,
- 0xff, 0xe6, 0x5e, 0xbe, 0xfd, 0x2f, 0xbf, 0xab,
- 0xe3, 0xa7, 0xff, 0xf7, 0xf2, 0x9c, 0xaf, 0x7e,
- 0xde, 0x5b, 0xdb, 0x5e, 0x61, 0xd3, 0xf7, 0xf5,
- 0x67, 0xac, 0xa7, 0x4f, 0xff, 0xbb, 0xf7, 0xee,
- 0xb7, 0xd6, 0xf5, 0x0e, 0x58, 0xe9, 0xc3, 0x5a,
- 0x9e, 0x20, 0x39, 0xff, 0xed, 0xe2, 0xb6, 0x5d,
- 0x18, 0x29, 0xdc, 0x86, 0x88, 0x0d, 0xc6, 0xa2,
- 0x00, 0x8e, 0x5b, 0xbd, 0xc6, 0x26, 0x6d, 0xe8,
- 0xc4, 0xe7, 0xff, 0xf7, 0x3f, 0x2b, 0xe1, 0x1f,
- 0x33, 0x7d, 0xed, 0x81, 0xb9, 0xd3, 0xff, 0xfd,
- 0xcf, 0xcf, 0xb4, 0xfc, 0xa5, 0xfb, 0xd4, 0x0e,
- 0x08, 0x42, 0x54, 0x59, 0x19, 0x7f, 0x61, 0x9f,
- 0xcb, 0x82, 0x9d, 0xc8, 0x68, 0x82, 0x67, 0xf9,
- 0x6f, 0x82, 0x9d, 0xc8, 0x68, 0xbe, 0x67, 0xde,
- 0x6d, 0xfc, 0xae, 0xc7, 0xf4, 0x87, 0x53, 0xfe,
- 0xa3, 0xa9, 0xdc, 0xcb, 0xff, 0x9b, 0x1d, 0x38,
- 0x21, 0x09, 0x53, 0xf5, 0xed, 0x89, 0xc2, 0x53,
- 0x8b, 0xc8, 0xa1, 0x13, 0x3f, 0x60, 0x9f, 0xfa,
- 0x86, 0x2d, 0x35, 0xfe, 0x51, 0xbd, 0xe7, 0x4f,
- 0xff, 0x6f, 0xa7, 0xfa, 0x12, 0xde, 0x00, 0x14,
- 0x5e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xed, 0xe0,
- 0x5f, 0xe5, 0x37, 0x29, 0xc5, 0xe4, 0xff, 0xfc,
- 0xdd, 0xe8, 0x4b, 0x7b, 0x6d, 0xb0, 0x3a, 0x2f,
- 0x5c, 0xa0, 0xe9, 0x75, 0x91, 0x57, 0xaa, 0x24,
- 0x3d, 0x54, 0x5f, 0xa1, 0xb4, 0x24, 0x8c, 0x49,
- 0xbc, 0x63, 0x73, 0xeb, 0x65, 0xda, 0x79, 0xd3,
- 0xfe, 0xcb, 0xa8, 0xd6, 0xcb, 0xfb, 0x9e, 0x20,
- 0x89, 0xfc, 0xb8, 0x29, 0xdc, 0x86, 0x88, 0x21,
- 0xc7, 0x93, 0x3f, 0x75, 0x84, 0x7c, 0x13, 0xa7,
- 0xed, 0xde, 0xc1, 0xef, 0xbc, 0xe8, 0xf9, 0xee,
- 0xea, 0x57, 0x16, 0x4c, 0xf0, 0x0e, 0x3f, 0x85,
- 0x44, 0xff, 0x2f, 0xef, 0xbf, 0x2d, 0xd4, 0x9d,
- 0x3f, 0xfd, 0xc1, 0xbe, 0x59, 0x7d, 0x7f, 0xe5,
- 0xbc, 0x74, 0x3d, 0x11, 0x1f, 0x3a, 0x9f, 0xd7,
- 0xde, 0xca, 0x87, 0xa9, 0x3a, 0x7b, 0xcd, 0x78,
- 0x27, 0x4f, 0xff, 0xb5, 0xa3, 0xeb, 0x96, 0x72,
- 0xdf, 0x2d, 0xa8, 0x9d, 0x3e, 0xcb, 0xd7, 0x7d,
- 0x76, 0x3f, 0x9d, 0xe4, 0x73, 0xf2, 0x5b, 0xdb,
- 0x9e, 0xd2, 0x74, 0xfc, 0xc5, 0xdd, 0xdb, 0x28,
- 0x3a, 0x7f, 0xff, 0xfb, 0xd7, 0xe6, 0x77, 0xc0,
- 0xff, 0x57, 0x56, 0x5b, 0xcb, 0x7b, 0x6b, 0xcc,
- 0x3a, 0x36, 0x47, 0x1f, 0x8c, 0xb8, 0xc6, 0x70,
- 0xef, 0xa9, 0xd3, 0xfe, 0xef, 0xa6, 0x0a, 0x77,
- 0x21, 0xa2, 0x11, 0x85, 0x3e, 0x2d, 0x47, 0x67,
- 0xff, 0x2e, 0x53, 0xbe, 0xfe, 0xfe, 0xaf, 0xca,
- 0x9d, 0x3f, 0xfd, 0xdd, 0x46, 0xfc, 0xb7, 0x31,
- 0xc1, 0x08, 0x4e, 0x96, 0x6c, 0x89, 0xe6, 0x93,
- 0x67, 0x04, 0x21, 0x2a, 0x7f, 0xb0, 0x1c, 0x38,
- 0xdb, 0x36, 0x29, 0xc5, 0xe4, 0xc1, 0x09, 0x53,
- 0x82, 0x10, 0x95, 0x3f, 0x75, 0x1b, 0x59, 0x6a,
- 0x53, 0x8b, 0xc8, 0xfa, 0x2d, 0x82, 0x8f, 0xb8,
- 0x65, 0x3e, 0x4f, 0x6d, 0xbd, 0x85, 0x38, 0xd9,
- 0xce, 0x08, 0x42, 0x54, 0xea, 0xa8, 0x94, 0xe2,
- 0xf2, 0x40, 0xf1, 0xff, 0xdd, 0x5a, 0x7e, 0xdb,
- 0xea, 0xfe, 0x43, 0xa7, 0xf6, 0xf1, 0xdb, 0xcd,
- 0x97, 0x63, 0xa7, 0xf5, 0xed, 0x8d, 0xb2, 0xf5,
- 0x3a, 0x05, 0x13, 0x16, 0x2c, 0xf9, 0xc4, 0x2a,
- 0x3b, 0xf2, 0x18, 0x13, 0xa9, 0xdd, 0x73, 0x75,
- 0x3a, 0x7f, 0xf6, 0x6e, 0xfb, 0xe0, 0xc4, 0x5b,
- 0x2b, 0x0e, 0x9f, 0x93, 0xd5, 0xb7, 0x9a, 0x2a,
- 0x7f, 0x7f, 0x29, 0x7d, 0x7d, 0xa4, 0xe9, 0xee,
- 0xe1, 0xd2, 0x74, 0x68, 0x3d, 0x7a, 0x0d, 0xa7,
- 0x97, 0x98, 0xd8, 0xa9, 0xc1, 0x08, 0x4a, 0x9f,
- 0xfe, 0xde, 0xa0, 0xcc, 0xfd, 0xed, 0xe5, 0xfd,
- 0x05, 0x38, 0xbc, 0x96, 0x22, 0x27, 0x98, 0x7d,
- 0x0a, 0x9f, 0x23, 0xca, 0xe9, 0x4a, 0xf4, 0x21,
- 0x6d, 0x0c, 0x39, 0xff, 0xf3, 0x31, 0x17, 0xfd,
- 0x7a, 0xed, 0xaf, 0x0b, 0xce, 0x9f, 0x2d, 0xea,
- 0xdb, 0x0e, 0x85, 0x3f, 0xcb, 0xaa, 0x4f, 0xff,
- 0x79, 0xb6, 0x7f, 0x6f, 0xf0, 0x73, 0xfd, 0xa4,
- 0xe9, 0xff, 0xfe, 0xda, 0xde, 0x0e, 0x37, 0xf9,
- 0x9d, 0x7a, 0xea, 0xfc, 0xa6, 0xe7, 0x46, 0x23,
- 0x03, 0x94, 0xe1, 0x5b, 0x21, 0x5a, 0x13, 0x5f,
- 0x1c, 0xbe, 0xd0, 0xf4, 0xc9, 0x65, 0x1e, 0x8e,
- 0x49, 0xa8, 0x5f, 0x09, 0x1b, 0x21, 0x5f, 0x68,
- 0xc9, 0xc1, 0x09, 0x2f, 0xc3, 0x02, 0xb2, 0xa7,
- 0x6f, 0x28, 0x2b, 0x58, 0x68, 0x86, 0x1c, 0x33,
- 0x9b, 0x2f, 0xce, 0x9f, 0xfe, 0xcf, 0xba, 0xfa,
- 0x7d, 0x4d, 0x6d, 0x80, 0xe3, 0xa5, 0x4b, 0xcf,
- 0xbf, 0x61, 0xd9, 0xfa, 0xcd, 0x7a, 0xde, 0x61,
- 0xd3, 0xfe, 0xfa, 0xde, 0xdc, 0x0e, 0xa6, 0xa7,
- 0x4e, 0x6b, 0x51, 0x3a, 0x7f, 0xdd, 0xe1, 0xca,
- 0x5c, 0x10, 0x84, 0xe8, 0xe3, 0xdb, 0xa8, 0xec,
- 0xff, 0xf7, 0xd5, 0xfa, 0x37, 0xdf, 0xdf, 0xd5,
- 0xf9, 0x53, 0xa3, 0x13, 0x3e, 0x42, 0xfb, 0x42,
- 0x64, 0x04, 0x33, 0xf9, 0x7e, 0xff, 0xe6, 0x00,
- 0xe9, 0xfc, 0xfc, 0x1a, 0xfd, 0x68, 0x3a, 0x7f,
- 0xf9, 0x5b, 0x28, 0xbb, 0x7d, 0xff, 0x94, 0x78,
- 0x4f, 0x77, 0xbc, 0xff, 0xf6, 0x5d, 0x7e, 0x99,
- 0x7b, 0x78, 0x40, 0x87, 0x4f, 0xba, 0xb9, 0xfb,
- 0x9d, 0x3a, 0xfd, 0xbb, 0x3a, 0x7f, 0x5e, 0xde,
- 0x70, 0x3b, 0xc7, 0x45, 0x09, 0x91, 0xec, 0xbf,
- 0xf4, 0xcb, 0x93, 0x6a, 0x3f, 0x3f, 0xb5, 0x02,
- 0xdb, 0xdc, 0xf3, 0xa7, 0xff, 0xef, 0xe5, 0x75,
- 0xd1, 0x96, 0xef, 0xe3, 0x4f, 0x5a, 0x4e, 0x9f,
- 0xf6, 0x57, 0x5c, 0x14, 0xee, 0x43, 0x44, 0x0d,
- 0x3e, 0xcb, 0xdb, 0x9f, 0xa1, 0x14, 0xbf, 0x5e,
- 0x9f, 0xff, 0xff, 0xb2, 0xf6, 0xef, 0xe9, 0xd1,
- 0x51, 0xee, 0xbb, 0x6c, 0xdb, 0x46, 0x33, 0xbf,
- 0x4b, 0xcf, 0x10, 0x5c, 0xff, 0xbb, 0xb4, 0xa7,
- 0x6d, 0xa3, 0x48, 0x4f, 0x10, 0x5c, 0xff, 0xd6,
- 0xf5, 0xbc, 0xbf, 0xbe, 0x8d, 0x21, 0x3c, 0x41,
- 0x73, 0xf9, 0x7d, 0xfb, 0xe8, 0xd2, 0x13, 0xc4,
- 0x17, 0x3f, 0x33, 0x36, 0xd1, 0xa4, 0x27, 0x88,
- 0x2e, 0x7f, 0xff, 0xbb, 0xff, 0xf3, 0x34, 0x55,
- 0x2d, 0xe1, 0xf6, 0x9a, 0x30, 0x27, 0x88, 0x2e,
- 0x6a, 0x74, 0x6c, 0x9d, 0x0a, 0x28, 0x0a, 0xb7,
- 0x22, 0x7c, 0xfe, 0x2c, 0xaa, 0x5b, 0xf2, 0x8f,
- 0xa7, 0xb8, 0x41, 0xc7, 0x4f, 0xfd, 0x6f, 0x5b,
- 0xcb, 0xfb, 0xe8, 0xd2, 0x13, 0xc4, 0x17, 0x3f,
- 0xcd, 0x55, 0x3d, 0x46, 0x8d, 0x21, 0x3c, 0x41,
- 0x73, 0xeb, 0xd5, 0x59, 0xa1, 0x11, 0x45, 0xbd,
- 0x5a, 0x7f, 0xf6, 0x84, 0xb7, 0x91, 0x6f, 0x5d,
- 0x1a, 0x42, 0x78, 0x82, 0xe7, 0xff, 0xfe, 0xff,
- 0xfc, 0xcd, 0x1a, 0xe6, 0x8a, 0xa5, 0xbc, 0x3e,
- 0xd3, 0x46, 0x04, 0xf1, 0x05, 0xc6, 0x26, 0x4d,
- 0x4a, 0x1f, 0x2e, 0x4f, 0xf5, 0xbc, 0x3e, 0xd3,
- 0x46, 0x04, 0xf1, 0x05, 0xcf, 0xff, 0x77, 0x52,
- 0xfa, 0xdb, 0xdb, 0x6c, 0xa2, 0xa5, 0x4f, 0xfb,
- 0x1e, 0xfd, 0x6a, 0x3f, 0xa3, 0x70, 0xf1, 0x05,
- 0xc2, 0x23, 0xa0, 0x52, 0x2a, 0xa1, 0x3f, 0xe4,
- 0xf0, 0xdf, 0x81, 0x5d, 0x01, 0x3c, 0x41, 0x73,
- 0xf5, 0xbd, 0x6b, 0x78, 0x06, 0x80, 0x2e, 0x7d,
- 0x80, 0xd1, 0xa4, 0x27, 0x88, 0x2e, 0x6c, 0xba,
- 0x1f, 0x9d, 0x8e, 0xe2, 0x94, 0x75, 0xd6, 0x17,
- 0xf3, 0xf3, 0x33, 0x6d, 0x1a, 0x42, 0x78, 0x82,
- 0xe7, 0xfc, 0x96, 0xf0, 0xfb, 0x4d, 0x18, 0x13,
- 0xc4, 0x17, 0x36, 0x68, 0xe4, 0x46, 0x54, 0xfe,
- 0x7f, 0x6b, 0xe6, 0x77, 0xe9, 0x79, 0xe2, 0x0b,
- 0x9f, 0xf6, 0x79, 0xb6, 0x7f, 0x36, 0xe7, 0x9e,
- 0x20, 0xb6, 0x1e, 0x14, 0x6c, 0xbb, 0x8e, 0x02,
- 0xcf, 0xc7, 0xcf, 0x58, 0xc6, 0x2f, 0x18, 0xce,
- 0xb0, 0xb5, 0x0b, 0x8c, 0xf8, 0x15, 0x00, 0x14,
- 0xd1, 0x05, 0xb9, 0x10, 0x13, 0xfe, 0xc7, 0xdb,
- 0x9e, 0xde, 0xdf, 0xad, 0x07, 0x4f, 0xe1, 0xfe,
- 0x6d, 0x6d, 0x42, 0x74, 0xfa, 0x9b, 0xf0, 0x80,
- 0xe9, 0xfb, 0x28, 0xeb, 0x2e, 0xec, 0xe8, 0xf2,
- 0x22, 0xf8, 0xd3, 0xe4, 0xf3, 0xb8, 0x68, 0x3a,
- 0x60, 0x29, 0xd3, 0xde, 0x56, 0x61, 0xd0, 0x74,
- 0xfd, 0xda, 0x6e, 0xa2, 0x03, 0xa3, 0x63, 0x6f,
- 0xf0, 0xa9, 0xff, 0xfc, 0xbe, 0xdb, 0xeb, 0xaa,
- 0x5f, 0x13, 0x65, 0x4d, 0xec, 0x3a, 0x60, 0x29,
- 0xd3, 0x2e, 0x93, 0xa7, 0xfb, 0x2f, 0x55, 0x66,
- 0xfc, 0x68, 0xe9, 0xfd, 0x5c, 0xb7, 0xab, 0xad,
- 0x07, 0x4c, 0x10, 0x95, 0x3f, 0xdf, 0xc6, 0xdc,
- 0xfa, 0xfb, 0x63, 0xa1, 0x13, 0xf7, 0xf0, 0xd8,
- 0x8a, 0xb1, 0x5e, 0xc4, 0x40, 0x62, 0x6e, 0xc5,
- 0x7e, 0x2f, 0x53, 0xa0, 0x9a, 0xef, 0x16, 0x9c,
- 0x10, 0x84, 0xa9, 0x30, 0xa7, 0x17, 0x93, 0xee,
- 0x6b, 0xb8, 0x4a, 0x72, 0x36, 0x77, 0xc2, 0xea,
- 0x7f, 0x53, 0x75, 0xcb, 0x65, 0x07, 0x42, 0xb6,
- 0x40, 0xf9, 0x1b, 0x46, 0x94, 0x1a, 0x4c, 0x7d,
- 0x1a, 0xa8, 0xa7, 0x5a, 0x1b, 0x1d, 0x49, 0x1e,
- 0xfa, 0x35, 0x61, 0xa3, 0xac, 0xaf, 0xf6, 0xc9,
- 0x73, 0xd8, 0x8b, 0x73, 0xa7, 0xb1, 0x99, 0x73,
- 0xa7, 0xba, 0x8d, 0xef, 0x3a, 0x14, 0xf8, 0xe9,
- 0x1f, 0x6f, 0x20, 0x9f, 0xbf, 0xae, 0xcc, 0xe7,
- 0x9d, 0x3f, 0xfd, 0x4b, 0xfe, 0xba, 0x19, 0xf5,
- 0xd3, 0x7f, 0x50, 0x74, 0xfe, 0xad, 0xdb, 0x67,
- 0xf3, 0x63, 0xa1, 0x51, 0x75, 0xe2, 0xfe, 0x56,
- 0x9d, 0xda, 0x37, 0x9d, 0x3f, 0xfd, 0xf7, 0xe8,
- 0xcd, 0xbd, 0x5a, 0x6f, 0xaf, 0x54, 0xe8, 0xd0,
- 0x7e, 0x98, 0x3f, 0x3f, 0x50, 0xd3, 0xdb, 0x83,
- 0x41, 0xd3, 0x3e, 0x83, 0xa7, 0xd6, 0xcf, 0x3e,
- 0xa7, 0x4f, 0xff, 0x59, 0x77, 0xba, 0xff, 0xe0,
- 0x56, 0xaa, 0x02, 0xa7, 0xf0, 0x30, 0x53, 0xb9,
- 0x0f, 0x10, 0x24, 0x3d, 0x16, 0x7b, 0x13, 0x8a,
- 0x8c, 0xcd, 0xef, 0x3a, 0x7a, 0xf4, 0x77, 0xce,
- 0x9e, 0xa6, 0xbd, 0x73, 0xa2, 0x83, 0xdd, 0xc1,
- 0x9b, 0x11, 0x4f, 0xef, 0xf0, 0x6b, 0x55, 0x01,
- 0xd3, 0x82, 0x10, 0x9f, 0x0f, 0xa9, 0xdd, 0xfd,
- 0x8b, 0x87, 0xd1, 0xc6, 0xa6, 0x36, 0x44, 0xa8,
- 0x16, 0xe7, 0xff, 0xd9, 0xff, 0x69, 0x75, 0x6f,
- 0x6d, 0x79, 0xef, 0x53, 0xa2, 0x83, 0xfc, 0xd2,
- 0x49, 0x1b, 0xa9, 0x57, 0x83, 0xcd, 0x32, 0x19,
- 0x5e, 0x84, 0x6f, 0x46, 0x81, 0x3e, 0xf5, 0xd6,
- 0xf5, 0x2a, 0x79, 0x16, 0xf5, 0x2a, 0x60, 0x84,
- 0xa8, 0x79, 0xee, 0xe1, 0x38, 0x48, 0x26, 0xc0,
- 0x94, 0xe3, 0x5d, 0x3f, 0xfe, 0xcb, 0xaa, 0x66,
- 0x7e, 0xf6, 0xf2, 0xfe, 0x83, 0xa0, 0x07, 0xf0,
- 0x12, 0x59, 0xff, 0xfc, 0xad, 0xbd, 0xf0, 0x68,
- 0xbd, 0x71, 0x2d, 0xdf, 0xbd, 0x4e, 0x9f, 0xcd,
- 0x52, 0xfb, 0x6a, 0xa2, 0x74, 0xe7, 0xf0, 0x9d,
- 0x3e, 0x7e, 0x5f, 0x36, 0x2a, 0x5e, 0x68, 0xf0,
- 0x6e, 0x35, 0x30, 0x14, 0xe9, 0x80, 0xa7, 0x4f,
- 0xdf, 0xd5, 0xf9, 0xf7, 0x78, 0xd5, 0x00, 0x56,
- 0x7f, 0xeb, 0xdb, 0x19, 0xbd, 0x41, 0x94, 0xdc,
- 0xe9, 0xfd, 0x4a, 0x78, 0x77, 0xae, 0xc7, 0x4f,
- 0x01, 0x9c, 0xfa, 0x9f, 0xdd, 0xd1, 0xa7, 0x6e,
- 0x65, 0x27, 0x42, 0x9e, 0xc7, 0x1c, 0xcf, 0x57,
- 0x5a, 0x6e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xb3,
- 0x4f, 0xf5, 0xa9, 0x4e, 0x2f, 0x27, 0xd8, 0xe0,
- 0x84, 0x27, 0x42, 0x9f, 0x05, 0xce, 0x67, 0x83,
- 0xdf, 0x79, 0xd3, 0x25, 0x8e, 0x9c, 0x10, 0x84,
- 0xa9, 0xfb, 0xdd, 0xa6, 0xde, 0xb9, 0x4e, 0x2f,
- 0x27, 0xd8, 0x0c, 0xc6, 0x8e, 0x95, 0x74, 0x22,
- 0x54, 0x4c, 0x7e, 0x7d, 0x3d, 0xef, 0xea, 0xfd,
- 0x91, 0xdb, 0x90, 0xb6, 0x85, 0x5c, 0x76, 0x79,
- 0x16, 0x32, 0x69, 0x76, 0x15, 0x3b, 0x46, 0x31,
- 0xc4, 0x15, 0x85, 0x05, 0xe3, 0x0e, 0x9f, 0x95,
- 0x82, 0x3d, 0x73, 0xa7, 0xff, 0xbc, 0xca, 0x5f,
- 0x5d, 0x19, 0xff, 0xe7, 0x80, 0x74, 0x58, 0xff,
- 0x6e, 0x55, 0x27, 0x37, 0x48, 0x43, 0x36, 0x2c,
- 0xae, 0xda, 0x23, 0x23, 0x7c, 0xa4, 0xdd, 0xa5,
- 0x80, 0xe5, 0x6e, 0x95, 0xa6, 0x37, 0x14, 0x8e,
- 0xca, 0x99, 0x54, 0xfe, 0x84, 0xeb, 0x53, 0xce,
- 0x43, 0x3a, 0x6a, 0xc9, 0x41, 0x76, 0x9f, 0x0a,
- 0xea, 0x79, 0x68, 0x25, 0x9c, 0xfe, 0x75, 0x82,
- 0xb5, 0x92, 0xf5, 0xeb, 0x39, 0xfd, 0x63, 0x35,
- 0x6d, 0x0e, 0xc0, 0xc2, 0x8b, 0x72, 0x58, 0x9e,
- 0xf9, 0xdd, 0x96, 0xf8, 0xc3, 0x61, 0xd0, 0x88,
- 0xd3, 0x7e, 0x21, 0xae, 0x27, 0xf3, 0xb0, 0x53,
- 0xb9, 0x0d, 0x17, 0x1c, 0xfe, 0x76, 0x0a, 0x77,
- 0x21, 0xa2, 0xeb, 0x9f, 0xf9, 0xdc, 0xf7, 0x60,
- 0xa7, 0x72, 0x1a, 0x25, 0x18, 0x58, 0x46, 0x14,
- 0x3c, 0xa3, 0x63, 0xbd, 0x27, 0x68, 0x77, 0xe8,
- 0x78, 0x6e, 0xd0, 0x3b, 0x11, 0x24, 0xb5, 0x38,
- 0xb9, 0xdb, 0x79, 0xdc, 0xff, 0xe7, 0x33, 0x9e,
- 0xec, 0x14, 0xee, 0x43, 0x44, 0xb5, 0x3e, 0x14,
- 0xee, 0x43, 0x44, 0x6f, 0x3f, 0xee, 0x7b, 0xb0,
- 0x53, 0xb9, 0x0d, 0x12, 0xfc, 0x9d, 0x87, 0xec,
- 0xc3, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
- 0x57, 0x3f, 0xda, 0x73, 0xf9, 0x4d, 0xf9, 0x87,
- 0x4d, 0xb7, 0x8e, 0x9f, 0xb0, 0x53, 0xb9, 0x0d,
- 0x12, 0x04, 0x68, 0x3c, 0xc7, 0x0b, 0xcf, 0xab,
- 0xdf, 0xea, 0x4e, 0x87, 0x9e, 0x5d, 0x24, 0x91,
- 0xa5, 0x1e, 0x9d, 0x0d, 0x19, 0xff, 0xbf, 0x94,
- 0x3b, 0x71, 0x7f, 0xfc, 0xb9, 0xd0, 0xe3, 0xf0,
- 0x12, 0x99, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
- 0x91, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb5,
- 0xe7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x17, 0x24,
- 0xf8, 0x53, 0xb9, 0x0d, 0x17, 0x64, 0xff, 0xb9,
- 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x51, 0xd2, 0x76,
- 0x1f, 0xb3, 0x0c, 0x27, 0xc2, 0x9d, 0xc8, 0x68,
- 0xa5, 0x67, 0xff, 0xff, 0xac, 0xb4, 0x2d, 0xbc,
- 0xdb, 0xb6, 0xb7, 0x9c, 0x96, 0xf3, 0x56, 0x5a,
- 0x30, 0xe9, 0xf3, 0x99, 0xcf, 0x76, 0x22, 0xc9,
- 0xa3, 0x08, 0xa1, 0x73, 0xbd, 0xf0, 0xc8, 0xa4,
- 0x9f, 0xd1, 0xcf, 0xb0, 0x84, 0x07, 0x75, 0x3b,
- 0xbc, 0x2c, 0x5b, 0x43, 0x66, 0x7f, 0x9e, 0xec,
- 0x14, 0xee, 0x43, 0x44, 0x71, 0x3f, 0xde, 0x76,
- 0x0a, 0x77, 0x21, 0xa2, 0xb5, 0x93, 0xb9, 0x10,
- 0x57, 0x41, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0x96, 0xe6, 0xca, 0x4e, 0x9f,
- 0xdb, 0x63, 0x18, 0xbe, 0xa9, 0xd1, 0x49, 0xe4,
- 0xf8, 0x5a, 0x75, 0xb6, 0x79, 0xd3, 0x9e, 0xc4,
- 0x3a, 0x7f, 0xfe, 0xb7, 0x52, 0x0d, 0xad, 0xcf,
- 0xca, 0xff, 0x5e, 0xde, 0x74, 0x1a, 0x21, 0xb9,
- 0xff, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x98,
- 0x27, 0x0e, 0xa0, 0x2a, 0x7f, 0x7f, 0x2f, 0x75,
- 0x1a, 0x9d, 0x27, 0x2a, 0x6c, 0x94, 0x11, 0xec,
- 0x3b, 0x83, 0x68, 0xbe, 0xc1, 0x7b, 0xa3, 0x6f,
- 0x1c, 0x9c, 0xcd, 0x44, 0xa9, 0xff, 0x73, 0xdd,
- 0x82, 0x9d, 0xc8, 0x68, 0x98, 0xe4, 0xef, 0x1f,
- 0x13, 0x07, 0x27, 0xe5, 0xae, 0x8b, 0xe5, 0x8e,
- 0x9f, 0xff, 0xfe, 0x7d, 0x6d, 0x9a, 0x86, 0xb6,
- 0xc4, 0xca, 0xe8, 0xca, 0x5f, 0x5f, 0x7f, 0xc7,
- 0x4f, 0x27, 0x72, 0x1a, 0x2b, 0x19, 0xff, 0x6e,
- 0x65, 0xff, 0x9a, 0xaf, 0xee, 0x74, 0x69, 0x4c,
- 0x6e, 0x92, 0xe1, 0x84, 0x0d, 0xca, 0xe7, 0xff,
- 0x2f, 0xef, 0xa7, 0x55, 0xfe, 0x22, 0x89, 0xd3,
- 0xfe, 0xcd, 0xad, 0x95, 0xa5, 0xeb, 0x63, 0xa7,
- 0xfd, 0x9b, 0x0f, 0xb5, 0xa0, 0x15, 0x79, 0xd3,
- 0xff, 0xff, 0x7f, 0x5a, 0x31, 0x34, 0x7f, 0x56,
- 0xfd, 0x19, 0x4b, 0xf3, 0x5f, 0x82, 0xa7, 0x4f,
- 0xed, 0xd5, 0x43, 0x4f, 0x6e, 0x0d, 0x07, 0x4e,
- 0xb7, 0x9d, 0x89, 0xe6, 0x22, 0x2d, 0x92, 0x7e,
- 0x7f, 0x74, 0x1d, 0xc7, 0xe9, 0xb5, 0x68, 0xe9,
- 0xf7, 0x7e, 0x8d, 0x6a, 0x74, 0x7c, 0xf0, 0x6a,
- 0x31, 0x3c, 0xa3, 0xdf, 0x3a, 0x7a, 0xb5, 0x50,
- 0x1d, 0x16, 0x3c, 0x00, 0x8f, 0xcf, 0x95, 0xe0,
- 0xd5, 0xe7, 0x4e, 0x5f, 0xbc, 0xe8, 0x68, 0xf0,
- 0xee, 0x51, 0x3f, 0x2b, 0x33, 0xfe, 0xd2, 0x74,
- 0xaa, 0x74, 0x78, 0xdf, 0x71, 0x74, 0xc0, 0x52,
- 0xa6, 0x08, 0x4a, 0x8f, 0x1a, 0xb0, 0x8a, 0xcf,
- 0xee, 0x7f, 0xf2, 0xf6, 0xf1, 0x4e, 0x34, 0x33,
- 0xdb, 0x75, 0x35, 0x3a, 0x72, 0xfd, 0xa3, 0xa6,
- 0xfa, 0x9d, 0x0d, 0x1b, 0x11, 0x1c, 0x9e, 0x10,
- 0x63, 0x79, 0xd3, 0xb7, 0x8e, 0x93, 0xa1, 0x51,
- 0x6f, 0x8a, 0x9e, 0x21, 0xb1, 0x1c, 0xd6, 0xb9,
- 0xd3, 0x82, 0x10, 0x95, 0x3f, 0xf6, 0x26, 0xcb,
- 0x46, 0xfc, 0xb7, 0x52, 0x53, 0x8b, 0xc9, 0xef,
- 0x0b, 0x7e, 0xc7, 0x48, 0x4e, 0x9f, 0x33, 0xd7,
- 0x07, 0x1d, 0x14, 0x1e, 0xde, 0xec, 0x97, 0x50,
- 0xf9, 0xfc, 0x9e, 0xaf, 0xf1, 0xb7, 0x1d, 0x36,
- 0x5c, 0xe8, 0xa4, 0xf2, 0x2c, 0x67, 0x3d, 0x7f,
- 0xe3, 0xce, 0x9f, 0xfd, 0xea, 0xdb, 0x36, 0xfe,
- 0x36, 0xfe, 0x54, 0xe8, 0x13, 0xed, 0xb9, 0x0c,
- 0x9c, 0xab, 0x9b, 0x1b, 0x31, 0x63, 0x28, 0xb0,
- 0xb1, 0xb2, 0xd0, 0xf9, 0xe3, 0xbf, 0x99, 0x56,
- 0x16, 0x17, 0x7d, 0xdf, 0x09, 0x09, 0xf0, 0xa7,
- 0x72, 0x1a, 0x2b, 0x79, 0xff, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0x9c, 0x24, 0xec, 0x3f, 0x66,
- 0x18, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x68, 0xcf,
- 0x63, 0x5e, 0xd2, 0x74, 0x9d, 0x87, 0xa9, 0x63,
- 0x09, 0xe4, 0xee, 0x43, 0x45, 0xb5, 0x3f, 0x59,
- 0x58, 0xbe, 0xd8, 0xe9, 0x9d, 0x82, 0x7b, 0x17,
- 0x2b, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x5c,
- 0xb3, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0xb6,
- 0x15, 0x9c, 0xad, 0x41, 0x43, 0xe3, 0xff, 0xda,
- 0x1b, 0x7a, 0x65, 0x87, 0xfa, 0x76, 0x13, 0x77,
- 0x19, 0x2d, 0x9e, 0xfe, 0xff, 0x52, 0xcb, 0x9d,
- 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2a, 0x79,
- 0xe4, 0xee, 0x43, 0x45, 0x73, 0x3f, 0x9d, 0x82,
- 0x9d, 0xc8, 0x68, 0xb3, 0xa0, 0x4f, 0x9a, 0xc5,
- 0x73, 0xe1, 0x4e, 0xe4, 0x34, 0x48, 0x53, 0xfd,
- 0xea, 0x6b, 0x7f, 0xab, 0x2a, 0x74, 0xcf, 0x76,
- 0x1f, 0x50, 0x0c, 0x27, 0x9b, 0xa5, 0x95, 0x87,
- 0x4f, 0xec, 0xb5, 0x6b, 0x83, 0x41, 0xd2, 0x76,
- 0x26, 0x23, 0xd0, 0x8b, 0xa9, 0x6d, 0xc9, 0xe7,
- 0xff, 0x39, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a,
- 0x27, 0xc8, 0x45, 0x49, 0x7b, 0xb8, 0xec, 0xac,
- 0x8f, 0x3e, 0x14, 0xee, 0x43, 0x45, 0x65, 0x3f,
- 0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x13, 0x74,
- 0xde, 0x76, 0x1f, 0xb3, 0x0c, 0x27, 0xc2, 0x9d,
- 0xc8, 0x68, 0x95, 0xa7, 0xfb, 0x4d, 0xbd, 0xa3,
- 0x54, 0xca, 0x9d, 0x3e, 0x73, 0x39, 0xee, 0xc3,
- 0xed, 0xe3, 0x09, 0xf0, 0xa7, 0x72, 0x1a, 0x25,
- 0xc9, 0xfe, 0xf7, 0x3e, 0xff, 0x56, 0x54, 0xe9,
- 0xe6, 0xde, 0xfa, 0x9d, 0x3e, 0x73, 0x39, 0xee,
- 0xc4, 0x45, 0xd8, 0xc3, 0x8e, 0x27, 0xfe, 0x77,
- 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x88, 0xee, 0x7f,
- 0xaf, 0x6c, 0x7b, 0xbb, 0xf5, 0x3a, 0x7e, 0x6e,
- 0x7d, 0x53, 0x3e, 0x74, 0xfd, 0xba, 0x7f, 0x2d,
- 0xd7, 0x3a, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0x86,
- 0x7d, 0x96, 0xbe, 0x50, 0x74, 0xff, 0xff, 0x6b,
- 0xdb, 0xbf, 0x51, 0x6e, 0xf5, 0xd6, 0xde, 0xbd,
- 0x73, 0x63, 0xa4, 0xed, 0xd1, 0x32, 0x46, 0xe1,
- 0x7e, 0x18, 0xdc, 0xc3, 0x70, 0x9e, 0x7c, 0x29,
- 0xdc, 0x86, 0x8a, 0xa2, 0x7f, 0xdc, 0xf7, 0x60,
- 0xa7, 0x72, 0x1a, 0x26, 0xb9, 0x3b, 0x0f, 0xd9,
- 0x86, 0x13, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8a,
- 0xb2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
- 0x68, 0x91, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xb4,
- 0xa7, 0xfd, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
- 0x7d, 0x93, 0xb0, 0xfd, 0x98, 0x61, 0x3f, 0xf9,
- 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x42,
- 0x4f, 0xad, 0xea, 0x14, 0x4e, 0x9f, 0x0a, 0x77,
- 0x21, 0xa2, 0x8f, 0x9f, 0xff, 0xb3, 0x6b, 0x2e,
- 0xf7, 0x5f, 0xfc, 0x0a, 0xd5, 0x40, 0x54, 0xf9,
- 0xcc, 0xe7, 0xb9, 0x51, 0x69, 0x84, 0xfb, 0x86,
- 0x10, 0xab, 0xc5, 0x94, 0x43, 0x21, 0xe9, 0x78,
- 0x99, 0xa6, 0x35, 0xc4, 0x86, 0x95, 0x24, 0xed,
- 0x1d, 0xda, 0x18, 0x40, 0x27, 0xbc, 0x60, 0xd3,
- 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x88, 0x8a, 0x7e,
- 0xc1, 0x4e, 0xe4, 0x34, 0x45, 0x73, 0xfd, 0xbb,
- 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xb8, 0x87, 0x1f,
- 0xd7, 0x1a, 0xcf, 0x65, 0xba, 0xe7, 0x4f, 0xec,
- 0xf0, 0x80, 0x1a, 0xd4, 0xe9, 0x6e, 0x9f, 0x3d,
- 0x3a, 0x90, 0x4f, 0xfd, 0xde, 0x7f, 0xbf, 0x7d,
- 0x6c, 0x38, 0x74, 0xfb, 0x3d, 0xb0, 0xe1, 0xd3,
- 0xaf, 0x5f, 0x58, 0xfa, 0xae, 0x89, 0x3e, 0x14,
- 0xee, 0x43, 0x45, 0x3d, 0x0d, 0xc4, 0x7d, 0xac,
- 0x25, 0xf0, 0xd2, 0x7f, 0xf7, 0x3d, 0xdb, 0x7f,
- 0x83, 0x5a, 0xa8, 0x0e, 0x87, 0x22, 0x07, 0x63,
- 0x79, 0xce, 0xdb, 0x0e, 0x9f, 0x2b, 0xc1, 0xab,
- 0xce, 0x9e, 0x4e, 0xe4, 0x34, 0x56, 0x70, 0xd1,
- 0xe9, 0x89, 0x44, 0xfd, 0x43, 0x17, 0xef, 0xa9,
- 0xd3, 0x96, 0x8f, 0x1d, 0x3e, 0xb8, 0x37, 0xfd,
- 0xe7, 0x4e, 0xd7, 0xaa, 0x74, 0xfb, 0x1a, 0xa3,
- 0x50, 0x1d, 0x27, 0x62, 0x37, 0x04, 0x8a, 0xc5,
- 0xdc, 0x39, 0xf2, 0xad, 0xe3, 0x93, 0xff, 0x3b,
- 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x8b, 0x3f,
- 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb2, 0x67, 0xf3,
- 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0xc4, 0xec, 0xae,
- 0x1d, 0x3e, 0x14, 0xee, 0x43, 0x45, 0xb7, 0x27,
- 0x3c, 0xf2, 0xb0, 0x6a, 0x7f, 0xcd, 0xc6, 0xe6,
- 0xeb, 0x5e, 0xd9, 0xf5, 0x01, 0xd3, 0xf2, 0xfd,
- 0xfb, 0x6a, 0xc3, 0xa7, 0xc2, 0x9d, 0xc8, 0x68,
- 0xbc, 0x27, 0xaf, 0xb9, 0x96, 0x3a, 0x7f, 0xe5,
- 0xde, 0xca, 0x5f, 0x7c, 0xfd, 0xea, 0x74, 0xfb,
- 0x3e, 0x06, 0xf5, 0x3a, 0x7c, 0xbb, 0xf5, 0xea,
- 0x9d, 0x3a, 0xea, 0x03, 0xa4, 0xed, 0xd7, 0x93,
- 0x84, 0xa1, 0x37, 0x0b, 0xe9, 0x30, 0xb1, 0x20,
- 0x11, 0xfe, 0x53, 0x72, 0x99, 0xde, 0xca, 0x4e,
- 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0xf4, 0x9f, 0xf7,
- 0xfa, 0xef, 0x5d, 0x37, 0xf5, 0x07, 0x4f, 0xb1,
- 0x96, 0xed, 0x8e, 0x93, 0xb6, 0x45, 0xa6, 0x0e,
- 0x6f, 0x30, 0x6f, 0x41, 0x85, 0x64, 0x52, 0xd1,
- 0x0b, 0x5c, 0x8f, 0xc1, 0x09, 0x3d, 0x1a, 0x58,
- 0xae, 0x31, 0x30, 0x07, 0x7f, 0x84, 0x2e, 0xb1,
- 0xd5, 0x86, 0x33, 0x69, 0xec, 0xb7, 0x5c, 0xe9,
- 0xfd, 0x9e, 0x10, 0x03, 0x5a, 0x9d, 0x2d, 0xd3,
- 0xe7, 0xa7, 0x52, 0x09, 0xf0, 0xa7, 0x72, 0x1a,
- 0x22, 0x39, 0xff, 0xeb, 0x6b, 0x5a, 0xe3, 0x3f,
- 0x8d, 0xb4, 0x2b, 0x75, 0x3a, 0x7f, 0xcf, 0x5a,
- 0x07, 0x2f, 0x7f, 0x5c, 0xe9, 0xff, 0xfe, 0x5b,
- 0x77, 0xae, 0xb6, 0xfe, 0x5e, 0xde, 0xb6, 0x78,
- 0x27, 0x4d, 0x43, 0x0a, 0x98, 0x21, 0x2a, 0x7f,
- 0xe7, 0xb9, 0x2d, 0xe6, 0xac, 0xb4, 0x38, 0x06,
- 0xb4, 0x22, 0xf3, 0xfb, 0x37, 0x7f, 0xcb, 0x75,
- 0xce, 0x9f, 0xff, 0x91, 0xc3, 0xdf, 0xf5, 0xdc,
- 0x2b, 0x7f, 0xf0, 0x0e, 0x86, 0xe2, 0xa7, 0x1c,
- 0x2d, 0x43, 0x0a, 0x56, 0x84, 0xfb, 0xa1, 0x25,
- 0x75, 0xd6, 0xc6, 0xb3, 0xe1, 0x4e, 0xe4, 0x34,
- 0x45, 0xd3, 0xeb, 0x83, 0x7f, 0xde, 0x5b, 0x3d,
- 0x92, 0x76, 0x1f, 0x47, 0x18, 0x43, 0x93, 0x09,
- 0x7c, 0x38, 0xe7, 0xfe, 0x67, 0x3d, 0xd8, 0x29,
- 0xdc, 0x86, 0x89, 0x9a, 0x75, 0x2b, 0x53, 0xa7,
- 0x27, 0x98, 0x74, 0xed, 0xd5, 0xb9, 0xba, 0x8e,
- 0x9f, 0x27, 0x5b, 0xcd, 0x1d, 0x3f, 0xf3, 0x7f,
- 0xaf, 0xe4, 0xf6, 0xd7, 0xc4, 0x3a, 0x7f, 0xff,
- 0xb5, 0xef, 0xa7, 0xf3, 0x6b, 0x6b, 0xa2, 0xca,
- 0xf1, 0x5a, 0x0e, 0x8c, 0x45, 0x8d, 0x91, 0xe7,
- 0xff, 0xdb, 0x7b, 0xf4, 0x65, 0x7d, 0xd6, 0x70,
- 0x42, 0x12, 0xa7, 0x93, 0xb9, 0x0d, 0x16, 0x7c,
- 0xff, 0xbd, 0x65, 0x7f, 0xae, 0xb7, 0xa9, 0xd3,
- 0xff, 0xde, 0x1b, 0x76, 0x8c, 0x6d, 0xfc, 0xae,
- 0x7c, 0xe9, 0xc1, 0x08, 0x4a, 0x9f, 0xf7, 0x3e,
- 0xbf, 0xc4, 0xdb, 0x04, 0xa7, 0x17, 0x93, 0xfc,
- 0xb6, 0xf6, 0xdf, 0xee, 0x68, 0xe9, 0xfe, 0xf7,
- 0xf6, 0xdf, 0xb6, 0xb7, 0xa9, 0xd0, 0x89, 0xf8,
- 0x8a, 0xc3, 0x0a, 0xec, 0x7c, 0x06, 0xdb, 0xa5,
- 0xb6, 0x39, 0x9f, 0xff, 0xff, 0xb3, 0x01, 0x5c,
- 0xcf, 0xe9, 0xde, 0x3f, 0x5c, 0xb3, 0xab, 0xfc,
- 0xa1, 0x98, 0xc3, 0xa7, 0x55, 0x68, 0x3a, 0x76,
- 0xe6, 0x58, 0xe8, 0x7a, 0x31, 0x2b, 0x08, 0xab,
- 0x8e, 0x4f, 0x52, 0x0d, 0x50, 0xe9, 0xf5, 0xbe,
- 0xb8, 0x26, 0x4f, 0xfb, 0xc2, 0xfc, 0x1a, 0x35,
- 0xed, 0x8d, 0x10, 0x6b, 0x8d, 0x2c, 0xfb, 0x93,
- 0xcc, 0x53, 0xa7, 0xe7, 0xdb, 0xfd, 0x4d, 0xce,
- 0x96, 0x21, 0xe9, 0xfc, 0x96, 0x7f, 0xff, 0xdc,
- 0x1b, 0xe5, 0xae, 0xb9, 0xfa, 0x6f, 0x83, 0xea,
- 0x39, 0x87, 0x43, 0xd3, 0x40, 0xc8, 0x57, 0xfc,
- 0x9a, 0x7e, 0x1c, 0xda, 0xb6, 0x53, 0xa7, 0xff,
- 0xf6, 0xbf, 0xed, 0x3a, 0x37, 0xff, 0xaf, 0x5f,
- 0x53, 0x6f, 0x04, 0xe9, 0xff, 0xfe, 0xad, 0x54,
- 0x6e, 0xae, 0x66, 0x5e, 0xbb, 0xeb, 0xcf, 0xc3,
- 0xa7, 0xad, 0x9e, 0x6c, 0x74, 0x79, 0x11, 0x36,
- 0x66, 0x99, 0x9b, 0xa1, 0xa2, 0xfc, 0x9f, 0xf9,
- 0xf7, 0xd5, 0xef, 0x65, 0xee, 0xac, 0x3a, 0x7f,
- 0xef, 0x67, 0xf3, 0x2b, 0xa1, 0xf5, 0x61, 0xd1,
- 0x4a, 0x22, 0xea, 0x8d, 0x3d, 0xff, 0xaa, 0x1d,
- 0x0a, 0x98, 0xd6, 0xc4, 0x79, 0x0b, 0x3e, 0x24,
- 0x9f, 0xff, 0xf9, 0xbd, 0x6d, 0xe6, 0x39, 0xa7,
- 0xf0, 0xef, 0xb7, 0xa9, 0xaa, 0x7a, 0x83, 0xa7,
- 0xfd, 0xcf, 0x67, 0x3e, 0xf5, 0x5d, 0x27, 0x4f,
- 0x65, 0x7d, 0xf3, 0xa3, 0xe7, 0xc1, 0xa9, 0xfc,
- 0xf6, 0xfd, 0x7a, 0xa7, 0x4f, 0xfa, 0xf5, 0x07,
- 0xa9, 0xa5, 0xf9, 0x73, 0xa1, 0x4f, 0x97, 0x09,
- 0x26, 0x6b, 0x53, 0xa4, 0xc3, 0xa2, 0x93, 0x50,
- 0xdd, 0x8c, 0x4f, 0xff, 0xfa, 0xde, 0xa6, 0xf9,
- 0x4d, 0xc4, 0x56, 0xe0, 0xdf, 0xf7, 0xdb, 0x0e,
- 0x9c, 0x10, 0x84, 0xa9, 0xed, 0xb6, 0xef, 0x94,
- 0xe2, 0xf2, 0x7f, 0xdd, 0x64, 0xf7, 0x68, 0xaf,
- 0x58, 0xe8, 0x54, 0xc8, 0x90, 0x9f, 0xd0, 0x8b,
- 0xb1, 0x94, 0xff, 0xd9, 0xfa, 0x6f, 0x83, 0xea,
- 0x39, 0x87, 0x4f, 0xb2, 0xef, 0x65, 0x8e, 0x85,
- 0x3e, 0xba, 0xa2, 0x4c, 0x0b, 0x1d, 0x3f, 0x50,
- 0xd3, 0xdb, 0x83, 0x41, 0xd3, 0xfb, 0x4d, 0xb2,
- 0xf6, 0xf5, 0xce, 0x9b, 0xc2, 0x74, 0x6e, 0xa3,
- 0xfe, 0xf1, 0xa5, 0x8d, 0x67, 0xfe, 0xd9, 0x76,
- 0x15, 0xbf, 0x93, 0xdb, 0x1d, 0x3f, 0x5b, 0x5a,
- 0x1a, 0xb7, 0x8e, 0x8d, 0x8f, 0xda, 0xc8, 0xb2,
- 0x73, 0x74, 0x66, 0xee, 0xee, 0xb0, 0xe2, 0x8d,
- 0xd0, 0x57, 0xb4, 0x36, 0x32, 0x50, 0x9d, 0x31,
- 0x94, 0xf8, 0xd5, 0xa8, 0xe2, 0x04, 0xd5, 0x85,
- 0x96, 0x94, 0x1b, 0xc8, 0x20, 0x86, 0xd7, 0xe1,
- 0x11, 0x58, 0xda, 0xaf, 0x0a, 0xc0, 0x90, 0xee,
- 0x42, 0x53, 0x7c, 0x2a, 0xe1, 0xcc, 0xf9, 0x0b,
- 0x53, 0x8a, 0x67, 0xff, 0x39, 0x9c, 0xf7, 0x60,
- 0xa7, 0x72, 0x1a, 0x26, 0xc9, 0xfc, 0xec, 0x14,
- 0xee, 0x43, 0x45, 0x5b, 0x3f, 0x9e, 0xfd, 0x6f,
- 0xf5, 0x79, 0xd3, 0xd9, 0x6e, 0xb9, 0xd2, 0xdd,
- 0x30, 0xf5, 0x3e, 0x69, 0x3e, 0x14, 0xee, 0x43,
- 0x45, 0x69, 0x3f, 0xfc, 0x8a, 0x38, 0x0e, 0x67,
- 0x3d, 0x7c, 0x87, 0x4f, 0xff, 0x3e, 0xb9, 0xf5,
- 0x67, 0x65, 0xee, 0xac, 0x3a, 0x6b, 0xdd, 0x51,
- 0x2f, 0xc9, 0x53, 0xf9, 0x5b, 0x6f, 0xbf, 0xd4,
- 0x07, 0x4f, 0xd4, 0x65, 0xbd, 0x8c, 0x3a, 0x7f,
- 0xb1, 0xbf, 0xea, 0x1a, 0x5f, 0x53, 0xa7, 0xf3,
- 0xf2, 0xfd, 0xf0, 0x6a, 0x74, 0x9c, 0xdc, 0x4f,
- 0xcb, 0x0b, 0x3d, 0x0c, 0x7b, 0x16, 0xf1, 0xb7,
- 0xcb, 0x6e, 0x79, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
- 0x68, 0xb0, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0x9d,
- 0x67, 0xff, 0xf5, 0x96, 0x8d, 0xb1, 0x8e, 0xad,
- 0x72, 0xde, 0xae, 0xb4, 0x1d, 0x3e, 0x73, 0x39,
- 0xee, 0xc4, 0x4a, 0xb4, 0x61, 0x3e, 0x14, 0xee,
- 0x43, 0x45, 0xb3, 0x3f, 0xe0, 0x2d, 0x5d, 0x6f,
- 0x27, 0x09, 0xd2, 0x76, 0x1f, 0x67, 0x18, 0x4f,
- 0x27, 0x72, 0x1a, 0x2e, 0x69, 0x30, 0xe9, 0x9d,
- 0x82, 0x6e, 0xc2, 0x57, 0x3f, 0x9d, 0x82, 0x9d,
- 0xc8, 0x68, 0xbb, 0xe7, 0x9d, 0xa7, 0x60, 0x1d,
- 0x0a, 0xda, 0xcb, 0x65, 0x3e, 0xe5, 0x0c, 0x29,
- 0x52, 0xf4, 0xa8, 0x11, 0x72, 0x64, 0x34, 0x01,
- 0x0a, 0xca, 0xb0, 0xdc, 0xaf, 0x79, 0xdc, 0xff,
- 0xbf, 0xce, 0x5a, 0xd5, 0x9c, 0xf3, 0xa7, 0xf7,
- 0xe8, 0xc6, 0xfb, 0xae, 0x93, 0xa7, 0xc2, 0x9d,
- 0xc8, 0x68, 0x95, 0xe7, 0xfd, 0xfe, 0x0e, 0xd6,
- 0x5a, 0x30, 0x27, 0x4f, 0x6b, 0xc2, 0xf3, 0xa7,
- 0xff, 0xf7, 0xaf, 0xcc, 0xef, 0x82, 0xc1, 0xef,
- 0xd0, 0x9e, 0xa0, 0xe8, 0xd9, 0x10, 0x7c, 0x43,
- 0x1b, 0x23, 0x96, 0xd0, 0xc2, 0x9d, 0xcf, 0x72,
- 0xa6, 0xed, 0x87, 0x15, 0x8c, 0x56, 0x75, 0xd7,
- 0x62, 0xa7, 0xff, 0x5b, 0xbd, 0x75, 0x7f, 0x86,
- 0x8d, 0x40, 0x54, 0xfe, 0xe4, 0x76, 0xc2, 0xdd,
- 0xb9, 0x4f, 0x9e, 0xa3, 0x92, 0x72, 0x2a, 0xae,
- 0x64, 0x76, 0x6d, 0xa1, 0x5b, 0x3f, 0xf9, 0xcc,
- 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x30, 0xcf,
- 0xff, 0xd8, 0xed, 0xe3, 0xc0, 0x76, 0x9b, 0xbc,
- 0x2b, 0x57, 0x9d, 0x3f, 0xf6, 0xe9, 0x94, 0xbf,
- 0x5e, 0xbf, 0xd5, 0xe7, 0x4f, 0xe5, 0xea, 0x2f,
- 0xa7, 0x84, 0xe9, 0xf7, 0x0b, 0xf9, 0x87, 0x47,
- 0xcf, 0x63, 0x53, 0x39, 0xf9, 0x8b, 0x9f, 0xbe,
- 0xe1, 0xd3, 0xe5, 0xcf, 0xdf, 0x70, 0xe9, 0xfa,
- 0xde, 0xbd, 0x7a, 0x9d, 0x07, 0xb0, 0xc2, 0xf9,
- 0xff, 0xff, 0x7f, 0x02, 0xdf, 0x7c, 0xb6, 0x8f,
- 0xe5, 0x1e, 0xcf, 0xd2, 0xfa, 0x9d, 0x3f, 0x36,
- 0xdf, 0x7f, 0xa8, 0x0e, 0x9f, 0xfc, 0xb7, 0x02,
- 0xbf, 0x29, 0xbd, 0x1a, 0x84, 0xe8, 0x53, 0xfd,
- 0xf1, 0x8c, 0xfd, 0x5f, 0x69, 0x67, 0x5c, 0xe9,
- 0xff, 0xff, 0x0e, 0x36, 0x5f, 0xdf, 0x46, 0xff,
- 0xad, 0xbb, 0xd7, 0x5b, 0xd4, 0xe9, 0x65, 0x28,
- 0x9f, 0x12, 0xf9, 0xef, 0xa8, 0x37, 0x9d, 0x3d,
- 0xdb, 0xf6, 0xc3, 0xa4, 0xe6, 0xe2, 0xb8, 0x3d,
- 0xa1, 0x44, 0x8f, 0x6d, 0x24, 0x5a, 0x1e, 0x1f,
- 0x86, 0x05, 0xca, 0x35, 0x23, 0x9f, 0x0a, 0x77,
- 0x21, 0xa2, 0xae, 0x9f, 0xe7, 0xbb, 0x05, 0x3b,
- 0x90, 0xd1, 0x1e, 0x49, 0xd8, 0x7e, 0x3c, 0x61,
- 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb0, 0x67,
- 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0x54, 0xfe,
- 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xd3, 0x9e, 0x4e,
- 0xe4, 0x34, 0x5b, 0x93, 0xff, 0x2e, 0x0e, 0x7f,
- 0x45, 0xb2, 0x90, 0x9d, 0x02, 0x7d, 0xf5, 0x2b,
- 0x9f, 0xe5, 0xfe, 0xac, 0x5a, 0xdf, 0xc7, 0x4f,
- 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x45, 0x0f,
- 0x3f, 0x57, 0xa9, 0xad, 0xfc, 0x74, 0xfd, 0xf6,
- 0xe6, 0x0a, 0xd4, 0xe9, 0xff, 0xfb, 0x36, 0xb2,
- 0xef, 0x75, 0xff, 0xc0, 0xad, 0x54, 0x05, 0x49,
- 0xd8, 0x9a, 0xd7, 0x88, 0x58, 0x73, 0x74, 0x6d,
- 0x4b, 0xb7, 0x0b, 0xe7, 0xf3, 0xb0, 0x53, 0xb9,
- 0x0d, 0x17, 0x9c, 0x2b, 0x22, 0xc9, 0xe8, 0x9b,
- 0x29, 0x64, 0xbe, 0x1a, 0x61, 0xfe, 0x24, 0xcc,
- 0x3b, 0xb1, 0xdf, 0xe5, 0x02, 0x36, 0x61, 0x9f,
- 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0xd3, 0xf9,
- 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x0a, 0x7f, 0x3b,
- 0x05, 0x3b, 0x90, 0xd1, 0x65, 0xcf, 0x3b, 0x4e,
- 0xeb, 0xe6, 0xea, 0x74, 0xe7, 0x6f, 0x61, 0xd3,
- 0xc8, 0xe5, 0xaa, 0x1e, 0x96, 0xa6, 0x93, 0xff,
- 0x9c, 0xce, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x14,
- 0x64, 0xfe, 0x72, 0xb6, 0x51, 0x50, 0x1d, 0x0f,
- 0x4e, 0xfc, 0x4e, 0xd8, 0x77, 0xd0, 0x8d, 0xa9,
- 0xc5, 0xd4, 0xa7, 0xfe, 0x77, 0x3d, 0xd8, 0x29,
- 0xdc, 0x86, 0x88, 0xe6, 0x7f, 0xf3, 0x99, 0xcf,
- 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x72, 0x9f, 0xce,
- 0xc1, 0x4e, 0xe4, 0x34, 0x59, 0x93, 0xff, 0x39,
- 0x40, 0x2b, 0x7b, 0x75, 0x2f, 0x3a, 0x7f, 0x3b,
- 0x05, 0x3b, 0x90, 0xd1, 0x6e, 0xcf, 0xfe, 0x73,
- 0x39, 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0x13,
- 0xff, 0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44,
- 0xa5, 0x14, 0x27, 0xea, 0xd2, 0x63, 0x14, 0x80,
- 0x77, 0xf4, 0x3b, 0x9d, 0xb7, 0xa9, 0x4f, 0xfb,
- 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xed, 0x3f,
- 0xfe, 0xf6, 0xda, 0xb1, 0x5b, 0xfb, 0x6f, 0xaf,
- 0xf1, 0x0e, 0x93, 0x98, 0x89, 0xfe, 0x46, 0x9f,
- 0xfb, 0x99, 0x6c, 0x4e, 0xb2, 0xef, 0x79, 0xd3,
- 0xff, 0x7f, 0x2d, 0xd4, 0x65, 0x7f, 0xd4, 0x9d,
- 0x36, 0xe3, 0xb6, 0x44, 0x3d, 0x50, 0xe1, 0x88,
- 0xe2, 0xdc, 0x85, 0x7c, 0xf8, 0x53, 0xb9, 0x0d,
- 0x11, 0x64, 0xff, 0xb9, 0xee, 0xc1, 0x4e, 0xe4,
- 0x34, 0x4b, 0xb3, 0xff, 0xf6, 0x6d, 0x65, 0xde,
- 0xeb, 0xff, 0x81, 0x5a, 0xa8, 0x0a, 0x93, 0xb1,
- 0x1a, 0x6c, 0x30, 0xdc, 0x46, 0x9f, 0xfc, 0xe6,
- 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x98, 0xa7,
- 0xec, 0x14, 0xee, 0x43, 0x45, 0x53, 0x3f, 0xff,
- 0xf8, 0x7a, 0xd4, 0xbf, 0x2e, 0xeb, 0x75, 0x47,
- 0xc1, 0xbd, 0xbc, 0x2f, 0x3a, 0x1c, 0x8a, 0xce,
- 0x35, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d,
- 0xc8, 0x68, 0x9d, 0x27, 0xf7, 0xb8, 0x55, 0xfc,
- 0xd8, 0xe9, 0xf3, 0x4a, 0xd2, 0xd4, 0xe9, 0xf8,
- 0x39, 0xe6, 0xd9, 0xf3, 0xa7, 0xbd, 0x65, 0x77,
- 0x8f, 0x5a, 0xa5, 0x13, 0xff, 0x6b, 0x5b, 0xad,
- 0x2e, 0xd5, 0xaf, 0x30, 0xe8, 0x62, 0x20, 0xac,
- 0x73, 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d,
- 0x13, 0xbc, 0xfa, 0xfa, 0xf3, 0x3c, 0x54, 0x9d,
- 0xb2, 0x73, 0x79, 0x18, 0x53, 0x08, 0xf9, 0x1a,
- 0x7f, 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21,
- 0xa2, 0x85, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0xa4, 0xa7, 0xff, 0xf6, 0x55,
- 0xdb, 0xf1, 0xab, 0x73, 0x2f, 0x65, 0xbe, 0xac,
- 0x3a, 0x28, 0x5c, 0x96, 0x79, 0xc2, 0x43, 0xf8,
- 0x48, 0x99, 0x1f, 0x68, 0x12, 0x75, 0x52, 0xdc,
- 0x52, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x44,
- 0x93, 0xff, 0x9c, 0xce, 0x7b, 0xb0, 0x53, 0xb9,
- 0x0d, 0x12, 0xf4, 0xf8, 0x53, 0xb9, 0x0d, 0x14,
- 0xbc, 0xff, 0xec, 0x7a, 0x82, 0xa2, 0xb4, 0xbf,
- 0xcc, 0x3a, 0x7c, 0xdf, 0xe6, 0x2d, 0x4e, 0x9f,
- 0x73, 0x6c, 0x1a, 0x9d, 0x25, 0xd8, 0xf4, 0x58,
- 0x55, 0x27, 0x62, 0x3c, 0x9a, 0x30, 0xbc, 0x26,
- 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x14, 0xe4,
- 0xff, 0xbc, 0x3d, 0x5b, 0x66, 0x7d, 0x0e, 0x9f,
- 0xf6, 0x59, 0x47, 0x1c, 0x10, 0x84, 0xa9, 0xbc,
- 0x13, 0xa6, 0xa1, 0xdb, 0x22, 0x37, 0x70, 0xed,
- 0xbc, 0xf2, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xf2,
- 0x7f, 0xfe, 0xcd, 0xac, 0xbb, 0xdd, 0x7f, 0xf0,
- 0x2b, 0x55, 0x01, 0x52, 0x76, 0x22, 0x37, 0x70,
- 0xc2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
- 0x68, 0x91, 0xe7, 0x78, 0x0a, 0x74, 0xe4, 0xc6,
- 0x14, 0xe2, 0xee, 0x7c, 0x29, 0xdc, 0x86, 0x89,
- 0x22, 0x79, 0xdc, 0xf7, 0x29, 0xec, 0xe1, 0x4c,
- 0xff, 0xce, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1,
- 0x25, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x78, 0xcf,
- 0xda, 0xfe, 0x9e, 0xa6, 0xa7, 0x4f, 0xab, 0x5b,
- 0xe2, 0x1d, 0x3f, 0xcf, 0x76, 0x0a, 0x77, 0x21,
- 0xa2, 0x4d, 0x93, 0xb1, 0x18, 0xf4, 0x98, 0x09,
- 0x87, 0x13, 0x42, 0xae, 0xe4, 0xd0, 0x76, 0xf8,
- 0xd1, 0x36, 0x3b, 0xf4, 0x32, 0x1a, 0x86, 0x8b,
- 0x0a, 0xed, 0x0c, 0x0b, 0x9b, 0xeb, 0x18, 0x9c,
- 0x2c, 0x6e, 0xd9, 0x14, 0x47, 0x5c, 0xf8, 0xf2,
- 0x76, 0x94, 0x35, 0x96, 0xeb, 0x5b, 0x4c, 0xa5,
- 0x84, 0xaf, 0xf7, 0xa9, 0x9e, 0x7b, 0xf4, 0xe7,
- 0xa6, 0xee, 0x3b, 0x06, 0xa9, 0xd8, 0x63, 0x48,
- 0xf5, 0x66, 0x23, 0x3e, 0xed, 0x3b, 0x51, 0xd4,
- 0xf7, 0x20, 0x4b, 0x0e, 0x6e, 0xe1, 0x63, 0xf9,
- 0xec, 0x6a, 0xd2, 0x57, 0x6f, 0x5d, 0x0f, 0xeb,
- 0x4c, 0x16, 0x6d, 0x29, 0x88, 0x32, 0x94, 0x37,
- 0x23, 0xeb, 0xdf, 0x3b, 0x28, 0xdf, 0x3c, 0x97,
- 0x00,
+ 0xb3, 0x6f, 0x02, 0xa7, 0xd3, 0xfa, 0x5c, 0x27,
+ 0xc9, 0xf2, 0xf9, 0xfb, 0xf4, 0xd5, 0xac, 0xb9,
+ 0xd3, 0xff, 0xdf, 0xbb, 0x58, 0x39, 0xcc, 0x5b,
+ 0x7b, 0x63, 0xa7, 0xd4, 0x6e, 0xfd, 0x94, 0x9d,
+ 0x3e, 0xf5, 0x56, 0x86, 0x1f, 0x2f, 0xd9, 0xf2,
+ 0xf0, 0x83, 0x53, 0xe5, 0xfb, 0x37, 0x3c, 0xf9,
+ 0x7e, 0xcf, 0x6a, 0xfc, 0xa9, 0xf2, 0xfd, 0x8d,
+ 0x8f, 0x47, 0xe4, 0x53, 0xe5, 0xca, 0xe7, 0xcf,
+ 0x97, 0xec, 0x1f, 0x2f, 0xd9, 0xba, 0xe7, 0xcb,
+ 0xf5, 0x85, 0xbc, 0x9f, 0xf3, 0xfa, 0xd5, 0x26,
+ 0x7b, 0x37, 0x3c, 0x03, 0xe5, 0xfb, 0x07, 0xcb,
+ 0xf6, 0x60, 0x29, 0xf2, 0xfd, 0x9f, 0xec, 0x07,
+ 0x0e, 0x36, 0xcd, 0x8f, 0x97, 0xec, 0xfd, 0x96,
+ 0xf5, 0x75, 0xa0, 0xf9, 0x7e, 0xc0, 0x11, 0x47,
+ 0xf2, 0x2a, 0xa2, 0xcf, 0x0d, 0x0b, 0x73, 0xe5,
+ 0xfb, 0x07, 0xcb, 0xf7, 0x0d, 0x74, 0xc1, 0x09,
+ 0xf2, 0xfd, 0x87, 0xab, 0x11, 0xd8, 0xd7, 0x21,
+ 0x09, 0x4c, 0x27, 0x44, 0xa5, 0x86, 0x35, 0x85,
+ 0xd5, 0xd7, 0x82, 0x4d, 0x3d, 0x8f, 0x5d, 0x25,
+ 0xcb, 0xf4, 0xe4, 0x47, 0xcf, 0xfb, 0x13, 0x6c,
+ 0x10, 0xf5, 0x9a, 0x3a, 0x67, 0xd0, 0x54, 0x50,
+ 0x89, 0x6a, 0x50, 0xbe, 0x7b, 0x02, 0xb9, 0x2b,
+ 0xd3, 0x8c, 0x73, 0xff, 0xf5, 0x2f, 0x15, 0x6d,
+ 0xcd, 0x2e, 0xd6, 0x56, 0x73, 0x47, 0x42, 0xae,
+ 0xe1, 0xe1, 0x37, 0x8b, 0xfa, 0x73, 0x93, 0x52,
+ 0xc9, 0xff, 0x69, 0x5a, 0x7e, 0xb6, 0xb6, 0xa8,
+ 0x74, 0xfd, 0xfe, 0xd3, 0x6e, 0x79, 0xd3, 0x82,
+ 0x10, 0x95, 0x3b, 0x7a, 0x80, 0xa7, 0x17, 0x93,
+ 0xfe, 0xff, 0x3f, 0x78, 0xe3, 0x6e, 0x13, 0xa7,
+ 0xfb, 0xfc, 0x0d, 0x0f, 0x50, 0x52, 0x74, 0x6c,
+ 0x99, 0x8b, 0x10, 0x40, 0x95, 0xf2, 0xcb, 0x9f,
+ 0xcf, 0xfb, 0xff, 0xf6, 0xad, 0xdd, 0x77, 0x16,
+ 0xe7, 0x4e, 0x08, 0x42, 0x58, 0x84, 0x13, 0xe1,
+ 0x4e, 0xe4, 0x2c, 0x42, 0x07, 0x1a, 0xa9, 0xc1,
+ 0x08, 0x4b, 0x10, 0x7a, 0x0b, 0x10, 0x79, 0xc6,
+ 0xaa, 0x65, 0x66, 0x22, 0x4d, 0x1a, 0xe7, 0xd7,
+ 0x5b, 0xab, 0x0e, 0x9e, 0xff, 0x97, 0x49, 0xd3,
+ 0xb7, 0xa8, 0x0e, 0x8a, 0x0f, 0x01, 0x84, 0x73,
+ 0xe4, 0x5b, 0x2b, 0x0a, 0x9f, 0x7f, 0xbf, 0xfc,
+ 0x2a, 0x6c, 0x42, 0xa6, 0x08, 0x4a, 0x8c, 0x3f,
+ 0x5a, 0x92, 0xdc, 0x98, 0x22, 0x93, 0xfb, 0xfb,
+ 0xd4, 0x16, 0xc6, 0xf2, 0x9c, 0x6e, 0xe1, 0x53,
+ 0x80, 0xf3, 0x37, 0x43, 0x4e, 0x7f, 0xf5, 0x94,
+ 0x15, 0xcc, 0xdb, 0xbf, 0xda, 0x4e, 0x9f, 0xd5,
+ 0xde, 0xca, 0x87, 0xa9, 0x3a, 0x15, 0x5d, 0x8e,
+ 0x26, 0x7a, 0x30, 0x51, 0x8e, 0xb3, 0x8d, 0x2a,
+ 0x95, 0x38, 0x21, 0x09, 0x53, 0xe7, 0x83, 0xbf,
+ 0xb1, 0x4e, 0x2f, 0x27, 0xff, 0xbf, 0x4e, 0x8a,
+ 0x40, 0xbf, 0x4e, 0xa3, 0xfc, 0x74, 0xff, 0xf6,
+ 0x2b, 0xb6, 0xfa, 0xea, 0x99, 0xa7, 0xc2, 0x74,
+ 0xf3, 0x7d, 0x80, 0xd8, 0xe8, 0x79, 0xfb, 0xf2,
+ 0x84, 0xff, 0xe7, 0xe0, 0x81, 0x9e, 0xae, 0xfa,
+ 0xae, 0x1d, 0x3d, 0xed, 0xb1, 0x87, 0x42, 0xa7,
+ 0x1c, 0xf3, 0x7e, 0x86, 0x57, 0xc8, 0x75, 0x4a,
+ 0x9f, 0xb7, 0x75, 0xf7, 0xe9, 0x79, 0xd3, 0xfe,
+ 0xe1, 0xdc, 0xf5, 0xb3, 0xa9, 0x01, 0xd3, 0xfe,
+ 0xad, 0x54, 0x6e, 0xae, 0xdb, 0xc7, 0x4f, 0xfb,
+ 0xfc, 0xd5, 0xb8, 0x47, 0xdb, 0x1d, 0x18, 0x8e,
+ 0xf4, 0x33, 0xf2, 0x03, 0x0f, 0xa7, 0x9f, 0xbf,
+ 0x1a, 0x3a, 0x7c, 0x3b, 0x66, 0x7c, 0xe9, 0xff,
+ 0xb7, 0x7e, 0xcb, 0x2b, 0x6a, 0xd9, 0x69, 0x3a,
+ 0x38, 0xfc, 0x2a, 0x4d, 0x3f, 0xfd, 0x97, 0xae,
+ 0x35, 0x65, 0x6d, 0x96, 0xb2, 0x9d, 0x3f, 0xae,
+ 0xdd, 0x5a, 0xfb, 0x74, 0xa3, 0x53, 0xa3, 0x64,
+ 0x5a, 0x7c, 0x86, 0xea, 0x13, 0xff, 0xde, 0xae,
+ 0x6d, 0x7a, 0xfb, 0x4d, 0xbb, 0xfe, 0x3a, 0x7f,
+ 0xff, 0x7e, 0xf9, 0x6f, 0x2d, 0xfc, 0x05, 0x7b,
+ 0x82, 0x10, 0x95, 0x3d, 0xb6, 0x66, 0x92, 0xa7,
+ 0x3f, 0xfa, 0x9a, 0x21, 0x99, 0xc1, 0x08, 0x4a,
+ 0x9d, 0x9f, 0x42, 0x9c, 0x5e, 0x4f, 0xfb, 0x28,
+ 0xcd, 0xb9, 0xff, 0x5a, 0x0e, 0x80, 0x1f, 0x47,
+ 0xca, 0x67, 0xf3, 0xff, 0x97, 0xbe, 0xb4, 0x1d,
+ 0x0a, 0x9c, 0x4d, 0x0c, 0x34, 0x91, 0x8c, 0x2b,
+ 0xb8, 0x8a, 0x7b, 0xd7, 0xf2, 0x9d, 0x3f, 0xb5,
+ 0xc1, 0x00, 0x3d, 0xf3, 0xa7, 0xff, 0xca, 0xff,
+ 0x6d, 0x6d, 0xf5, 0xc1, 0x4e, 0xe4, 0x34, 0x41,
+ 0x91, 0x64, 0x4a, 0x5c, 0xce, 0x7d, 0x51, 0xf0,
+ 0x77, 0x67, 0x4f, 0xed, 0xcc, 0xae, 0xe6, 0x0a,
+ 0x9d, 0x0f, 0x4c, 0xe7, 0xd0, 0xb5, 0xa9, 0x1d,
+ 0xca, 0xe7, 0xff, 0x97, 0xf4, 0x68, 0x6b, 0xdf,
+ 0xcd, 0xb3, 0xfa, 0x4e, 0x9c, 0xa2, 0xd1, 0xd0,
+ 0xab, 0xb9, 0x9b, 0x1d, 0xe4, 0x69, 0x08, 0x63,
+ 0xe8, 0xf7, 0x3a, 0x38, 0x8d, 0x50, 0xf7, 0x15,
+ 0xa7, 0xff, 0x91, 0x6b, 0x55, 0x66, 0x5f, 0xd5,
+ 0xb7, 0x1d, 0x3f, 0xbf, 0xf5, 0x7b, 0x17, 0xc7,
+ 0x4f, 0xeb, 0xf9, 0xb7, 0xae, 0xf5, 0x2a, 0x4c,
+ 0x3a, 0x7e, 0xcf, 0xe9, 0x15, 0x77, 0x8f, 0x17,
+ 0x79, 0xac, 0x62, 0x61, 0x7e, 0x4d, 0xab, 0xbc,
+ 0xf0, 0xeb, 0x4b, 0xce, 0x9f, 0xdf, 0x7f, 0xf1,
+ 0x8a, 0x87, 0x4e, 0x66, 0xd8, 0x74, 0x29, 0xf8,
+ 0x61, 0x1f, 0x18, 0xce, 0xbf, 0xa8, 0x3a, 0x7f,
+ 0xda, 0xde, 0xbb, 0xc4, 0x0c, 0xf5, 0x4e, 0x9f,
+ 0xf9, 0x7f, 0xd6, 0x50, 0x38, 0x6b, 0x52, 0xa3,
+ 0x64, 0x42, 0x31, 0x0a, 0x7d, 0x6f, 0x7a, 0x9a,
+ 0x9d, 0x05, 0x4f, 0xd5, 0xde, 0xa2, 0xac, 0x2a,
+ 0x0a, 0x82, 0xa0, 0xa8, 0x2a, 0x1e, 0x7b, 0xfe,
+ 0x0a, 0x01, 0x6e, 0xa1, 0x5b, 0x81, 0x4d, 0xe1,
+ 0x53, 0x5b, 0x0a, 0x9f, 0xbb, 0xae, 0xd2, 0xb0,
+ 0xad, 0x05, 0xac, 0x9b, 0xb2, 0xa0, 0xa8, 0x2a,
+ 0x1e, 0x5a, 0x78, 0x2a, 0x0a, 0x82, 0xa0, 0xa8,
+ 0x2a, 0x0a, 0x82, 0xa2, 0x83, 0x79, 0xb0, 0x57,
+ 0x82, 0x80, 0x15, 0x50, 0xa6, 0xc1, 0x50, 0x54,
+ 0x15, 0x0f, 0x2d, 0x2a, 0x15, 0x05, 0x41, 0x50,
+ 0x54, 0x15, 0x0f, 0x35, 0x00, 0x0a, 0xb8, 0x53,
+ 0x78, 0x54, 0x15, 0x05, 0x41, 0x50, 0x54, 0x50,
+ 0x6a, 0x34, 0x85, 0x08, 0x55, 0x82, 0xa5, 0xa4,
+ 0xa8, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0xd8, 0xd4,
+ 0x52, 0x14, 0x00, 0xad, 0x42, 0xa0, 0xa8, 0x2a,
+ 0x0a, 0x9f, 0x59, 0x41, 0x5c, 0x2a, 0x0a, 0x87,
+ 0x9e, 0x72, 0x05, 0x58, 0x2b, 0x82, 0x80, 0x4d,
+ 0x24, 0x2a, 0x0a, 0x82, 0xa0, 0xa8, 0x2a, 0x1e,
+ 0x6a, 0x29, 0x0a, 0xf0, 0x53, 0x60, 0xa8, 0x2a,
+ 0x0a, 0x82, 0xa0, 0xa8, 0x79, 0xa8, 0xd8, 0x2a,
+ 0xc1, 0x5f, 0x0a, 0x95, 0x8a, 0x82, 0xa0, 0xa9,
+ 0x3c, 0xa8, 0x2a, 0x92, 0xc2, 0x0a, 0x82, 0xa0,
+ 0xa8, 0x2a, 0x28, 0x3e, 0x67, 0x85, 0x69, 0x1a,
+ 0x41, 0xa6, 0x82, 0x80, 0x15, 0x70, 0xa9, 0x61,
+ 0x50, 0x54, 0x15, 0x27, 0x95, 0x05, 0x52, 0x58,
+ 0x41, 0x50, 0x54, 0x29, 0xe9, 0x3c, 0x2b, 0xc3,
+ 0x42, 0x34, 0xc0, 0xa8, 0x2a, 0x0a, 0x82, 0xa0,
+ 0xa8, 0x2a, 0x14, 0xd9, 0x52, 0x14, 0x21, 0x4c,
+ 0x0a, 0xf8, 0x54, 0x15, 0x05, 0x41, 0x50, 0x25,
+ 0xf5, 0x42, 0xae, 0x15, 0x05, 0x41, 0x50, 0x54,
+ 0x30, 0xbe, 0xf8, 0x55, 0xc2, 0xa4, 0xc2, 0xa0,
+ 0xa8, 0x2a, 0x00, 0x5a, 0x6a, 0x15, 0x05, 0x41,
+ 0x50, 0x54, 0x15, 0x0a, 0x6a, 0x1a, 0x0a, 0xb0,
+ 0x56, 0xa1, 0x50, 0xab, 0xf5, 0xb4, 0x39, 0x3c,
+ 0xf7, 0x62, 0x9c, 0x5c, 0x46, 0xda, 0x52, 0x3c,
+ 0xcd, 0xbb, 0x3d, 0x68, 0xe8, 0x61, 0x18, 0xc4,
+ 0x7b, 0x1b, 0xf3, 0x30, 0x0f, 0x3e, 0xed, 0x56,
+ 0x6b, 0xb0, 0xea, 0xf2, 0xd9, 0x94, 0x29, 0x5b,
+ 0x85, 0xbb, 0xc9, 0x1b, 0xd2, 0x67, 0xcf, 0xfa,
+ 0xe5, 0x4a, 0x72, 0x6a, 0xf3, 0xbc, 0xac, 0x2a,
+ 0x7b, 0xc9, 0xc2, 0x74, 0xef, 0x6d, 0x87, 0x4e,
+ 0x5d, 0xee, 0xa5, 0x11, 0xe2, 0x73, 0x61, 0xbb,
+ 0x8f, 0xcf, 0xeb, 0x78, 0x3b, 0x0a, 0xd0, 0x74,
+ 0x52, 0x88, 0x46, 0x94, 0x26, 0x02, 0x9d, 0x3f,
+ 0x0f, 0x7f, 0x7a, 0x80, 0xe9, 0xb8, 0x4e, 0x97,
+ 0x8e, 0x42, 0xd2, 0x48, 0x74, 0x98, 0x74, 0xec,
+ 0xdc, 0x77, 0x91, 0x26, 0x22, 0xb6, 0x41, 0xe1,
+ 0xed, 0xe1, 0xf3, 0xff, 0xed, 0x57, 0x47, 0x08,
+ 0xf0, 0x15, 0xc1, 0x08, 0x4e, 0x87, 0xb3, 0x66,
+ 0xf6, 0x85, 0x02, 0x16, 0x7a, 0x14, 0x2d, 0x12,
+ 0x75, 0x2a, 0x7f, 0xf0, 0xb8, 0xba, 0xf4, 0xfe,
+ 0x5f, 0xdf, 0xbf, 0xae, 0x1d, 0x3f, 0x3f, 0xfe,
+ 0x7d, 0xb0, 0xe9, 0xf5, 0x1e, 0x15, 0x79, 0xd0,
+ 0x27, 0xa9, 0xf2, 0xd9, 0xff, 0x59, 0x44, 0x1f,
+ 0xc0, 0xf0, 0x0e, 0x9d, 0x98, 0xd1, 0xd2, 0xcb,
+ 0x1e, 0xb8, 0x0f, 0x27, 0x98, 0xb9, 0x41, 0xd3,
+ 0xec, 0x6d, 0xf5, 0xa4, 0xe8, 0xf1, 0xe5, 0x54,
+ 0x86, 0x79, 0x7f, 0x74, 0x3a, 0x4b, 0x89, 0x95,
+ 0xfd, 0xe2, 0xee, 0x3b, 0x84, 0x53, 0xda, 0xf0,
+ 0xbc, 0xe9, 0xe5, 0xd5, 0xbb, 0xa9, 0x53, 0xe7,
+ 0xb8, 0x21, 0x09, 0xd1, 0xf3, 0xcf, 0xd4, 0x9e,
+ 0x36, 0x44, 0x9e, 0x38, 0x43, 0x15, 0x56, 0x02,
+ 0x3b, 0x1d, 0x61, 0xb1, 0x3f, 0x0e, 0xa0, 0xcf,
+ 0xa1, 0xd3, 0xfd, 0x47, 0xf1, 0xf6, 0xc0, 0x54,
+ 0xe9, 0xed, 0xb6, 0x56, 0xc7, 0x4f, 0xff, 0x96,
+ 0xca, 0xc4, 0x5b, 0xe0, 0xa7, 0x72, 0x1a, 0x2f,
+ 0x89, 0xfc, 0x1e, 0xbd, 0x57, 0x28, 0x3a, 0x7f,
+ 0xfe, 0xcb, 0xef, 0x7a, 0xb6, 0xf7, 0xc0, 0x3e,
+ 0x56, 0x61, 0x53, 0x5f, 0x0e, 0x9f, 0x0f, 0xa8,
+ 0xe6, 0x1a, 0x61, 0x39, 0xeb, 0xea, 0xbc, 0x69,
+ 0x84, 0xe6, 0x02, 0x9a, 0x81, 0x39, 0xfd, 0xfe,
+ 0xd3, 0x75, 0x10, 0x1a, 0x81, 0x39, 0xfd, 0x5c,
+ 0xb7, 0xab, 0xad, 0x06, 0x98, 0x4e, 0x6c, 0xd8,
+ 0xd3, 0x09, 0xcc, 0x10, 0x9e, 0x61, 0x38, 0xc4,
+ 0xd3, 0x29, 0x34, 0xf1, 0x73, 0x08, 0xaa, 0x80,
+ 0xd9, 0x08, 0x24, 0x72, 0xb9, 0x66, 0x13, 0x38,
+ 0xf9, 0xe5, 0xea, 0x53, 0xf7, 0x0c, 0x79, 0x11,
+ 0x55, 0x50, 0xb7, 0x94, 0xa9, 0x0a, 0xae, 0x73,
+ 0x63, 0x94, 0x25, 0xb2, 0xdd, 0xe5, 0x5b, 0xcf,
+ 0xb6, 0xc1, 0xf6, 0x93, 0xa7, 0xdf, 0xcd, 0xf8,
+ 0xd1, 0xd3, 0xfd, 0x6e, 0x65, 0xbc, 0xb4, 0xbc,
+ 0xe9, 0xfb, 0x7f, 0xdf, 0xb9, 0xd4, 0x1d, 0x1e,
+ 0x3e, 0xc0, 0x1c, 0xc7, 0xd1, 0x6f, 0x78, 0x4a,
+ 0xc2, 0xae, 0x91, 0x64, 0xbc, 0x8f, 0x29, 0x74,
+ 0x38, 0x27, 0xff, 0x32, 0xf5, 0xf7, 0xe9, 0x7d,
+ 0xfd, 0x5f, 0x1d, 0x3f, 0xff, 0xbf, 0x94, 0xe5,
+ 0x7b, 0xf6, 0xf2, 0xde, 0xda, 0xf3, 0x0e, 0x9f,
+ 0xbf, 0xab, 0x3d, 0x65, 0x3a, 0x7f, 0xfd, 0xdf,
+ 0xbf, 0x75, 0xbe, 0xb7, 0xa8, 0x72, 0xc7, 0x4e,
+ 0x1a, 0xd4, 0xf1, 0x01, 0xcf, 0xff, 0x6f, 0x15,
+ 0xb2, 0xe8, 0xc1, 0x4e, 0xe4, 0x34, 0x40, 0x6e,
+ 0x35, 0x10, 0x04, 0x72, 0xdd, 0xee, 0x31, 0x33,
+ 0x6f, 0x46, 0x27, 0x3f, 0xff, 0xb9, 0xf9, 0x5f,
+ 0x08, 0xf9, 0x9b, 0xef, 0x6c, 0x0d, 0xce, 0x9f,
+ 0xff, 0xee, 0x7e, 0x7d, 0xa7, 0xe5, 0x2f, 0xde,
+ 0xa0, 0x70, 0x42, 0x12, 0xa2, 0xc8, 0xcb, 0xfb,
+ 0x0c, 0xfe, 0x5c, 0x14, 0xee, 0x43, 0x44, 0x13,
+ 0x3f, 0xcb, 0x7c, 0x14, 0xee, 0x43, 0x45, 0xf3,
+ 0x3e, 0xf3, 0x6f, 0xe5, 0x76, 0x3f, 0xa4, 0x3a,
+ 0x9f, 0xf5, 0x1d, 0x4e, 0xe6, 0x5f, 0xfc, 0xd8,
+ 0xe9, 0xc1, 0x08, 0x4a, 0x9f, 0xaf, 0x6c, 0x4e,
+ 0x12, 0x9c, 0x5e, 0x45, 0x08, 0x99, 0xfb, 0x04,
+ 0xff, 0xd4, 0x31, 0x69, 0xaf, 0xf2, 0x8d, 0xef,
+ 0x3a, 0x7f, 0xfb, 0x7d, 0x3f, 0xd0, 0x96, 0xf0,
+ 0x00, 0xa2, 0xf3, 0xa7, 0x04, 0x21, 0x2a, 0x7f,
+ 0x6f, 0x02, 0xff, 0x29, 0xb9, 0x4e, 0x2f, 0x27,
+ 0xff, 0xe6, 0xef, 0x42, 0x5b, 0xdb, 0x6d, 0x81,
+ 0xd1, 0x7a, 0xe5, 0x07, 0x4b, 0xac, 0x8a, 0xbd,
+ 0x51, 0x21, 0xea, 0xa2, 0xfd, 0x0d, 0xa1, 0x24,
+ 0x62, 0x4d, 0xe3, 0x1b, 0x9f, 0x5b, 0x2e, 0xd3,
+ 0xce, 0x9f, 0xf6, 0x5d, 0x46, 0xb6, 0x5f, 0xdc,
+ 0xf1, 0x04, 0x4f, 0xe5, 0xc1, 0x4e, 0xe4, 0x34,
+ 0x41, 0x0e, 0x3c, 0x99, 0xfb, 0xac, 0x23, 0xe0,
+ 0x9d, 0x3f, 0x6e, 0xf6, 0x0f, 0x7d, 0xe7, 0x47,
+ 0xcf, 0x77, 0x52, 0xb8, 0xb2, 0x67, 0x80, 0x71,
+ 0xfc, 0x2a, 0x27, 0xf9, 0x7f, 0x7d, 0xf9, 0x6e,
+ 0xa4, 0xe9, 0xff, 0xee, 0x0d, 0xf2, 0xcb, 0xeb,
+ 0xff, 0x2d, 0xe3, 0xa1, 0xe8, 0x88, 0xf9, 0xd4,
+ 0xfe, 0xbe, 0xf6, 0x54, 0x3d, 0x49, 0xd3, 0xde,
+ 0x6b, 0xc1, 0x3a, 0x7f, 0xfd, 0xad, 0x1f, 0x5c,
+ 0xb3, 0x96, 0xf9, 0x6d, 0x44, 0xe9, 0xf6, 0x5e,
+ 0xbb, 0xeb, 0xb1, 0xfc, 0xef, 0x23, 0x9f, 0x92,
+ 0xde, 0xdc, 0xf6, 0x93, 0xa7, 0xe6, 0x2e, 0xee,
+ 0xd9, 0x41, 0xd3, 0xff, 0xff, 0xde, 0xbf, 0x33,
+ 0xbe, 0x07, 0xfa, 0xba, 0xb2, 0xde, 0x5b, 0xdb,
+ 0x5e, 0x61, 0xd1, 0xb2, 0x38, 0xfc, 0x65, 0xc6,
+ 0x33, 0x87, 0x7d, 0x4e, 0x9f, 0xf7, 0x7d, 0x30,
+ 0x53, 0xb9, 0x0d, 0x10, 0x8c, 0x29, 0xf1, 0x6a,
+ 0x3b, 0x3f, 0xf9, 0x72, 0x9d, 0xf7, 0xf7, 0xf5,
+ 0x7e, 0x54, 0xe9, 0xff, 0xee, 0xea, 0x37, 0xe5,
+ 0xb9, 0x8e, 0x08, 0x42, 0x74, 0xb3, 0x64, 0x4f,
+ 0x34, 0x9b, 0x38, 0x21, 0x09, 0x53, 0xfd, 0x80,
+ 0xe1, 0xc6, 0xd9, 0xb1, 0x4e, 0x2f, 0x26, 0x08,
+ 0x4a, 0x9c, 0x10, 0x84, 0xa9, 0xfb, 0xa8, 0xda,
+ 0xcb, 0x52, 0x9c, 0x5e, 0x47, 0xd1, 0x6c, 0x14,
+ 0x7d, 0xc3, 0x29, 0xf2, 0x7b, 0x6d, 0xec, 0x29,
+ 0xc6, 0xce, 0x70, 0x42, 0x12, 0xa7, 0x55, 0x44,
+ 0xa7, 0x17, 0x92, 0x07, 0x8f, 0xfe, 0xea, 0xd3,
+ 0xf6, 0xdf, 0x57, 0xf2, 0x1d, 0x3f, 0xb7, 0x8e,
+ 0xde, 0x6c, 0xbb, 0x1d, 0x3f, 0xaf, 0x6c, 0x6d,
+ 0x97, 0xa9, 0xd0, 0x28, 0x98, 0xb1, 0x67, 0xce,
+ 0x21, 0x51, 0xdf, 0x90, 0xc0, 0x9d, 0x4e, 0xeb,
+ 0x9b, 0xa9, 0xd3, 0xff, 0xb3, 0x77, 0xdf, 0x06,
+ 0x22, 0xd9, 0x58, 0x74, 0xfc, 0x9e, 0xad, 0xbc,
+ 0xd1, 0x53, 0xfb, 0xf9, 0x4b, 0xeb, 0xed, 0x27,
+ 0x4f, 0x77, 0x0e, 0x93, 0xa3, 0x41, 0xeb, 0xd0,
+ 0x6d, 0x3c, 0xbc, 0xc6, 0xc5, 0x4e, 0x08, 0x42,
+ 0x54, 0xff, 0xf6, 0xf5, 0x06, 0x67, 0xef, 0x6f,
+ 0x2f, 0xe8, 0x29, 0xc5, 0xe4, 0xb1, 0x11, 0x3c,
+ 0xc3, 0xe8, 0x54, 0xf9, 0x1e, 0x57, 0x4a, 0x57,
+ 0xa1, 0x0b, 0x68, 0x61, 0xcf, 0xff, 0x99, 0x88,
+ 0xbf, 0xeb, 0xd7, 0x6d, 0x78, 0x5e, 0x74, 0xf9,
+ 0x6f, 0x56, 0xd8, 0x74, 0x29, 0xfe, 0x5d, 0x52,
+ 0x7f, 0xfb, 0xcd, 0xb3, 0xfb, 0x7f, 0x83, 0x9f,
+ 0xed, 0x27, 0x4f, 0xff, 0xf6, 0xd6, 0xf0, 0x71,
+ 0xbf, 0xcc, 0xeb, 0xd7, 0x57, 0xe5, 0x37, 0x3a,
+ 0x31, 0x18, 0x1c, 0xa7, 0x0a, 0xd9, 0x0a, 0xd0,
+ 0x9a, 0xf8, 0xe5, 0xf6, 0x87, 0xa6, 0x4b, 0x28,
+ 0xf4, 0x72, 0x4d, 0x42, 0xf8, 0x48, 0xd9, 0x0a,
+ 0xfb, 0x46, 0x4e, 0x08, 0x49, 0x7e, 0x18, 0x15,
+ 0x95, 0x3b, 0x79, 0x41, 0x5a, 0xc3, 0x44, 0x30,
+ 0xe1, 0x9c, 0xd9, 0x7e, 0x74, 0xff, 0xf6, 0x7d,
+ 0xd7, 0xd3, 0xea, 0x6b, 0x6c, 0x07, 0x1d, 0x2a,
+ 0x5e, 0x7d, 0xfb, 0x0e, 0xcf, 0xd6, 0x6b, 0xd6,
+ 0xf3, 0x0e, 0x9f, 0xf7, 0xd6, 0xf6, 0xe0, 0x75,
+ 0x35, 0x3a, 0x73, 0x5a, 0x89, 0xd3, 0xfe, 0xef,
+ 0x0e, 0x52, 0xe0, 0x84, 0x27, 0x47, 0x1e, 0xdd,
+ 0x47, 0x67, 0xff, 0xbe, 0xaf, 0xd1, 0xbe, 0xfe,
+ 0xfe, 0xaf, 0xca, 0x9d, 0x18, 0x99, 0xf2, 0x17,
+ 0xda, 0x13, 0x20, 0x21, 0x9f, 0xcb, 0xf7, 0xff,
+ 0x30, 0x07, 0x4f, 0xe7, 0xe0, 0xd7, 0xeb, 0x41,
+ 0xd3, 0xff, 0xca, 0xd9, 0x45, 0xdb, 0xef, 0xfc,
+ 0xa3, 0xc2, 0x7b, 0xbd, 0xe7, 0xff, 0xb2, 0xeb,
+ 0xf4, 0xcb, 0xdb, 0xc2, 0x04, 0x3a, 0x7d, 0xd5,
+ 0xcf, 0xdc, 0xe9, 0xd7, 0xed, 0xd9, 0xd3, 0xfa,
+ 0xf6, 0xf3, 0x81, 0xde, 0x3a, 0x28, 0x4c, 0x8f,
+ 0x65, 0xff, 0xa6, 0x5c, 0x9b, 0x51, 0xf9, 0xfd,
+ 0xa8, 0x16, 0xde, 0xe7, 0x9d, 0x3f, 0xff, 0x7f,
+ 0x2b, 0xae, 0x8c, 0xb7, 0x7f, 0x1a, 0x7a, 0xd2,
+ 0x74, 0xff, 0xb2, 0xba, 0xe0, 0xa7, 0x72, 0x1a,
+ 0x20, 0x69, 0xf6, 0x5e, 0xdc, 0xfd, 0x08, 0xa5,
+ 0xfa, 0xf4, 0xff, 0xff, 0xfd, 0x97, 0xb7, 0x7f,
+ 0x4e, 0x8a, 0x8f, 0x75, 0xdb, 0x66, 0xda, 0x31,
+ 0x9d, 0xfa, 0x5e, 0x78, 0x82, 0xe7, 0xfd, 0xdd,
+ 0xa5, 0x3b, 0x6d, 0x1a, 0x42, 0x78, 0x82, 0xe7,
+ 0xfe, 0xb7, 0xad, 0xe5, 0xfd, 0xf4, 0x69, 0x09,
+ 0xe2, 0x0b, 0x9f, 0xcb, 0xef, 0xdf, 0x46, 0x90,
+ 0x9e, 0x20, 0xb9, 0xf9, 0x99, 0xb6, 0x8d, 0x21,
+ 0x3c, 0x41, 0x73, 0xff, 0xfd, 0xdf, 0xff, 0x99,
+ 0xa2, 0xa9, 0x6f, 0x0f, 0xb4, 0xd1, 0x81, 0x3c,
+ 0x41, 0x73, 0x53, 0xa3, 0x64, 0xe8, 0x51, 0x40,
+ 0x55, 0xb9, 0x13, 0xe7, 0xf1, 0x65, 0x52, 0xdf,
+ 0x94, 0x7d, 0x3d, 0xc2, 0x0e, 0x3a, 0x7f, 0xeb,
+ 0x7a, 0xde, 0x5f, 0xdf, 0x46, 0x90, 0x9e, 0x20,
+ 0xb9, 0xfe, 0x6a, 0xa9, 0xea, 0x34, 0x69, 0x09,
+ 0xe2, 0x0b, 0x9f, 0x5e, 0xaa, 0xcd, 0x08, 0x8a,
+ 0x2d, 0xea, 0xd3, 0xff, 0xb4, 0x25, 0xbc, 0x8b,
+ 0x7a, 0xe8, 0xd2, 0x13, 0xc4, 0x17, 0x3f, 0xff,
+ 0xf7, 0xff, 0xe6, 0x68, 0xd7, 0x34, 0x55, 0x2d,
+ 0xe1, 0xf6, 0x9a, 0x30, 0x27, 0x88, 0x2e, 0x31,
+ 0x32, 0x6a, 0x50, 0xf9, 0x72, 0x7f, 0xad, 0xe1,
+ 0xf6, 0x9a, 0x30, 0x27, 0x88, 0x2e, 0x7f, 0xfb,
+ 0xba, 0x97, 0xd6, 0xde, 0xdb, 0x65, 0x15, 0x2a,
+ 0x7f, 0xd8, 0xf7, 0xeb, 0x51, 0xfd, 0x1b, 0x87,
+ 0x88, 0x2e, 0x11, 0x1d, 0x02, 0x91, 0x55, 0x09,
+ 0xff, 0x27, 0x86, 0xfc, 0x0a, 0xe8, 0x09, 0xe2,
+ 0x0b, 0x9f, 0xad, 0xeb, 0x5b, 0xc0, 0x34, 0x01,
+ 0x73, 0xec, 0x06, 0x8d, 0x21, 0x3c, 0x41, 0x73,
+ 0x65, 0xd0, 0xfc, 0xec, 0x77, 0x14, 0xa3, 0xae,
+ 0xb0, 0xbf, 0x9f, 0x99, 0x9b, 0x68, 0xd2, 0x13,
+ 0xc4, 0x17, 0x3f, 0xe4, 0xb7, 0x87, 0xda, 0x68,
+ 0xc0, 0x9e, 0x20, 0xb9, 0xb3, 0x47, 0x22, 0x32,
+ 0xa7, 0xf3, 0xfb, 0x5f, 0x33, 0xbf, 0x4b, 0xcf,
+ 0x10, 0x5c, 0xff, 0xb3, 0xcd, 0xb3, 0xf9, 0xb7,
+ 0x3c, 0xf1, 0x05, 0xb0, 0xf0, 0xa3, 0x65, 0xdc,
+ 0x70, 0x16, 0x7e, 0x3e, 0x7a, 0xc6, 0x31, 0x78,
+ 0xc6, 0x75, 0x85, 0xa8, 0x5c, 0x67, 0xc0, 0xa8,
+ 0x00, 0xa6, 0x88, 0x2d, 0xc8, 0x80, 0x9f, 0xf6,
+ 0x3e, 0xdc, 0xf6, 0xf6, 0xfd, 0x68, 0x3a, 0x7f,
+ 0x0f, 0xf3, 0x6b, 0x6a, 0x13, 0xa7, 0xd4, 0xdf,
+ 0x84, 0x07, 0x4f, 0xd9, 0x47, 0x59, 0x77, 0x67,
+ 0x47, 0x91, 0x17, 0xc6, 0x9f, 0x27, 0x9d, 0xc3,
+ 0x41, 0xd3, 0x01, 0x4e, 0x9e, 0xf2, 0xb3, 0x0e,
+ 0x83, 0xa7, 0xee, 0xd3, 0x75, 0x10, 0x1d, 0x1b,
+ 0x1b, 0x7f, 0x85, 0x4f, 0xff, 0xe5, 0xf6, 0xdf,
+ 0x5d, 0x52, 0xf8, 0x9b, 0x2a, 0x6f, 0x61, 0xd3,
+ 0x01, 0x4e, 0x99, 0x74, 0x9d, 0x3f, 0xd9, 0x7a,
+ 0xab, 0x37, 0xe3, 0x47, 0x4f, 0xea, 0xe5, 0xbd,
+ 0x5d, 0x68, 0x3a, 0x60, 0x84, 0xa9, 0xfe, 0xfe,
+ 0x36, 0xe7, 0xd7, 0xdb, 0x1d, 0x08, 0x9f, 0xbf,
+ 0x86, 0xc4, 0x55, 0x8a, 0xf6, 0x22, 0x03, 0x13,
+ 0x76, 0x2b, 0xf1, 0x7a, 0x9d, 0x04, 0xd7, 0x78,
+ 0xb4, 0xe0, 0x84, 0x25, 0x49, 0x85, 0x38, 0xbc,
+ 0x9f, 0x73, 0x5d, 0xc2, 0x53, 0x91, 0xb3, 0xbe,
+ 0x17, 0x53, 0xfa, 0x9b, 0xae, 0x5b, 0x28, 0x3a,
+ 0x15, 0xb2, 0x07, 0xc8, 0xda, 0x34, 0xa0, 0xd2,
+ 0x63, 0xe8, 0xd5, 0x45, 0x3a, 0xd0, 0xd8, 0xea,
+ 0x48, 0xf7, 0xd1, 0xab, 0x0d, 0x1d, 0x65, 0x7f,
+ 0xb6, 0x4b, 0x9e, 0xc4, 0x5b, 0x9d, 0x3d, 0x8c,
+ 0xcb, 0x9d, 0x3d, 0xd4, 0x6f, 0x79, 0xd0, 0xa7,
+ 0xc7, 0x48, 0xfb, 0x79, 0x04, 0xfd, 0xfd, 0x76,
+ 0x67, 0x3c, 0xe9, 0xff, 0xea, 0x5f, 0xf5, 0xd0,
+ 0xcf, 0xae, 0x9b, 0xfa, 0x83, 0xa7, 0xf5, 0x6e,
+ 0xdb, 0x3f, 0x9b, 0x1d, 0x0a, 0x8b, 0xaf, 0x17,
+ 0xf2, 0xb4, 0xee, 0xd1, 0xbc, 0xe9, 0xff, 0xef,
+ 0xbf, 0x46, 0x6d, 0xea, 0xd3, 0x7d, 0x7a, 0xa7,
+ 0x46, 0x83, 0xf4, 0xc1, 0xf9, 0xfa, 0x86, 0x9e,
+ 0xdc, 0x1a, 0x0e, 0x99, 0xf4, 0x1d, 0x3e, 0xb6,
+ 0x79, 0xf5, 0x3a, 0x7f, 0xfa, 0xcb, 0xbd, 0xd7,
+ 0xff, 0x02, 0xb5, 0x50, 0x15, 0x3f, 0x81, 0x82,
+ 0x9d, 0xc8, 0x78, 0x81, 0x21, 0xe8, 0xb3, 0xd8,
+ 0x9c, 0x54, 0x66, 0x6f, 0x79, 0xd3, 0xd7, 0xa3,
+ 0xbe, 0x74, 0xf5, 0x35, 0xeb, 0x9d, 0x14, 0x1e,
+ 0xee, 0x0c, 0xd8, 0x8a, 0x7f, 0x7f, 0x83, 0x5a,
+ 0xa8, 0x0e, 0x9c, 0x10, 0x84, 0xf8, 0x7d, 0x4e,
+ 0xef, 0xec, 0x5c, 0x3e, 0x8e, 0x35, 0x31, 0xb2,
+ 0x25, 0x40, 0xb7, 0x3f, 0xfe, 0xcf, 0xfb, 0x4b,
+ 0xab, 0x7b, 0x6b, 0xcf, 0x7a, 0x9d, 0x14, 0x1f,
+ 0xe6, 0x92, 0x48, 0xdd, 0x4a, 0xbc, 0x1e, 0x69,
+ 0x90, 0xca, 0xf4, 0x23, 0x7a, 0x34, 0x09, 0xf7,
+ 0xae, 0xb7, 0xa9, 0x53, 0xc8, 0xb7, 0xa9, 0x53,
+ 0x04, 0x25, 0x43, 0xcf, 0x77, 0x09, 0xc2, 0x41,
+ 0x36, 0x04, 0xa7, 0x1a, 0xe9, 0xff, 0xf6, 0x5d,
+ 0x53, 0x33, 0xf7, 0xb7, 0x97, 0xf4, 0x1d, 0x00,
+ 0x3f, 0x80, 0x92, 0xcf, 0xff, 0xe5, 0x6d, 0xef,
+ 0x83, 0x45, 0xeb, 0x89, 0x6e, 0xfd, 0xea, 0x74,
+ 0xfe, 0x6a, 0x97, 0xdb, 0x55, 0x13, 0xa7, 0x3f,
+ 0x84, 0xe9, 0xf3, 0xf2, 0xf9, 0xb1, 0x52, 0xf3,
+ 0x47, 0x83, 0x71, 0xa9, 0x80, 0xa7, 0x4c, 0x05,
+ 0x3a, 0x7e, 0xfe, 0xaf, 0xcf, 0xbb, 0xc6, 0xa8,
+ 0x02, 0xb3, 0xff, 0x5e, 0xd8, 0xcd, 0xea, 0x0c,
+ 0xa6, 0xe7, 0x4f, 0xea, 0x53, 0xc3, 0xbd, 0x76,
+ 0x3a, 0x78, 0x0c, 0xe7, 0xd4, 0xfe, 0xee, 0x8d,
+ 0x3b, 0x73, 0x29, 0x3a, 0x14, 0xf6, 0x38, 0xe6,
+ 0x7a, 0xba, 0xd3, 0x73, 0xa7, 0x04, 0x21, 0x2a,
+ 0x7d, 0x9a, 0x7f, 0xad, 0x4a, 0x71, 0x79, 0x3e,
+ 0xc7, 0x04, 0x21, 0x3a, 0x14, 0xf8, 0x2e, 0x73,
+ 0x3c, 0x1e, 0xfb, 0xce, 0x99, 0x2c, 0x74, 0xe0,
+ 0x84, 0x25, 0x4f, 0xde, 0xed, 0x36, 0xf5, 0xca,
+ 0x71, 0x79, 0x3e, 0xc0, 0x66, 0x34, 0x74, 0xab,
+ 0xa1, 0x12, 0xa2, 0x63, 0xf3, 0xe9, 0xef, 0x7f,
+ 0x57, 0xec, 0x8e, 0xdc, 0x85, 0xb4, 0x2a, 0xe3,
+ 0xb3, 0xc8, 0xb1, 0x93, 0x4b, 0xb0, 0xa9, 0xda,
+ 0x31, 0x8e, 0x20, 0xac, 0x28, 0x2f, 0x18, 0x74,
+ 0xfc, 0xac, 0x11, 0xeb, 0x9d, 0x3f, 0xfd, 0xe6,
+ 0x52, 0xfa, 0xe8, 0xcf, 0xff, 0x3c, 0x03, 0xa2,
+ 0xc7, 0xfb, 0x72, 0xa9, 0x39, 0xba, 0x42, 0x19,
+ 0xe5, 0x65, 0x76, 0xd1, 0x19, 0x1b, 0xe5, 0x26,
+ 0xed, 0x2c, 0x07, 0x2b, 0x74, 0xad, 0x31, 0xb8,
+ 0xa4, 0x76, 0x54, 0xca, 0xa7, 0xf4, 0x27, 0x5a,
+ 0x9e, 0x7f, 0x19, 0xd3, 0x56, 0x4a, 0x0b, 0xb4,
+ 0xf8, 0x57, 0x53, 0xcb, 0x41, 0x2c, 0xe7, 0xf3,
+ 0xac, 0x15, 0xac, 0x97, 0xaf, 0x59, 0xcf, 0xeb,
+ 0x19, 0xab, 0x68, 0x76, 0x06, 0x14, 0x5b, 0x92,
+ 0xc4, 0xf7, 0xce, 0xec, 0xb7, 0xc6, 0x1b, 0x0e,
+ 0x84, 0x47, 0x03, 0xf1, 0x0d, 0x8b, 0x3f, 0x9d,
+ 0x82, 0x9d, 0xc8, 0x68, 0xb8, 0xe7, 0xf3, 0xb0,
+ 0x53, 0xb9, 0x0d, 0x17, 0x5c, 0xff, 0xce, 0xe7,
+ 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x28, 0xc2, 0xc2,
+ 0x30, 0xd5, 0xe5, 0x1b, 0x1d, 0xe9, 0x3b, 0x43,
+ 0xbf, 0x43, 0xc3, 0x76, 0x81, 0xd8, 0x89, 0x32,
+ 0xa9, 0xc5, 0xce, 0xdb, 0xce, 0xe7, 0xff, 0x39,
+ 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x25, 0xa9,
+ 0xf0, 0xa7, 0x72, 0x1a, 0x23, 0x79, 0xff, 0x73,
+ 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x97, 0xe4, 0xec,
+ 0x3f, 0x66, 0x18, 0x4f, 0xe7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x2a, 0xb9, 0xfe, 0xd3, 0x9f, 0xca, 0x6f,
+ 0xcc, 0x3a, 0x6d, 0xbc, 0x74, 0xfd, 0x82, 0x9d,
+ 0xc8, 0x68, 0x90, 0x23, 0x41, 0xe6, 0x38, 0x5e,
+ 0x7d, 0x5e, 0xff, 0x52, 0x74, 0x3c, 0xf2, 0xe9,
+ 0x24, 0x8d, 0x28, 0xf4, 0xe8, 0x68, 0xcf, 0xfd,
+ 0xfc, 0xa1, 0xdb, 0x8b, 0xff, 0xe5, 0xce, 0x87,
+ 0x1f, 0x80, 0x94, 0xcf, 0xe7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x2c, 0x89, 0xfc, 0xec, 0x14, 0xee, 0x43,
+ 0x45, 0xaf, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
+ 0xb9, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xbb, 0x27,
+ 0xfd, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x8e,
+ 0x93, 0xb0, 0xfd, 0x98, 0x61, 0x3e, 0x14, 0xee,
+ 0x43, 0x45, 0x2b, 0x3f, 0xff, 0xfd, 0x65, 0xa1,
+ 0x6d, 0xe6, 0xdd, 0xb5, 0xbc, 0xe4, 0xb7, 0x9a,
+ 0xb2, 0xd1, 0x87, 0x4f, 0x9c, 0xce, 0x7b, 0xb1,
+ 0x16, 0x4d, 0x18, 0x45, 0x0b, 0x9d, 0xef, 0x86,
+ 0x45, 0x24, 0xfe, 0x8e, 0x7d, 0x84, 0x20, 0x3b,
+ 0xa9, 0xdd, 0xe1, 0x62, 0xda, 0x1b, 0x33, 0xfc,
+ 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x23, 0x89, 0xfe,
+ 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x15, 0xac, 0x9d,
+ 0xc8, 0x82, 0xba, 0x0c, 0xff, 0xe7, 0x33, 0x9e,
+ 0xec, 0x14, 0xee, 0x43, 0x44, 0xb7, 0x36, 0x52,
+ 0x74, 0xfe, 0xdb, 0x18, 0xc5, 0xf5, 0x4e, 0x8a,
+ 0x4f, 0x27, 0xc2, 0xd3, 0xad, 0xb3, 0xce, 0x9c,
+ 0xf6, 0x21, 0xd3, 0xff, 0xf5, 0xba, 0x90, 0x6d,
+ 0x6e, 0x7e, 0x57, 0xfa, 0xf6, 0xf3, 0xa0, 0xd1,
+ 0x0d, 0xcf, 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43,
+ 0x44, 0xc1, 0x38, 0x75, 0x01, 0x53, 0xfb, 0xf9,
+ 0x7b, 0xa8, 0xd4, 0xe9, 0x39, 0x53, 0x64, 0xa0,
+ 0x8f, 0x61, 0xdc, 0x1b, 0x45, 0xf6, 0x0b, 0xdd,
+ 0x1b, 0x78, 0xe4, 0xe6, 0x6a, 0x25, 0x4f, 0xfb,
+ 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xc7, 0x27,
+ 0x78, 0xf8, 0x98, 0x39, 0x3f, 0x2d, 0x74, 0x5f,
+ 0x2c, 0x74, 0xff, 0xff, 0xf3, 0xeb, 0x6c, 0xd4,
+ 0x35, 0xb6, 0x26, 0x57, 0x46, 0x52, 0xfa, 0xfb,
+ 0xfe, 0x3a, 0x79, 0x3b, 0x90, 0xd1, 0x58, 0xcf,
+ 0xfb, 0x73, 0x2f, 0xfc, 0xd5, 0x7f, 0x73, 0xa3,
+ 0x4a, 0x63, 0x74, 0x97, 0x0c, 0x20, 0x6e, 0x57,
+ 0x3f, 0xf9, 0x7f, 0x7d, 0x3a, 0xaf, 0xf1, 0x14,
+ 0x4e, 0x9f, 0xf6, 0x6d, 0x6c, 0xad, 0x2f, 0x5b,
+ 0x1d, 0x3f, 0xec, 0xd8, 0x7d, 0xad, 0x00, 0xab,
+ 0xce, 0x9f, 0xff, 0xfb, 0xfa, 0xd1, 0x89, 0xa3,
+ 0xfa, 0xb7, 0xe8, 0xca, 0x5f, 0x9a, 0xfc, 0x15,
+ 0x3a, 0x7f, 0x6e, 0xaa, 0x1a, 0x7b, 0x70, 0x68,
+ 0x3a, 0x75, 0xbc, 0xec, 0x4f, 0x31, 0x11, 0x6c,
+ 0x93, 0xf3, 0xfb, 0xa0, 0xee, 0x3f, 0x4d, 0xab,
+ 0x47, 0x4f, 0xbb, 0xf4, 0x6b, 0x53, 0xa3, 0xe7,
+ 0x83, 0x51, 0x89, 0xe5, 0x1e, 0xf9, 0xd3, 0xd5,
+ 0xaa, 0x80, 0xe8, 0xb1, 0xe0, 0x04, 0x7e, 0x7c,
+ 0xaf, 0x06, 0xaf, 0x3a, 0x72, 0xfd, 0xe7, 0x43,
+ 0x47, 0x87, 0x72, 0x89, 0xf9, 0x59, 0x9f, 0xf6,
+ 0x93, 0xa5, 0x53, 0xa3, 0xc6, 0xfb, 0x8b, 0xa6,
+ 0x02, 0x95, 0x30, 0x42, 0x54, 0x78, 0xd5, 0x84,
+ 0x56, 0x7f, 0x73, 0xff, 0x97, 0xb7, 0x8a, 0x71,
+ 0xa1, 0x9e, 0xdb, 0xa9, 0xa9, 0xd3, 0x97, 0xed,
+ 0x1d, 0x37, 0xd4, 0xe8, 0x68, 0xd8, 0x88, 0xe4,
+ 0xf0, 0x83, 0x1b, 0xce, 0x9d, 0xbc, 0x74, 0x9d,
+ 0x0a, 0x8b, 0x7c, 0x54, 0xf1, 0x0d, 0x88, 0xe6,
+ 0xb5, 0xce, 0x9c, 0x10, 0x84, 0xa9, 0xff, 0xb1,
+ 0x36, 0x5a, 0x37, 0xe5, 0xba, 0x92, 0x9c, 0x5e,
+ 0x4f, 0x78, 0x5b, 0xf6, 0x3a, 0x42, 0x74, 0xf9,
+ 0x9e, 0xb8, 0x38, 0xe8, 0xa0, 0xf6, 0xf7, 0x64,
+ 0xba, 0x87, 0xcf, 0xe4, 0xf5, 0x7f, 0x8d, 0xb8,
+ 0xe9, 0xb2, 0xe7, 0x45, 0x27, 0x91, 0x63, 0x39,
+ 0xeb, 0xff, 0x1e, 0x74, 0xff, 0xef, 0x56, 0xd9,
+ 0xb7, 0xf1, 0xb7, 0xf2, 0xa7, 0x40, 0x9f, 0x6d,
+ 0xc8, 0x64, 0xe5, 0x5c, 0xd8, 0xd9, 0x8b, 0x19,
+ 0x45, 0x85, 0x8d, 0x96, 0x87, 0xcf, 0x1d, 0xfc,
+ 0xca, 0xb0, 0xb0, 0xbb, 0xee, 0xf8, 0x48, 0x4f,
+ 0x85, 0x3b, 0x90, 0xd1, 0x5b, 0xcf, 0xfb, 0x9e,
+ 0xec, 0x14, 0xee, 0x43, 0x44, 0xe1, 0x27, 0x61,
+ 0xfb, 0x30, 0xc2, 0x7c, 0x29, 0xdc, 0x86, 0x8b,
+ 0x46, 0x7b, 0x1a, 0xf6, 0x93, 0xa4, 0xec, 0x3d,
+ 0x4b, 0x18, 0x4f, 0x27, 0x72, 0x1a, 0x2d, 0xa9,
+ 0xfa, 0xca, 0xc5, 0xf6, 0xc7, 0x4c, 0xec, 0x13,
+ 0xd8, 0xb9, 0x5c, 0xfe, 0x76, 0x0a, 0x77, 0x21,
+ 0xa2, 0xe5, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
+ 0x5d, 0xb0, 0xac, 0xe5, 0x6a, 0x0a, 0x1f, 0x1f,
+ 0xfe, 0xd0, 0xdb, 0xd3, 0x2c, 0x3f, 0xd3, 0xb0,
+ 0x9b, 0xb8, 0xc9, 0x6c, 0xf7, 0xf7, 0xfa, 0x96,
+ 0x5c, 0xee, 0x7f, 0x3b, 0x05, 0x3b, 0x90, 0xd1,
+ 0x53, 0xcf, 0x27, 0x72, 0x1a, 0x2b, 0x99, 0xfc,
+ 0xec, 0x14, 0xee, 0x43, 0x45, 0x9d, 0x02, 0x7c,
+ 0xd6, 0x2b, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0x42,
+ 0x9f, 0xef, 0x53, 0x5b, 0xfd, 0x59, 0x53, 0xa6,
+ 0x7b, 0xb0, 0xfa, 0x80, 0x61, 0x3c, 0xdd, 0x2c,
+ 0xac, 0x3a, 0x7f, 0x65, 0xab, 0x5c, 0x1a, 0x0e,
+ 0x93, 0xb1, 0x31, 0x1e, 0x84, 0x5d, 0x4b, 0x6e,
+ 0x4f, 0x3f, 0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b,
+ 0x90, 0xd1, 0x3e, 0x42, 0x2a, 0x4b, 0xdd, 0xc7,
+ 0x65, 0x64, 0x79, 0xf0, 0xa7, 0x72, 0x1a, 0x2b,
+ 0x29, 0xff, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68,
+ 0x9b, 0xa6, 0xf3, 0xb0, 0xfd, 0x98, 0x61, 0x3e,
+ 0x14, 0xee, 0x43, 0x44, 0xad, 0x3f, 0xda, 0x6d,
+ 0xed, 0x1a, 0xa6, 0x54, 0xe9, 0xf3, 0x99, 0xcf,
+ 0x76, 0x1f, 0x6f, 0x18, 0x4f, 0x85, 0x3b, 0x90,
+ 0xd1, 0x2e, 0x4f, 0xf7, 0xb9, 0xf7, 0xfa, 0xb2,
+ 0xa7, 0x4f, 0x36, 0xf7, 0xd4, 0xe9, 0xf3, 0x99,
+ 0xcf, 0x76, 0x22, 0x2e, 0xc6, 0x1c, 0x71, 0x3f,
+ 0xf3, 0xb9, 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x47,
+ 0x73, 0xfd, 0x7b, 0x63, 0xdd, 0xdf, 0xa9, 0xd3,
+ 0xf3, 0x73, 0xea, 0x99, 0xf3, 0xa7, 0xed, 0xd3,
+ 0xf9, 0x6e, 0xb9, 0xd3, 0xe1, 0x4e, 0xe4, 0x34,
+ 0x54, 0x33, 0xec, 0xb5, 0xf2, 0x83, 0xa7, 0xff,
+ 0xfb, 0x5e, 0xdd, 0xfa, 0x8b, 0x77, 0xae, 0xb6,
+ 0xf5, 0xeb, 0x9b, 0x1d, 0x27, 0x6e, 0x89, 0x92,
+ 0x37, 0x0b, 0xf0, 0xc6, 0xe6, 0x1b, 0x84, 0xf3,
+ 0xe1, 0x4e, 0xe4, 0x34, 0x55, 0x13, 0xfe, 0xe7,
+ 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x35, 0xc9, 0xd8,
+ 0x7e, 0xcc, 0x30, 0x9f, 0xce, 0xc1, 0x4e, 0xe4,
+ 0x34, 0x55, 0x93, 0xff, 0x3b, 0x9e, 0xec, 0x14,
+ 0xee, 0x43, 0x44, 0x89, 0x3e, 0x14, 0xee, 0x43,
+ 0x45, 0xa5, 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9,
+ 0x0d, 0x13, 0xec, 0x9d, 0x87, 0xec, 0xc3, 0x09,
+ 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc, 0x86,
+ 0x8a, 0x12, 0x7d, 0x6f, 0x50, 0xa2, 0x74, 0xf8,
+ 0x53, 0xb9, 0x0d, 0x14, 0x7c, 0xff, 0xfd, 0x9b,
+ 0x59, 0x77, 0xba, 0xff, 0xe0, 0x56, 0xaa, 0x02,
+ 0xa7, 0xce, 0x67, 0x3d, 0xca, 0x8b, 0x4c, 0x27,
+ 0xdc, 0x30, 0x85, 0x5e, 0x2c, 0xa2, 0x19, 0x0f,
+ 0x4b, 0xc4, 0xcd, 0x31, 0xae, 0x24, 0x34, 0xa9,
+ 0x27, 0x68, 0xee, 0xd0, 0xc2, 0x01, 0x3d, 0xe3,
+ 0x06, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x44,
+ 0x53, 0xf6, 0x0a, 0x77, 0x21, 0xa2, 0x2b, 0x9f,
+ 0xed, 0xdb, 0xb0, 0x53, 0xb9, 0x0d, 0x15, 0xc4,
+ 0x38, 0xfe, 0xb8, 0xd6, 0x7b, 0x2d, 0xd7, 0x3a,
+ 0x7f, 0x67, 0x84, 0x00, 0xd6, 0xa7, 0x4b, 0x74,
+ 0xf9, 0xe9, 0xd4, 0x82, 0x7f, 0xee, 0xf3, 0xfd,
+ 0xfb, 0xeb, 0x61, 0xc3, 0xa7, 0xd9, 0xed, 0x87,
+ 0x0e, 0x9d, 0x7a, 0xfa, 0xc7, 0xd5, 0x74, 0x49,
+ 0xf0, 0xa7, 0x72, 0x1a, 0x29, 0xe8, 0x6e, 0x23,
+ 0xed, 0x61, 0x2f, 0x86, 0x93, 0xff, 0xb9, 0xee,
+ 0xdb, 0xfc, 0x1a, 0xd5, 0x40, 0x74, 0x39, 0x10,
+ 0x3b, 0x1b, 0xce, 0x76, 0xd8, 0x74, 0xf9, 0x5e,
+ 0x0d, 0x5e, 0x74, 0xf2, 0x77, 0x21, 0xa2, 0xb3,
+ 0x86, 0x8f, 0x4c, 0x4a, 0x27, 0xea, 0x18, 0xbf,
+ 0x7d, 0x4e, 0x9c, 0xb4, 0x78, 0xe9, 0xf5, 0xc1,
+ 0xbf, 0xef, 0x3a, 0x76, 0xbd, 0x53, 0xa7, 0xd8,
+ 0xd5, 0x1a, 0x80, 0xe9, 0x3b, 0x11, 0xb8, 0x24,
+ 0x56, 0x2e, 0xe1, 0xcf, 0x95, 0x6f, 0x1c, 0x9f,
+ 0xf9, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x24,
+ 0x59, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45, 0x93,
+ 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb6, 0x27,
+ 0x65, 0x70, 0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x2d,
+ 0xb9, 0x39, 0xe7, 0x95, 0x83, 0x53, 0xfe, 0x6e,
+ 0x37, 0x37, 0x5a, 0xf6, 0xcf, 0xa8, 0x0e, 0x9f,
+ 0x97, 0xef, 0xdb, 0x56, 0x1d, 0x3e, 0x14, 0xee,
+ 0x43, 0x45, 0xe1, 0x3d, 0x7d, 0xcc, 0xb1, 0xd3,
+ 0xff, 0x2e, 0xf6, 0x52, 0xfb, 0xe7, 0xef, 0x53,
+ 0xa7, 0xd9, 0xf0, 0x37, 0xa9, 0xd3, 0xe5, 0xdf,
+ 0xaf, 0x54, 0xe9, 0xd7, 0x50, 0x1d, 0x27, 0x6e,
+ 0xbc, 0x9c, 0x25, 0x09, 0xb8, 0x5f, 0x49, 0x85,
+ 0x89, 0x00, 0x8f, 0xf2, 0x9b, 0x94, 0xce, 0xf6,
+ 0x52, 0x74, 0xf8, 0x53, 0xb9, 0x0d, 0x17, 0xa4,
+ 0xff, 0xbf, 0xd7, 0x7a, 0xe9, 0xbf, 0xa8, 0x3a,
+ 0x7d, 0x8c, 0xb7, 0x6c, 0x74, 0x9d, 0xb2, 0x2d,
+ 0x30, 0x73, 0x79, 0x83, 0x7a, 0x0c, 0x2b, 0x22,
+ 0x96, 0x88, 0x5a, 0xe4, 0x7e, 0x08, 0x49, 0xe8,
+ 0xd2, 0xc5, 0x71, 0x89, 0x80, 0x3b, 0xfc, 0x21,
+ 0x75, 0x8e, 0xac, 0x31, 0x9b, 0x4f, 0x65, 0xba,
+ 0xe7, 0x4f, 0xec, 0xf0, 0x80, 0x1a, 0xd4, 0xe9,
+ 0x6e, 0x9f, 0x3d, 0x3a, 0x90, 0x4f, 0x85, 0x3b,
+ 0x90, 0xd1, 0x11, 0xcf, 0xff, 0x5b, 0x5a, 0xd7,
+ 0x19, 0xfc, 0x6d, 0xa1, 0x5b, 0xa9, 0xd3, 0xfe,
+ 0x7a, 0xd0, 0x39, 0x7b, 0xfa, 0xe7, 0x4f, 0xff,
+ 0xf2, 0xdb, 0xbd, 0x75, 0xb7, 0xf2, 0xf6, 0xf5,
+ 0xb3, 0xc1, 0x3a, 0x6a, 0x18, 0x54, 0xc1, 0x09,
+ 0x53, 0xff, 0x3d, 0xc9, 0x6f, 0x35, 0x65, 0xa1,
+ 0xc0, 0x35, 0xa1, 0x17, 0x9f, 0xd9, 0xbb, 0xfe,
+ 0x5b, 0xae, 0x74, 0xff, 0xfc, 0x8e, 0x1e, 0xff,
+ 0xae, 0xe1, 0x5b, 0xff, 0x80, 0x74, 0x37, 0x15,
+ 0x38, 0xe1, 0x6a, 0x18, 0x52, 0xb4, 0x27, 0xdd,
+ 0x09, 0x2b, 0xae, 0xb6, 0x35, 0x9f, 0x0a, 0x77,
+ 0x21, 0xa2, 0x2e, 0x9f, 0x5c, 0x1b, 0xfe, 0xf2,
+ 0xd9, 0xec, 0x93, 0xb0, 0xfa, 0x38, 0xc2, 0x1c,
+ 0x98, 0x4b, 0xe1, 0xc7, 0x3f, 0xf3, 0x39, 0xee,
+ 0xc1, 0x4e, 0xe4, 0x34, 0x4c, 0xd3, 0xa9, 0x5a,
+ 0x9d, 0x39, 0x3c, 0xc3, 0xa7, 0x6e, 0xad, 0xcd,
+ 0xd4, 0x74, 0xf9, 0x3a, 0xde, 0x68, 0xe9, 0xff,
+ 0x9b, 0xfd, 0x7f, 0x27, 0xb6, 0xbe, 0x21, 0xd3,
+ 0xff, 0xfd, 0xaf, 0x7d, 0x3f, 0x9b, 0x5b, 0x5d,
+ 0x16, 0x57, 0x8a, 0xd0, 0x74, 0x62, 0x2c, 0x6c,
+ 0x8f, 0x3f, 0xfe, 0xdb, 0xdf, 0xa3, 0x2b, 0xee,
+ 0xb3, 0x82, 0x10, 0x95, 0x3c, 0x9d, 0xc8, 0x68,
+ 0xb3, 0xe7, 0xfd, 0xeb, 0x2b, 0xfd, 0x75, 0xbd,
+ 0x4e, 0x9f, 0xfe, 0xf0, 0xdb, 0xb4, 0x63, 0x6f,
+ 0xe5, 0x73, 0xe7, 0x4e, 0x08, 0x42, 0x54, 0xff,
+ 0xb9, 0xf5, 0xfe, 0x26, 0xd8, 0x25, 0x38, 0xbc,
+ 0x9f, 0xe5, 0xb7, 0xb6, 0xff, 0x73, 0x47, 0x4f,
+ 0xf7, 0xbf, 0xb6, 0xfd, 0xb5, 0xbd, 0x4e, 0x84,
+ 0x4f, 0xc4, 0x56, 0x18, 0x57, 0x63, 0xe0, 0x36,
+ 0xdd, 0x2d, 0xb1, 0xcc, 0xff, 0xff, 0xfd, 0x98,
+ 0x0a, 0xe6, 0x7f, 0x4e, 0xf1, 0xfa, 0xe5, 0x9d,
+ 0x5f, 0xe5, 0x0c, 0xc6, 0x1d, 0x3a, 0xab, 0x41,
+ 0xd3, 0xb7, 0x32, 0xc7, 0x43, 0xd1, 0x89, 0x58,
+ 0x45, 0x5c, 0x72, 0x7a, 0x90, 0x6a, 0x87, 0x4f,
+ 0xad, 0xf5, 0xc1, 0x32, 0x7f, 0xde, 0x17, 0xe0,
+ 0xd1, 0xaf, 0x6c, 0x68, 0x83, 0x5c, 0x69, 0x67,
+ 0xdc, 0x9e, 0x62, 0x9d, 0x3f, 0x3e, 0xdf, 0xea,
+ 0x6e, 0x74, 0xb1, 0x0f, 0x4f, 0xe4, 0xb3, 0xff,
+ 0xfe, 0xe0, 0xdf, 0x2d, 0x75, 0xcf, 0xd3, 0x7c,
+ 0x1f, 0x51, 0xcc, 0x3a, 0x1e, 0x9a, 0x06, 0x42,
+ 0xbf, 0xe4, 0xd3, 0xf0, 0xe6, 0xd5, 0xb2, 0x9d,
+ 0x3f, 0xff, 0xb5, 0xff, 0x69, 0xd1, 0xbf, 0xfd,
+ 0x7a, 0xfa, 0x9b, 0x78, 0x27, 0x4f, 0xff, 0xf5,
+ 0x6a, 0xa3, 0x75, 0x73, 0x32, 0xf5, 0xdf, 0x5e,
+ 0x7e, 0x1d, 0x3d, 0x6c, 0xf3, 0x63, 0xa3, 0xc8,
+ 0x89, 0xb3, 0x34, 0xcc, 0xdd, 0x0d, 0x17, 0xe4,
+ 0xff, 0xcf, 0xbe, 0xaf, 0x7b, 0x2f, 0x75, 0x61,
+ 0xd3, 0xff, 0x7b, 0x3f, 0x99, 0x5d, 0x0f, 0xab,
+ 0x0e, 0x8a, 0x51, 0x17, 0x54, 0x69, 0xef, 0xfd,
+ 0x50, 0xe8, 0x54, 0xc6, 0xb6, 0x23, 0xc8, 0x59,
+ 0xf1, 0x24, 0xff, 0xff, 0xcd, 0xeb, 0x6f, 0x31,
+ 0xcd, 0x3f, 0x87, 0x7d, 0xbd, 0x4d, 0x53, 0xd4,
+ 0x1d, 0x3f, 0xee, 0x7b, 0x39, 0xf7, 0xaa, 0xe9,
+ 0x3a, 0x7b, 0x2b, 0xef, 0x9d, 0x1f, 0x3e, 0x0d,
+ 0x4f, 0xe7, 0xb7, 0xeb, 0xd5, 0x3a, 0x7f, 0xd7,
+ 0xa8, 0x3d, 0x4d, 0x2f, 0xcb, 0x9d, 0x0a, 0x7c,
+ 0xb8, 0x49, 0x33, 0x5a, 0x9d, 0x26, 0x1d, 0x14,
+ 0x9a, 0x86, 0xec, 0x62, 0x7f, 0xff, 0xd6, 0xf5,
+ 0x37, 0xca, 0x6e, 0x22, 0xb7, 0x06, 0xff, 0xbe,
+ 0xd8, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0x6d, 0xb7,
+ 0x7c, 0xa7, 0x17, 0x93, 0xfe, 0xeb, 0x27, 0xbb,
+ 0x45, 0x7a, 0xc7, 0x42, 0xa6, 0x44, 0x84, 0xfe,
+ 0x84, 0x5d, 0x8c, 0xa7, 0xfe, 0xcf, 0xd3, 0x7c,
+ 0x1f, 0x51, 0xcc, 0x3a, 0x7d, 0x97, 0x7b, 0x2c,
+ 0x74, 0x29, 0xf5, 0xd5, 0x12, 0x60, 0x58, 0xe9,
+ 0xfa, 0x86, 0x9e, 0xdc, 0x1a, 0x0e, 0x9f, 0xda,
+ 0x6d, 0x97, 0xb7, 0xae, 0x74, 0xde, 0x13, 0xa3,
+ 0x75, 0x1f, 0xf7, 0x8d, 0x2c, 0x6b, 0x3f, 0xf6,
+ 0xcb, 0xb0, 0xad, 0xfc, 0x9e, 0xd8, 0xe9, 0xfa,
+ 0xda, 0xd0, 0xd5, 0xbc, 0x74, 0x6c, 0x7e, 0xd6,
+ 0x45, 0x93, 0x9b, 0xa3, 0x37, 0x77, 0x75, 0x87,
+ 0x14, 0x6e, 0x82, 0xbd, 0xa1, 0xb1, 0x92, 0x84,
+ 0xe9, 0x8c, 0xa7, 0xc6, 0xad, 0x47, 0x10, 0x26,
+ 0xac, 0x2c, 0xb4, 0xa0, 0xde, 0x41, 0x04, 0x36,
+ 0xbf, 0x08, 0x8a, 0xc6, 0xd5, 0x78, 0x56, 0x04,
+ 0x87, 0x72, 0x12, 0x9b, 0xe1, 0x57, 0x0e, 0x67,
+ 0xc8, 0x5a, 0x9c, 0x53, 0x3f, 0xf9, 0xcc, 0xe7,
+ 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x36, 0x4f, 0xe7,
+ 0x60, 0xa7, 0x72, 0x1a, 0x2a, 0xd9, 0xfc, 0xf7,
+ 0xeb, 0x7f, 0xab, 0xce, 0x9e, 0xcb, 0x75, 0xce,
+ 0x96, 0xe9, 0x87, 0xa9, 0xf3, 0x49, 0xf0, 0xa7,
+ 0x72, 0x1a, 0x2b, 0x49, 0xff, 0xe4, 0x51, 0xc0,
+ 0x73, 0x39, 0xeb, 0xe4, 0x3a, 0x7f, 0xf9, 0xf5,
+ 0xcf, 0xab, 0x3b, 0x2f, 0x75, 0x61, 0xd3, 0x5e,
+ 0xea, 0x89, 0x7e, 0x4a, 0x9f, 0xca, 0xdb, 0x7d,
+ 0xfe, 0xa0, 0x3a, 0x7e, 0xa3, 0x2d, 0xec, 0x61,
+ 0xd3, 0xfd, 0x8d, 0xff, 0x50, 0xd2, 0xfa, 0x9d,
+ 0x3f, 0x9f, 0x97, 0xef, 0x83, 0x53, 0xa4, 0xe6,
+ 0xe2, 0x7e, 0x58, 0x59, 0xe8, 0x63, 0xd8, 0xb7,
+ 0x8d, 0xbe, 0x5b, 0x73, 0xc9, 0xfc, 0xec, 0x14,
+ 0xee, 0x43, 0x45, 0x81, 0x3e, 0x14, 0xee, 0x43,
+ 0x44, 0xeb, 0x3f, 0xff, 0xac, 0xb4, 0x6d, 0x8c,
+ 0x75, 0x6b, 0x96, 0xf5, 0x75, 0xa0, 0xe9, 0xf3,
+ 0x99, 0xcf, 0x76, 0x22, 0x55, 0xa3, 0x09, 0xf0,
+ 0xa7, 0x72, 0x1a, 0x2d, 0x99, 0xff, 0x01, 0x6a,
+ 0xeb, 0x79, 0x38, 0x4e, 0x93, 0xb0, 0xfb, 0x38,
+ 0xc2, 0x79, 0x3b, 0x90, 0xd1, 0x73, 0x49, 0x87,
+ 0x4c, 0xec, 0x13, 0x76, 0x12, 0xb9, 0xfc, 0xec,
+ 0x14, 0xee, 0x43, 0x45, 0xdf, 0x3c, 0xed, 0x3b,
+ 0x00, 0xe8, 0x56, 0xd6, 0x5b, 0x29, 0xf7, 0x28,
+ 0x61, 0x4a, 0x97, 0xa5, 0x40, 0x8b, 0x93, 0x21,
+ 0xa0, 0x08, 0x56, 0x55, 0x86, 0xe5, 0x7b, 0xce,
+ 0xe7, 0xfd, 0xfe, 0x72, 0xd6, 0xac, 0xe7, 0x9d,
+ 0x3f, 0xbf, 0x46, 0x37, 0xdd, 0x74, 0x9d, 0x3e,
+ 0x14, 0xee, 0x43, 0x44, 0xaf, 0x3f, 0xef, 0xf0,
+ 0x76, 0xb2, 0xd1, 0x81, 0x3a, 0x7b, 0x5e, 0x17,
+ 0x9d, 0x3f, 0xff, 0xbd, 0x7e, 0x67, 0x7c, 0x16,
+ 0x0f, 0x7e, 0x84, 0xf5, 0x07, 0x46, 0xc8, 0x83,
+ 0xe2, 0x18, 0xd9, 0x1c, 0xb6, 0x86, 0x14, 0xee,
+ 0x7b, 0x95, 0x37, 0x6c, 0x38, 0xac, 0x62, 0xb3,
+ 0xae, 0xbb, 0x15, 0x3f, 0xfa, 0xdd, 0xeb, 0xab,
+ 0xfc, 0x34, 0x6a, 0x02, 0xa7, 0xf7, 0x23, 0xb6,
+ 0x16, 0xed, 0xca, 0x7c, 0xf5, 0x1c, 0x93, 0x91,
+ 0x55, 0x73, 0x23, 0xb3, 0x6d, 0x0a, 0xd9, 0xff,
+ 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89,
+ 0x86, 0x7f, 0xfe, 0xc7, 0x6f, 0x1e, 0x03, 0xb4,
+ 0xdd, 0xe1, 0x5a, 0xbc, 0xe9, 0xff, 0xb7, 0x4c,
+ 0xa5, 0xfa, 0xf5, 0xfe, 0xaf, 0x3a, 0x7f, 0x2f,
+ 0x51, 0x7d, 0x3c, 0x27, 0x4f, 0xb8, 0x5f, 0xcc,
+ 0x3a, 0x3e, 0x7b, 0x1a, 0x99, 0xcf, 0xcc, 0x5c,
+ 0xfd, 0xf7, 0x0e, 0x9f, 0x2e, 0x7e, 0xfb, 0x87,
+ 0x4f, 0xd6, 0xf5, 0xeb, 0xd4, 0xe8, 0x3d, 0x86,
+ 0x17, 0xcf, 0xff, 0xfb, 0xf8, 0x16, 0xfb, 0xe5,
+ 0xb4, 0x7f, 0x28, 0xf6, 0x7e, 0x97, 0xd4, 0xe9,
+ 0xf9, 0xb6, 0xfb, 0xfd, 0x40, 0x74, 0xff, 0xe5,
+ 0xb8, 0x15, 0xf9, 0x4d, 0xe8, 0xd4, 0x27, 0x42,
+ 0x9f, 0xef, 0x8c, 0x67, 0xea, 0xfb, 0x4b, 0x3a,
+ 0xe7, 0x4f, 0xff, 0xf8, 0x71, 0xb2, 0xfe, 0xfa,
+ 0x37, 0xfd, 0x6d, 0xde, 0xba, 0xde, 0xa7, 0x4b,
+ 0x29, 0x44, 0xf8, 0x97, 0xcf, 0x7d, 0x41, 0xbc,
+ 0xe9, 0xee, 0xdf, 0xb6, 0x1d, 0x27, 0x37, 0x15,
+ 0xc1, 0xed, 0x0a, 0x24, 0x7b, 0x69, 0x22, 0xd0,
+ 0xf0, 0xfc, 0x30, 0x2e, 0x51, 0xa9, 0x1c, 0xf8,
+ 0x53, 0xb9, 0x0d, 0x15, 0x74, 0xff, 0x3d, 0xd8,
+ 0x29, 0xdc, 0x86, 0x88, 0xf2, 0x4e, 0xc3, 0xf1,
+ 0xe3, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
+ 0x83, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xb2,
+ 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0x9c,
+ 0xf2, 0x77, 0x21, 0xa2, 0xdc, 0x9f, 0xf9, 0x70,
+ 0x73, 0xfa, 0x2d, 0x94, 0x84, 0xe8, 0x13, 0xef,
+ 0xa9, 0x5c, 0xff, 0x2f, 0xf5, 0x62, 0xd6, 0xfe,
+ 0x3a, 0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a,
+ 0x28, 0x79, 0xfa, 0xbd, 0x4d, 0x6f, 0xe3, 0xa7,
+ 0xef, 0xb7, 0x30, 0x56, 0xa7, 0x4f, 0xff, 0xd9,
+ 0xb5, 0x97, 0x7b, 0xaf, 0xfe, 0x05, 0x6a, 0xa0,
+ 0x2a, 0x4e, 0xc4, 0xd6, 0xbc, 0x42, 0xc3, 0x9b,
+ 0xa3, 0x6a, 0x5d, 0xb8, 0x5f, 0x3f, 0x9d, 0x82,
+ 0x9d, 0xc8, 0x68, 0xbc, 0xe1, 0x59, 0x16, 0x4f,
+ 0x44, 0xd9, 0x4b, 0x25, 0xf0, 0xd3, 0x0f, 0xf1,
+ 0x26, 0x61, 0xdd, 0x8e, 0xff, 0x28, 0x11, 0xb3,
+ 0x0c, 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x96,
+ 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x58, 0x53,
+ 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x2e, 0x79,
+ 0xda, 0x77, 0x5f, 0x37, 0x53, 0xa7, 0x3b, 0x7b,
+ 0x0e, 0x9e, 0x47, 0x2d, 0x50, 0xf4, 0xb5, 0x34,
+ 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
+ 0x68, 0xa3, 0x27, 0xf3, 0x95, 0xb2, 0x8a, 0x80,
+ 0xe8, 0x7a, 0x77, 0xe2, 0x76, 0xc3, 0xbe, 0x84,
+ 0x6d, 0x4e, 0x2e, 0xa5, 0x3f, 0xf3, 0xb9, 0xee,
+ 0xc1, 0x4e, 0xe4, 0x34, 0x47, 0x33, 0xff, 0x9c,
+ 0xce, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x13, 0x94,
+ 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xcc, 0x9f,
+ 0xf9, 0xca, 0x01, 0x5b, 0xdb, 0xa9, 0x79, 0xd3,
+ 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x76, 0x7f,
+ 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
+ 0x90, 0x9f, 0xf9, 0xdc, 0xf7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x25, 0x28, 0xa1, 0x3f, 0x56, 0x93, 0x18,
+ 0xa4, 0x03, 0xbf, 0xa1, 0xdc, 0xed, 0xbd, 0x4a,
+ 0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27,
+ 0x69, 0xff, 0xf7, 0xb6, 0xd5, 0x8a, 0xdf, 0xdb,
+ 0x7d, 0x7f, 0x88, 0x74, 0x9c, 0xc4, 0x4f, 0xf2,
+ 0x34, 0xff, 0xdc, 0xcb, 0x62, 0x75, 0x97, 0x7b,
+ 0xce, 0x9f, 0xfb, 0xf9, 0x6e, 0xa3, 0x2b, 0xfe,
+ 0xa4, 0xe9, 0xb7, 0x1d, 0xb2, 0x21, 0xea, 0x87,
+ 0x0c, 0x47, 0x16, 0xe4, 0x2b, 0xe7, 0xc2, 0x9d,
+ 0xc8, 0x68, 0x8b, 0x27, 0xfd, 0xcf, 0x76, 0x0a,
+ 0x77, 0x21, 0xa2, 0x5d, 0x9f, 0xff, 0xb3, 0x6b,
+ 0x2e, 0xf7, 0x5f, 0xfc, 0x0a, 0xd5, 0x40, 0x54,
+ 0x9d, 0x88, 0xd3, 0x61, 0x86, 0xe2, 0x34, 0xff,
+ 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44,
+ 0xc5, 0x3f, 0x60, 0xa7, 0x72, 0x1a, 0x2a, 0x99,
+ 0xff, 0xff, 0xc3, 0xd6, 0xa5, 0xf9, 0x77, 0x5b,
+ 0xaa, 0x3e, 0x0d, 0xed, 0xe1, 0x79, 0xd0, 0xe4,
+ 0x56, 0x71, 0xac, 0xff, 0xe7, 0x33, 0x9e, 0xec,
+ 0x14, 0xee, 0x43, 0x44, 0xe9, 0x3f, 0xbd, 0xc2,
+ 0xaf, 0xe6, 0xc7, 0x4f, 0x9a, 0x56, 0x96, 0xa7,
+ 0x4f, 0xc1, 0xcf, 0x36, 0xcf, 0x9d, 0x3d, 0xeb,
+ 0x2b, 0xbc, 0x7a, 0xd5, 0x28, 0x9f, 0xfb, 0x5a,
+ 0xdd, 0x69, 0x76, 0xad, 0x79, 0x87, 0x43, 0x11,
+ 0x05, 0x63, 0x99, 0xff, 0x73, 0xdd, 0x82, 0x9d,
+ 0xc8, 0x68, 0x9d, 0xe7, 0xd7, 0xd7, 0x99, 0xe2,
+ 0xa4, 0xed, 0x93, 0x9b, 0xc8, 0xc2, 0x98, 0x47,
+ 0xc8, 0xd3, 0xff, 0x9c, 0xce, 0x7b, 0xb0, 0x53,
+ 0xb9, 0x0d, 0x14, 0x2c, 0xff, 0xe7, 0x33, 0x9e,
+ 0xec, 0x14, 0xee, 0x43, 0x45, 0x25, 0x3f, 0xff,
+ 0xb2, 0xae, 0xdf, 0x8d, 0x5b, 0x99, 0x7b, 0x2d,
+ 0xf5, 0x61, 0xd1, 0x42, 0xe4, 0xb3, 0xce, 0x12,
+ 0x1f, 0xc2, 0x44, 0xc8, 0xfb, 0x40, 0x93, 0xaa,
+ 0x96, 0xe2, 0x94, 0xfe, 0x76, 0x0a, 0x77, 0x21,
+ 0xa2, 0x24, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82,
+ 0x9d, 0xc8, 0x68, 0x97, 0xa7, 0xc2, 0x9d, 0xc8,
+ 0x68, 0xa5, 0xe7, 0xff, 0x63, 0xd4, 0x15, 0x15,
+ 0xa5, 0xfe, 0x61, 0xd3, 0xe6, 0xff, 0x31, 0x6a,
+ 0x74, 0xfb, 0x9b, 0x60, 0xd4, 0xe9, 0x2e, 0xc7,
+ 0xa2, 0xc2, 0xa9, 0x3b, 0x11, 0xe4, 0xd1, 0x85,
+ 0xe1, 0x35, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
+ 0xa7, 0x27, 0xfd, 0xe1, 0xea, 0xdb, 0x33, 0xe8,
+ 0x74, 0xff, 0xb2, 0xca, 0x38, 0xe0, 0x84, 0x25,
+ 0x4d, 0xe0, 0x9d, 0x35, 0x0e, 0xd9, 0x11, 0xbb,
+ 0x87, 0x6d, 0xe7, 0x93, 0xe1, 0x4e, 0xe4, 0x34,
+ 0x57, 0x93, 0xff, 0xf6, 0x6d, 0x65, 0xde, 0xeb,
+ 0xff, 0x81, 0x5a, 0xa8, 0x0a, 0x93, 0xb1, 0x11,
+ 0xbb, 0x86, 0x13, 0xff, 0x3b, 0x9e, 0xec, 0x14,
+ 0xee, 0x43, 0x44, 0x8f, 0x3b, 0xc0, 0x53, 0xa7,
+ 0x26, 0x30, 0xa7, 0x17, 0x73, 0xe1, 0x4e, 0xe4,
+ 0x34, 0x49, 0x13, 0xce, 0xe7, 0xb9, 0x4f, 0x67,
+ 0x0a, 0x67, 0xfe, 0x77, 0x3d, 0xd8, 0x29, 0xdc,
+ 0x86, 0x89, 0x2a, 0x7c, 0x29, 0xdc, 0x86, 0x8b,
+ 0xc6, 0x7e, 0xd7, 0xf4, 0xf5, 0x35, 0x3a, 0x7d,
+ 0x5a, 0xdf, 0x10, 0xe9, 0xfe, 0x7b, 0xb0, 0x53,
+ 0xb9, 0x0d, 0x12, 0x6c, 0x9d, 0x88, 0xc7, 0xa4,
+ 0xc0, 0x4c, 0x38, 0x9a, 0x15, 0x77, 0x26, 0x83,
+ 0xb7, 0xc6, 0x89, 0xb1, 0xdf, 0xa1, 0x90, 0xd4,
+ 0x34, 0x58, 0x57, 0x68, 0x60, 0x5c, 0xdf, 0x58,
+ 0xc4, 0xe1, 0x63, 0x76, 0xd5, 0xa2, 0x3a, 0xe7,
+ 0xc7, 0x93, 0xb4, 0xa1, 0xac, 0xb7, 0x5a, 0xda,
+ 0x65, 0x2c, 0x25, 0x7f, 0xbd, 0x4c, 0xf3, 0xdf,
+ 0xa7, 0x3d, 0x37, 0x71, 0xd8, 0x35, 0x4e, 0xc3,
+ 0x1a, 0x47, 0xab, 0x31, 0x1a, 0x11, 0x69, 0xda,
+ 0x8e, 0xa7, 0xb9, 0x02, 0x58, 0x73, 0x77, 0x0b,
+ 0x1f, 0xcf, 0x63, 0x56, 0x92, 0xbb, 0x7a, 0xe8,
+ 0x7f, 0x5a, 0x60, 0xb3, 0x69, 0x4c, 0x41, 0x94,
+ 0xa1, 0xb9, 0x1f, 0x5e, 0xf9, 0xd9, 0x46, 0xf9,
+ 0xe4, 0xb8,
};
-static const unsigned kPreloadedHSTSBits = 97858;
+static const unsigned kPreloadedHSTSBits = 97871;
-static const unsigned kHSTSRootPosition = 97280;
+static const unsigned kHSTSRootPosition = 97293;
#endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 39ca582..59eb9f7 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -186,6 +186,14 @@
"DigiCertEVRoot",
"FacebookBackup"
]
+ },
+ {
+ "name": "spideroak",
+ "static_spki_hashes": [
+ "RapidSSL",
+ "SpiderOak1",
+ "SpiderOak2"
+ ]
}
],
@@ -1266,7 +1274,7 @@
{ "name": "ravchat.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "sciencex.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "shiinko.com", "include_subdomains": true, "mode": "force-https" },
- { "name": "spideroak.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spideroak.com", "include_subdomains": true, "mode": "force-https", "pins": "spideroak" },
{ "name": "thorncreek.net", "include_subdomains": true, "mode": "force-https" },
{ "name": "tno.io", "include_subdomains": true, "mode": "force-https" },
{ "name": "translatoruk.co.uk", "include_subdomains": true, "mode": "force-https" },
@@ -1393,9 +1401,10 @@
{ "name": "fleximus.org", "include_subdomains": true, "mode": "force-https" },
// Facebook would like to have pinning enforced on (*.)facebook.com and
- // HSTS enforced on specific names. We can't (yet) represent that in JSON
- // So we're currently only applying pinning on the specific names.
- { "name": "facebook.com", "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true },
+ // HSTS enforced on specific names. We have the
+ // "include_subdomains_for_pinning" flag that can do that, but it triggered a
+ // wave of pinning failures and so isn't used until that can be investigated.
+ { "name": "facebook.com", "mode": "force-https", "pins": "facebook" },
{ "name": "www.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
{ "name": "m.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
{ "name": "tablet.facebook.com", "include_subdomains": true, "mode": "force-https", "pins": "facebook" },
@@ -1777,6 +1786,7 @@
"DROPBOX_COM",
"YOUTUBE_NOCOOKIE_COM",
"2MDN_NET",
- "FACEBOOK_COM"
+ "FACEBOOK_COM",
+ "SPIDEROAK_COM"
]
}
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index cf5f243..1872e72 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -540,9 +540,7 @@
EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
EXPECT_TRUE(StaticShouldRedirect("facebook.com"));
- EXPECT_TRUE(state.GetStaticDomainState("foo.facebook.com", &domain_state));
- EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
- EXPECT_FALSE(StaticShouldRedirect("foo.facebook.com"));
+ EXPECT_FALSE(state.GetStaticDomainState("foo.facebook.com", &domain_state));
EXPECT_TRUE(state.GetStaticDomainState("www.facebook.com", &domain_state));
EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
diff --git a/net/net.gyp b/net/net.gyp
index e9379e0..3c9a520 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -487,10 +487,14 @@
['include', '^base/platform_mime_util_linux\\.cc$'],
['include', '^base/address_tracker_linux\\.cc$'],
['include', '^base/address_tracker_linux\\.h$'],
+ ['include', '^base/net_util_linux\\.cc$'],
+ ['include', '^base/net_util_linux\\.h$'],
],
}],
['OS == "ios"', {
'sources/': [
+ ['include', '^base/net_util_mac\\.cc$'],
+ ['include', '^base/net_util_mac\\.h$'],
['include', '^base/network_change_notifier_mac\\.cc$'],
['include', '^base/network_config_watcher_mac\\.cc$'],
['include', '^base/platform_mime_util_mac\\.mm$'],
diff --git a/net/net.gypi b/net/net.gypi
index fef6136..337f016 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -246,7 +246,11 @@
'base/net_log_logger.h',
'base/net_log_util.cc',
'base/net_log_util.h',
+ 'base/net_util_linux.cc',
+ 'base/net_util_mac.cc',
'base/net_util_win.cc',
+ 'base/network_activity_monitor.cc',
+ 'base/network_activity_monitor.h',
'base/network_change_notifier.cc',
'base/network_change_notifier.h',
'base/network_change_notifier_factory.h',
@@ -275,8 +279,12 @@
'base/request_priority.h',
'base/sdch_manager.cc',
'base/sdch_manager.h',
+ 'base/sdch_net_log_params.cc',
+ 'base/sdch_net_log_params.h',
'base/sdch_observer.cc',
'base/sdch_observer.h',
+ 'base/sdch_problem_code_list.h',
+ 'base/sdch_problem_codes.h',
'base/static_cookie_policy.cc',
'base/static_cookie_policy.h',
'base/test_data_stream.cc',
@@ -751,8 +759,6 @@
'quic/congestion_control/cubic.h',
'quic/congestion_control/hybrid_slow_start.cc',
'quic/congestion_control/hybrid_slow_start.h',
- 'quic/congestion_control/leaky_bucket.cc',
- 'quic/congestion_control/leaky_bucket.h',
'quic/congestion_control/loss_detection_interface.cc',
'quic/congestion_control/loss_detection_interface.h',
'quic/congestion_control/pacing_sender.cc',
@@ -785,6 +791,8 @@
'quic/crypto/aes_128_gcm_12_encrypter.h',
'quic/crypto/aes_128_gcm_12_encrypter_nss.cc',
'quic/crypto/aes_128_gcm_12_encrypter_openssl.cc',
+ 'quic/crypto/cached_network_parameters.cc',
+ 'quic/crypto/cached_network_parameters.h',
'quic/crypto/cert_compressor.cc',
'quic/crypto/cert_compressor.h',
'quic/crypto/chacha20_poly1305_decrypter.h',
@@ -1276,6 +1284,7 @@
'base/net_log_util_unittest.cc',
'base/net_util_unittest.cc',
'base/net_util_icu_unittest.cc',
+ 'base/network_activity_monitor_unittest.cc',
'base/network_change_notifier_unittest.cc',
'base/network_change_notifier_win_unittest.cc',
'base/prioritized_dispatcher_unittest.cc',
@@ -1440,7 +1449,6 @@
'quic/congestion_control/cube_root_test.cc',
'quic/congestion_control/cubic_test.cc',
'quic/congestion_control/hybrid_slow_start_test.cc',
- 'quic/congestion_control/leaky_bucket_test.cc',
'quic/congestion_control/pacing_sender_test.cc',
'quic/congestion_control/prr_sender_test.cc',
'quic/congestion_control/rtt_stats_test.cc',
diff --git a/net/quic/congestion_control/hybrid_slow_start.cc b/net/quic/congestion_control/hybrid_slow_start.cc
index 4b1e842..e3789b4 100644
--- a/net/quic/congestion_control/hybrid_slow_start.cc
+++ b/net/quic/congestion_control/hybrid_slow_start.cc
@@ -23,6 +23,7 @@
HybridSlowStart::HybridSlowStart(const QuicClock* clock)
: clock_(clock),
+ ack_train_detection_(true),
started_(false),
hystart_found_(NOT_FOUND),
last_sent_sequence_number_(0),
@@ -84,12 +85,8 @@
// more than the capacity.
// This first trigger will not come into play until we hit roughly 9.6 Mbps
// with delayed acks (or 4.8Mbps without delayed acks)
- // TODO(ianswett): QUIC always uses delayed acks, even at the beginning, so
- // this should likely be at least 4ms.
- // TODO(pwestin): we need to make sure our pacing don't trigger this detector.
- // TODO(ianswett): Pacing or other cases could be handled by checking the send
- // time of the first acked packet in a receive round.
- if (current_time.Subtract(last_close_ack_pair_time_).ToMicroseconds() <=
+ if (ack_train_detection_ &&
+ current_time.Subtract(last_close_ack_pair_time_).ToMicroseconds() <=
kHybridStartDelayMinThresholdUs) {
last_close_ack_pair_time_ = current_time;
if (current_time.Subtract(round_start_).ToMicroseconds() >=
diff --git a/net/quic/congestion_control/hybrid_slow_start.h b/net/quic/congestion_control/hybrid_slow_start.h
index 5d36c53..cee9a60 100644
--- a/net/quic/congestion_control/hybrid_slow_start.h
+++ b/net/quic/congestion_control/hybrid_slow_start.h
@@ -53,6 +53,14 @@
// Call for the start of each receive round (burst) in the slow start phase.
void StartReceiveRound(QuicPacketSequenceNumber last_sent);
+ void set_ack_train_detection(bool ack_train_detection) {
+ ack_train_detection_ = ack_train_detection;
+ }
+
+ bool ack_train_detection() const {
+ return ack_train_detection_;
+ }
+
// Whether slow start has started.
bool started() const {
return started_;
@@ -67,6 +75,7 @@
};
const QuicClock* clock_;
+ bool ack_train_detection_;
// Whether the hybrid slow start has been started.
bool started_;
HystartState hystart_found_;
diff --git a/net/quic/congestion_control/hybrid_slow_start_test.cc b/net/quic/congestion_control/hybrid_slow_start_test.cc
index dd74933..bcdf8d9 100644
--- a/net/quic/congestion_control/hybrid_slow_start_test.cc
+++ b/net/quic/congestion_control/hybrid_slow_start_test.cc
@@ -54,26 +54,33 @@
// At a typical RTT 60 ms, assuming that the inter arrival timestamp is 1 ms,
// we expect to be able to send a burst of 30 packet before we trigger the
// ack train detection.
- const int kMaxLoopCount = 5;
- QuicPacketSequenceNumber sequence_number = 2;
- QuicPacketSequenceNumber end_sequence_number = 2;
- for (int burst = 0; burst < kMaxLoopCount; ++burst) {
+ // Run this test for both enabled and disabled ack train detection.
+ for (int i = 0; i < 2; ++i) {
+ const bool ack_train_detection = (i == 1);
+ slow_start_->set_ack_train_detection(ack_train_detection);
+
+ const int kMaxLoopCount = 5;
+ QuicPacketSequenceNumber sequence_number = 2;
+ QuicPacketSequenceNumber end_sequence_number = 2;
+ for (int burst = 0; burst < kMaxLoopCount; ++burst) {
+ slow_start_->StartReceiveRound(end_sequence_number);
+ do {
+ clock_.AdvanceTime(one_ms_);
+ EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
+ } while (!slow_start_->IsEndOfRound(sequence_number++));
+ end_sequence_number *= 2; // Exponential growth.
+ }
slow_start_->StartReceiveRound(end_sequence_number);
- do {
+
+ for (int n = 0;
+ n < 29 && !slow_start_->IsEndOfRound(sequence_number++); ++n) {
clock_.AdvanceTime(one_ms_);
EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
- } while (!slow_start_->IsEndOfRound(sequence_number++));
- end_sequence_number *= 2; // Exponential growth.
- }
- slow_start_->StartReceiveRound(end_sequence_number);
-
- for (int n = 0;
- n < 29 && !slow_start_->IsEndOfRound(sequence_number++); ++n) {
+ }
clock_.AdvanceTime(one_ms_);
- EXPECT_FALSE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
+ EXPECT_EQ(ack_train_detection,
+ slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
}
- clock_.AdvanceTime(one_ms_);
- EXPECT_TRUE(slow_start_->ShouldExitSlowStart(rtt_, rtt_, 100));
}
TEST_F(HybridSlowStartTest, Delay) {
diff --git a/net/quic/congestion_control/leaky_bucket.cc b/net/quic/congestion_control/leaky_bucket.cc
deleted file mode 100644
index f3972f6..0000000
--- a/net/quic/congestion_control/leaky_bucket.cc
+++ /dev/null
@@ -1,54 +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 "net/quic/congestion_control/leaky_bucket.h"
-
-#include "base/time/time.h"
-
-namespace net {
-
-LeakyBucket::LeakyBucket(QuicBandwidth draining_rate)
- : bytes_(0),
- time_last_updated_(QuicTime::Zero()),
- draining_rate_(draining_rate) {
-}
-
-void LeakyBucket::SetDrainingRate(QuicTime now, QuicBandwidth draining_rate) {
- Update(now);
- draining_rate_ = draining_rate;
-}
-
-void LeakyBucket::Add(QuicTime now, QuicByteCount bytes) {
- Update(now);
- bytes_ += bytes;
-}
-
-QuicTime::Delta LeakyBucket::TimeRemaining(QuicTime now) const {
- QuicTime::Delta time_since_last_update = now.Subtract(time_last_updated_);
- QuicTime::Delta send_delay = QuicTime::Delta::FromMicroseconds(
- (bytes_ * base::Time::kMicrosecondsPerSecond) /
- draining_rate_.ToBytesPerSecond());
- if (send_delay < time_since_last_update) {
- return QuicTime::Delta::Zero();
- }
- return send_delay.Subtract(time_since_last_update);
-}
-
-QuicByteCount LeakyBucket::BytesPending(QuicTime now) {
- Update(now);
- return bytes_;
-}
-
-void LeakyBucket::Update(QuicTime now) {
- QuicTime::Delta elapsed_time = now.Subtract(time_last_updated_);
- QuicByteCount bytes_cleared = draining_rate_.ToBytesPerPeriod(elapsed_time);
- if (bytes_cleared >= bytes_) {
- bytes_ = 0;
- } else {
- bytes_ -= bytes_cleared;
- }
- time_last_updated_ = now;
-}
-
-} // namespace net
diff --git a/net/quic/congestion_control/leaky_bucket.h b/net/quic/congestion_control/leaky_bucket.h
deleted file mode 100644
index eb4cdb0..0000000
--- a/net/quic/congestion_control/leaky_bucket.h
+++ /dev/null
@@ -1,49 +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.
-//
-// Helper class to track the rate data can leave the buffer for pacing.
-// A leaky bucket drains the data at a constant rate regardless of fullness of
-// the buffer.
-// See http://en.wikipedia.org/wiki/Leaky_bucket for more details.
-
-#ifndef NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
-#define NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
-
-#include "base/basictypes.h"
-#include "net/base/net_export.h"
-#include "net/quic/quic_bandwidth.h"
-#include "net/quic/quic_protocol.h"
-#include "net/quic/quic_time.h"
-
-namespace net {
-
-class NET_EXPORT_PRIVATE LeakyBucket {
- public:
- explicit LeakyBucket(QuicBandwidth draining_rate);
-
- // Set the rate at which the bytes leave the buffer.
- void SetDrainingRate(QuicTime now, QuicBandwidth draining_rate);
-
- // Add data to the buffer.
- void Add(QuicTime now, QuicByteCount bytes);
-
- // Time until the buffer is empty.
- QuicTime::Delta TimeRemaining(QuicTime now) const;
-
- // Number of bytes in the buffer.
- QuicByteCount BytesPending(QuicTime now);
-
- private:
- void Update(QuicTime now);
-
- QuicByteCount bytes_;
- QuicTime time_last_updated_;
- QuicBandwidth draining_rate_;
-
- DISALLOW_COPY_AND_ASSIGN(LeakyBucket);
-};
-
-} // namespace net
-
-#endif // NET_QUIC_CONGESTION_CONTROL_LEAKY_BUCKET_H_
diff --git a/net/quic/congestion_control/leaky_bucket_test.cc b/net/quic/congestion_control/leaky_bucket_test.cc
deleted file mode 100644
index 8387ada..0000000
--- a/net/quic/congestion_control/leaky_bucket_test.cc
+++ /dev/null
@@ -1,75 +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 "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/quic/congestion_control/leaky_bucket.h"
-#include "net/quic/test_tools/mock_clock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-namespace test {
-
-class LeakyBucketTest : public ::testing::Test {
- protected:
- void SetUp() override {
- leaky_bucket_.reset(new LeakyBucket(QuicBandwidth::Zero()));
- }
- MockClock clock_;
- scoped_ptr<LeakyBucket> leaky_bucket_;
-};
-
-TEST_F(LeakyBucketTest, Basic) {
- QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
- leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
- leaky_bucket_->Add(clock_.Now(), 2000);
- EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
- leaky_bucket_->Add(clock_.Now(), 2000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(11));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
- leaky_bucket_->Add(clock_.Now(), 2000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- leaky_bucket_->Add(clock_.Now(), 2000);
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(10));
- EXPECT_EQ(0u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_TRUE(leaky_bucket_->TimeRemaining(clock_.Now()).IsZero());
-}
-
-TEST_F(LeakyBucketTest, ChangeDrainRate) {
- QuicBandwidth draining_rate = QuicBandwidth::FromBytesPerSecond(200000);
- leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
- leaky_bucket_->Add(clock_.Now(), 2000);
- EXPECT_EQ(2000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(5),
- leaky_bucket_->TimeRemaining(clock_.Now()));
- draining_rate = draining_rate.Scale(0.5f); // Cut drain rate in half.
- leaky_bucket_->SetDrainingRate(clock_.Now(), draining_rate);
- EXPECT_EQ(1000u, leaky_bucket_->BytesPending(clock_.Now()));
- EXPECT_EQ(QuicTime::Delta::FromMilliseconds(10),
- leaky_bucket_->TimeRemaining(clock_.Now()));
-}
-
-} // namespace test
-} // namespace net
diff --git a/net/quic/congestion_control/pacing_sender.cc b/net/quic/congestion_control/pacing_sender.cc
index 061f6ec..8073c5b 100644
--- a/net/quic/congestion_control/pacing_sender.cc
+++ b/net/quic/congestion_control/pacing_sender.cc
@@ -20,8 +20,11 @@
PacingSender::~PacingSender() {}
-void PacingSender::SetFromConfig(const QuicConfig& config, bool is_server) {
- sender_->SetFromConfig(config, is_server);
+void PacingSender::SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) {
+ DCHECK(using_pacing);
+ sender_->SetFromConfig(config, is_server, using_pacing);
}
void PacingSender::SetNumEmulatedConnections(int num_connections) {
diff --git a/net/quic/congestion_control/pacing_sender.h b/net/quic/congestion_control/pacing_sender.h
index f16172a..4eb3dab 100644
--- a/net/quic/congestion_control/pacing_sender.h
+++ b/net/quic/congestion_control/pacing_sender.h
@@ -35,7 +35,9 @@
~PacingSender() override;
// SendAlgorithmInterface methods.
- void SetFromConfig(const QuicConfig& config, bool is_server) override;
+ void SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) override;
void SetNumEmulatedConnections(int num_connections) override;
void OnCongestionEvent(bool rtt_updated,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/rtt_stats.cc b/net/quic/congestion_control/rtt_stats.cc
index dfb50ef..32e3b58 100644
--- a/net/quic/congestion_control/rtt_stats.cc
+++ b/net/quic/congestion_control/rtt_stats.cc
@@ -28,7 +28,7 @@
min_rtt_(QuicTime::Delta::Zero()),
smoothed_rtt_(QuicTime::Delta::Zero()),
mean_deviation_(QuicTime::Delta::Zero()),
- initial_rtt_us_(kInitialRttMs * base::Time::kMicrosecondsPerMillisecond),
+ initial_rtt_us_(kInitialRttMs * kNumMicrosPerMilli),
num_min_rtt_samples_remaining_(0),
recent_min_rtt_window_(QuicTime::Delta::Infinite()) {}
diff --git a/net/quic/congestion_control/send_algorithm_interface.cc b/net/quic/congestion_control/send_algorithm_interface.cc
index 7245e33..82f1135 100644
--- a/net/quic/congestion_control/send_algorithm_interface.cc
+++ b/net/quic/congestion_control/send_algorithm_interface.cc
@@ -16,17 +16,23 @@
const QuicClock* clock,
const RttStats* rtt_stats,
CongestionControlType congestion_control_type,
- QuicConnectionStats* stats) {
+ QuicConnectionStats* stats,
+ QuicPacketCount initial_congestion_window) {
switch (congestion_control_type) {
case kCubic:
- return new TcpCubicSender(clock, rtt_stats,
- false /* don't use Reno */,
+ return new TcpCubicSender(clock, rtt_stats, false /* don't use Reno */,
+ initial_congestion_window,
kMaxTcpCongestionWindow, stats);
case kReno:
- return new TcpCubicSender(clock, rtt_stats,
- true /* use Reno */,
+ return new TcpCubicSender(clock, rtt_stats, true /* use Reno */,
+ initial_congestion_window,
kMaxTcpCongestionWindow, stats);
case kBBR:
+ // TODO(rtenneti): Enable BbrTcpSender.
+#if 0
+ return new BbrTcpSender(clock, rtt_stats, initial_congestion_window,
+ kMaxTcpCongestionWindow, stats);
+#endif
LOG(DFATAL) << "BbrTcpSender is not supported.";
return nullptr;
}
diff --git a/net/quic/congestion_control/send_algorithm_interface.h b/net/quic/congestion_control/send_algorithm_interface.h
index 4f74628..7195f81 100644
--- a/net/quic/congestion_control/send_algorithm_interface.h
+++ b/net/quic/congestion_control/send_algorithm_interface.h
@@ -29,14 +29,17 @@
typedef std::vector<std::pair<QuicPacketSequenceNumber, TransmissionInfo>>
CongestionVector;
- static SendAlgorithmInterface* Create(const QuicClock* clock,
- const RttStats* rtt_stats,
- CongestionControlType type,
- QuicConnectionStats* stats);
+ static SendAlgorithmInterface* Create(
+ const QuicClock* clock,
+ const RttStats* rtt_stats,
+ CongestionControlType type,
+ QuicConnectionStats* stats,
+ QuicPacketCount initial_congestion_window);
virtual ~SendAlgorithmInterface() {}
- virtual void SetFromConfig(const QuicConfig& config, bool is_server) = 0;
+ virtual void SetFromConfig(
+ const QuicConfig& config, bool is_server, bool using_pacing) = 0;
// Sets the number of connections to emulate when doing congestion control,
// particularly for congestion avoidance. Can be set any time.
diff --git a/net/quic/congestion_control/tcp_cubic_sender.cc b/net/quic/congestion_control/tcp_cubic_sender.cc
index 5f20597..2d0efd7 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender.cc
@@ -31,6 +31,7 @@
const QuicClock* clock,
const RttStats* rtt_stats,
bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
QuicPacketCount max_tcp_congestion_window,
QuicConnectionStats* stats)
: hybrid_slow_start_(clock),
@@ -43,7 +44,7 @@
largest_sent_sequence_number_(0),
largest_acked_sequence_number_(0),
largest_sent_at_last_cutback_(0),
- congestion_window_(kDefaultInitialWindow),
+ congestion_window_(initial_tcp_congestion_window),
previous_congestion_window_(0),
slowstart_threshold_(max_tcp_congestion_window),
previous_slowstart_threshold_(0),
@@ -55,20 +56,19 @@
UMA_HISTOGRAM_COUNTS("Net.QuicSession.FinalTcpCwnd", congestion_window_);
}
-void TcpCubicSender::SetFromConfig(const QuicConfig& config, bool is_server) {
+void TcpCubicSender::SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) {
if (is_server) {
if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kIW10)) {
- // Initial window experiment. Ignore the initial congestion
- // window suggested by the client and use the default ICWND of
- // 10 instead.
- congestion_window_ = kDefaultInitialWindow;
- } else if (config.HasReceivedInitialCongestionWindow()) {
- // Set the initial window size.
- congestion_window_ = max(kMinimumCongestionWindow,
- min(kMaxInitialWindow,
- static_cast<QuicPacketCount>(
- config.ReceivedInitialCongestionWindow())));
+ // Initial window experiment.
+ congestion_window_ = 10;
+ }
+ if (using_pacing) {
+ // Disable the ack train mode in hystart when pacing is enabled, since it
+ // may be falsely triggered.
+ hybrid_slow_start_.set_ack_train_detection(false);
}
}
}
diff --git a/net/quic/congestion_control/tcp_cubic_sender.h b/net/quic/congestion_control/tcp_cubic_sender.h
index 7491565..a7507a2 100644
--- a/net/quic/congestion_control/tcp_cubic_sender.h
+++ b/net/quic/congestion_control/tcp_cubic_sender.h
@@ -34,12 +34,15 @@
TcpCubicSender(const QuicClock* clock,
const RttStats* rtt_stats,
bool reno,
+ QuicPacketCount initial_tcp_congestion_window,
QuicPacketCount max_tcp_congestion_window,
QuicConnectionStats* stats);
~TcpCubicSender() override;
// Start implementation of SendAlgorithmInterface.
- void SetFromConfig(const QuicConfig& config, bool is_server) override;
+ void SetFromConfig(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing) override;
void SetNumEmulatedConnections(int num_connections) override;
void OnCongestionEvent(bool rtt_updated,
QuicByteCount bytes_in_flight,
diff --git a/net/quic/congestion_control/tcp_cubic_sender_test.cc b/net/quic/congestion_control/tcp_cubic_sender_test.cc
index 48a1300..427dd8c 100644
--- a/net/quic/congestion_control/tcp_cubic_sender_test.cc
+++ b/net/quic/congestion_control/tcp_cubic_sender_test.cc
@@ -21,19 +21,22 @@
namespace net {
namespace test {
-const uint32 kDefaultWindowTCP = kDefaultInitialWindow * kDefaultTCPMSS;
+// TODO(ianswett): A number of theses tests were written with the assumption of
+// an initial CWND of 10. They have carefully calculated values which should be
+// updated to be based on kInitialCongestionWindowInsecure.
+const uint32 kInitialCongestionWindowPackets = 10;
+const uint32 kDefaultWindowTCP =
+ kInitialCongestionWindowPackets * kDefaultTCPMSS;
const float kRenoBeta = 0.7f; // Reno backoff factor.
-// TODO(ianswett): Remove 10000 once b/10075719 is fixed.
-const QuicPacketCount kDefaultMaxCongestionWindowTCP = 10000;
-
class TcpCubicSenderPeer : public TcpCubicSender {
public:
TcpCubicSenderPeer(const QuicClock* clock,
bool reno,
QuicPacketCount max_tcp_congestion_window)
: TcpCubicSender(
- clock, &rtt_stats_, reno, max_tcp_congestion_window, &stats_) {
+ clock, &rtt_stats_, reno, kInitialCongestionWindowPackets,
+ max_tcp_congestion_window, &stats_) {
}
QuicPacketCount congestion_window() {
@@ -61,7 +64,7 @@
TcpCubicSenderTest()
: one_ms_(QuicTime::Delta::FromMilliseconds(1)),
sender_(new TcpCubicSenderPeer(&clock_, true,
- kDefaultMaxCongestionWindowTCP)),
+ kMaxTcpCongestionWindow)),
receiver_(new TcpReceiver()),
sequence_number_(1),
acked_sequence_number_(0),
@@ -209,7 +212,7 @@
TEST_F(TcpCubicSenderTest, SlowStartAckTrain) {
sender_->SetNumEmulatedConnections(1);
- EXPECT_EQ(kDefaultMaxCongestionWindowTCP * kDefaultTCPMSS,
+ EXPECT_EQ(kMaxTcpCongestionWindow * kDefaultTCPMSS,
sender_->GetSlowStartThreshold());
// Make sure that we fall out of slow start when we send ACK train longer
@@ -305,7 +308,7 @@
TEST_F(TcpCubicSenderTest, NoPRRWhenLessThanOnePacketInFlight) {
SendAvailableSendWindow();
- LoseNPackets(kDefaultInitialWindow - 1);
+ LoseNPackets(kInitialCongestionWindowPackets - 1);
AckNPackets(1);
// PRR will allow 2 packets for every ack during recovery.
EXPECT_EQ(2, SendAvailableSendWindow());
@@ -424,7 +427,7 @@
TEST_F(TcpCubicSenderTest, RTOCongestionWindowAndRevert) {
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(10000u, sender_->slowstart_threshold());
+ EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold());
// Expect the window to decrease to the minimum once the RTO fires
// and slow start threshold to be set to 1/2 of the CWND.
@@ -435,7 +438,7 @@
// Now repair the RTO and ensure the slowstart threshold reverts.
sender_->RevertRetransmissionTimeout();
EXPECT_EQ(kDefaultWindowTCP, sender_->GetCongestionWindow());
- EXPECT_EQ(10000u, sender_->slowstart_threshold());
+ EXPECT_EQ(kMaxTcpCongestionWindow, sender_->slowstart_threshold());
}
TEST_F(TcpCubicSenderTest, RTOCongestionWindowNoRetransmission) {
@@ -574,20 +577,26 @@
}
TEST_F(TcpCubicSenderTest, ConfigureMaxInitialWindow) {
- QuicPacketCount congestion_window = sender_->congestion_window();
QuicConfig config;
- QuicConfigPeer::SetReceivedInitialWindow(&config, 2 * congestion_window);
- sender_->SetFromConfig(config, true);
- EXPECT_EQ(2 * congestion_window, sender_->congestion_window());
-
- // Verify that kCOPT: kIW10 forces the congestion window to the
- // default of 10 regardless of ReceivedInitialWindow.
+ // Verify that kCOPT: kIW10 forces the congestion window to the default of 10.
QuicTagVector options;
options.push_back(kIW10);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- sender_->SetFromConfig(config, true);
- EXPECT_EQ(congestion_window, sender_->congestion_window());
+ sender_->SetFromConfig(config,
+ /* is_server= */ true,
+ /* using_pacing= */ false);
+ EXPECT_EQ(10u, sender_->congestion_window());
+}
+
+TEST_F(TcpCubicSenderTest, DisableAckTrainDetectionWithPacing) {
+ EXPECT_TRUE(sender_->hybrid_slow_start().ack_train_detection());
+
+ QuicConfig config;
+ sender_->SetFromConfig(config,
+ /* is_server= */ true,
+ /* using_pacing= */ true);
+ EXPECT_FALSE(sender_->hybrid_slow_start().ack_train_detection());
}
TEST_F(TcpCubicSenderTest, 2ConnectionCongestionAvoidanceAtEndOfRecovery) {
diff --git a/net/quic/crypto/cached_network_parameters.cc b/net/quic/crypto/cached_network_parameters.cc
new file mode 100644
index 0000000..20a438b
--- /dev/null
+++ b/net/quic/crypto/cached_network_parameters.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 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 "net/quic/crypto/cached_network_parameters.h"
+
+namespace net {
+
+CachedNetworkParameters::CachedNetworkParameters()
+ : bandwidth_estimate_bytes_per_second_(0),
+ max_bandwidth_estimate_bytes_per_second_(0),
+ max_bandwidth_timestamp_seconds_(0),
+ min_rtt_ms_(0),
+ previous_connection_state_(0),
+ timestamp_(0) {
+}
+
+CachedNetworkParameters::~CachedNetworkParameters() {
+}
+
+bool CachedNetworkParameters::operator==(
+ const CachedNetworkParameters& other) const {
+ return serving_region_ == other.serving_region_ &&
+ bandwidth_estimate_bytes_per_second_ ==
+ other.bandwidth_estimate_bytes_per_second_ &&
+ max_bandwidth_estimate_bytes_per_second_ ==
+ other.max_bandwidth_estimate_bytes_per_second_ &&
+ max_bandwidth_timestamp_seconds_ ==
+ other.max_bandwidth_timestamp_seconds_ &&
+ min_rtt_ms_ == other.min_rtt_ms_ &&
+ previous_connection_state_ == other.previous_connection_state_ &&
+ timestamp_ == other.timestamp_;
+}
+
+bool CachedNetworkParameters::operator!=(
+ const CachedNetworkParameters& other) const {
+ return !(*this == other);
+}
+
+} // namespace net
diff --git a/net/quic/crypto/cached_network_parameters.h b/net/quic/crypto/cached_network_parameters.h
new file mode 100644
index 0000000..5f22070
--- /dev/null
+++ b/net/quic/crypto/cached_network_parameters.h
@@ -0,0 +1,109 @@
+// Copyright (c) 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 NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
+#define NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
+
+#include <string>
+
+#include "base/basictypes.h"
+#include "base/strings/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+// TODO(rtenneti): sync with server more rationally.
+// CachedNetworkParameters contains data that can be used to choose appropriate
+// connection parameters (initial RTT, initial CWND, etc.) in new connections.
+class NET_EXPORT_PRIVATE CachedNetworkParameters {
+ public:
+ // Describes the state of the connection during which the supplied network
+ // parameters were calculated.
+ enum PreviousConnectionState {
+ SLOW_START = 0,
+ CONGESTION_AVOIDANCE = 1,
+ };
+
+ CachedNetworkParameters();
+ ~CachedNetworkParameters();
+
+ bool operator==(const CachedNetworkParameters& other) const;
+ bool operator!=(const CachedNetworkParameters& other) const;
+
+ std::string serving_region() const {
+ return serving_region_;
+ }
+ void set_serving_region(base::StringPiece serving_region) {
+ serving_region_ = serving_region.as_string();
+ }
+
+ int32 bandwidth_estimate_bytes_per_second() const {
+ return bandwidth_estimate_bytes_per_second_;
+ }
+ void set_bandwidth_estimate_bytes_per_second(
+ int32 bandwidth_estimate_bytes_per_second) {
+ bandwidth_estimate_bytes_per_second_ = bandwidth_estimate_bytes_per_second;
+ }
+
+ int32 max_bandwidth_estimate_bytes_per_second() const {
+ return max_bandwidth_estimate_bytes_per_second_;
+ }
+ void set_max_bandwidth_estimate_bytes_per_second(
+ int32 max_bandwidth_estimate_bytes_per_second) {
+ max_bandwidth_estimate_bytes_per_second_ =
+ max_bandwidth_estimate_bytes_per_second;
+ }
+
+ int64 max_bandwidth_timestamp_seconds() const {
+ return max_bandwidth_timestamp_seconds_;
+ }
+ void set_max_bandwidth_timestamp_seconds(
+ int64 max_bandwidth_timestamp_seconds) {
+ max_bandwidth_timestamp_seconds_ = max_bandwidth_timestamp_seconds;
+ }
+
+ int32 min_rtt_ms() const {
+ return min_rtt_ms_;
+ }
+ void set_min_rtt_ms(int32 min_rtt_ms) {
+ min_rtt_ms_ = min_rtt_ms;
+ }
+
+ int32 previous_connection_state() const {
+ return previous_connection_state_;
+ }
+ void set_previous_connection_state(int32 previous_connection_state) {
+ previous_connection_state_ = previous_connection_state;
+ }
+
+ int64 timestamp() const { return timestamp_; }
+ void set_timestamp(int64 timestamp) { timestamp_ = timestamp; }
+
+ private:
+ // serving_region_ is used to decide whether or not the bandwidth estimate and
+ // min RTT are reasonable and if they should be used.
+ // For example a group of geographically close servers may share the same
+ // serving_region_ string if they are expected to have similar network
+ // performance.
+ std::string serving_region_;
+ // The server can supply a bandwidth estimate (in bytes/s) which it may re-use
+ // on receipt of a source-address token with this field set.
+ int32 bandwidth_estimate_bytes_per_second_;
+ // The maximum bandwidth seen by the client, not necessarily the latest.
+ int32 max_bandwidth_estimate_bytes_per_second_;
+ // Timestamp (seconds since UNIX epoch) that indicates when the max bandwidth
+ // was seen by the server.
+ int64 max_bandwidth_timestamp_seconds_;
+ // The min RTT seen on a previous connection can be used by the server to
+ // inform initial connection parameters for new connections.
+ int32 min_rtt_ms_;
+ // Encodes the PreviousConnectionState enum.
+ int32 previous_connection_state_;
+ // UNIX timestamp when this bandwidth estimate was created.
+ int64 timestamp_;
+};
+
+} // namespace net
+
+#endif // NET_QUIC_CRYPTO_CACHED_NETWORK_PARAMETERS_H_
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index 4828c3a..268c8ee 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -847,8 +847,9 @@
break;
}
}
- if (i == canonical_suffixes_.size())
+ if (i == canonical_suffixes_.size()) {
return false;
+ }
QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
server_id.is_https(),
diff --git a/net/quic/crypto/quic_crypto_server_config.h b/net/quic/crypto/quic_crypto_server_config.h
index dbbff1a..8a58aea 100644
--- a/net/quic/crypto/quic_crypto_server_config.h
+++ b/net/quic/crypto/quic_crypto_server_config.h
@@ -15,11 +15,11 @@
#include "base/synchronization/lock.h"
#include "net/base/ip_endpoint.h"
#include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/crypto/crypto_handshake.h"
#include "net/quic/crypto/crypto_handshake_message.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_secret_boxer.h"
-#include "net/quic/crypto/source_address_token.h"
#include "net/quic/quic_time.h"
namespace net {
diff --git a/net/quic/crypto/source_address_token.cc b/net/quic/crypto/source_address_token.cc
index 0b514fe..5faedaa 100644
--- a/net/quic/crypto/source_address_token.cc
+++ b/net/quic/crypto/source_address_token.cc
@@ -11,37 +11,6 @@
namespace net {
-CachedNetworkParameters::CachedNetworkParameters()
- : bandwidth_estimate_bytes_per_second_(0),
- max_bandwidth_estimate_bytes_per_second_(0),
- max_bandwidth_timestamp_seconds_(0),
- min_rtt_ms_(0),
- previous_connection_state_(0),
- timestamp_(0) {
-}
-
-CachedNetworkParameters::~CachedNetworkParameters() {
-}
-
-bool CachedNetworkParameters::operator==(
- const CachedNetworkParameters& other) const {
- return serving_region_ == other.serving_region_ &&
- bandwidth_estimate_bytes_per_second_ ==
- other.bandwidth_estimate_bytes_per_second_ &&
- max_bandwidth_estimate_bytes_per_second_ ==
- other.max_bandwidth_estimate_bytes_per_second_ &&
- max_bandwidth_timestamp_seconds_ ==
- other.max_bandwidth_timestamp_seconds_ &&
- min_rtt_ms_ == other.min_rtt_ms_ &&
- previous_connection_state_ == other.previous_connection_state_ &&
- timestamp_ == other.timestamp_;
-}
-
-bool CachedNetworkParameters::operator!=(
- const CachedNetworkParameters& other) const {
- return !(*this == other);
-}
-
SourceAddressToken::SourceAddressToken()
: has_cached_network_parameters_(false) {
}
diff --git a/net/quic/crypto/source_address_token.h b/net/quic/crypto/source_address_token.h
index 76c3454..f9a5098 100644
--- a/net/quic/crypto/source_address_token.h
+++ b/net/quic/crypto/source_address_token.h
@@ -10,101 +10,11 @@
#include "base/basictypes.h"
#include "base/strings/string_piece.h"
#include "net/base/net_export.h"
+#include "net/quic/crypto/cached_network_parameters.h"
namespace net {
// TODO(rtenneti): sync with server more rationally.
-// CachedNetworkParameters contains data that can be used to choose appropriate
-// connection parameters (initial RTT, initial CWND, etc.) in new connections.
-class NET_EXPORT_PRIVATE CachedNetworkParameters {
- public:
- // Describes the state of the connection during which the supplied network
- // parameters were calculated.
- enum PreviousConnectionState {
- SLOW_START = 0,
- CONGESTION_AVOIDANCE = 1,
- };
-
- CachedNetworkParameters();
- ~CachedNetworkParameters();
-
- bool operator==(const CachedNetworkParameters& other) const;
- bool operator!=(const CachedNetworkParameters& other) const;
-
- std::string serving_region() const {
- return serving_region_;
- }
- void set_serving_region(base::StringPiece serving_region) {
- serving_region_ = serving_region.as_string();
- }
-
- int32 bandwidth_estimate_bytes_per_second() const {
- return bandwidth_estimate_bytes_per_second_;
- }
- void set_bandwidth_estimate_bytes_per_second(
- int32 bandwidth_estimate_bytes_per_second) {
- bandwidth_estimate_bytes_per_second_ = bandwidth_estimate_bytes_per_second;
- }
-
- int32 max_bandwidth_estimate_bytes_per_second() const {
- return max_bandwidth_estimate_bytes_per_second_;
- }
- void set_max_bandwidth_estimate_bytes_per_second(
- int32 max_bandwidth_estimate_bytes_per_second) {
- max_bandwidth_estimate_bytes_per_second_ =
- max_bandwidth_estimate_bytes_per_second;
- }
-
- int64 max_bandwidth_timestamp_seconds() const {
- return max_bandwidth_timestamp_seconds_;
- }
- void set_max_bandwidth_timestamp_seconds(
- int64 max_bandwidth_timestamp_seconds) {
- max_bandwidth_timestamp_seconds_ = max_bandwidth_timestamp_seconds;
- }
-
- int32 min_rtt_ms() const {
- return min_rtt_ms_;
- }
- void set_min_rtt_ms(int32 min_rtt_ms) {
- min_rtt_ms_ = min_rtt_ms;
- }
-
- int32 previous_connection_state() const {
- return previous_connection_state_;
- }
- void set_previous_connection_state(int32 previous_connection_state) {
- previous_connection_state_ = previous_connection_state;
- }
-
- int64 timestamp() const { return timestamp_; }
- void set_timestamp(int64 timestamp) { timestamp_ = timestamp; }
-
- private:
- // serving_region_ is used to decide whether or not the bandwidth estimate and
- // min RTT are reasonable and if they should be used.
- // For example a group of geographically close servers may share the same
- // serving_region_ string if they are expected to have similar network
- // performance.
- std::string serving_region_;
- // The server can supply a bandwidth estimate (in bytes/s) which it may re-use
- // on receipt of a source-address token with this field set.
- int32 bandwidth_estimate_bytes_per_second_;
- // The maximum bandwidth seen by the client, not necessarily the latest.
- int32 max_bandwidth_estimate_bytes_per_second_;
- // Timestamp (seconds since UNIX epoch) that indicates when the max bandwidth
- // was seen by the server.
- int64 max_bandwidth_timestamp_seconds_;
- // The min RTT seen on a previous connection can be used by the server to
- // inform initial connection parameters for new connections.
- int32 min_rtt_ms_;
- // Encodes the PreviousConnectionState enum.
- int32 previous_connection_state_;
- // UNIX timestamp when this bandwidth estimate was created.
- int64 timestamp_;
-};
-
-// TODO(rtenneti): sync with server more rationally.
// A SourceAddressToken is serialised, encrypted and sent to clients so that
// they can prove ownership of an IP address.
class NET_EXPORT_PRIVATE SourceAddressToken {
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 73a5aec..274099c 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -155,10 +155,9 @@
TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
const QuicConfig& config,
- bool is_secure,
base::TaskRunner* task_runner,
NetLog* net_log)
- : QuicClientSessionBase(connection, config, is_secure),
+ : QuicClientSessionBase(connection, config),
require_confirmation_(false),
stream_factory_(stream_factory),
socket_(socket.Pass()),
diff --git a/net/quic/quic_client_session.h b/net/quic/quic_client_session.h
index 6c33eb5..b1a35d9 100644
--- a/net/quic/quic_client_session.h
+++ b/net/quic/quic_client_session.h
@@ -96,7 +96,6 @@
TransportSecurityState* transport_security_state,
scoped_ptr<QuicServerInfo> server_info,
const QuicConfig& config,
- bool is_secure,
base::TaskRunner* task_runner,
NetLog* net_log);
~QuicClientSession() override;
diff --git a/net/quic/quic_client_session_base.cc b/net/quic/quic_client_session_base.cc
index 5b5902b..40d4b86 100644
--- a/net/quic/quic_client_session_base.cc
+++ b/net/quic/quic_client_session_base.cc
@@ -10,9 +10,8 @@
QuicClientSessionBase::QuicClientSessionBase(
QuicConnection* connection,
- const QuicConfig& config,
- bool is_secure)
- : QuicSession(connection, config, is_secure) {}
+ const QuicConfig& config)
+ : QuicSession(connection, config) {}
QuicClientSessionBase::~QuicClientSessionBase() {}
diff --git a/net/quic/quic_client_session_base.h b/net/quic/quic_client_session_base.h
index a7f64fb..d72996c 100644
--- a/net/quic/quic_client_session_base.h
+++ b/net/quic/quic_client_session_base.h
@@ -14,8 +14,7 @@
class NET_EXPORT_PRIVATE QuicClientSessionBase : public QuicSession {
public:
QuicClientSessionBase(QuicConnection* connection,
- const QuicConfig& config,
- bool is_secure);
+ const QuicConfig& config);
~QuicClientSessionBase() override;
diff --git a/net/quic/quic_client_session_test.cc b/net/quic/quic_client_session_test.cc
index 8860f2e..66583b8 100644
--- a/net/quic/quic_client_session_test.cc
+++ b/net/quic/quic_client_session_test.cc
@@ -46,7 +46,6 @@
session_(connection_, GetSocket().Pass(), nullptr,
&transport_security_state_,
make_scoped_ptr((QuicServerInfo*)nullptr), DefaultQuicConfig(),
- /*is_secure=*/false,
base::MessageLoop::current()->message_loop_proxy().get(),
&net_log_) {
session_.InitializeSession(QuicServerId(kServerHostname, kServerPort,
diff --git a/net/quic/quic_config.cc b/net/quic/quic_config.cc
index b1b7343..622cf3f 100644
--- a/net/quic/quic_config.cc
+++ b/net/quic/quic_config.cc
@@ -434,7 +434,6 @@
keepalive_timeout_seconds_(kKATO, PRESENCE_OPTIONAL),
max_streams_per_connection_(kMSPC, PRESENCE_REQUIRED),
bytes_for_connection_id_(kTCID, PRESENCE_OPTIONAL),
- initial_congestion_window_(kSWND, PRESENCE_OPTIONAL),
initial_round_trip_time_us_(kIRTT, PRESENCE_OPTIONAL),
// TODO(rjshade): Remove this when retiring QUIC_VERSION_19.
initial_flow_control_window_bytes_(kIFCW, PRESENCE_OPTIONAL),
@@ -524,18 +523,6 @@
return bytes_for_connection_id_.GetReceivedValue();
}
-void QuicConfig::SetInitialCongestionWindowToSend(size_t initial_window) {
- initial_congestion_window_.SetSendValue(initial_window);
-}
-
-bool QuicConfig::HasReceivedInitialCongestionWindow() const {
- return initial_congestion_window_.HasReceivedValue();
-}
-
-uint32 QuicConfig::ReceivedInitialCongestionWindow() const {
- return initial_congestion_window_.GetReceivedValue();
-}
-
void QuicConfig::SetInitialRoundTripTimeUsToSend(size_t rtt) {
initial_round_trip_time_us_.SetSendValue(rtt);
}
@@ -675,7 +662,6 @@
keepalive_timeout_seconds_.ToHandshakeMessage(out);
max_streams_per_connection_.ToHandshakeMessage(out);
bytes_for_connection_id_.ToHandshakeMessage(out);
- initial_congestion_window_.ToHandshakeMessage(out);
initial_round_trip_time_us_.ToHandshakeMessage(out);
initial_flow_control_window_bytes_.ToHandshakeMessage(out);
initial_stream_flow_control_window_bytes_.ToHandshakeMessage(out);
@@ -712,10 +698,6 @@
peer_hello, hello_type, error_details);
}
if (error == QUIC_NO_ERROR) {
- error = initial_congestion_window_.ProcessPeerHello(
- peer_hello, hello_type, error_details);
- }
- if (error == QUIC_NO_ERROR) {
error = initial_round_trip_time_us_.ProcessPeerHello(
peer_hello, hello_type, error_details);
}
diff --git a/net/quic/quic_config.h b/net/quic/quic_config.h
index a4d6129..cf3775c 100644
--- a/net/quic/quic_config.h
+++ b/net/quic/quic_config.h
@@ -319,13 +319,6 @@
uint32 ReceivedBytesForConnectionId() const;
- // Sets the peer's default initial congestion window in packets.
- void SetInitialCongestionWindowToSend(size_t initial_window);
-
- bool HasReceivedInitialCongestionWindow() const;
-
- uint32 ReceivedInitialCongestionWindow() const;
-
// Sets an estimated initial round trip time in us.
void SetInitialRoundTripTimeUsToSend(size_t rtt_us);
@@ -413,8 +406,6 @@
QuicNegotiableUint32 max_streams_per_connection_;
// The number of bytes required for the connection ID.
QuicFixedUint32 bytes_for_connection_id_;
- // Initial congestion window in packets.
- QuicFixedUint32 initial_congestion_window_;
// Initial round trip time estimate in microseconds.
QuicFixedUint32 initial_round_trip_time_us_;
diff --git a/net/quic/quic_config_test.cc b/net/quic/quic_config_test.cc
index 914b137..413d7fb 100644
--- a/net/quic/quic_config_test.cc
+++ b/net/quic/quic_config_test.cc
@@ -81,8 +81,7 @@
QuicTime::Delta::FromSeconds(kMaximumIdleTimeoutSecs));
client_config.SetMaxStreamsPerConnection(
2 * kDefaultMaxStreamsPerConnection, kDefaultMaxStreamsPerConnection);
- client_config.SetInitialRoundTripTimeUsToSend(
- 10 * base::Time::kMicrosecondsPerMillisecond);
+ client_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
client_config.SetInitialFlowControlWindowToSend(
2 * kInitialSessionFlowControlWindowForTest);
client_config.SetInitialStreamFlowControlWindowToSend(
@@ -107,8 +106,7 @@
EXPECT_EQ(kDefaultMaxStreamsPerConnection,
config_.MaxStreamsPerConnection());
EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
- EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
- config_.ReceivedInitialRoundTripTimeUs());
+ EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
EXPECT_TRUE(config_.HasReceivedConnectionOptions());
EXPECT_EQ(2u, config_.ReceivedConnectionOptions().size());
EXPECT_EQ(config_.ReceivedConnectionOptions()[0], kTBBR);
@@ -134,9 +132,7 @@
server_config.SetMaxStreamsPerConnection(
kDefaultMaxStreamsPerConnection / 2,
kDefaultMaxStreamsPerConnection / 2);
- server_config.SetInitialCongestionWindowToSend(kDefaultInitialWindow / 2);
- server_config.SetInitialRoundTripTimeUsToSend(
- 10 * base::Time::kMicrosecondsPerMillisecond);
+ server_config.SetInitialRoundTripTimeUsToSend(10 * kNumMicrosPerMilli);
server_config.SetInitialFlowControlWindowToSend(
2 * kInitialSessionFlowControlWindowForTest);
server_config.SetInitialStreamFlowControlWindowToSend(
@@ -156,11 +152,8 @@
config_.IdleConnectionStateLifetime());
EXPECT_EQ(kDefaultMaxStreamsPerConnection / 2,
config_.MaxStreamsPerConnection());
- EXPECT_EQ(kDefaultInitialWindow / 2,
- config_.ReceivedInitialCongestionWindow());
EXPECT_EQ(QuicTime::Delta::FromSeconds(0), config_.KeepaliveTimeout());
- EXPECT_EQ(10 * base::Time::kMicrosecondsPerMillisecond,
- config_.ReceivedInitialRoundTripTimeUs());
+ EXPECT_EQ(10 * kNumMicrosPerMilli, config_.ReceivedInitialRoundTripTimeUs());
EXPECT_EQ(config_.ReceivedInitialFlowControlWindowBytes(),
2 * kInitialSessionFlowControlWindowForTest);
EXPECT_EQ(config_.ReceivedInitialStreamFlowControlWindowBytes(),
diff --git a/net/quic/quic_connection.cc b/net/quic/quic_connection.cc
index 6308d88..fd9ec5f 100644
--- a/net/quic/quic_connection.cc
+++ b/net/quic/quic_connection.cc
@@ -189,6 +189,7 @@
const PacketWriterFactory& writer_factory,
bool owns_writer,
bool is_server,
+ bool is_secure,
const QuicVersionVector& supported_versions)
: framer_(supported_versions, helper->GetClock()->ApproximateNow(),
is_server),
@@ -222,9 +223,7 @@
timeout_alarm_(helper->CreateAlarm(new TimeoutAlarm(this))),
ping_alarm_(helper->CreateAlarm(new PingAlarm(this))),
packet_generator_(connection_id_, &framer_, random_generator_, this),
- idle_network_timeout_(FLAGS_quic_unified_timeouts ?
- QuicTime::Delta::Infinite() :
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs)),
+ idle_network_timeout_(QuicTime::Delta::Infinite()),
overall_connection_timeout_(QuicTime::Delta::Infinite()),
time_of_last_received_packet_(clock_->ApproximateNow()),
time_of_last_sent_new_packet_(clock_->ApproximateNow()),
@@ -232,7 +231,8 @@
sent_packet_manager_(
is_server, clock_, &stats_,
FLAGS_quic_use_bbr_congestion_control ? kBBR : kCubic,
- FLAGS_quic_use_time_loss_detection ? kTime : kNack),
+ FLAGS_quic_use_time_loss_detection ? kTime : kNack,
+ is_secure),
version_negotiation_state_(START_NEGOTIATION),
is_server_(is_server),
connected_(true),
@@ -240,12 +240,10 @@
peer_port_changed_(false),
self_ip_changed_(false),
self_port_changed_(false),
- can_truncate_connection_ids_(true) {
+ can_truncate_connection_ids_(true),
+ is_secure_(is_secure) {
DVLOG(1) << ENDPOINT << "Created connection with connection_id: "
<< connection_id;
- if (!FLAGS_quic_unified_timeouts) {
- timeout_alarm_->Set(clock_->ApproximateNow().Add(idle_network_timeout_));
- }
framer_.set_visitor(this);
framer_.set_received_entropy_calculator(&received_packet_manager_);
stats_.connection_creation_time = clock_->ApproximateNow();
@@ -266,17 +264,14 @@
}
void QuicConnection::SetFromConfig(const QuicConfig& config) {
- if (FLAGS_quic_unified_timeouts) {
- if (config.negotiated()) {
- SetNetworkTimeouts(QuicTime::Delta::Infinite(),
- config.IdleConnectionStateLifetime());
- } else {
- SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
- config.max_idle_time_before_crypto_handshake());
- }
+ if (config.negotiated()) {
+ SetNetworkTimeouts(QuicTime::Delta::Infinite(),
+ config.IdleConnectionStateLifetime());
} else {
- SetIdleNetworkTimeout(config.IdleConnectionStateLifetime());
+ SetNetworkTimeouts(config.max_time_before_crypto_handshake(),
+ config.max_idle_time_before_crypto_handshake());
}
+
sent_packet_manager_.SetFromConfig(config);
if (FLAGS_allow_truncated_connection_ids_for_quic &&
config.HasReceivedBytesForConnectionId() &&
@@ -1898,11 +1893,11 @@
}
}
-size_t QuicConnection::max_packet_length() const {
+QuicByteCount QuicConnection::max_packet_length() const {
return packet_generator_.max_packet_length();
}
-void QuicConnection::set_max_packet_length(size_t length) {
+void QuicConnection::set_max_packet_length(QuicByteCount length) {
return packet_generator_.set_max_packet_length(length);
}
@@ -1928,32 +1923,6 @@
pending_handshake);
}
-void QuicConnection::SetIdleNetworkTimeout(QuicTime::Delta timeout) {
- // Adjust the idle timeout on client and server to prevent clients from
- // sending requests to servers which have already closed the connection.
- if (is_server_) {
- timeout = timeout.Add(QuicTime::Delta::FromSeconds(3));
- } else if (timeout > QuicTime::Delta::FromSeconds(1)) {
- timeout = timeout.Subtract(QuicTime::Delta::FromSeconds(1));
- }
-
- if (timeout < idle_network_timeout_) {
- idle_network_timeout_ = timeout;
- SetTimeoutAlarm();
- } else {
- idle_network_timeout_ = timeout;
- }
-}
-
-void QuicConnection::SetOverallConnectionTimeout(QuicTime::Delta timeout) {
- if (timeout < overall_connection_timeout_) {
- overall_connection_timeout_ = timeout;
- SetTimeoutAlarm();
- } else {
- overall_connection_timeout_ = timeout;
- }
-}
-
void QuicConnection::SetNetworkTimeouts(QuicTime::Delta overall_timeout,
QuicTime::Delta idle_timeout) {
LOG_IF(DFATAL, idle_timeout > overall_timeout)
diff --git a/net/quic/quic_connection.h b/net/quic/quic_connection.h
index f9f8733..96f5cbc 100644
--- a/net/quic/quic_connection.h
+++ b/net/quic/quic_connection.h
@@ -251,6 +251,7 @@
const PacketWriterFactory& writer_factory,
bool owns_writer,
bool is_server,
+ bool is_secure,
const QuicVersionVector& supported_versions);
~QuicConnection() override;
@@ -397,8 +398,8 @@
QuicConnectionId connection_id() const { return connection_id_; }
const QuicClock* clock() const { return clock_; }
QuicRandom* random_generator() const { return random_generator_; }
- size_t max_packet_length() const;
- void set_max_packet_length(size_t length);
+ QuicByteCount max_packet_length() const;
+ void set_max_packet_length(QuicByteCount length);
bool connected() const { return connected_; }
@@ -425,16 +426,6 @@
// Returns true if the connection has queued packets or frames.
bool HasQueuedData() const;
- // TODO(ianswett): Remove when quic_unified_timeouts is removed.
- // Sets (or resets) the idle state connection timeout. Also, checks and times
- // out the connection if network timer has expired for |timeout|.
- void SetIdleNetworkTimeout(QuicTime::Delta timeout);
-
- // Sets (or resets) the total time delta the connection can be alive for.
- // Used to limit the time a connection can be alive before crypto handshake
- // finishes.
- void SetOverallConnectionTimeout(QuicTime::Delta timeout);
-
// Sets the overall and idle state connection timeouts.
void SetNetworkTimeouts(QuicTime::Delta overall_timeout,
QuicTime::Delta idle_timeout);
@@ -530,6 +521,9 @@
QuicPacketSequenceNumber sequence_number_of_last_sent_packet() const {
return sequence_number_of_last_sent_packet_;
}
+ const QuicPacketWriter* writer() const { return writer_; }
+
+ bool is_secure() const { return is_secure_; }
protected:
// Packets which have not been written to the wire.
@@ -567,7 +561,6 @@
bool SelectMutualVersion(const QuicVersionVector& available_versions);
QuicPacketWriter* writer() { return writer_; }
- const QuicPacketWriter* writer() const { return writer_; }
bool peer_port_changed() const { return peer_port_changed_; }
@@ -702,7 +695,7 @@
// decrypted.
bool last_packet_decrypted_;
bool last_packet_revived_; // True if the last packet was revived from FEC.
- size_t last_size_; // Size of the last received packet.
+ QuicByteCount last_size_; // Size of the last received packet.
EncryptionLevel last_decrypted_packet_level_;
QuicPacketHeader last_header_;
std::vector<QuicStreamFrame> last_stream_frames_;
@@ -837,6 +830,9 @@
// version negotiation packet.
QuicVersionVector server_supported_versions_;
+ // True if this is a secure QUIC connection.
+ bool is_secure_;
+
DISALLOW_COPY_AND_ASSIGN(QuicConnection);
};
diff --git a/net/quic/quic_connection_test.cc b/net/quic/quic_connection_test.cc
index 66cb89c..4e58dfd 100644
--- a/net/quic/quic_connection_test.cc
+++ b/net/quic/quic_connection_test.cc
@@ -408,6 +408,7 @@
factory,
/* owns_writer= */ false,
is_server,
+ /* is_secure= */ false,
SupportedVersions(version)) {
// Disable tail loss probes for most tests.
QuicSentPacketManagerPeer::SetMaxTailLossProbes(
@@ -2506,7 +2507,7 @@
TEST_P(QuicConnectionTest, BufferNonDecryptablePackets) {
// SetFromConfig is always called after construction from InitializeSession.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
connection_.SetFromConfig(config);
EXPECT_CALL(visitor_, OnSuccessfulVersionNegotiation(_));
@@ -2536,7 +2537,7 @@
TEST_P(QuicConnectionTest, Buffer100NonDecryptablePackets) {
// SetFromConfig is always called after construction from InitializeSession.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
config.set_max_undecryptable_packets(100);
connection_.SetFromConfig(config);
@@ -2775,36 +2776,12 @@
}
TEST_P(QuicConnectionTest, InitialTimeout) {
- if (!FLAGS_quic_unified_timeouts) {
- EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_,
- OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
-
- QuicTime default_timeout = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
- EXPECT_EQ(default_timeout, connection_.GetTimeoutAlarm()->deadline());
-
- // Simulate the timeout alarm firing.
- clock_.AdvanceTime(QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
- connection_.GetTimeoutAlarm()->Fire();
-
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
-
- EXPECT_FALSE(connection_.GetAckAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetPingAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetResumeWritesAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetRetransmissionAlarm()->IsSet());
- EXPECT_FALSE(connection_.GetSendAlarm()->IsSet());
- return;
- }
EXPECT_TRUE(connection_.connected());
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(AnyNumber());
EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
// SetFromConfig sets the initial timeouts before negotiation.
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
connection_.SetFromConfig(config);
// Subtract a second from the idle timeout on the client side.
@@ -2913,44 +2890,8 @@
}
TEST_P(QuicConnectionTest, TimeoutAfterSend) {
- if (!FLAGS_quic_unified_timeouts) {
- EXPECT_TRUE(connection_.connected());
-
- QuicTime default_timeout = clock_.ApproximateNow().Add(
- QuicTime::Delta::FromSeconds(kDefaultIdleTimeoutSecs));
-
- // When we send a packet, the timeout will change to 5000 +
- // kDefaultInitialTimeoutSecs.
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
-
- // 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=5000. The alarm will reregister.
- clock_.AdvanceTime(QuicTime::Delta::FromMicroseconds(
- kDefaultIdleTimeoutSecs * 1000000 - 5000));
- EXPECT_EQ(default_timeout, clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_TRUE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_TRUE(connection_.connected());
- EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
- connection_.GetTimeoutAlarm()->deadline());
-
- // This time, we should time out.
- EXPECT_CALL(visitor_, OnConnectionClosed(QUIC_CONNECTION_TIMED_OUT, false));
- EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _));
- clock_.AdvanceTime(QuicTime::Delta::FromMilliseconds(5));
- EXPECT_EQ(default_timeout.Add(QuicTime::Delta::FromMilliseconds(5)),
- clock_.ApproximateNow());
- connection_.GetTimeoutAlarm()->Fire();
- EXPECT_FALSE(connection_.GetTimeoutAlarm()->IsSet());
- EXPECT_FALSE(connection_.connected());
- return;
- }
EXPECT_TRUE(connection_.connected());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
QuicConfig config;
connection_.SetFromConfig(config);
@@ -3055,7 +2996,7 @@
// Set up a larger payload than will fit in one packet.
const string payload(connection_.max_packet_length(), 'a');
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)).Times(AnyNumber());
// Now send some packets with no truncation.
EXPECT_CALL(*send_algorithm_, OnPacketSent(_, _, _, _, _)).Times(2);
diff --git a/net/quic/quic_crypto_server_stream.cc b/net/quic/quic_crypto_server_stream.cc
index dac2087..1d62376 100644
--- a/net/quic/quic_crypto_server_stream.cc
+++ b/net/quic/quic_crypto_server_stream.cc
@@ -6,10 +6,10 @@
#include "base/base64.h"
#include "crypto/secure_hash.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/crypto/crypto_protocol.h"
#include "net/quic/crypto/crypto_utils.h"
#include "net/quic/crypto/quic_crypto_server_config.h"
-#include "net/quic/crypto/source_address_token.h"
#include "net/quic/quic_config.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_protocol.h"
diff --git a/net/quic/quic_dispatcher.cc b/net/quic/quic_dispatcher.cc
index aede7c2..d27b454 100644
--- a/net/quic/quic_dispatcher.cc
+++ b/net/quic/quic_dispatcher.cc
@@ -352,8 +352,7 @@
QuicServerSession* session = new QuicServerSession(
config_,
CreateQuicConnection(connection_id, server_address, client_address),
- this,
- crypto_config_.HasProofSource());
+ this);
session->InitializeSession(crypto_config_);
return session;
}
@@ -368,6 +367,7 @@
connection_writer_factory_,
/* owns_writer= */ true,
/* is_server= */ true,
+ crypto_config_.HasProofSource(),
supported_versions_);
}
diff --git a/net/quic/quic_flags.cc b/net/quic/quic_flags.cc
index 8d6dd86..47d58ce 100644
--- a/net/quic/quic_flags.cc
+++ b/net/quic/quic_flags.cc
@@ -36,10 +36,6 @@
// limit.
bool FLAGS_quic_allow_more_open_streams = false;
-// If true, then QUIC connections will set both idle and overall timeouts in a
-// single method.
-bool FLAGS_quic_unified_timeouts = true;
-
// If true, QUIC will be more resilliant to junk packets with valid connection
// IDs.
bool FLAGS_quic_drop_junk_packets = true;
diff --git a/net/quic/quic_flags.h b/net/quic/quic_flags.h
index d49f47a..a75f79b 100644
--- a/net/quic/quic_flags.h
+++ b/net/quic/quic_flags.h
@@ -15,7 +15,6 @@
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_allow_more_open_streams;
-NET_EXPORT_PRIVATE extern bool FLAGS_quic_unified_timeouts;
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;
diff --git a/net/quic/quic_framer.cc b/net/quic/quic_framer.cc
index e2487b4..d2a7694 100644
--- a/net/quic/quic_framer.cc
+++ b/net/quic/quic_framer.cc
@@ -978,30 +978,30 @@
QuicFramer::AckFrameInfo QuicFramer::GetAckFrameInfo(
const QuicAckFrame& frame) {
AckFrameInfo ack_info;
- if (!frame.missing_packets.empty()) {
- DCHECK_GE(frame.largest_observed, *frame.missing_packets.rbegin());
- size_t cur_range_length = 0;
- SequenceNumberSet::const_iterator iter = frame.missing_packets.begin();
- QuicPacketSequenceNumber last_missing = *iter;
- ++iter;
- for (; iter != frame.missing_packets.end(); ++iter) {
- if (cur_range_length != numeric_limits<uint8>::max() &&
- *iter == (last_missing + 1)) {
- ++cur_range_length;
- } else {
- ack_info.nack_ranges[last_missing - cur_range_length] =
- cur_range_length;
- cur_range_length = 0;
- }
- ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing);
- last_missing = *iter;
- }
- // Include the last nack range.
- ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
- // Include the range to the largest observed.
- ack_info.max_delta = max(ack_info.max_delta,
- frame.largest_observed - last_missing);
+ if (frame.missing_packets.empty()) {
+ return ack_info;
}
+ DCHECK_GE(frame.largest_observed, *frame.missing_packets.rbegin());
+ size_t cur_range_length = 0;
+ SequenceNumberSet::const_iterator iter = frame.missing_packets.begin();
+ QuicPacketSequenceNumber last_missing = *iter;
+ ++iter;
+ for (; iter != frame.missing_packets.end(); ++iter) {
+ if (cur_range_length != numeric_limits<uint8>::max() &&
+ *iter == (last_missing + 1)) {
+ ++cur_range_length;
+ } else {
+ ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
+ cur_range_length = 0;
+ }
+ ack_info.max_delta = max(ack_info.max_delta, *iter - last_missing);
+ last_missing = *iter;
+ }
+ // Include the last nack range.
+ ack_info.nack_ranges[last_missing - cur_range_length] = cur_range_length;
+ // Include the range to the largest observed.
+ ack_info.max_delta =
+ max(ack_info.max_delta, frame.largest_observed - last_missing);
return ack_info;
}
diff --git a/net/quic/quic_http_stream_test.cc b/net/quic/quic_http_stream_test.cc
index db97aac..a172c24 100644
--- a/net/quic/quic_http_stream_test.cc
+++ b/net/quic/quic_http_stream_test.cc
@@ -65,8 +65,9 @@
address,
helper,
writer_factory,
- true /* owns_writer */,
+ true /* owns_writer */,
false /* is_server */,
+ false /* is_secure */,
versions) {
}
@@ -215,7 +216,7 @@
WillRepeatedly(Return(QuicTime::Delta::Zero()));
EXPECT_CALL(*send_algorithm_, BandwidthEstimate()).WillRepeatedly(
Return(QuicBandwidth::Zero()));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _)).Times(AnyNumber());
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _)).Times(AnyNumber());
helper_.reset(new QuicConnectionHelper(runner_.get(), &clock_,
&random_generator_));
TestPacketWriterFactory writer_factory(socket);
@@ -232,7 +233,6 @@
&transport_security_state_,
make_scoped_ptr((QuicServerInfo*)nullptr),
DefaultQuicConfig(),
- /*is_secure=*/false,
base::MessageLoop::current()->
message_loop_proxy().get(),
nullptr));
diff --git a/net/quic/quic_packet_creator.h b/net/quic/quic_packet_creator.h
index 287cde1..bada2c3 100644
--- a/net/quic/quic_packet_creator.h
+++ b/net/quic/quic_packet_creator.h
@@ -212,11 +212,11 @@
next_sequence_number_length_ = length;
}
- size_t max_packet_length() const {
+ QuicByteCount max_packet_length() const {
return max_packet_length_;
}
- void set_max_packet_length(size_t length) {
+ void set_max_packet_length(QuicByteCount length) {
// |max_packet_length_| should not be changed mid-packet or mid-FEC group.
DCHECK(fec_group_.get() == nullptr && queued_frames_.empty());
max_packet_length_ = length;
@@ -272,7 +272,7 @@
// packet.
bool send_version_in_packet_;
// Maximum length including headers and encryption (UDP payload length.)
- size_t max_packet_length_;
+ QuicByteCount max_packet_length_;
// 0 indicates FEC is disabled.
size_t max_packets_per_fec_group_;
// Length of connection_id to send over the wire.
diff --git a/net/quic/quic_packet_generator.cc b/net/quic/quic_packet_generator.cc
index 2481ddc..21ab10c 100644
--- a/net/quic/quic_packet_generator.cc
+++ b/net/quic/quic_packet_generator.cc
@@ -357,11 +357,11 @@
return packet_creator_.sequence_number();
}
-size_t QuicPacketGenerator::max_packet_length() const {
+QuicByteCount QuicPacketGenerator::max_packet_length() const {
return packet_creator_.max_packet_length();
}
-void QuicPacketGenerator::set_max_packet_length(size_t length) {
+void QuicPacketGenerator::set_max_packet_length(QuicByteCount length) {
packet_creator_.set_max_packet_length(length);
}
diff --git a/net/quic/quic_packet_generator.h b/net/quic/quic_packet_generator.h
index 3fec02a..2882aab 100644
--- a/net/quic/quic_packet_generator.h
+++ b/net/quic/quic_packet_generator.h
@@ -177,9 +177,9 @@
// created.
QuicPacketSequenceNumber sequence_number() const;
- size_t max_packet_length() const;
+ QuicByteCount max_packet_length() const;
- void set_max_packet_length(size_t length);
+ void set_max_packet_length(QuicByteCount length);
void set_debug_delegate(DebugDelegate* debug_delegate) {
debug_delegate_ = debug_delegate;
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index ad920d0..00064ff 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -60,8 +60,11 @@
const QuicByteCount kDefaultTCPMSS = 1460;
// Maximum size of the initial congestion window in packets.
-const QuicPacketCount kDefaultInitialWindow = 10;
const QuicPacketCount kMaxInitialWindow = 100;
+// We match SPDY's use of 32 when secure (since we'd compete with SPDY).
+const QuicPacketCount kInitialCongestionWindowSecure = 32;
+// Be conservative, and just use double a typical TCP ICWND for HTTP.
+const QuicPacketCount kInitialCongestionWindowInsecure = 20;
// Default size of initial flow control window, for both stream and session.
const uint32 kDefaultFlowControlSendWindow = 16 * 1024; // 16 KB
diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc
index e186b03..68651cb 100644
--- a/net/quic/quic_reliable_client_stream.cc
+++ b/net/quic/quic_reliable_client_stream.cc
@@ -83,7 +83,7 @@
void QuicReliableClientStream::SetDelegate(
QuicReliableClientStream::Delegate* delegate) {
- DCHECK((!delegate_ && delegate) || (delegate_ && !delegate));
+ DCHECK(!(delegate_ && delegate));
delegate_ = delegate;
}
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index 9e2d04f..7978fed 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -34,8 +34,8 @@
static const int64 kMaxRetransmissionTimeMs = 60000;
static const size_t kMaxRetransmissions = 10;
-// Only exponentially back off the handshake timer 5 times due to a timeout.
-static const size_t kMaxHandshakeRetransmissionBackoffs = 5;
+// Ensure the handshake timer isnt't faster than 10ms.
+// This limits the tenth retransmitted packet to 10s after the initial CHLO.
static const int64 kMinHandshakeTimeoutMs = 10;
// Sends up to two tail loss probes before firing an RTO,
@@ -49,6 +49,10 @@
// Number of unpaced packets to send after quiescence.
static const size_t kInitialUnpacedBurst = 10;
+// Fraction of the receive buffer that can be used for encrypted bytes.
+// Allows a 5% overhead for IP and UDP framing, as well as ack only packets.
+static const float kUsableRecieveBufferFraction = 0.95f;
+
bool HasCryptoHandshake(const TransmissionInfo& transmission_info) {
if (transmission_info.retransmittable_frames == nullptr) {
return false;
@@ -66,17 +70,22 @@
const QuicClock* clock,
QuicConnectionStats* stats,
CongestionControlType congestion_control_type,
- LossDetectionType loss_type)
+ LossDetectionType loss_type,
+ bool is_secure)
: unacked_packets_(),
is_server_(is_server),
clock_(clock),
stats_(stats),
debug_delegate_(nullptr),
network_change_visitor_(nullptr),
- send_algorithm_(SendAlgorithmInterface::Create(clock,
- &rtt_stats_,
- congestion_control_type,
- stats)),
+ initial_congestion_window_(is_secure ? kInitialCongestionWindowSecure
+ : kInitialCongestionWindowInsecure),
+ send_algorithm_(
+ SendAlgorithmInterface::Create(clock,
+ &rtt_stats_,
+ congestion_control_type,
+ stats,
+ initial_congestion_window_)),
loss_algorithm_(LossDetectionInterface::Create(loss_type)),
n_connection_simulation_(false),
receive_buffer_bytes_(kDefaultSocketReceiveBuffer),
@@ -116,15 +125,17 @@
rtt_stats_.set_recent_min_rtt_window(
QuicTime::Delta::FromSeconds(FLAGS_quic_recent_min_rtt_window_s));
}
- send_algorithm_.reset(
- SendAlgorithmInterface::Create(clock_, &rtt_stats_, kBBR, stats_));
+ send_algorithm_.reset(SendAlgorithmInterface::Create(
+ clock_, &rtt_stats_, kBBR, stats_, initial_congestion_window_));
}
if (config.HasReceivedConnectionOptions() &&
ContainsQuicTag(config.ReceivedConnectionOptions(), kRENO)) {
- send_algorithm_.reset(
- SendAlgorithmInterface::Create(clock_, &rtt_stats_, kReno, stats_));
+ send_algorithm_.reset(SendAlgorithmInterface::Create(
+ clock_, &rtt_stats_, kReno, stats_, initial_congestion_window_));
}
- if (HasClientSentConnectionOption(config, kPACE)) {
+ if (HasClientSentConnectionOption(config, kPACE) ||
+ (FLAGS_quic_allow_bbr &&
+ HasClientSentConnectionOption(config, kTBBR))) {
EnablePacing();
}
if (HasClientSentConnectionOption(config, k1CON)) {
@@ -145,7 +156,7 @@
max(kMinSocketReceiveBuffer,
static_cast<QuicByteCount>(config.ReceivedSocketReceiveBuffer()));
}
- send_algorithm_->SetFromConfig(config, is_server_);
+ send_algorithm_->SetFromConfig(config, is_server_, using_pacing_);
if (network_change_visitor_ != nullptr) {
network_change_visitor_->OnCongestionWindowChange();
@@ -595,10 +606,7 @@
void QuicSentPacketManager::RetransmitCryptoPackets() {
DCHECK_EQ(HANDSHAKE_MODE, GetRetransmissionMode());
- // TODO(ianswett): Typical TCP implementations only retransmit 5 times.
- consecutive_crypto_retransmission_count_ =
- min(kMaxHandshakeRetransmissionBackoffs,
- consecutive_crypto_retransmission_count_ + 1);
+ ++consecutive_crypto_retransmission_count_;
bool packet_retransmitted = false;
QuicPacketSequenceNumber sequence_number = unacked_packets_.GetLeastUnacked();
for (QuicUnackedPacketMap::const_iterator it = unacked_packets_.begin();
@@ -757,7 +765,8 @@
if (pending_timer_transmission_count_ > 0) {
return QuicTime::Delta::Zero();
}
- if (unacked_packets_.bytes_in_flight() >= receive_buffer_bytes_) {
+ if (unacked_packets_.bytes_in_flight() >=
+ kUsableRecieveBufferFraction * receive_buffer_bytes_) {
return QuicTime::Delta::Infinite();
}
return send_algorithm_->TimeUntilSend(
diff --git a/net/quic/quic_sent_packet_manager.h b/net/quic/quic_sent_packet_manager.h
index f82e34b..2a3ea64 100644
--- a/net/quic/quic_sent_packet_manager.h
+++ b/net/quic/quic_sent_packet_manager.h
@@ -93,7 +93,8 @@
const QuicClock* clock,
QuicConnectionStats* stats,
CongestionControlType congestion_control_type,
- LossDetectionType loss_type);
+ LossDetectionType loss_type,
+ bool is_secure);
virtual ~QuicSentPacketManager();
virtual void SetFromConfig(const QuicConfig& config);
@@ -351,6 +352,7 @@
QuicConnectionStats* stats_;
DebugDelegate* debug_delegate_;
NetworkChangeVisitor* network_change_visitor_;
+ const QuicPacketCount initial_congestion_window_;
RttStats rtt_stats_;
scoped_ptr<SendAlgorithmInterface> send_algorithm_;
scoped_ptr<LossDetectionInterface> loss_algorithm_;
diff --git a/net/quic/quic_sent_packet_manager_test.cc b/net/quic/quic_sent_packet_manager_test.cc
index d7a846a..d710120 100644
--- a/net/quic/quic_sent_packet_manager_test.cc
+++ b/net/quic/quic_sent_packet_manager_test.cc
@@ -45,7 +45,7 @@
class QuicSentPacketManagerTest : public ::testing::TestWithParam<bool> {
protected:
QuicSentPacketManagerTest()
- : manager_(true, &clock_, &stats_, kCubic, kNack),
+ : manager_(true, &clock_, &stats_, kCubic, kNack, false),
send_algorithm_(new StrictMock<MockSendAlgorithm>),
network_change_visitor_(new StrictMock<MockNetworkChangeVisitor>) {
QuicSentPacketManagerPeer::SetSendAlgorithm(&manager_, send_algorithm_);
@@ -1080,12 +1080,12 @@
// Check the min.
RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(&manager_);
- rtt_stats->set_initial_rtt_us(1 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
manager_.GetRetransmissionTime());
// Test with a standard smoothed RTT.
- rtt_stats->set_initial_rtt_us(100 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
QuicTime::Delta srtt =
QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
@@ -1109,12 +1109,12 @@
// Check the min.
RttStats* rtt_stats = QuicSentPacketManagerPeer::GetRttStats(&manager_);
- rtt_stats->set_initial_rtt_us(1 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(1 * kNumMicrosPerMilli);
EXPECT_EQ(clock_.Now().Add(QuicTime::Delta::FromMilliseconds(10)),
manager_.GetRetransmissionTime());
// Test with a standard smoothed RTT.
- rtt_stats->set_initial_rtt_us(100 * base::Time::kMicrosecondsPerMillisecond);
+ rtt_stats->set_initial_rtt_us(100 * kNumMicrosPerMilli);
QuicTime::Delta srtt =
QuicTime::Delta::FromMicroseconds(rtt_stats->initial_rtt_us());
QuicTime::Delta expected_tlp_delay = srtt.Multiply(2);
@@ -1277,7 +1277,7 @@
QuicTagVector options;
options.push_back(kTIME);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
@@ -1318,7 +1318,7 @@
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(config);
QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
@@ -1326,7 +1326,7 @@
client_config.SetConnectionOptionsToSend(options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(1));
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(client_config);
}
@@ -1340,7 +1340,7 @@
options.push_back(kNCON);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(config);
EXPECT_CALL(*send_algorithm_, SetNumEmulatedConnections(5));
@@ -1354,7 +1354,7 @@
options.push_back(kNTLP);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(config);
EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
}
@@ -1367,7 +1367,7 @@
QuicSentPacketManagerPeer::SetIsServer(&manager_, false);
client_config.SetConnectionOptionsToSend(options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
manager_.SetFromConfig(client_config);
EXPECT_EQ(0u, QuicSentPacketManagerPeer::GetMaxTailLossProbes(&manager_));
}
@@ -1380,7 +1380,7 @@
options.push_back(kPACE);
QuicConfigPeer::SetReceivedConnectionOptions(&config, options);
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, /* using_pacing= */ true));
manager_.SetFromConfig(config);
EXPECT_TRUE(manager_.using_pacing());
@@ -1393,7 +1393,7 @@
// Try to set a size below the minimum and ensure it gets set to the min.
QuicConfig client_config;
QuicConfigPeer::SetReceivedSocketReceiveBuffer(&client_config, 1024);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(client_config);
@@ -1417,6 +1417,27 @@
manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
}
+TEST_F(QuicSentPacketManagerTest, ReceiveWindowLimited) {
+ EXPECT_EQ(kDefaultSocketReceiveBuffer,
+ QuicSentPacketManagerPeer::GetReceiveWindow(&manager_));
+
+ // Ensure the smaller send window only allows 256 * 0.95 packets to be sent.
+ for (QuicPacketSequenceNumber i = 1; i <= 244; ++i) {
+ EXPECT_CALL(*send_algorithm_, TimeUntilSend(_, _, _)).WillOnce(Return(
+ QuicTime::Delta::Zero()));
+ EXPECT_EQ(QuicTime::Delta::Zero(),
+ manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+ EXPECT_CALL(*send_algorithm_, OnPacketSent(_, BytesInFlight(), i,
+ 1024, HAS_RETRANSMITTABLE_DATA))
+ .WillOnce(Return(true));
+ SerializedPacket packet(CreatePacket(i, true));
+ manager_.OnPacketSent(&packet, 0, clock_.Now(), 1024,
+ NOT_RETRANSMISSION, HAS_RETRANSMITTABLE_DATA);
+ }
+ EXPECT_EQ(QuicTime::Delta::Infinite(),
+ manager_.TimeUntilSend(clock_.Now(), HAS_RETRANSMITTABLE_DATA));
+}
+
TEST_F(QuicSentPacketManagerTest, UseInitialRoundTripTimeToSend) {
uint32 initial_rtt_us = 325000;
EXPECT_NE(initial_rtt_us,
@@ -1424,7 +1445,7 @@
QuicConfig config;
config.SetInitialRoundTripTimeUsToSend(initial_rtt_us);
- EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _));
+ EXPECT_CALL(*send_algorithm_, SetFromConfig(_, _, _));
EXPECT_CALL(*network_change_visitor_, OnCongestionWindowChange());
manager_.SetFromConfig(config);
diff --git a/net/quic/quic_server_session.cc b/net/quic/quic_server_session.cc
index 7fab509..1d48182 100644
--- a/net/quic/quic_server_session.cc
+++ b/net/quic/quic_server_session.cc
@@ -5,7 +5,7 @@
#include "net/quic/quic_server_session.h"
#include "base/logging.h"
-#include "net/quic/crypto/source_address_token.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flags.h"
#include "net/quic/quic_spdy_server_stream.h"
@@ -15,9 +15,8 @@
QuicServerSession::QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure)
- : QuicSession(connection, config, is_secure),
+ QuicServerSessionVisitor* visitor)
+ : QuicSession(connection, config),
visitor_(visitor),
bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
last_scup_time_(QuicTime::Zero()),
diff --git a/net/quic/quic_server_session.h b/net/quic/quic_server_session.h
index a402005..43107a0 100644
--- a/net/quic/quic_server_session.h
+++ b/net/quic/quic_server_session.h
@@ -46,8 +46,7 @@
public:
QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure);
+ QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
void OnConnectionClosed(QuicErrorCode error, bool from_peer) override;
diff --git a/net/quic/quic_session.cc b/net/quic/quic_session.cc
index 34a668d..2318ab4 100644
--- a/net/quic/quic_session.cc
+++ b/net/quic/quic_session.cc
@@ -95,8 +95,7 @@
QuicSession* session_;
};
-QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config,
- bool is_secure)
+QuicSession::QuicSession(QuicConnection* connection, const QuicConfig& config)
: connection_(connection),
visitor_shim_(new VisitorShim(this)),
config_(config),
@@ -106,8 +105,7 @@
error_(QUIC_NO_ERROR),
goaway_received_(false),
goaway_sent_(false),
- has_pending_handshake_(false),
- is_secure_(is_secure) {
+ has_pending_handshake_(false) {
if (connection_->version() == QUIC_VERSION_19) {
flow_controller_.reset(new QuicFlowController(
connection_.get(), 0, is_server(), kDefaultFlowControlSendWindow,
@@ -124,10 +122,6 @@
void QuicSession::InitializeSession() {
connection_->set_visitor(visitor_shim_.get());
connection_->SetFromConfig(config_);
- if (!FLAGS_quic_unified_timeouts && connection_->connected()) {
- connection_->SetOverallConnectionTimeout(
- config_.max_time_before_crypto_handshake());
- }
headers_stream_.reset(new QuicHeadersStream(this));
}
@@ -569,9 +563,6 @@
// Discard originally encrypted packets, since they can't be decrypted by
// the peer.
connection_->NeuterUnencryptedPackets();
- if (!FLAGS_quic_unified_timeouts) {
- connection_->SetOverallConnectionTimeout(QuicTime::Delta::Infinite());
- }
if (!FLAGS_quic_allow_more_open_streams) {
max_open_streams_ = config_.MaxStreamsPerConnection();
}
diff --git a/net/quic/quic_session.h b/net/quic/quic_session.h
index 6ca9ce0..43f4042 100644
--- a/net/quic/quic_session.h
+++ b/net/quic/quic_session.h
@@ -52,9 +52,7 @@
HANDSHAKE_CONFIRMED,
};
- QuicSession(QuicConnection* connection,
- const QuicConfig& config,
- bool is_secure);
+ QuicSession(QuicConnection* connection, const QuicConfig& config);
void InitializeSession();
~QuicSession() override;
@@ -212,8 +210,8 @@
bool IsStreamFlowControlBlocked();
// Returns true if this is a secure QUIC session.
- bool is_secure() const {
- return is_secure_;
+ bool IsSecure() const {
+ return connection()->is_secure();
}
size_t get_max_open_streams() const { return max_open_streams_; }
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index edbfbee..d14d875 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -125,9 +125,7 @@
class TestSession : public QuicSession {
public:
explicit TestSession(QuicConnection* connection)
- : QuicSession(connection,
- DefaultQuicConfig(),
- false),
+ : QuicSession(connection, DefaultQuicConfig()),
crypto_stream_(this),
writev_consumes_all_data_(false) {
InitializeSession();
@@ -580,8 +578,7 @@
}
TEST_P(QuicSessionTest, IncreasedTimeoutAfterCryptoHandshake) {
- EXPECT_EQ((FLAGS_quic_unified_timeouts ?
- kInitialIdleTimeoutSecs : kDefaultIdleTimeoutSecs) + 3,
+ EXPECT_EQ(kInitialIdleTimeoutSecs + 3,
QuicConnectionPeer::GetNetworkTimeout(connection_).ToSeconds());
CryptoHandshakeMessage msg;
session_.GetCryptoStream()->OnHandshakeMessage(msg);
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index 076797a..32adeda 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -60,16 +60,6 @@
// The initial receive window size for both streams and sessions.
const int32 kInitialReceiveWindowSize = 10 * 1024 * 1024; // 10MB
-// The suggested initial congestion windows for a server to use.
-// TODO: This should be tested and optimized, and even better, suggest a window
-// that corresponds to historical bandwidth and min-RTT.
-// Larger initial congestion windows can, if we don't overshoot, reduce latency
-// by avoiding the RTT needed for slow start to double (and re-double) from a
-// default of 10.
-// We match SPDY's use of 32 when secure (since we'd compete with SPDY).
-const int32 kServerSecureInitialCongestionWindow = 32;
-// Be conservative, and just use double a typical TCP ICWND for HTTP.
-const int32 kServerInecureInitialCongestionWindow = 20;
// Set the maximum number of undecryptable packets the connection will store.
const int32 kMaxUndecryptablePackets = 100;
@@ -922,15 +912,13 @@
packet_writer_factory,
true /* owns_writer */,
false /* is_server */,
+ server_id.is_https(),
supported_versions_);
connection->set_max_packet_length(max_packet_length_);
InitializeCachedStateInCryptoConfig(server_id, server_info);
QuicConfig config = config_;
- config.SetInitialCongestionWindowToSend(
- server_id.is_https() ? kServerSecureInitialCongestionWindow
- : kServerInecureInitialCongestionWindow);
config.set_max_undecryptable_packets(kMaxUndecryptablePackets);
config.SetInitialFlowControlWindowToSend(kInitialReceiveWindowSize);
config.SetInitialStreamFlowControlWindowToSend(kInitialReceiveWindowSize);
@@ -954,7 +942,7 @@
*session = new QuicClientSession(
connection, socket.Pass(), this, transport_security_state_,
- server_info.Pass(), config, server_id.is_https(),
+ server_info.Pass(), config,
base::MessageLoop::current()->message_loop_proxy().get(),
net_log.net_log());
all_sessions_[*session] = server_id; // owning pointer
diff --git a/net/quic/quic_time_wait_list_manager.cc b/net/quic/quic_time_wait_list_manager.cc
index d59cbc4..67d347f 100644
--- a/net/quic/quic_time_wait_list_manager.cc
+++ b/net/quic/quic_time_wait_list_manager.cc
@@ -27,9 +27,8 @@
namespace {
-// Time period for which a given connection_id should live in the time-wait
-// state.
-int64 FLAGS_quic_time_wait_list_seconds = 5;
+// Time period for which the connection_id should live in time wait state.
+const int kTimeWaitSeconds = 5;
} // namespace
@@ -40,7 +39,8 @@
public:
explicit ConnectionIdCleanUpAlarm(
QuicTimeWaitListManager* time_wait_list_manager)
- : time_wait_list_manager_(time_wait_list_manager) {}
+ : time_wait_list_manager_(time_wait_list_manager) {
+ }
QuicTime OnAlarm() override {
time_wait_list_manager_->CleanUpOldConnectionIds();
@@ -67,7 +67,8 @@
QuicEncryptedPacket* packet)
: server_address_(server_address),
client_address_(client_address),
- packet_(packet) {}
+ packet_(packet) {
+ }
const IPEndPoint& server_address() const { return server_address_; }
const IPEndPoint& client_address() const { return client_address_; }
@@ -87,8 +88,7 @@
QuicConnectionHelperInterface* helper,
const QuicVersionVector& supported_versions)
: helper_(helper),
- kTimeWaitPeriod_(
- QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
+ kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
connection_id_clean_up_alarm_(
helper_->CreateAlarm(new ConnectionIdCleanUpAlarm(this))),
writer_(writer),
@@ -276,7 +276,6 @@
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/test_tools/quic_config_peer.cc b/net/quic/test_tools/quic_config_peer.cc
index 7c84001..d0f5bfd 100644
--- a/net/quic/test_tools/quic_config_peer.cc
+++ b/net/quic/test_tools/quic_config_peer.cc
@@ -10,12 +10,6 @@
namespace test {
// static
-void QuicConfigPeer::SetReceivedInitialWindow(QuicConfig* config,
- size_t initial_window) {
- config->initial_congestion_window_.SetReceivedValue(initial_window);
-}
-
-// static
void QuicConfigPeer::SetReceivedSocketReceiveBuffer(
QuicConfig* config,
uint32 receive_buffer_bytes) {
diff --git a/net/quic/test_tools/quic_config_peer.h b/net/quic/test_tools/quic_config_peer.h
index 6c5e237..32e6bff 100644
--- a/net/quic/test_tools/quic_config_peer.h
+++ b/net/quic/test_tools/quic_config_peer.h
@@ -15,9 +15,6 @@
class QuicConfigPeer {
public:
- static void SetReceivedInitialWindow(QuicConfig* config,
- size_t initial_window);
-
static void SetReceivedSocketReceiveBuffer(QuicConfig* config,
uint32 receive_buffer_bytes);
diff --git a/net/quic/test_tools/quic_test_utils.cc b/net/quic/test_tools/quic_test_utils.cc
index ae3abfe..13e5eb1 100644
--- a/net/quic/test_tools/quic_test_utils.cc
+++ b/net/quic/test_tools/quic_test_utils.cc
@@ -221,21 +221,10 @@
clock_.AdvanceTime(delta);
}
-namespace {
-class NiceMockPacketWriterFactory
- : public QuicConnection::PacketWriterFactory {
- public:
- NiceMockPacketWriterFactory() {}
- ~NiceMockPacketWriterFactory() override {}
-
- QuicPacketWriter* Create(QuicConnection* /*connection*/) const override {
- return new testing::NiceMock<MockPacketWriter>();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
-};
-} // namespace
+QuicPacketWriter* NiceMockPacketWriterFactory::Create(
+ QuicConnection* /*connection*/) const {
+ return new testing::NiceMock<MockPacketWriter>();
+}
MockConnection::MockConnection(bool is_server)
: QuicConnection(kTestConnectionId,
@@ -243,7 +232,21 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
+ helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server, bool is_secure)
+ : QuicConnection(kTestConnectionId,
+ IPEndPoint(TestPeerIPAddress(), kTestPort),
+ new testing::NiceMock<MockHelper>(),
+ NiceMockPacketWriterFactory(),
+ /* owns_writer= */ true,
+ is_server,
+ is_secure,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -253,7 +256,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -264,7 +269,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -275,7 +282,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, supported_versions),
+ is_server,
+ /* is_secure= */ false,
+ supported_versions),
helper_(helper()) {
}
@@ -316,7 +325,7 @@
}
MockSession::MockSession(QuicConnection* connection)
- : QuicSession(connection, DefaultQuicConfig(), /*is_secure=*/false) {
+ : QuicSession(connection, DefaultQuicConfig()) {
InitializeSession();
ON_CALL(*this, WritevData(_, _, _, _, _, _))
.WillByDefault(testing::Return(QuicConsumedData(0, false)));
@@ -326,7 +335,7 @@
}
TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
- : QuicSession(connection, config, /*is_secure=*/false),
+ : QuicSession(connection, config),
crypto_stream_(nullptr) {
InitializeSession();
}
@@ -343,7 +352,7 @@
TestClientSession::TestClientSession(QuicConnection* connection,
const QuicConfig& config)
- : QuicClientSessionBase(connection, config, /*is_secure=*/false),
+ : QuicClientSessionBase(connection, config),
crypto_stream_(nullptr) {
EXPECT_CALL(*this, OnProofValid(_)).Times(AnyNumber());
InitializeSession();
diff --git a/net/quic/test_tools/quic_test_utils.h b/net/quic/test_tools/quic_test_utils.h
index ea5e5ef..fa987de 100644
--- a/net/quic/test_tools/quic_test_utils.h
+++ b/net/quic/test_tools/quic_test_utils.h
@@ -265,11 +265,25 @@
DISALLOW_COPY_AND_ASSIGN(MockHelper);
};
+class NiceMockPacketWriterFactory : public QuicConnection::PacketWriterFactory {
+ public:
+ NiceMockPacketWriterFactory() {}
+ ~NiceMockPacketWriterFactory() override {}
+
+ QuicPacketWriter* Create(QuicConnection* /*connection*/) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
+};
+
class MockConnection : public QuicConnection {
public:
// Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
explicit MockConnection(bool is_server);
+ // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
+ MockConnection(bool is_server, bool is_secure);
+
// Uses a MockHelper, ConnectionId of 42.
MockConnection(IPEndPoint address, bool is_server);
@@ -437,7 +451,9 @@
MockSendAlgorithm();
virtual ~MockSendAlgorithm();
- MOCK_METHOD2(SetFromConfig, void(const QuicConfig& config, bool is_server));
+ MOCK_METHOD3(SetFromConfig, void(const QuicConfig& config,
+ bool is_server,
+ bool using_pacing));
MOCK_METHOD1(SetNumEmulatedConnections, void(int num_connections));
MOCK_METHOD1(SetMaxPacketSize, void(QuicByteCount max_packet_size));
MOCK_METHOD2(OnIncomingQuicCongestionFeedbackFrame,
diff --git a/net/socket/tcp_socket_libevent.cc b/net/socket/tcp_socket_libevent.cc
index cc23765..d7fa9fa 100644
--- a/net/socket/tcp_socket_libevent.cc
+++ b/net/socket/tcp_socket_libevent.cc
@@ -21,6 +21,7 @@
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/base/network_change_notifier.h"
#include "net/socket/socket_libevent.h"
#include "net/socket/socket_net_log_params.h"
@@ -601,6 +602,8 @@
read_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
+
return rv;
}
@@ -633,6 +636,7 @@
write_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
return rv;
}
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc
index fd3c8b7..0c3d26f 100644
--- a/net/socket/tcp_socket_win.cc
+++ b/net/socket/tcp_socket_win.cc
@@ -18,6 +18,7 @@
#include "net/base/ip_endpoint.h"
#include "net/base/net_errors.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/base/network_change_notifier.h"
#include "net/base/winsock_init.h"
#include "net/base/winsock_util.h"
@@ -545,6 +546,7 @@
write_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(rv);
return rv;
}
} else {
@@ -913,6 +915,7 @@
read_bytes.Add(rv);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_RECEIVED, rv,
buf->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(rv);
return rv;
}
@@ -982,6 +985,7 @@
write_bytes.Add(num_bytes);
net_log_.AddByteTransferEvent(NetLog::TYPE_SOCKET_BYTES_SENT, num_bytes,
core_->write_iobuffer_->data());
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(num_bytes);
}
}
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 1fb3e79..33f30fc 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -920,11 +920,10 @@
EXPECT_EQ(2u, client_negotiated_config->MaxStreamsPerConnection());
}
-TEST_P(EndToEndTest, LimitCongestionWindowAndRTT) {
- // Client tries to request twice the server's max initial window, and the
- // server limits it to the max.
- client_config_.SetInitialCongestionWindowToSend(2 * kMaxInitialWindow);
- client_config_.SetInitialRoundTripTimeUsToSend(20000);
+TEST_P(EndToEndTest, ClientSuggestsRTT) {
+ // Client suggests initial RTT, verify it is used.
+ const uint32 kInitialRTT = 20000;
+ client_config_.SetInitialRoundTripTimeUsToSend(kInitialRTT);
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -940,33 +939,21 @@
const QuicSentPacketManager& server_sent_packet_manager =
*GetSentPacketManagerFromFirstServerSession();
- // The client shouldn't set its initial window based on the negotiated value.
- EXPECT_EQ(kDefaultInitialWindow,
- client_sent_packet_manager.GetCongestionWindowInTcpMss());
- EXPECT_EQ(kMaxInitialWindow,
- server_sent_packet_manager.GetCongestionWindowInTcpMss());
+ // BBR automatically enables pacing.
+ EXPECT_EQ(GetParam().use_pacing ||
+ (FLAGS_quic_allow_bbr &&
+ GetParam().congestion_control_tag == kTBBR),
+ server_sent_packet_manager.using_pacing());
+ EXPECT_EQ(GetParam().use_pacing ||
+ (FLAGS_quic_allow_bbr &&
+ GetParam().congestion_control_tag == kTBBR),
+ client_sent_packet_manager.using_pacing());
- EXPECT_EQ(GetParam().use_pacing, server_sent_packet_manager.using_pacing());
- EXPECT_EQ(GetParam().use_pacing, client_sent_packet_manager.using_pacing());
-
- // The client *should* set the intitial RTT, but it's increased to 10ms.
- EXPECT_EQ(20000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us());
- EXPECT_EQ(20000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
-
- // Now use the negotiated limits with packet loss.
- SetPacketLossPercentage(30);
-
- // 10 KB body.
- string body;
- GenerateBody(&body, 1024 * 10);
-
- HTTPMessage request(HttpConstants::HTTP_1_1,
- HttpConstants::POST, "/foo");
- request.AddBody(body, true);
-
+ EXPECT_EQ(kInitialRTT,
+ client_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ EXPECT_EQ(kInitialRTT,
+ server_sent_packet_manager.GetRttStats()->initial_rtt_us());
server_thread_->Resume();
-
- EXPECT_EQ(kFooResponseBody, client_->SendCustomSynchronousRequest(request));
}
TEST_P(EndToEndTest, MaxInitialRTT) {
@@ -1025,7 +1012,7 @@
EXPECT_FALSE(
client_sent_packet_manager.GetRttStats()->smoothed_rtt().IsInfinite());
// Expect the default rtt of 100ms.
- EXPECT_EQ(static_cast<int64>(100 * base::Time::kMicrosecondsPerMillisecond),
+ EXPECT_EQ(static_cast<int64>(100 * kNumMicrosPerMilli),
server_sent_packet_manager.GetRttStats()->initial_rtt_us());
// Ensure the bandwidth is valid.
client_sent_packet_manager.BandwidthEstimate();
diff --git a/net/tools/quic/quic_client.cc b/net/tools/quic/quic_client.cc
index b28ec2b..74874d7 100644
--- a/net/tools/quic/quic_client.cc
+++ b/net/tools/quic/quic_client.cc
@@ -199,8 +199,8 @@
factory,
/* owns_writer= */ false,
/* is_server= */ false,
- supported_versions_),
- server_id_.is_https()));
+ server_id_.is_https(),
+ supported_versions_)));
// Reset |writer_| after |session_| so that the old writer outlives the old
// session.
diff --git a/net/tools/quic/quic_client_session.cc b/net/tools/quic/quic_client_session.cc
index 87ca0ce..235eeb0 100644
--- a/net/tools/quic/quic_client_session.cc
+++ b/net/tools/quic/quic_client_session.cc
@@ -15,9 +15,8 @@
namespace tools {
QuicClientSession::QuicClientSession(const QuicConfig& config,
- QuicConnection* connection,
- bool is_secure)
- : QuicClientSessionBase(connection, config, is_secure) {
+ QuicConnection* connection)
+ : QuicClientSessionBase(connection, config) {
}
QuicClientSession::~QuicClientSession() {
@@ -26,18 +25,16 @@
void QuicClientSession::InitializeSession(
const QuicServerId& server_id,
QuicCryptoClientConfig* crypto_config) {
- QuicClientSessionBase::InitializeSession();
crypto_stream_.reset(
new QuicCryptoClientStream(server_id, this, nullptr, crypto_config));
+ QuicClientSessionBase::InitializeSession();
}
void QuicClientSession::OnProofValid(
- const QuicCryptoClientConfig::CachedState& /*cached*/) {
-}
+ const QuicCryptoClientConfig::CachedState& /*cached*/) {}
void QuicClientSession::OnProofVerifyDetailsAvailable(
- const ProofVerifyDetails& /*verify_details*/) {
-}
+ const ProofVerifyDetails& /*verify_details*/) {}
QuicSpdyClientStream* QuicClientSession::CreateOutgoingDataStream() {
if (!crypto_stream_->encryption_established()) {
diff --git a/net/tools/quic/quic_client_session.h b/net/tools/quic/quic_client_session.h
index d1cd38c..3c92efa 100644
--- a/net/tools/quic/quic_client_session.h
+++ b/net/tools/quic/quic_client_session.h
@@ -25,9 +25,7 @@
class QuicClientSession : public QuicClientSessionBase {
public:
- QuicClientSession(const QuicConfig& config,
- QuicConnection* connection,
- bool is_secure);
+ QuicClientSession(const QuicConfig& config, QuicConnection* connection);
~QuicClientSession() override;
void InitializeSession(const QuicServerId& server_id,
diff --git a/net/tools/quic/quic_client_session_test.cc b/net/tools/quic/quic_client_session_test.cc
index 61422e1..5b5c415 100644
--- a/net/tools/quic/quic_client_session_test.cc
+++ b/net/tools/quic/quic_client_session_test.cc
@@ -42,8 +42,7 @@
ToolsQuicClientSessionTest()
: connection_(
new PacketSavingConnection(false, SupportedVersions(GetParam()))) {
- session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_,
- /*is_secure=*/false));
+ session_.reset(new QuicClientSession(DefaultQuicConfig(), connection_));
session_->InitializeSession(
QuicServerId(kServerHostname, kPort, false, PRIVACY_MODE_DISABLED),
&crypto_config_);
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc
index 16cee2b..4ea48e9 100644
--- a/net/tools/quic/quic_dispatcher.cc
+++ b/net/tools/quic/quic_dispatcher.cc
@@ -364,8 +364,7 @@
QuicServerSession* session = new QuicServerSession(
config_,
CreateQuicConnection(connection_id, server_address, client_address),
- this,
- crypto_config_.HasProofSource());
+ this);
session->InitializeSession(crypto_config_);
return session;
}
@@ -380,6 +379,7 @@
connection_writer_factory_,
/* owns_writer= */ true,
/* is_server= */ true,
+ crypto_config_.HasProofSource(),
supported_versions_);
}
diff --git a/net/tools/quic/quic_server_session.cc b/net/tools/quic/quic_server_session.cc
index 1dd5748..45c1379 100644
--- a/net/tools/quic/quic_server_session.cc
+++ b/net/tools/quic/quic_server_session.cc
@@ -5,7 +5,7 @@
#include "net/tools/quic/quic_server_session.h"
#include "base/logging.h"
-#include "net/quic/crypto/source_address_token.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_flags.h"
#include "net/quic/reliable_quic_stream.h"
@@ -16,9 +16,8 @@
QuicServerSession::QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure)
- : QuicSession(connection, config, is_secure),
+ QuicServerSessionVisitor* visitor)
+ : QuicSession(connection, config),
visitor_(visitor),
bandwidth_estimate_sent_to_client_(QuicBandwidth::Zero()),
last_scup_time_(QuicTime::Zero()),
diff --git a/net/tools/quic/quic_server_session.h b/net/tools/quic/quic_server_session.h
index cdc2bf3..603ad35 100644
--- a/net/tools/quic/quic_server_session.h
+++ b/net/tools/quic/quic_server_session.h
@@ -47,8 +47,7 @@
public:
QuicServerSession(const QuicConfig& config,
QuicConnection* connection,
- QuicServerSessionVisitor* visitor,
- bool is_secure);
+ QuicServerSessionVisitor* visitor);
// Override the base class to notify the owner of the connection close.
void OnConnectionClosed(QuicErrorCode error, bool from_peer) override;
diff --git a/net/tools/quic/quic_server_session_test.cc b/net/tools/quic/quic_server_session_test.cc
index 202022f..6a17f53 100644
--- a/net/tools/quic/quic_server_session_test.cc
+++ b/net/tools/quic/quic_server_session_test.cc
@@ -4,9 +4,9 @@
#include "net/tools/quic/quic_server_session.h"
+#include "net/quic/crypto/cached_network_parameters.h"
#include "net/quic/crypto/quic_crypto_server_config.h"
#include "net/quic/crypto/quic_random.h"
-#include "net/quic/crypto/source_address_token.h"
#include "net/quic/quic_connection.h"
#include "net/quic/quic_crypto_server_stream.h"
#include "net/quic/quic_flags.h"
@@ -79,8 +79,7 @@
connection_ =
new StrictMock<MockConnection>(true, SupportedVersions(GetParam()));
- session_.reset(new QuicServerSession(config_, connection_, &owner_,
- /*is_secure=*/false));
+ session_.reset(new QuicServerSession(config_, connection_, &owner_));
MockClock clock;
handshake_message_.reset(crypto_config_.AddDefaultConfig(
QuicRandom::GetInstance(), &clock,
diff --git a/net/tools/quic/quic_spdy_client_stream_test.cc b/net/tools/quic/quic_spdy_client_stream_test.cc
index d2106d9..090e2da 100644
--- a/net/tools/quic/quic_spdy_client_stream_test.cc
+++ b/net/tools/quic/quic_spdy_client_stream_test.cc
@@ -29,7 +29,7 @@
QuicSpdyClientStreamTest()
: connection_(new StrictMock<MockConnection>(
false, SupportedVersions(GetParam()))),
- session_(DefaultQuicConfig(), connection_, /*is_secure=*/false),
+ session_(DefaultQuicConfig(), connection_),
body_("hello world") {
session_.InitializeSession(
QuicServerId("example.com", 80, false, PRIVACY_MODE_DISABLED),
diff --git a/net/tools/quic/quic_time_wait_list_manager.cc b/net/tools/quic/quic_time_wait_list_manager.cc
index 58f50fe..f54a465 100644
--- a/net/tools/quic/quic_time_wait_list_manager.cc
+++ b/net/tools/quic/quic_time_wait_list_manager.cc
@@ -28,9 +28,8 @@
namespace {
-// Time period for which a given connection_id should live in the time-wait
-// state.
-int64 FLAGS_quic_time_wait_list_seconds = 5;
+// Time period for which the connection_id should live in time wait state.
+const int kTimeWaitSeconds = 5;
} // namespace
@@ -91,8 +90,7 @@
EpollServer* epoll_server,
const QuicVersionVector& supported_versions)
: epoll_server_(epoll_server),
- kTimeWaitPeriod_(
- QuicTime::Delta::FromSeconds(FLAGS_quic_time_wait_list_seconds)),
+ kTimeWaitPeriod_(QuicTime::Delta::FromSeconds(kTimeWaitSeconds)),
connection_id_clean_up_alarm_(new ConnectionIdCleanUpAlarm(this)),
clock_(epoll_server_),
writer_(writer),
@@ -122,7 +120,9 @@
delete it->second.close_packet;
connection_id_map_.erase(it);
}
- ConnectionIdData data(num_packets, version, clock_.ApproximateNow(),
+ ConnectionIdData data(num_packets,
+ version,
+ clock_.ApproximateNow(),
close_packet);
connection_id_map_.insert(make_pair(connection_id, data));
}
@@ -168,12 +168,12 @@
return;
}
if (it->second.close_packet) {
- QueuedPacket* queued_packet =
- new QueuedPacket(server_address,
- client_address,
- it->second.close_packet->Clone());
- // Takes ownership of the packet.
- SendOrQueuePacket(queued_packet);
+ QueuedPacket* queued_packet =
+ new QueuedPacket(server_address,
+ client_address,
+ it->second.close_packet->Clone());
+ // Takes ownership of the packet.
+ SendOrQueuePacket(queued_packet);
} else {
SendPublicReset(server_address,
client_address,
@@ -282,7 +282,6 @@
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/quic_test_utils.cc b/net/tools/quic/test_tools/quic_test_utils.cc
index 40b7e88..91cd003 100644
--- a/net/tools/quic/test_tools/quic_test_utils.cc
+++ b/net/tools/quic/test_tools/quic_test_utils.cc
@@ -18,21 +18,10 @@
namespace tools {
namespace test {
-namespace {
-class NiceMockPacketWriterFactory
- : public QuicConnection::PacketWriterFactory {
- public:
- NiceMockPacketWriterFactory() {}
- ~NiceMockPacketWriterFactory() override {}
-
- QuicPacketWriter* Create(QuicConnection* /*connection*/) const override {
- return new testing::NiceMock<MockPacketWriter>();
- }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
-};
-} // namespace
+QuicPacketWriter* NiceMockPacketWriterFactory::Create(
+ QuicConnection* /*connection*/) const {
+ return new testing::NiceMock<MockPacketWriter>();
+}
MockConnection::MockConnection(bool is_server)
: QuicConnection(kTestConnectionId,
@@ -40,7 +29,21 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
+ helper_(helper()) {
+}
+
+MockConnection::MockConnection(bool is_server, bool is_secure)
+ : QuicConnection(kTestConnectionId,
+ IPEndPoint(net::test::Loopback4(), kTestPort),
+ new testing::NiceMock<MockHelper>(),
+ NiceMockPacketWriterFactory(),
+ /* owns_writer= */ true,
+ is_server,
+ is_secure,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -50,7 +53,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -61,7 +66,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ QuicSupportedVersions()),
helper_(helper()) {
}
@@ -72,7 +79,9 @@
new testing::NiceMock<MockHelper>(),
NiceMockPacketWriterFactory(),
/* owns_writer= */ true,
- is_server, QuicSupportedVersions()),
+ is_server,
+ /* is_secure= */ false,
+ supported_versions),
helper_(helper()) {
}
@@ -93,9 +102,8 @@
return ack;
}
-TestSession::TestSession(QuicConnection* connection,
- const QuicConfig& config)
- : QuicSession(connection, config, /*is_secure=*/false),
+TestSession::TestSession(QuicConnection* connection, const QuicConfig& config)
+ : QuicSession(connection, config),
crypto_stream_(nullptr) {
InitializeSession();
}
diff --git a/net/tools/quic/test_tools/quic_test_utils.h b/net/tools/quic/test_tools/quic_test_utils.h
index cbd7fbe..9db9fb5 100644
--- a/net/tools/quic/test_tools/quic_test_utils.h
+++ b/net/tools/quic/test_tools/quic_test_utils.h
@@ -39,11 +39,25 @@
QuicAckFrame MakeAckFrameWithNackRanges(size_t num_nack_ranges,
QuicPacketSequenceNumber least_unacked);
+class NiceMockPacketWriterFactory : public QuicConnection::PacketWriterFactory {
+ public:
+ NiceMockPacketWriterFactory() {}
+ ~NiceMockPacketWriterFactory() override {}
+
+ QuicPacketWriter* Create(QuicConnection* /*connection*/) const override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NiceMockPacketWriterFactory);
+};
+
class MockConnection : public QuicConnection {
public:
// Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
explicit MockConnection(bool is_server);
+ // Uses a MockHelper, ConnectionId of 42, and 127.0.0.1:123.
+ MockConnection(bool is_server, bool is_secure);
+
// Uses a MockHelper, ConnectionId of 42.
MockConnection(IPEndPoint address, bool is_server);
@@ -83,10 +97,12 @@
void ReallyProcessUdpPacket(const IPEndPoint& self_address,
const IPEndPoint& peer_address,
const QuicEncryptedPacket& packet) {
- return QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
+ QuicConnection::ProcessUdpPacket(self_address, peer_address, packet);
}
- virtual bool OnProtocolVersionMismatch(QuicVersion version) { return false; }
+ virtual bool OnProtocolVersionMismatch(QuicVersion version) override {
+ return false;
+ }
private:
scoped_ptr<QuicConnectionHelperInterface> helper_;
diff --git a/net/udp/udp_socket_libevent.cc b/net/udp/udp_socket_libevent.cc
index 9b1a995..2dffff3 100644
--- a/net/udp/udp_socket_libevent.cc
+++ b/net/udp/udp_socket_libevent.cc
@@ -24,6 +24,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/socket/socket_descriptor.h"
#include "net/udp/udp_net_log_parameters.h"
@@ -414,6 +415,7 @@
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
}
int UDPSocketLibevent::CreateSocket(int addr_family) {
@@ -458,6 +460,7 @@
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
}
int UDPSocketLibevent::InternalRecvFrom(IOBuffer* buf, int buf_len,
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index 4c307fd..11c731f 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -20,6 +20,7 @@
#include "net/base/net_errors.h"
#include "net/base/net_log.h"
#include "net/base/net_util.h"
+#include "net/base/network_activity_monitor.h"
#include "net/base/winsock_init.h"
#include "net/base/winsock_util.h"
#include "net/socket/socket_descriptor.h"
@@ -595,6 +596,7 @@
base::StatsCounter read_bytes("udp.read_bytes");
read_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesReceived(result);
}
void UDPSocketWin::DidCompleteWrite() {
@@ -626,6 +628,7 @@
base::StatsCounter write_bytes("udp.write_bytes");
write_bytes.Add(result);
+ NetworkActivityMonitor::GetInstance()->IncrementBytesSent(result);
}
int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc
index 5806193..5ac65ef 100644
--- a/net/url_request/sdch_dictionary_fetcher.cc
+++ b/net/url_request/sdch_dictionary_fetcher.cc
@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "base/thread_task_runner_handle.h"
#include "net/base/load_flags.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_status.h"
#include "net/url_request/url_request_throttler_manager.h"
@@ -45,16 +46,15 @@
// Avoid pushing duplicate copy onto queue. We may fetch this url again later
// and get a different dictionary, but there is no reason to have it in the
// queue twice at one time.
- if (!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) {
+ if ((!fetch_queue_.empty() && fetch_queue_.back() == dictionary_url) ||
+ attempted_load_.find(dictionary_url) != attempted_load_.end()) {
+ // TODO(rdsmith): log this error to the net log of the URLRequest
+ // initiating this fetch, once URLRequest will be passed here.
SdchManager::SdchErrorRecovery(
- SdchManager::DICTIONARY_ALREADY_SCHEDULED_TO_DOWNLOAD);
+ SDCH_DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD);
return;
}
- if (attempted_load_.find(dictionary_url) != attempted_load_.end()) {
- SdchManager::SdchErrorRecovery(
- SdchManager::DICTIONARY_ALREADY_TRIED_TO_DOWNLOAD);
- return;
- }
+
attempted_load_.insert(dictionary_url);
fetch_queue_.push(dictionary_url);
@@ -166,6 +166,7 @@
next_state_ = STATE_REQUEST_STARTED;
current_request_->Start();
+ current_request_->net_log().AddEvent(NetLog::TYPE_SDCH_DICTIONARY_FETCH);
return OK;
}
@@ -207,7 +208,12 @@
// an infinite loop. It's not clear how to handle a read failure
// without a promise to invoke the callback at some point in the future,
// so the request is failed.
- SdchManager::SdchErrorRecovery(SdchManager::DICTIONARY_FETCH_READ_FAILED);
+ SdchManager::SdchErrorRecovery(SDCH_DICTIONARY_FETCH_READ_FAILED);
+ current_request_->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+ base::Bind(&NetLogSdchDictionaryFetchProblemCallback,
+ SDCH_DICTIONARY_FETCH_READ_FAILED, current_request_->url(),
+ true));
DLOG(FATAL)
<< "URLRequest::Read() returned false without IO pending or error!";
return ERR_FAILED;
@@ -228,8 +234,10 @@
DCHECK(CalledOnValidThread());
// If the dictionary was successfully fetched, add it to the manager.
- if (rv == OK)
- dictionary_fetched_callback_.Run(dictionary_, current_request_->url());
+ if (rv == OK) {
+ dictionary_fetched_callback_.Run(dictionary_, current_request_->url(),
+ current_request_->net_log());
+ }
current_request_.reset();
buffer_ = NULL;
diff --git a/net/url_request/sdch_dictionary_fetcher.h b/net/url_request/sdch_dictionary_fetcher.h
index 5b6f269..79d8778 100644
--- a/net/url_request/sdch_dictionary_fetcher.h
+++ b/net/url_request/sdch_dictionary_fetcher.h
@@ -36,7 +36,8 @@
public base::NonThreadSafe {
public:
typedef base::Callback<void(const std::string& dictionary_text,
- const GURL& dictionary_url)>
+ const GURL& dictionary_url,
+ const BoundNetLog& net_log)>
OnDictionaryFetchedCallback;
// The consumer must guarantee that |*context| outlives this object.
diff --git a/net/url_request/sdch_dictionary_fetcher_unittest.cc b/net/url_request/sdch_dictionary_fetcher_unittest.cc
index 0febd7e..ae76cbc 100644
--- a/net/url_request/sdch_dictionary_fetcher_unittest.cc
+++ b/net/url_request/sdch_dictionary_fetcher_unittest.cc
@@ -99,7 +99,8 @@
}
void OnDictionaryFetched(const std::string& dictionary_text,
- const GURL& dictionary_url) {
+ const GURL& dictionary_url,
+ const BoundNetLog& net_log) {
dictionary_additions.push_back(
DictionaryAdditions(dictionary_text, dictionary_url));
}
diff --git a/net/url_request/test_url_fetcher_factory.cc b/net/url_request/test_url_fetcher_factory.cc
index af76576..357dfeb 100644
--- a/net/url_request/test_url_fetcher_factory.cc
+++ b/net/url_request/test_url_fetcher_factory.cc
@@ -48,6 +48,7 @@
fake_response_destination_(STRING),
fake_was_fetched_via_proxy_(false),
fake_max_retries_(0) {
+ CHECK(original_url_.is_valid());
}
TestURLFetcher::~TestURLFetcher() {
diff --git a/net/url_request/url_fetcher.cc b/net/url_request/url_fetcher.cc
index 96a2510..ddad12d 100644
--- a/net/url_request/url_fetcher.cc
+++ b/net/url_request/url_fetcher.cc
@@ -36,11 +36,6 @@
}
// static
-void net::URLFetcher::SetEnableInterceptionForTests(bool enabled) {
- URLFetcherImpl::SetEnableInterceptionForTests(enabled);
-}
-
-// static
void net::URLFetcher::SetIgnoreCertificateRequests(bool ignored) {
URLFetcherImpl::SetIgnoreCertificateRequests(ignored);
}
diff --git a/net/url_request/url_fetcher.h b/net/url_request/url_fetcher.h
index 1b379c4..5dcaedd 100644
--- a/net/url_request/url_fetcher.h
+++ b/net/url_request/url_fetcher.h
@@ -119,11 +119,6 @@
// thread though, even though the task won't ever run.
static void CancelAll();
- // Normally interception is disabled for URLFetcher, but you can use this
- // to enable it for tests. Also see ScopedURLFetcherFactory for another way
- // of testing code that uses an URLFetcher.
- static void SetEnableInterceptionForTests(bool enabled);
-
// Normally, URLFetcher will abort loads that request SSL client certificate
// authentication, but this method may be used to cause URLFetchers to ignore
// requests for client certificates and continue anonymously. Because such
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index 5ea3921..aae47d9 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -34,7 +34,6 @@
const int kBufferSize = 4096;
const int kUploadProgressTimerInterval = 100;
-bool g_interception_enabled = false;
bool g_ignore_certificate_requests = false;
void EmptyCompletionCallback(int result) {}
@@ -470,10 +469,6 @@
return g_registry.Get().size();
}
-void URLFetcherCore::SetEnableInterceptionForTests(bool enabled) {
- g_interception_enabled = enabled;
-}
-
void URLFetcherCore::SetIgnoreCertificateRequests(bool ignored) {
g_ignore_certificate_requests = ignored;
}
@@ -514,8 +509,6 @@
original_url_, DEFAULT_PRIORITY, this, NULL);
request_->set_stack_trace(stack_trace_);
int flags = request_->load_flags() | load_flags_;
- if (!g_interception_enabled)
- flags = flags | LOAD_DISABLE_INTERCEPT;
if (is_chunked_upload_)
request_->EnableChunkedUpload();
diff --git a/net/url_request/url_fetcher_impl.cc b/net/url_request/url_fetcher_impl.cc
index fc44551..179adfb 100644
--- a/net/url_request/url_fetcher_impl.cc
+++ b/net/url_request/url_fetcher_impl.cc
@@ -193,11 +193,6 @@
}
// static
-void URLFetcherImpl::SetEnableInterceptionForTests(bool enabled) {
- URLFetcherCore::SetEnableInterceptionForTests(enabled);
-}
-
-// static
void URLFetcherImpl::SetIgnoreCertificateRequests(bool ignored) {
URLFetcherCore::SetIgnoreCertificateRequests(ignored);
}
diff --git a/net/url_request/url_fetcher_impl.h b/net/url_request/url_fetcher_impl.h
index 29c8bd5..f0a57af 100644
--- a/net/url_request/url_fetcher_impl.h
+++ b/net/url_request/url_fetcher_impl.h
@@ -90,7 +90,6 @@
static void CancelAll();
- static void SetEnableInterceptionForTests(bool enabled);
static void SetIgnoreCertificateRequests(bool ignored);
// TODO(akalin): Make these private again once URLFetcher::Create()
diff --git a/net/url_request/url_request.cc b/net/url_request/url_request.cc
index 613d9bb..a2ce07e 100644
--- a/net/url_request/url_request.cc
+++ b/net/url_request/url_request.cc
@@ -142,31 +142,6 @@
} // namespace
-void URLRequest::Deprecated::RegisterRequestInterceptor(
- Interceptor* interceptor) {
- URLRequest::RegisterRequestInterceptor(interceptor);
-}
-
-void URLRequest::Deprecated::UnregisterRequestInterceptor(
- Interceptor* interceptor) {
- URLRequest::UnregisterRequestInterceptor(interceptor);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// URLRequest::Interceptor
-
-URLRequestJob* URLRequest::Interceptor::MaybeInterceptRedirect(
- URLRequest* request,
- NetworkDelegate* network_delegate,
- const GURL& location) {
- return NULL;
-}
-
-URLRequestJob* URLRequest::Interceptor::MaybeInterceptResponse(
- URLRequest* request, NetworkDelegate* network_delegate) {
- return NULL;
-}
-
///////////////////////////////////////////////////////////////////////////////
// URLRequest::Delegate
@@ -624,17 +599,6 @@
net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE);
}
-// static
-void URLRequest::RegisterRequestInterceptor(Interceptor* interceptor) {
- URLRequestJobManager::GetInstance()->RegisterRequestInterceptor(interceptor);
-}
-
-// static
-void URLRequest::UnregisterRequestInterceptor(Interceptor* interceptor) {
- URLRequestJobManager::GetInstance()->UnregisterRequestInterceptor(
- interceptor);
-}
-
void URLRequest::BeforeRequestComplete(int error) {
DCHECK(!job_.get());
DCHECK_NE(ERR_IO_PENDING, error);
diff --git a/net/url_request/url_request.h b/net/url_request/url_request.h
index 3db6c68..6117419 100644
--- a/net/url_request/url_request.h
+++ b/net/url_request/url_request.h
@@ -40,12 +40,6 @@
} // namespace debug
} // namespace base
-// Temporary layering violation to allow existing users of a deprecated
-// interface.
-namespace content {
-class AppCacheInterceptor;
-}
-
namespace net {
class ChunkedUploadDataStream;
@@ -120,58 +114,6 @@
UPDATE_FIRST_PARTY_URL_ON_REDIRECT,
};
- // This class handles network interception. Use with
- // (Un)RegisterRequestInterceptor.
- class NET_EXPORT Interceptor {
- public:
- virtual ~Interceptor() {}
-
- // Called for every request made. Should return a new job to handle the
- // request if it should be intercepted, or NULL to allow the request to
- // be handled in the normal manner.
- virtual URLRequestJob* MaybeIntercept(
- URLRequest* request, NetworkDelegate* network_delegate) = 0;
-
- // Called after having received a redirect response, but prior to the
- // the request delegate being informed of the redirect. Can return a new
- // job to replace the existing job if it should be intercepted, or NULL
- // to allow the normal handling to continue. If a new job is provided,
- // the delegate never sees the original redirect response, instead the
- // response produced by the intercept job will be returned.
- virtual URLRequestJob* MaybeInterceptRedirect(
- URLRequest* request,
- NetworkDelegate* network_delegate,
- const GURL& location);
-
- // Called after having received a final response, but prior to the
- // the request delegate being informed of the response. This is also
- // called when there is no server response at all to allow interception
- // on dns or network errors. Can return a new job to replace the existing
- // job if it should be intercepted, or NULL to allow the normal handling to
- // continue. If a new job is provided, the delegate never sees the original
- // response, instead the response produced by the intercept job will be
- // returned.
- virtual URLRequestJob* MaybeInterceptResponse(
- URLRequest* request, NetworkDelegate* network_delegate);
- };
-
- // Deprecated interfaces in net::URLRequest. They have been moved to
- // URLRequest's private section to prevent new uses. Existing uses are
- // explicitly friended here and should be removed over time.
- class NET_EXPORT Deprecated {
- private:
- // TODO(willchan): Kill off these friend declarations.
- friend class TestInterceptor;
- friend class content::AppCacheInterceptor;
-
- // TODO(pauljensen): Remove this when AppCacheInterceptor is a
- // ProtocolHandler, see crbug.com/161547.
- static void RegisterRequestInterceptor(Interceptor* interceptor);
- static void UnregisterRequestInterceptor(Interceptor* interceptor);
-
- DISALLOW_IMPLICIT_CONSTRUCTORS(Deprecated);
- };
-
// The delegate's methods are called from the message loop of the thread
// on which the request's Start() method is called. See above for the
// ordering of callbacks.
@@ -717,10 +659,6 @@
CookieStore* cookie_store,
NetworkDelegate* network_delegate);
- // Registers or unregisters a network interception class.
- static void RegisterRequestInterceptor(Interceptor* interceptor);
- static void UnregisterRequestInterceptor(Interceptor* interceptor);
-
// Resumes or blocks a request paused by the NetworkDelegate::OnBeforeRequest
// handler. If |blocked| is true, the request is blocked and an error page is
// returned indicating so. This should only be called after Start is called
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 04c190c..41420d5 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -214,7 +214,8 @@
ftp_enabled_(false),
#endif
http_cache_enabled_(true),
- throttling_enabled_(false) {
+ throttling_enabled_(false),
+ channel_id_enabled_(true) {
}
URLRequestContextBuilder::~URLRequestContextBuilder() {}
@@ -296,12 +297,14 @@
storage->set_http_auth_handler_factory(http_auth_handler_registry_factory);
storage->set_cookie_store(new CookieMonster(NULL, NULL));
- // TODO(mmenke): This always creates a file thread, even when it ends up
- // not being used. Consider lazily creating the thread.
- storage->set_channel_id_service(
- new ChannelIDService(
- new DefaultChannelIDStore(NULL),
- context->GetFileThread()->message_loop_proxy()));
+ if (channel_id_enabled_) {
+ // TODO(mmenke): This always creates a file thread, even when it ends up
+ // not being used. Consider lazily creating the thread.
+ storage->set_channel_id_service(
+ new ChannelIDService(
+ new DefaultChannelIDStore(NULL),
+ context->GetFileThread()->message_loop_proxy()));
+ }
storage->set_transport_security_state(new net::TransportSecurityState());
if (!transport_security_persister_path_.empty()) {
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index a7d9d7b..f26552a 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -174,6 +174,10 @@
throttling_enabled_ = throttling_enabled;
}
+ void set_channel_id_enabled(bool enable) {
+ channel_id_enabled_ = enable;
+ }
+
URLRequestContext* Build();
private:
@@ -200,6 +204,7 @@
#endif
bool http_cache_enabled_;
bool throttling_enabled_;
+ bool channel_id_enabled_;
HttpCacheParams http_cache_params_;
HttpNetworkSessionParams http_network_session_params_;
diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc
index 4261b92..33a5088 100644
--- a/net/url_request/url_request_http_job.cc
+++ b/net/url_request/url_request_http_job.cc
@@ -24,6 +24,7 @@
#include "net/base/net_util.h"
#include "net/base/network_delegate.h"
#include "net/base/sdch_manager.h"
+#include "net/base/sdch_net_log_params.h"
#include "net/cert/cert_status_flags.h"
#include "net/cookies/cookie_store.h"
#include "net/http/http_content_disposition.h"
@@ -70,6 +71,7 @@
int GetResponseCode() const override;
const URLRequestContext* GetURLRequestContext() const override;
void RecordPacketStats(StatisticSelector statistic) const override;
+ const BoundNetLog& GetNetLog() const override;
// Method to allow us to reset filter context for a response that should have
// been SDCH encoded when there is an update due to an explicit HTTP header.
@@ -78,6 +80,10 @@
private:
URLRequestHttpJob* job_;
+ // URLRequestHttpJob may be detached from URLRequest, but we still need to
+ // return something.
+ BoundNetLog dummy_log_;
+
DISALLOW_COPY_AND_ASSIGN(HttpFilterContext);
};
@@ -147,6 +153,10 @@
job_->RecordPacketStats(statistic);
}
+const BoundNetLog& URLRequestHttpJob::HttpFilterContext::GetNetLog() const {
+ return job_->request() ? job_->request()->net_log() : dummy_log_;
+}
+
// TODO(darin): make sure the port blocking code is not lost
// static
URLRequestJob* URLRequestHttpJob::Factory(URLRequest* request,
@@ -321,21 +331,42 @@
ProcessPublicKeyPinsHeader();
SdchManager* sdch_manager(request()->context()->sdch_manager());
- if (sdch_manager && sdch_manager->IsInSupportedDomain(request_->url())) {
- const std::string name = "Get-Dictionary";
- std::string url_text;
- void* iter = NULL;
- // TODO(jar): We need to not fetch dictionaries the first time they are
- // seen, but rather wait until we can justify their usefulness.
- // For now, we will only fetch the first dictionary, which will at least
- // require multiple suggestions before we get additional ones for this site.
- // Eventually we should wait until a dictionary is requested several times
- // before we even download it (so that we don't waste memory or bandwidth).
- if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
- // Resolve suggested URL relative to request url.
- GURL sdch_dictionary_url = request_->url().Resolve(url_text);
- if (sdch_dictionary_url.is_valid()) {
- sdch_manager->OnGetDictionary(request_->url(), sdch_dictionary_url);
+ if (sdch_manager) {
+ SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
+ if (rv != SDCH_OK) {
+ // If SDCH is just disabled, it is not a real error.
+ if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+ SdchManager::SdchErrorRecovery(rv);
+ request()->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, rv));
+ }
+ } else {
+ const std::string name = "Get-Dictionary";
+ std::string url_text;
+ void* iter = NULL;
+ // TODO(jar): We need to not fetch dictionaries the first time they are
+ // seen, but rather wait until we can justify their usefulness.
+ // For now, we will only fetch the first dictionary, which will at least
+ // require multiple suggestions before we get additional ones for this
+ // site. Eventually we should wait until a dictionary is requested
+ // several times
+ // before we even download it (so that we don't waste memory or
+ // bandwidth).
+ if (GetResponseHeaders()->EnumerateHeader(&iter, name, &url_text)) {
+ // Resolve suggested URL relative to request url.
+ GURL sdch_dictionary_url = request_->url().Resolve(url_text);
+ if (sdch_dictionary_url.is_valid()) {
+ rv = sdch_manager->OnGetDictionary(request_->url(),
+ sdch_dictionary_url);
+ if (rv != SDCH_OK) {
+ SdchManager::SdchErrorRecovery(rv);
+ request_->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DICTIONARY_ERROR,
+ base::Bind(&NetLogSdchDictionaryFetchProblemCallback, rv,
+ sdch_dictionary_url, false));
+ }
+ }
}
}
}
@@ -483,13 +514,24 @@
// simple_data_source.
if (!request_info_.extra_headers.HasHeader(
HttpRequestHeaders::kAcceptEncoding)) {
- bool advertise_sdch = sdch_manager &&
- // We don't support SDCH responses to POST as there is a possibility
- // of having SDCH encoded responses returned (e.g. by the cache)
- // which we cannot decode, and in those situations, we will need
- // to retransmit the request without SDCH, which is illegal for a POST.
- request()->method() != "POST" &&
- sdch_manager->IsInSupportedDomain(request_->url());
+ // We don't support SDCH responses to POST as there is a possibility
+ // of having SDCH encoded responses returned (e.g. by the cache)
+ // which we cannot decode, and in those situations, we will need
+ // to retransmit the request without SDCH, which is illegal for a POST.
+ bool advertise_sdch = sdch_manager != NULL && request()->method() != "POST";
+ if (advertise_sdch) {
+ SdchProblemCode rv = sdch_manager->IsInSupportedDomain(request()->url());
+ if (rv != SDCH_OK) {
+ advertise_sdch = false;
+ // If SDCH is just disabled, it is not a real error.
+ if (rv != SDCH_DISABLED && rv != SDCH_SECURE_SCHEME_NOT_SUPPORTED) {
+ SdchManager::SdchErrorRecovery(rv);
+ request()->net_log().AddEvent(
+ NetLog::TYPE_SDCH_DECODING_ERROR,
+ base::Bind(&NetLogSdchResourceProblemCallback, rv));
+ }
+ }
+ }
std::string avail_dictionaries;
if (advertise_sdch) {
sdch_manager->GetAvailDictionaryList(request_->url(),
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index 6fcff22..a1540fa 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -68,18 +68,6 @@
// See if the request should be intercepted.
//
-
- // TODO(pauljensen): Remove this when AppCacheInterceptor is a
- // ProtocolHandler, see crbug.com/161547.
- if (!(request->load_flags() & LOAD_DISABLE_INTERCEPT)) {
- InterceptorList::const_iterator i;
- for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeIntercept(request, network_delegate);
- if (job)
- return job;
- }
- }
-
URLRequestJob* job = job_factory->MaybeCreateJobWithProtocolHandler(
scheme, request, network_delegate);
if (job)
@@ -108,7 +96,6 @@
const GURL& location) const {
DCHECK(IsAllowedThread());
if (!request->url().is_valid() ||
- request->load_flags() & LOAD_DISABLE_INTERCEPT ||
request->status().status() == URLRequestStatus::CANCELED) {
return NULL;
}
@@ -120,15 +107,6 @@
if (!job_factory->IsHandledProtocol(scheme))
return NULL;
- InterceptorList::const_iterator i;
- for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeInterceptRedirect(request,
- network_delegate,
- location);
- if (job)
- return job;
- }
-
URLRequestJob* job =
request->context()->job_factory()->MaybeInterceptRedirect(
request, network_delegate, location);
@@ -142,7 +120,6 @@
URLRequest* request, NetworkDelegate* network_delegate) const {
DCHECK(IsAllowedThread());
if (!request->url().is_valid() ||
- request->load_flags() & LOAD_DISABLE_INTERCEPT ||
request->status().status() == URLRequestStatus::CANCELED) {
return NULL;
}
@@ -154,14 +131,6 @@
if (!job_factory->IsHandledProtocol(scheme))
return NULL;
- InterceptorList::const_iterator i;
- for (i = interceptors_.begin(); i != interceptors_.end(); ++i) {
- URLRequestJob* job = (*i)->MaybeInterceptResponse(request,
- network_delegate);
- if (job)
- return job;
- }
-
URLRequestJob* job =
request->context()->job_factory()->MaybeInterceptResponse(
request, network_delegate);
@@ -181,29 +150,6 @@
return false;
}
-void URLRequestJobManager::RegisterRequestInterceptor(
- URLRequest::Interceptor* interceptor) {
- DCHECK(IsAllowedThread());
-
- base::AutoLock locked(lock_);
-
- DCHECK(std::find(interceptors_.begin(), interceptors_.end(), interceptor) ==
- interceptors_.end());
- interceptors_.push_back(interceptor);
-}
-
-void URLRequestJobManager::UnregisterRequestInterceptor(
- URLRequest::Interceptor* interceptor) {
- DCHECK(IsAllowedThread());
-
- base::AutoLock locked(lock_);
-
- InterceptorList::iterator i =
- std::find(interceptors_.begin(), interceptors_.end(), interceptor);
- DCHECK(i != interceptors_.end());
- interceptors_.erase(i);
-}
-
URLRequestJobManager::URLRequestJobManager()
: allowed_thread_(0),
allowed_thread_initialized_(false) {
diff --git a/net/url_request/url_request_job_manager.h b/net/url_request/url_request_job_manager.h
index 9877bed..ca67e56 100644
--- a/net/url_request/url_request_job_manager.h
+++ b/net/url_request/url_request_job_manager.h
@@ -51,12 +51,7 @@
// Returns true if the manager has a built-in handler for |scheme|.
static bool SupportsScheme(const std::string& scheme);
- // Register/unregister a request interceptor.
- void RegisterRequestInterceptor(URLRequest::Interceptor* interceptor);
- void UnregisterRequestInterceptor(URLRequest::Interceptor* interceptor);
-
private:
- typedef std::vector<URLRequest::Interceptor*> InterceptorList;
friend struct DefaultSingletonTraits<URLRequestJobManager>;
URLRequestJobManager();
@@ -92,7 +87,6 @@
#endif
mutable base::Lock lock_;
- InterceptorList interceptors_;
DISALLOW_COPY_AND_ASSIGN(URLRequestJobManager);
};
diff --git a/net/url_request/url_request_simple_job.cc b/net/url_request/url_request_simple_job.cc
index b855932..55a0f88 100644
--- a/net/url_request/url_request_simple_job.cc
+++ b/net/url_request/url_request_simple_job.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/compiler_specific.h"
+#include "base/memory/ref_counted_memory.h"
#include "base/message_loop/message_loop.h"
#include "base/profiler/scoped_tracker.h"
#include "net/base/io_buffer.h"
@@ -50,12 +51,31 @@
int remaining = byte_range_.last_byte_position() - data_offset_ + 1;
if (buf_size > remaining)
buf_size = remaining;
- memcpy(buf->data(), data_.data() + data_offset_, buf_size);
+ memcpy(buf->data(), data_->front() + data_offset_, buf_size);
data_offset_ += buf_size;
*bytes_read = buf_size;
return true;
}
+int URLRequestSimpleJob::GetData(std::string* mime_type,
+ std::string* charset,
+ std::string* data,
+ const CompletionCallback& callback) const {
+ NOTREACHED();
+ return ERR_UNEXPECTED;
+}
+
+int URLRequestSimpleJob::GetRefCountedData(
+ std::string* mime_type,
+ std::string* charset,
+ scoped_refptr<base::RefCountedMemory>* data,
+ const CompletionCallback& callback) const {
+ scoped_refptr<base::RefCountedString> str_data(new base::RefCountedString());
+ int result = GetData(mime_type, charset, &str_data->data(), callback);
+ *data = str_data;
+ return result;
+}
+
void URLRequestSimpleJob::StartAsync() {
if (!request_)
return;
@@ -82,11 +102,10 @@
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"422489 URLRequestSimpleJob::StartAsync 2"));
- result = GetData(&mime_type_,
- &charset_,
- &data_,
- base::Bind(&URLRequestSimpleJob::OnGetDataCompleted,
- weak_factory_.GetWeakPtr()));
+ result =
+ GetRefCountedData(&mime_type_, &charset_, &data_,
+ base::Bind(&URLRequestSimpleJob::OnGetDataCompleted,
+ weak_factory_.GetWeakPtr()));
}
if (result != ERR_IO_PENDING) {
@@ -107,7 +126,7 @@
if (result == OK) {
// Notify that the headers are complete
- if (!byte_range_.ComputeBounds(data_.size())) {
+ if (!byte_range_.ComputeBounds(data_->size())) {
NotifyDone(URLRequestStatus(URLRequestStatus::FAILED,
ERR_REQUEST_RANGE_NOT_SATISFIABLE));
return;
diff --git a/net/url_request/url_request_simple_job.h b/net/url_request/url_request_simple_job.h
index 85d8f7e..99b6cb6 100644
--- a/net/url_request/url_request_simple_job.h
+++ b/net/url_request/url_request_simple_job.h
@@ -7,11 +7,17 @@
#include <string>
+#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
+#include "base/strings/string_piece.h"
#include "net/base/completion_callback.h"
#include "net/base/net_export.h"
#include "net/url_request/url_range_request_job.h"
+namespace base {
+class RefCountedMemory;
+}
+
namespace net {
class URLRequest;
@@ -28,7 +34,8 @@
protected:
~URLRequestSimpleJob() override;
- // Subclasses must override the way response data is determined.
+ // Subclasses must override either GetData or GetRefCountedData to define the
+ // way response data is determined.
// The return value should be:
// - OK if data is obtained;
// - ERR_IO_PENDING if async processing is needed to finish obtaining data.
@@ -41,9 +48,15 @@
virtual int GetData(std::string* mime_type,
std::string* charset,
std::string* data,
- const CompletionCallback& callback) const = 0;
+ const CompletionCallback& callback) const;
- protected:
+ // Similar to GetData(), except |*data| can share ownership of the bytes
+ // instead of copying them into a std::string.
+ virtual int GetRefCountedData(std::string* mime_type,
+ std::string* charset,
+ scoped_refptr<base::RefCountedMemory>* data,
+ const CompletionCallback& callback) const;
+
void StartAsync();
private:
@@ -52,7 +65,7 @@
HttpByteRange byte_range_;
std::string mime_type_;
std::string charset_;
- std::string data_;
+ scoped_refptr<base::RefCountedMemory> data_;
int data_offset_;
base::WeakPtrFactory<URLRequestSimpleJob> weak_factory_;
};
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 2aeecc6..1d777dc 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -1158,445 +1158,6 @@
~CancelThenRestartTestJob() override {}
};
-// An Interceptor for use with interceptor tests
-class TestInterceptor : URLRequest::Interceptor {
- public:
- TestInterceptor()
- : intercept_main_request_(false), restart_main_request_(false),
- cancel_main_request_(false), cancel_then_restart_main_request_(false),
- simulate_main_network_error_(false),
- intercept_redirect_(false), cancel_redirect_request_(false),
- intercept_final_response_(false), cancel_final_request_(false),
- did_intercept_main_(false), did_restart_main_(false),
- did_cancel_main_(false), did_cancel_then_restart_main_(false),
- did_simulate_error_main_(false),
- did_intercept_redirect_(false), did_cancel_redirect_(false),
- did_intercept_final_(false), did_cancel_final_(false) {
- URLRequest::Deprecated::RegisterRequestInterceptor(this);
- }
-
- ~TestInterceptor() override {
- URLRequest::Deprecated::UnregisterRequestInterceptor(this);
- }
-
- URLRequestJob* MaybeIntercept(URLRequest* request,
- NetworkDelegate* network_delegate) override {
- if (restart_main_request_) {
- restart_main_request_ = false;
- did_restart_main_ = true;
- return new RestartTestJob(request, network_delegate);
- }
- if (cancel_main_request_) {
- cancel_main_request_ = false;
- did_cancel_main_ = true;
- return new CancelTestJob(request, network_delegate);
- }
- if (cancel_then_restart_main_request_) {
- cancel_then_restart_main_request_ = false;
- did_cancel_then_restart_main_ = true;
- return new CancelThenRestartTestJob(request, network_delegate);
- }
- if (simulate_main_network_error_) {
- simulate_main_network_error_ = false;
- did_simulate_error_main_ = true;
- // will error since the requeted url is not one of its canned urls
- return new URLRequestTestJob(request, network_delegate, true);
- }
- if (!intercept_main_request_)
- return NULL;
- intercept_main_request_ = false;
- did_intercept_main_ = true;
- URLRequestTestJob* job = new URLRequestTestJob(request,
- network_delegate,
- main_headers_,
- main_data_,
- true);
- job->set_load_timing_info(main_request_load_timing_info_);
- return job;
- }
-
- URLRequestJob* MaybeInterceptRedirect(URLRequest* request,
- NetworkDelegate* network_delegate,
- const GURL& location) override {
- if (cancel_redirect_request_) {
- cancel_redirect_request_ = false;
- did_cancel_redirect_ = true;
- return new CancelTestJob(request, network_delegate);
- }
- if (!intercept_redirect_)
- return NULL;
- intercept_redirect_ = false;
- did_intercept_redirect_ = true;
- return new URLRequestTestJob(request,
- network_delegate,
- redirect_headers_,
- redirect_data_,
- true);
- }
-
- URLRequestJob* MaybeInterceptResponse(
- URLRequest* request,
- NetworkDelegate* network_delegate) override {
- if (cancel_final_request_) {
- cancel_final_request_ = false;
- did_cancel_final_ = true;
- return new CancelTestJob(request, network_delegate);
- }
- if (!intercept_final_response_)
- return NULL;
- intercept_final_response_ = false;
- did_intercept_final_ = true;
- return new URLRequestTestJob(request,
- network_delegate,
- final_headers_,
- final_data_,
- true);
- }
-
- // Whether to intercept the main request, and if so the response to return and
- // the LoadTimingInfo to use.
- bool intercept_main_request_;
- std::string main_headers_;
- std::string main_data_;
- LoadTimingInfo main_request_load_timing_info_;
-
- // Other actions we take at MaybeIntercept time
- bool restart_main_request_;
- bool cancel_main_request_;
- bool cancel_then_restart_main_request_;
- bool simulate_main_network_error_;
-
- // Whether to intercept redirects, and if so the response to return.
- bool intercept_redirect_;
- std::string redirect_headers_;
- std::string redirect_data_;
-
- // Other actions we can take at MaybeInterceptRedirect time
- bool cancel_redirect_request_;
-
- // Whether to intercept final response, and if so the response to return.
- bool intercept_final_response_;
- std::string final_headers_;
- std::string final_data_;
-
- // Other actions we can take at MaybeInterceptResponse time
- bool cancel_final_request_;
-
- // If we did something or not
- bool did_intercept_main_;
- bool did_restart_main_;
- bool did_cancel_main_;
- bool did_cancel_then_restart_main_;
- bool did_simulate_error_main_;
- bool did_intercept_redirect_;
- bool did_cancel_redirect_;
- bool did_intercept_final_;
- bool did_cancel_final_;
-
- // Static getters for canned response header and data strings
-
- static std::string ok_data() {
- return URLRequestTestJob::test_data_1();
- }
-
- static std::string ok_headers() {
- return URLRequestTestJob::test_headers();
- }
-
- static std::string redirect_data() {
- return std::string();
- }
-
- static std::string redirect_headers() {
- return URLRequestTestJob::test_redirect_headers();
- }
-
- static std::string error_data() {
- return std::string("ohhh nooooo mr. bill!");
- }
-
- static std::string error_headers() {
- return URLRequestTestJob::test_error_headers();
- }
-};
-
-TEST_F(URLRequestTest, Intercept) {
- TestInterceptor interceptor;
-
- // intercept the main request and respond with a simple response
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::ok_headers();
- interceptor.main_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- base::SupportsUserData::Data* user_data0 = new base::SupportsUserData::Data();
- base::SupportsUserData::Data* user_data1 = new base::SupportsUserData::Data();
- base::SupportsUserData::Data* user_data2 = new base::SupportsUserData::Data();
- req->SetUserData(NULL, user_data0);
- req->SetUserData(&user_data1, user_data1);
- req->SetUserData(&user_data2, user_data2);
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Make sure we can retrieve our specific user data
- EXPECT_EQ(user_data0, req->GetUserData(NULL));
- EXPECT_EQ(user_data1, req->GetUserData(&user_data1));
- EXPECT_EQ(user_data2, req->GetUserData(&user_data2));
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
-
- // Check we got one good response
- EXPECT_TRUE(req->status().is_success());
- EXPECT_EQ(200, req->response_headers()->response_code());
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptRedirect) {
- TestInterceptor interceptor;
-
- // intercept the main request and respond with a redirect
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::redirect_headers();
- interceptor.main_data_ = TestInterceptor::redirect_data();
-
- // intercept that redirect and respond a final OK response
- interceptor.intercept_redirect_ = true;
- interceptor.redirect_headers_ = TestInterceptor::ok_headers();
- interceptor.redirect_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
- EXPECT_TRUE(interceptor.did_intercept_redirect_);
-
- // Check we got one good response
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success()) {
- EXPECT_EQ(200, req->response_headers()->response_code());
- }
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptServerError) {
- TestInterceptor interceptor;
-
- // intercept the main request to generate a server error response
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::error_headers();
- interceptor.main_data_ = TestInterceptor::error_data();
-
- // intercept that error and respond with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
- EXPECT_TRUE(interceptor.did_intercept_final_);
-
- // Check we got one good response
- EXPECT_TRUE(req->status().is_success());
- EXPECT_EQ(200, req->response_headers()->response_code());
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptNetworkError) {
- TestInterceptor interceptor;
-
- // intercept the main request to simulate a network error
- interceptor.simulate_main_network_error_ = true;
-
- // intercept that error and respond with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_simulate_error_main_);
- EXPECT_TRUE(interceptor.did_intercept_final_);
-
- // Check we received one good response
- EXPECT_TRUE(req->status().is_success());
- EXPECT_EQ(200, req->response_headers()->response_code());
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptRestartRequired) {
- TestInterceptor interceptor;
-
- // restart the main request
- interceptor.restart_main_request_ = true;
-
- // then intercept the new main request and respond with an OK response
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::ok_headers();
- interceptor.main_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_restart_main_);
- EXPECT_TRUE(interceptor.did_intercept_main_);
-
- // Check we received one good response
- EXPECT_TRUE(req->status().is_success());
- if (req->status().is_success()) {
- EXPECT_EQ(200, req->response_headers()->response_code());
- }
- EXPECT_EQ(TestInterceptor::ok_data(), d.data_received());
- EXPECT_EQ(1, d.response_started_count());
- EXPECT_EQ(0, d.received_redirect_count());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelMain) {
- TestInterceptor interceptor;
-
- // intercept the main request and cancel from within the restarted job
- interceptor.cancel_main_request_ = true;
-
- // setup to intercept final response and override it with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_cancel_main_);
- EXPECT_FALSE(interceptor.did_intercept_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelRedirect) {
- TestInterceptor interceptor;
-
- // intercept the main request and respond with a redirect
- interceptor.intercept_main_request_ = true;
- interceptor.main_headers_ = TestInterceptor::redirect_headers();
- interceptor.main_data_ = TestInterceptor::redirect_data();
-
- // intercept the redirect and cancel from within that job
- interceptor.cancel_redirect_request_ = true;
-
- // setup to intercept final response and override it with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_intercept_main_);
- EXPECT_TRUE(interceptor.did_cancel_redirect_);
- EXPECT_FALSE(interceptor.did_intercept_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelFinal) {
- TestInterceptor interceptor;
-
- // intercept the main request to simulate a network error
- interceptor.simulate_main_network_error_ = true;
-
- // setup to intercept final response and cancel from within that job
- interceptor.cancel_final_request_ = true;
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_simulate_error_main_);
- EXPECT_TRUE(interceptor.did_cancel_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
-TEST_F(URLRequestTest, InterceptRespectsCancelInRestart) {
- TestInterceptor interceptor;
-
- // intercept the main request and cancel then restart from within that job
- interceptor.cancel_then_restart_main_request_ = true;
-
- // setup to intercept final response and override it with an OK response
- interceptor.intercept_final_response_ = true;
- interceptor.final_headers_ = TestInterceptor::ok_headers();
- interceptor.final_data_ = TestInterceptor::ok_data();
-
- TestDelegate d;
- scoped_ptr<URLRequest> req(default_context_.CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
- req->set_method("GET");
- req->Start();
- base::RunLoop().Run();
-
- // Check the interceptor got called as expected
- EXPECT_TRUE(interceptor.did_cancel_then_restart_main_);
- EXPECT_FALSE(interceptor.did_intercept_final_);
-
- // Check we see a canceled request
- EXPECT_FALSE(req->status().is_success());
- EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
-}
-
// An Interceptor for use with interceptor tests.
class MockURLRequestInterceptor : public URLRequestInterceptor {
public:
@@ -2144,8 +1705,8 @@
// Set up to intercept the final response and override it with an OK response.
interceptor()->set_intercept_final_response(true);
- interceptor()->set_final_headers(TestInterceptor::ok_headers());
- interceptor()->set_final_data(TestInterceptor::ok_data());
+ interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
TestDelegate d;
scoped_ptr<URLRequest> req(default_context().CreateRequest(
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.cc b/sandbox/linux/bpf_dsl/policy_compiler.cc
index 5be32f4..2bc22e9 100644
--- a/sandbox/linux/bpf_dsl/policy_compiler.cc
+++ b/sandbox/linux/bpf_dsl/policy_compiler.cc
@@ -18,7 +18,6 @@
#include "sandbox/linux/seccomp-bpf/codegen.h"
#include "sandbox/linux/seccomp-bpf/die.h"
#include "sandbox/linux/seccomp-bpf/errorcode.h"
-#include "sandbox/linux/seccomp-bpf/instruction.h"
#include "sandbox/linux/seccomp-bpf/linux_seccomp.h"
#include "sandbox/linux/seccomp-bpf/syscall.h"
#include "sandbox/linux/seccomp-bpf/syscall_iterator.h"
@@ -146,7 +145,7 @@
return program.Pass();
}
-Instruction* PolicyCompiler::AssemblePolicy() {
+CodeGen::Node PolicyCompiler::AssemblePolicy() {
// A compiled policy consists of three logical parts:
// 1. Check that the "arch" field matches the expected architecture.
// 2. If the policy involves unsafe traps, check if the syscall was
@@ -156,7 +155,7 @@
return CheckArch(MaybeAddEscapeHatch(DispatchSyscall()));
}
-Instruction* PolicyCompiler::CheckArch(Instruction* passed) {
+CodeGen::Node PolicyCompiler::CheckArch(CodeGen::Node passed) {
// If the architecture doesn't match SECCOMP_ARCH, disallow the
// system call.
return gen_.MakeInstruction(
@@ -169,7 +168,7 @@
RetExpression(Kill("Invalid audit architecture in BPF filter"))));
}
-Instruction* PolicyCompiler::MaybeAddEscapeHatch(Instruction* rest) {
+CodeGen::Node PolicyCompiler::MaybeAddEscapeHatch(CodeGen::Node rest) {
// If no unsafe traps, then simply return |rest|.
if (!has_unsafe_traps_) {
return rest;
@@ -206,14 +205,14 @@
rest));
}
-Instruction* PolicyCompiler::DispatchSyscall() {
+CodeGen::Node PolicyCompiler::DispatchSyscall() {
// Evaluate all possible system calls and group their ErrorCodes into
// ranges of identical codes.
Ranges ranges;
FindRanges(&ranges);
// Compile the system call ranges to an optimized BPF jumptable
- Instruction* jumptable = AssembleJumpTable(ranges.begin(), ranges.end());
+ CodeGen::Node jumptable = AssembleJumpTable(ranges.begin(), ranges.end());
// Grab the system call number, so that we can check it and then
// execute the jump table.
@@ -221,11 +220,11 @@
BPF_LD + BPF_W + BPF_ABS, SECCOMP_NR_IDX, CheckSyscallNumber(jumptable));
}
-Instruction* PolicyCompiler::CheckSyscallNumber(Instruction* passed) {
+CodeGen::Node PolicyCompiler::CheckSyscallNumber(CodeGen::Node passed) {
if (kIsIntel) {
// On Intel architectures, verify that system call numbers are in the
// expected number range.
- Instruction* invalidX32 =
+ CodeGen::Node invalidX32 =
RetExpression(Kill("Illegal mixing of system call ABIs"));
if (kIsX32) {
// The newer x32 API always sets bit 30.
@@ -268,8 +267,8 @@
ranges->push_back(Range(old_sysnum, old_err));
}
-Instruction* PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
- Ranges::const_iterator stop) {
+CodeGen::Node PolicyCompiler::AssembleJumpTable(Ranges::const_iterator start,
+ Ranges::const_iterator stop) {
// We convert the list of system call ranges into jump table that performs
// a binary search over the ranges.
// As a sanity check, we need to have at least one distinct ranges for us
@@ -289,12 +288,12 @@
Ranges::const_iterator mid = start + (stop - start) / 2;
// Sub-divide the list of ranges and continue recursively.
- Instruction* jf = AssembleJumpTable(start, mid);
- Instruction* jt = AssembleJumpTable(mid, stop);
+ CodeGen::Node jf = AssembleJumpTable(start, mid);
+ CodeGen::Node jt = AssembleJumpTable(mid, stop);
return gen_.MakeInstruction(BPF_JMP + BPF_JGE + BPF_K, mid->from, jt, jf);
}
-Instruction* PolicyCompiler::RetExpression(const ErrorCode& err) {
+CodeGen::Node PolicyCompiler::RetExpression(const ErrorCode& err) {
switch (err.error_type()) {
case ErrorCode::ET_COND:
return CondExpression(err);
@@ -306,7 +305,7 @@
}
}
-Instruction* PolicyCompiler::CondExpression(const ErrorCode& cond) {
+CodeGen::Node PolicyCompiler::CondExpression(const ErrorCode& cond) {
// Sanity check that |cond| makes sense.
if (cond.argno_ < 0 || cond.argno_ >= 6) {
SANDBOX_DIE("sandbox_bpf: invalid argument number");
@@ -328,8 +327,8 @@
// TODO(mdempsky): Reject TP_64BIT on 32-bit platforms. For now we allow it
// because some SandboxBPF unit tests exercise it.
- Instruction* passed = RetExpression(*cond.passed_);
- Instruction* failed = RetExpression(*cond.failed_);
+ CodeGen::Node passed = RetExpression(*cond.passed_);
+ CodeGen::Node failed = RetExpression(*cond.failed_);
// We want to emit code to check "(arg & mask) == value" where arg, mask, and
// value are 64-bit values, but the BPF machine is only 32-bit. We implement
@@ -341,16 +340,16 @@
failed);
}
-Instruction* PolicyCompiler::CondExpressionHalf(const ErrorCode& cond,
- ArgHalf half,
- Instruction* passed,
- Instruction* failed) {
+CodeGen::Node PolicyCompiler::CondExpressionHalf(const ErrorCode& cond,
+ ArgHalf half,
+ CodeGen::Node passed,
+ CodeGen::Node failed) {
if (cond.width_ == ErrorCode::TP_32BIT && half == UpperHalf) {
// Special logic for sanity checking the upper 32-bits of 32-bit system
// call arguments.
// TODO(mdempsky): Compile Unexpected64bitArgument() just per program.
- Instruction* invalid_64bit = RetExpression(Unexpected64bitArgument());
+ CodeGen::Node invalid_64bit = RetExpression(Unexpected64bitArgument());
const uint32_t upper = SECCOMP_ARG_MSB_IDX(cond.argno_);
const uint32_t lower = SECCOMP_ARG_LSB_IDX(cond.argno_);
diff --git a/sandbox/linux/bpf_dsl/policy_compiler.h b/sandbox/linux/bpf_dsl/policy_compiler.h
index 4aec5fd..4ef8cf3 100644
--- a/sandbox/linux/bpf_dsl/policy_compiler.h
+++ b/sandbox/linux/bpf_dsl/policy_compiler.h
@@ -18,8 +18,6 @@
#include "sandbox/sandbox_export.h"
namespace sandbox {
-struct Instruction;
-
namespace bpf_dsl {
class Policy;
@@ -101,28 +99,28 @@
};
// Compile the configured policy into a complete instruction sequence.
- Instruction* AssemblePolicy();
+ CodeGen::Node AssemblePolicy();
// Return an instruction sequence that checks the
// arch_seccomp_data's "arch" field is valid, and then passes
// control to |passed| if so.
- Instruction* CheckArch(Instruction* passed);
+ CodeGen::Node CheckArch(CodeGen::Node passed);
// If |has_unsafe_traps_| is true, returns an instruction sequence
// that allows all system calls from Syscall::Call(), and otherwise
// passes control to |rest|. Otherwise, simply returns |rest|.
- Instruction* MaybeAddEscapeHatch(Instruction* rest);
+ CodeGen::Node MaybeAddEscapeHatch(CodeGen::Node rest);
// Return an instruction sequence that loads and checks the system
// call number, performs a binary search, and then dispatches to an
// appropriate instruction sequence compiled from the current
// policy.
- Instruction* DispatchSyscall();
+ CodeGen::Node DispatchSyscall();
// Return an instruction sequence that checks the system call number
// (expected to be loaded in register A) and if valid, passes
// control to |passed| (with register A still valid).
- Instruction* CheckSyscallNumber(Instruction* passed);
+ CodeGen::Node CheckSyscallNumber(CodeGen::Node passed);
// Finds all the ranges of system calls that need to be handled. Ranges are
// sorted in ascending order of system call numbers. There are no gaps in the
@@ -132,28 +130,28 @@
// Returns a BPF program snippet that implements a jump table for the
// given range of system call numbers. This function runs recursively.
- Instruction* AssembleJumpTable(Ranges::const_iterator start,
- Ranges::const_iterator stop);
+ CodeGen::Node AssembleJumpTable(Ranges::const_iterator start,
+ Ranges::const_iterator stop);
// Returns a BPF program snippet that makes the BPF filter program exit
// with the given ErrorCode "err". N.B. the ErrorCode may very well be a
// conditional expression; if so, this function will recursively call
// CondExpression() and possibly RetExpression() to build a complex set of
// instructions.
- Instruction* RetExpression(const ErrorCode& err);
+ CodeGen::Node RetExpression(const ErrorCode& err);
// Returns a BPF program that evaluates the conditional expression in
// "cond" and returns the appropriate value from the BPF filter program.
// This function recursively calls RetExpression(); it should only ever be
// called from RetExpression().
- Instruction* CondExpression(const ErrorCode& cond);
+ CodeGen::Node CondExpression(const ErrorCode& cond);
// Returns a BPF program that evaluates half of a conditional expression;
// it should only ever be called from CondExpression().
- Instruction* CondExpressionHalf(const ErrorCode& cond,
- ArgHalf half,
- Instruction* passed,
- Instruction* failed);
+ CodeGen::Node CondExpressionHalf(const ErrorCode& cond,
+ ArgHalf half,
+ CodeGen::Node passed,
+ CodeGen::Node failed);
// MakeTrap is the common implementation for Trap and UnsafeTrap.
ErrorCode MakeTrap(TrapRegistry::TrapFnc fnc, const void* aux, bool safe);
diff --git a/sandbox/linux/seccomp-bpf/codegen.cc b/sandbox/linux/seccomp-bpf/codegen.cc
index 1ee79b6..18d26da 100644
--- a/sandbox/linux/seccomp-bpf/codegen.cc
+++ b/sandbox/linux/seccomp-bpf/codegen.cc
@@ -15,6 +15,11 @@
namespace sandbox {
+// Unfortunately this needs to be defined out-of-line because inline
+// initializing a static member to "nullptr" requires "constexpr",
+// which is currently banned by the Chromium style guide.
+const CodeGen::Node CodeGen::kNullNode = nullptr;
+
CodeGen::CodeGen() : compiled_(false) {}
CodeGen::~CodeGen() {
@@ -30,47 +35,28 @@
}
}
-Instruction* CodeGen::MakeInstruction(uint16_t code,
- uint32_t k,
- Instruction* next) {
- // We can handle non-jumping instructions and "always" jumps. Both of
- // them are followed by exactly one "next" instruction.
- // We allow callers to defer specifying "next", but then they must call
- // "joinInstructions" later.
- if (BPF_CLASS(code) == BPF_JMP && BPF_OP(code) != BPF_JA) {
- SANDBOX_DIE(
- "Must provide both \"true\" and \"false\" branch "
- "for a BPF_JMP");
- }
- if (next && BPF_CLASS(code) == BPF_RET) {
- SANDBOX_DIE("Cannot append instructions after a return statement");
- }
+CodeGen::Node CodeGen::MakeInstruction(uint16_t code,
+ uint32_t k,
+ Node jt,
+ Node jf) {
+ Node insn;
if (BPF_CLASS(code) == BPF_JMP) {
- // "Always" jumps use the "true" branch target, only.
- Instruction* insn = new Instruction(code, 0, next, NULL);
- instructions_.push_back(insn);
- return insn;
+ CHECK_NE(kNullNode, jt);
+ if (BPF_OP(code) == BPF_JA) {
+ CHECK_EQ(kNullNode, jf);
+ } else {
+ CHECK_NE(kNullNode, jf);
+ }
+ insn = new Instruction(code, k, jt, jf);
} else {
- // Non-jumping instructions do not use any of the branch targets.
- Instruction* insn = new Instruction(code, k, next);
- instructions_.push_back(insn);
- return insn;
+ if (BPF_CLASS(code) == BPF_RET) {
+ CHECK_EQ(kNullNode, jt);
+ } else {
+ CHECK_NE(kNullNode, jt);
+ }
+ CHECK_EQ(kNullNode, jf);
+ insn = new Instruction(code, k, jt);
}
-}
-
-Instruction* CodeGen::MakeInstruction(uint16_t code,
- uint32_t k,
- Instruction* jt,
- Instruction* jf) {
- // We can handle all conditional jumps. They are followed by both a
- // "true" and a "false" branch.
- if (BPF_CLASS(code) != BPF_JMP || BPF_OP(code) == BPF_JA) {
- SANDBOX_DIE("Expected a BPF_JMP instruction");
- }
- if (!jt || !jf) {
- SANDBOX_DIE("Branches must jump to a valid instruction");
- }
- Instruction* insn = new Instruction(code, k, jt, jf);
instructions_.push_back(insn);
return insn;
}
diff --git a/sandbox/linux/seccomp-bpf/codegen.h b/sandbox/linux/seccomp-bpf/codegen.h
index 671b09e..fd229f7 100644
--- a/sandbox/linux/seccomp-bpf/codegen.h
+++ b/sandbox/linux/seccomp-bpf/codegen.h
@@ -24,17 +24,18 @@
typedef std::map<const Instruction*, BasicBlock*> TargetsToBlocks;
typedef std::map<const BasicBlock*, int> IncomingBranches;
-// The code generator instantiates a basic compiler that can convert a
-// graph of BPF instructions into a well-formed stream of BPF instructions.
-// Most notably, it ensures that jumps are always forward and don't exceed
-// the limit of 255 instructions imposed by the instruction set.
+// The code generator implements a basic assembler that can convert a
+// graph of BPF instructions into a well-formed array of BPF
+// instructions. Most notably, it ensures that jumps are always
+// forward and don't exceed the limit of 255 instructions imposed by
+// the instruction set.
//
-// Callers would typically create a new CodeGen object and then use it to
-// build a DAG of Instructions. They'll eventually call Compile() to convert
-// this DAG to a Program.
+// Callers would typically create a new CodeGen object and then use it
+// to build a DAG of instruction nodes. They'll eventually call
+// Compile() to convert this DAG to a Program.
//
// CodeGen gen;
-// Instruction *allow, *branch, *dag;
+// CodeGen::Node allow, branch, dag;
//
// allow =
// gen.MakeInstruction(BPF_RET+BPF_K,
@@ -60,25 +61,32 @@
// program in the kernel.
typedef std::vector<struct sock_filter> Program;
+ // Node represents a node within the instruction DAG being compiled.
+ // Nodes are owned by the CodeGen object and need not be explicitly
+ // deleted.
+ using Node = Instruction*;
+
+ // kNullNode represents the "null" node; i.e., the reserved node
+ // value guaranteed to not equal any actual nodes.
+ static const Node kNullNode;
+
CodeGen();
~CodeGen();
- // Create a new instruction. Instructions form a DAG. The instruction objects
- // are owned by the CodeGen object. They do not need to be explicitly
- // deleted.
- // For details on the possible parameters refer to <linux/filter.h>
- Instruction* MakeInstruction(uint16_t code,
- uint32_t k,
- Instruction* next = nullptr);
- Instruction* MakeInstruction(uint16_t code,
- uint32_t k,
- Instruction* jt,
- Instruction* jf);
+ // MakeInstruction creates a node representing the specified
+ // instruction. For details on the possible parameters refer to
+ // https://www.kernel.org/doc/Documentation/networking/filter.txt.
+ // TODO(mdempsky): Reconsider using default arguments here.
+ Node MakeInstruction(uint16_t code,
+ uint32_t k,
+ Node jt = kNullNode,
+ Node jf = kNullNode);
- // Compiles the graph of instructions into a BPF program that can be passed
- // to the kernel. Please note that this function modifies the graph in place
- // and must therefore only be called once per graph.
- void Compile(Instruction* instructions, Program* program);
+ // Compile linearizes the instruction DAG into a BPF program that
+ // can be executed by a BPF virtual machine. Please note that this
+ // function modifies the graph in place and must therefore only be
+ // called once per graph.
+ void Compile(Node head, Program* program);
private:
friend class CodeGenUnittestHelper;
diff --git a/sandbox/linux/seccomp-bpf/codegen_unittest.cc b/sandbox/linux/seccomp-bpf/codegen_unittest.cc
index 77e2238..3f1a04b 100644
--- a/sandbox/linux/seccomp-bpf/codegen_unittest.cc
+++ b/sandbox/linux/seccomp-bpf/codegen_unittest.cc
@@ -6,116 +6,213 @@
#include <linux/filter.h>
-#include <set>
-#include <string>
+#include <map>
+#include <utility>
#include <vector>
-#include "sandbox/linux/seccomp-bpf/basicblock.h"
-#include "sandbox/linux/seccomp-bpf/errorcode.h"
-#include "sandbox/linux/seccomp-bpf/instruction.h"
+#include "base/macros.h"
+#include "base/md5.h"
+#include "base/strings/string_piece.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace sandbox {
-
-// We want to access some of the private methods in the code generator. We
-// do so by defining a "friend" that makes these methods public for us.
-class CodeGenUnittestHelper : public CodeGen {
- public:
- using CodeGen::CutGraphIntoBasicBlocks;
- using CodeGen::FindBranchTargets;
- using CodeGen::MergeTails;
-};
-
namespace {
-enum {
- NO_FLAGS = 0x0000,
- HAS_MERGEABLE_TAILS = 0x0001,
-};
+// Hash provides an abstraction for building "hash trees" from BPF
+// control flow graphs, and efficiently identifying equivalent graphs.
+//
+// For simplicity, we use MD5, because base happens to provide a
+// convenient API for its use. However, any collision-resistant hash
+// should suffice.
+class Hash {
+ public:
+ static const Hash kZero;
-using ProgramTestFunc = void (*)(CodeGenUnittestHelper* gen,
- Instruction* head,
- int flags);
+ Hash() : digest_() {}
-class ProgramTest : public ::testing::TestWithParam<ProgramTestFunc> {
- protected:
- ProgramTest() : gen_() {}
-
- // RunTest runs the test function argument. It should be called at
- // the end of each program test case.
- void RunTest(Instruction* head, int flags) { GetParam()(&gen_, head, flags); }
-
- Instruction* MakeInstruction(uint16_t code,
- uint32_t k,
- Instruction* next = nullptr) {
- Instruction* ret = gen_.MakeInstruction(code, k, next);
- EXPECT_NE(nullptr, ret);
- EXPECT_EQ(code, ret->code);
- EXPECT_EQ(k, ret->k);
- if (code == BPF_JMP + BPF_JA) {
- // Annoying inconsistency.
- EXPECT_EQ(nullptr, ret->next);
- EXPECT_EQ(next, ret->jt_ptr);
- } else {
- EXPECT_EQ(next, ret->next);
- EXPECT_EQ(nullptr, ret->jt_ptr);
- }
- EXPECT_EQ(nullptr, ret->jf_ptr);
- return ret;
+ Hash(uint16_t code,
+ uint32_t k,
+ const Hash& jt = kZero,
+ const Hash& jf = kZero)
+ : digest_() {
+ base::MD5Context ctx;
+ base::MD5Init(&ctx);
+ HashValue(&ctx, code);
+ HashValue(&ctx, k);
+ HashValue(&ctx, jt);
+ HashValue(&ctx, jf);
+ base::MD5Final(&digest_, &ctx);
}
- Instruction* MakeInstruction(uint16_t code,
- uint32_t k,
- Instruction* jt,
- Instruction* jf) {
- Instruction* ret = gen_.MakeInstruction(code, k, jt, jf);
- EXPECT_NE(nullptr, ret);
- EXPECT_EQ(code, ret->code);
- EXPECT_EQ(k, ret->k);
- EXPECT_EQ(nullptr, ret->next);
- EXPECT_EQ(jt, ret->jt_ptr);
- EXPECT_EQ(jf, ret->jf_ptr);
- return ret;
+ Hash(const Hash& hash) = default;
+ Hash& operator=(const Hash& rhs) = default;
+
+ friend bool operator==(const Hash& lhs, const Hash& rhs) {
+ return lhs.Base16() == rhs.Base16();
+ }
+ friend bool operator!=(const Hash& lhs, const Hash& rhs) {
+ return !(lhs == rhs);
}
private:
- CodeGenUnittestHelper gen_;
+ template <typename T>
+ void HashValue(base::MD5Context* ctx, const T& value) {
+ base::MD5Update(ctx,
+ base::StringPiece(reinterpret_cast<const char*>(&value),
+ sizeof(value)));
+ }
+
+ std::string Base16() const {
+ return MD5DigestToBase16(digest_);
+ }
+
+ base::MD5Digest digest_;
};
-TEST_P(ProgramTest, OneInstruction) {
- // Create the most basic valid BPF program:
- // RET 0
- Instruction* head = MakeInstruction(BPF_RET + BPF_K, 0);
- RunTest(head, NO_FLAGS);
+const Hash Hash::kZero;
+
+// Sanity check that equality and inequality work on Hash as required.
+TEST(CodeGen, HashSanity) {
+ std::vector<Hash> hashes;
+
+ // Push a bunch of logically distinct hashes.
+ hashes.push_back(Hash::kZero);
+ for (int i = 0; i < 4; ++i) {
+ hashes.push_back(Hash(i & 1, i & 2));
+ }
+ for (int i = 0; i < 16; ++i) {
+ hashes.push_back(Hash(i & 1, i & 2, Hash(i & 4, i & 8)));
+ }
+ for (int i = 0; i < 64; ++i) {
+ hashes.push_back(
+ Hash(i & 1, i & 2, Hash(i & 4, i & 8), Hash(i & 16, i & 32)));
+ }
+
+ for (const Hash& a : hashes) {
+ for (const Hash& b : hashes) {
+ // Hashes should equal themselves, but not equal all others.
+ if (&a == &b) {
+ EXPECT_EQ(a, b);
+ } else {
+ EXPECT_NE(a, b);
+ }
+ }
+ }
}
-TEST_P(ProgramTest, SimpleBranch) {
+// ProgramTest provides a fixture for writing compiling sample
+// programs with CodeGen and verifying the linearized output matches
+// the input DAG.
+class ProgramTest : public ::testing::Test {
+ protected:
+ ProgramTest() : gen_(), node_hashes_() {}
+
+ // MakeInstruction calls CodeGen::MakeInstruction() and associated
+ // the returned address with a hash of the instruction.
+ CodeGen::Node MakeInstruction(uint16_t code,
+ uint32_t k,
+ CodeGen::Node jt = CodeGen::kNullNode,
+ CodeGen::Node jf = CodeGen::kNullNode) {
+ CodeGen::Node res = gen_.MakeInstruction(code, k, jt, jf);
+ EXPECT_NE(CodeGen::kNullNode, res);
+
+ Hash digest;
+ if (code == BPF_JMP + BPF_JA) {
+ // TODO(mdempsky): Disallow use of JA.
+ digest = Lookup(jt);
+ } else {
+ digest = Hash(code, k, Lookup(jt), Lookup(jf));
+ }
+ auto it = node_hashes_.insert(std::make_pair(res, digest));
+ EXPECT_EQ(digest, it.first->second);
+
+ return res;
+ }
+
+ // RunTest compiles the program and verifies that the output matches
+ // what is expected. It should be called at the end of each program
+ // test case.
+ void RunTest(CodeGen::Node head) {
+ // Compile the program
+ CodeGen::Program program;
+ gen_.Compile(head, &program);
+
+ // Walk the program backwards, and compute the hash for each instruction.
+ std::vector<Hash> prog_hashes(program.size());
+ for (size_t i = program.size(); i > 0; --i) {
+ const sock_filter& insn = program.at(i - 1);
+ Hash& hash = prog_hashes.at(i - 1);
+
+ if (BPF_CLASS(insn.code) == BPF_JMP) {
+ if (BPF_OP(insn.code) == BPF_JA) {
+ // The compiler adds JA instructions as needed, so skip them.
+ hash = prog_hashes.at(i + insn.k);
+ } else {
+ hash = Hash(insn.code, insn.k, prog_hashes.at(i + insn.jt),
+ prog_hashes.at(i + insn.jf));
+ }
+ } else if (BPF_CLASS(insn.code) == BPF_RET) {
+ hash = Hash(insn.code, insn.k);
+ } else {
+ hash = Hash(insn.code, insn.k, prog_hashes.at(i));
+ }
+ }
+
+ EXPECT_EQ(Lookup(head), prog_hashes.at(0));
+ }
+
+ private:
+ const Hash& Lookup(CodeGen::Node next) const {
+ if (next == CodeGen::kNullNode) {
+ return Hash::kZero;
+ }
+ auto it = node_hashes_.find(next);
+ if (it == node_hashes_.end()) {
+ ADD_FAILURE() << "No hash found for node " << next;
+ return Hash::kZero;
+ }
+ return it->second;
+ }
+
+ CodeGen gen_;
+ std::map<CodeGen::Node, Hash> node_hashes_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProgramTest);
+};
+
+TEST_F(ProgramTest, OneInstruction) {
+ // Create the most basic valid BPF program:
+ // RET 0
+ CodeGen::Node head = MakeInstruction(BPF_RET + BPF_K, 0);
+ RunTest(head);
+}
+
+TEST_F(ProgramTest, SimpleBranch) {
// Create a program with a single branch:
// JUMP if eq 42 then $0 else $1
// 0: RET 1
// 1: RET 0
- Instruction* head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K,
- 42,
- MakeInstruction(BPF_RET + BPF_K, 1),
- MakeInstruction(BPF_RET + BPF_K, 0));
- RunTest(head, NO_FLAGS);
+ CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42,
+ MakeInstruction(BPF_RET + BPF_K, 1),
+ MakeInstruction(BPF_RET + BPF_K, 0));
+ RunTest(head);
}
-TEST_P(ProgramTest, AtypicalBranch) {
+TEST_F(ProgramTest, AtypicalBranch) {
// Create a program with a single branch:
// JUMP if eq 42 then $0 else $0
// 0: RET 0
- Instruction* ret = MakeInstruction(BPF_RET + BPF_K, 0);
- Instruction* head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret);
+ CodeGen::Node ret = MakeInstruction(BPF_RET + BPF_K, 0);
+ CodeGen::Node head = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, ret, ret);
// N.B.: As the instructions in both sides of the branch are already
// the same object, we do not actually have any "mergeable" branches.
// This needs to be reflected in our choice of "flags".
- RunTest(head, NO_FLAGS);
+ RunTest(head);
}
-TEST_P(ProgramTest, Complex) {
+TEST_F(ProgramTest, Complex) {
// Creates a basic BPF program that we'll use to test some of the code:
// JUMP if eq 42 the $0 else $1 (insn6)
// 0: LD 23 (insn5)
@@ -125,18 +222,18 @@
// RET 42 (insn0)
// 4: LD 42 (insn3)
// RET 42 (insn3+)
- Instruction* insn0 = MakeInstruction(BPF_RET + BPF_K, 42);
- Instruction* insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0);
- Instruction* insn2 = MakeInstruction(BPF_JMP + BPF_JA, 0, insn1);
+ CodeGen::Node insn0 = MakeInstruction(BPF_RET + BPF_K, 42);
+ CodeGen::Node insn1 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42, insn0);
+ CodeGen::Node insn2 = MakeInstruction(BPF_JMP + BPF_JA, 0, insn1);
// We explicitly duplicate instructions so that MergeTails() can coalesce
// them later.
- Instruction* insn3 = MakeInstruction(
- BPF_LD + BPF_W + BPF_ABS, 42, MakeInstruction(BPF_RET + BPF_K, 42));
+ CodeGen::Node insn3 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 42,
+ MakeInstruction(BPF_RET + BPF_K, 42));
- Instruction* insn4 =
+ CodeGen::Node insn4 =
MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn2, insn3);
- Instruction* insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4);
+ CodeGen::Node insn5 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 23, insn4);
// Force a basic block that ends in neither a jump instruction nor a return
// instruction. It only contains "insn5". This exercises one of the less
@@ -144,13 +241,13 @@
// This also gives us a diamond-shaped pattern in our graph, which stresses
// another aspect of the topo-sort algorithm (namely, the ability to
// correctly count the incoming branches for subtrees that are not disjunct).
- Instruction* insn6 =
+ CodeGen::Node insn6 =
MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 42, insn5, insn4);
- RunTest(insn6, HAS_MERGEABLE_TAILS);
+ RunTest(insn6);
}
-TEST_P(ProgramTest, ConfusingTails) {
+TEST_F(ProgramTest, ConfusingTails) {
// This simple program demonstrates https://crbug.com/351103/
// The two "LOAD 0" instructions are blocks of their own. MergeTails() could
// be tempted to merge them since they are the same. However, they are
@@ -169,19 +266,19 @@
// 6) RET 0
// 7) RET 1
- Instruction* i7 = MakeInstruction(BPF_RET + BPF_K, 1);
- Instruction* i6 = MakeInstruction(BPF_RET + BPF_K, 0);
- Instruction* i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
- Instruction* i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
- Instruction* i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
- Instruction* i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
- Instruction* i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
- Instruction* i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+ CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
+ CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
+ CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
+ CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
+ CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+ CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
+ CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+ CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
- RunTest(i0, NO_FLAGS);
+ RunTest(i0);
}
-TEST_P(ProgramTest, ConfusingTailsBasic) {
+TEST_F(ProgramTest, ConfusingTailsBasic) {
// Without the fix for https://crbug.com/351103/, (see
// SampleProgramConfusingTails()), this would generate a cyclic graph and
// crash as the two "LOAD 0" instructions would get merged.
@@ -193,17 +290,17 @@
// 4) LOAD 0 // System call number
// 5) RET 1
- Instruction* i5 = MakeInstruction(BPF_RET + BPF_K, 1);
- Instruction* i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
- Instruction* i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
- Instruction* i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
- Instruction* i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
- Instruction* i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+ CodeGen::Node i5 = MakeInstruction(BPF_RET + BPF_K, 1);
+ CodeGen::Node i4 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i5);
+ CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+ CodeGen::Node i2 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 0, i3);
+ CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+ CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
- RunTest(i0, NO_FLAGS);
+ RunTest(i0);
}
-TEST_P(ProgramTest, ConfusingTailsMergeable) {
+TEST_F(ProgramTest, ConfusingTailsMergeable) {
// This is similar to SampleProgramConfusingTails(), except that
// instructions 2 and 4 are now RET instructions.
// In PointerCompare(), this exercises the path where two blocks are of the
@@ -219,295 +316,17 @@
// 6) RET 0
// 7) RET 1
- Instruction* i7 = MakeInstruction(BPF_RET + BPF_K, 1);
- Instruction* i6 = MakeInstruction(BPF_RET + BPF_K, 0);
- Instruction* i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
- Instruction* i4 = MakeInstruction(BPF_RET + BPF_K, 42);
- Instruction* i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
- Instruction* i2 = MakeInstruction(BPF_RET + BPF_K, 42);
- Instruction* i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
- Instruction* i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
+ CodeGen::Node i7 = MakeInstruction(BPF_RET + BPF_K, 1);
+ CodeGen::Node i6 = MakeInstruction(BPF_RET + BPF_K, 0);
+ CodeGen::Node i5 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i6, i7);
+ CodeGen::Node i4 = MakeInstruction(BPF_RET + BPF_K, 42);
+ CodeGen::Node i3 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 2, i4, i5);
+ CodeGen::Node i2 = MakeInstruction(BPF_RET + BPF_K, 42);
+ CodeGen::Node i1 = MakeInstruction(BPF_JMP + BPF_JEQ + BPF_K, 1, i2, i3);
+ CodeGen::Node i0 = MakeInstruction(BPF_LD + BPF_W + BPF_ABS, 1, i1);
- RunTest(i0, HAS_MERGEABLE_TAILS);
+ RunTest(i0);
}
-void MakeInstruction(CodeGenUnittestHelper* codegen,
- Instruction* program, int) {
- // Nothing to do here
-}
-
-void FindBranchTargets(CodeGenUnittestHelper* codegen, Instruction* prg, int) {
- BranchTargets branch_targets;
- codegen->FindBranchTargets(*prg, &branch_targets);
-
- // Verifying the general properties that should be true for every
- // well-formed BPF program.
- // Perform a depth-first traversal of the BPF program an verify that all
- // targets of BPF_JMP instructions are represented in the "branch_targets".
- // At the same time, compute a set of both the branch targets and all the
- // instructions in the program.
- std::vector<Instruction*> stack;
- std::set<Instruction*> all_instructions;
- std::set<Instruction*> target_instructions;
- BranchTargets::const_iterator end = branch_targets.end();
- for (Instruction* insn = prg;;) {
- all_instructions.insert(insn);
- if (BPF_CLASS(insn->code) == BPF_JMP) {
- target_instructions.insert(insn->jt_ptr);
- ASSERT_TRUE(insn->jt_ptr != NULL);
- ASSERT_TRUE(branch_targets.find(insn->jt_ptr) != end);
- if (BPF_OP(insn->code) != BPF_JA) {
- target_instructions.insert(insn->jf_ptr);
- ASSERT_TRUE(insn->jf_ptr != NULL);
- ASSERT_TRUE(branch_targets.find(insn->jf_ptr) != end);
- stack.push_back(insn->jf_ptr);
- }
- insn = insn->jt_ptr;
- } else if (BPF_CLASS(insn->code) == BPF_RET) {
- ASSERT_TRUE(insn->next == NULL);
- if (stack.empty()) {
- break;
- }
- insn = stack.back();
- stack.pop_back();
- } else {
- ASSERT_TRUE(insn->next != NULL);
- insn = insn->next;
- }
- }
- ASSERT_TRUE(target_instructions.size() == branch_targets.size());
-
- // We can now subtract the set of the branch targets from the set of all
- // instructions. This gives us a set with the instructions that nobody
- // ever jumps to. Verify that they are no included in the
- // "branch_targets" that FindBranchTargets() computed for us.
- Instructions non_target_instructions(all_instructions.size() -
- target_instructions.size());
- set_difference(all_instructions.begin(),
- all_instructions.end(),
- target_instructions.begin(),
- target_instructions.end(),
- non_target_instructions.begin());
- for (Instructions::const_iterator iter = non_target_instructions.begin();
- iter != non_target_instructions.end();
- ++iter) {
- ASSERT_TRUE(branch_targets.find(*iter) == end);
- }
-}
-
-void CutGraphIntoBasicBlocks(CodeGenUnittestHelper* codegen,
- Instruction* prg,
- int) {
- BranchTargets branch_targets;
- codegen->FindBranchTargets(*prg, &branch_targets);
- TargetsToBlocks all_blocks;
- BasicBlock* first_block =
- codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks);
- ASSERT_TRUE(first_block != NULL);
- ASSERT_TRUE(first_block->instructions.size() > 0);
- Instruction* first_insn = first_block->instructions[0];
-
- // Basic blocks are supposed to start with a branch target and end with
- // either a jump or a return instruction. It can also end, if the next
- // instruction forms the beginning of a new basic block. There should be
- // no other jumps or return instructions in the middle of a basic block.
- for (TargetsToBlocks::const_iterator bb_iter = all_blocks.begin();
- bb_iter != all_blocks.end();
- ++bb_iter) {
- BasicBlock* bb = bb_iter->second;
- ASSERT_TRUE(bb != NULL);
- ASSERT_TRUE(bb->instructions.size() > 0);
- Instruction* insn = bb->instructions[0];
- ASSERT_TRUE(insn == first_insn ||
- branch_targets.find(insn) != branch_targets.end());
- for (Instructions::const_iterator insn_iter = bb->instructions.begin();;) {
- insn = *insn_iter;
- if (++insn_iter != bb->instructions.end()) {
- ASSERT_TRUE(BPF_CLASS(insn->code) != BPF_JMP);
- ASSERT_TRUE(BPF_CLASS(insn->code) != BPF_RET);
- } else {
- ASSERT_TRUE(BPF_CLASS(insn->code) == BPF_JMP ||
- BPF_CLASS(insn->code) == BPF_RET ||
- branch_targets.find(insn->next) != branch_targets.end());
- break;
- }
- ASSERT_TRUE(branch_targets.find(*insn_iter) == branch_targets.end());
- }
- }
-}
-
-void MergeTails(CodeGenUnittestHelper* codegen, Instruction* prg, int flags) {
- BranchTargets branch_targets;
- codegen->FindBranchTargets(*prg, &branch_targets);
- TargetsToBlocks all_blocks;
- BasicBlock* first_block =
- codegen->CutGraphIntoBasicBlocks(prg, branch_targets, &all_blocks);
-
- // The shape of our graph and thus the function of our program should
- // still be unchanged after we run MergeTails(). We verify this by
- // serializing the graph and verifying that it is still the same.
- // We also verify that at least some of the edges changed because of
- // tail merging.
- std::string graph[2];
- std::string edges[2];
-
- // The loop executes twice. After the first run, we call MergeTails() on
- // our graph.
- for (int i = 0;;) {
- // Traverse the entire program in depth-first order.
- std::vector<BasicBlock*> stack;
- for (BasicBlock* bb = first_block;;) {
- // Serialize the instructions in this basic block. In general, we only
- // need to serialize "code" and "k"; except for a BPF_JA instruction
- // where "k" isn't set.
- // The stream of instructions should be unchanged after MergeTails().
- for (Instructions::const_iterator iter = bb->instructions.begin();
- iter != bb->instructions.end();
- ++iter) {
- graph[i].append(reinterpret_cast<char*>(&(*iter)->code),
- sizeof((*iter)->code));
- if (BPF_CLASS((*iter)->code) != BPF_JMP ||
- BPF_OP((*iter)->code) != BPF_JA) {
- graph[i].append(reinterpret_cast<char*>(&(*iter)->k),
- sizeof((*iter)->k));
- }
- }
-
- // Also serialize the addresses the basic blocks as we encounter them.
- // This will change as basic blocks are coalesed by MergeTails().
- edges[i].append(reinterpret_cast<char*>(&bb), sizeof(bb));
-
- // Depth-first traversal of the graph. We only ever need to look at the
- // very last instruction in the basic block, as that is the only one that
- // can change code flow.
- Instruction* insn = bb->instructions.back();
- if (BPF_CLASS(insn->code) == BPF_JMP) {
- // For jump instructions, we need to remember the "false" branch while
- // traversing the "true" branch. This is not necessary for BPF_JA which
- // only has a single branch.
- if (BPF_OP(insn->code) != BPF_JA) {
- stack.push_back(all_blocks[insn->jf_ptr]);
- }
- bb = all_blocks[insn->jt_ptr];
- } else if (BPF_CLASS(insn->code) == BPF_RET) {
- // After a BPF_RET, see if we need to back track.
- if (stack.empty()) {
- break;
- }
- bb = stack.back();
- stack.pop_back();
- } else {
- // For "normal" instructions, just follow to the next basic block.
- bb = all_blocks[insn->next];
- }
- }
-
- // Our loop runs exactly two times.
- if (++i > 1) {
- break;
- }
- codegen->MergeTails(&all_blocks);
- }
- ASSERT_TRUE(graph[0] == graph[1]);
- if (flags & HAS_MERGEABLE_TAILS) {
- ASSERT_TRUE(edges[0] != edges[1]);
- } else {
- ASSERT_TRUE(edges[0] == edges[1]);
- }
-}
-
-void CompileAndCompare(CodeGenUnittestHelper* codegen, Instruction* prg, int) {
- // TopoSortBasicBlocks() has internal checks that cause it to fail, if it
- // detects a problem. Typically, if anything goes wrong, this looks to the
- // TopoSort algorithm as if there had been cycles in the input data.
- // This provides a pretty good unittest.
- // We hand-crafted the program returned by SampleProgram() to exercise
- // several of the more interesting code-paths. See comments in
- // SampleProgram() for details.
- // In addition to relying on the internal consistency checks in the compiler,
- // we also serialize the graph and the resulting BPF program and compare
- // them. With the exception of BPF_JA instructions that might have been
- // inserted, both instruction streams should be equivalent.
- // As Compile() modifies the instructions, we have to serialize the graph
- // before calling Compile().
- std::string source;
- Instructions source_stack;
- for (const Instruction* insn = prg, *next; insn; insn = next) {
- if (BPF_CLASS(insn->code) == BPF_JMP) {
- if (BPF_OP(insn->code) == BPF_JA) {
- // Do not serialize BPF_JA instructions (see above).
- next = insn->jt_ptr;
- continue;
- } else {
- source_stack.push_back(insn->jf_ptr);
- next = insn->jt_ptr;
- }
- } else if (BPF_CLASS(insn->code) == BPF_RET) {
- if (source_stack.empty()) {
- next = NULL;
- } else {
- next = source_stack.back();
- source_stack.pop_back();
- }
- } else {
- next = insn->next;
- }
- // Only serialize "code" and "k". That's all the information we need to
- // compare. The rest of the information is encoded in the order of
- // instructions.
- source.append(reinterpret_cast<const char*>(&insn->code),
- sizeof(insn->code));
- source.append(reinterpret_cast<const char*>(&insn->k), sizeof(insn->k));
- }
-
- // Compile the program
- CodeGen::Program bpf;
- codegen->Compile(prg, &bpf);
-
- // Serialize the resulting BPF instructions.
- std::string assembly;
- std::vector<int> assembly_stack;
- for (int idx = 0; idx >= 0;) {
- ASSERT_TRUE(idx < (int)bpf.size());
- struct sock_filter& insn = bpf[idx];
- if (BPF_CLASS(insn.code) == BPF_JMP) {
- if (BPF_OP(insn.code) == BPF_JA) {
- // Do not serialize BPF_JA instructions (see above).
- idx += insn.k + 1;
- continue;
- } else {
- assembly_stack.push_back(idx + insn.jf + 1);
- idx += insn.jt + 1;
- }
- } else if (BPF_CLASS(insn.code) == BPF_RET) {
- if (assembly_stack.empty()) {
- idx = -1;
- } else {
- idx = assembly_stack.back();
- assembly_stack.pop_back();
- }
- } else {
- ++idx;
- }
- // Serialize the same information that we serialized before compilation.
- assembly.append(reinterpret_cast<char*>(&insn.code), sizeof(insn.code));
- assembly.append(reinterpret_cast<char*>(&insn.k), sizeof(insn.k));
- }
- ASSERT_TRUE(source == assembly);
-}
-
-const ProgramTestFunc kProgramTestFuncs[] = {
- MakeInstruction,
- FindBranchTargets,
- CutGraphIntoBasicBlocks,
- MergeTails,
- CompileAndCompare,
-};
-
-INSTANTIATE_TEST_CASE_P(CodeGen,
- ProgramTest,
- ::testing::ValuesIn(kProgramTestFuncs));
-
} // namespace
-
} // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_process.cc b/sandbox/linux/syscall_broker/broker_process.cc
index ebd7d05..9b92c49 100644
--- a/sandbox/linux/syscall_broker/broker_process.cc
+++ b/sandbox/linux/syscall_broker/broker_process.cc
@@ -98,6 +98,7 @@
_exit(1);
}
NOTREACHED();
+ return false;
}
void BrokerProcess::CloseChannel() {
diff --git a/testing/android/junit/BUILD.gn b/testing/android/junit/BUILD.gn
index bd8b517..5c668d5 100644
--- a/testing/android/junit/BUILD.gn
+++ b/testing/android/junit/BUILD.gn
@@ -6,22 +6,20 @@
import("//build/config/android/rules.gni")
-# TODO(GYP): should be java_library
# GYP: //testing/android/junit_test.gyp:junit_test_support
-android_library("junit_test_support") {
+java_library("junit_test_support") {
DEPRECATED_java_in_dir = "java/src"
deps = [
"//third_party/junit"
]
}
-# TODO(GYP): should be java_library
# GYP: //testing/android/junit_test.gyp:junit_unit_tests
-android_library("junit_unittests") {
+java_binary("junit_unittests") {
deps = [
":junit_test_support",
"//third_party/junit",
]
-#main_class = "org.chromium.testing.local.JuniTestMain"
+ main_class = "org.chromium.testing.local.JunitTestMain"
DEPRECATED_java_in_dir = "javatests/src"
}
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index d763318..a2a9b23 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -45,7 +45,6 @@
}
},
"jingle_unittests",
- "content_unittests",
"device_unittests",
"media_unittests",
{
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c9869f7..bee8677 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -46,7 +46,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
],
@@ -112,7 +111,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
],
@@ -178,7 +176,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
],
@@ -244,7 +241,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
],
diff --git a/testing/buildbot/tryserver.chromium.perf.json b/testing/buildbot/tryserver.chromium.perf.json
new file mode 100644
index 0000000..2c63c08
--- /dev/null
+++ b/testing/buildbot/tryserver.chromium.perf.json
@@ -0,0 +1,2 @@
+{
+}
diff --git a/testing/scripts/common.py b/testing/scripts/common.py
index 1afbe6b..f3617c7 100644
--- a/testing/scripts/common.py
+++ b/testing/scripts/common.py
@@ -68,6 +68,7 @@
'--builder-name', cmd_args.properties['buildername'],
'--slave-name', cmd_args.properties['slavename'],
'--build-number', str(cmd_args.properties['buildnumber']),
+ '--build-properties', json.dumps(cmd_args.properties),
] + runtest_args)
diff --git a/third_party/qcms/qcms.gyp b/third_party/qcms/qcms.gyp
index 298f615..6f33aba 100644
--- a/third_party/qcms/qcms.gyp
+++ b/third_party/qcms/qcms.gyp
@@ -47,7 +47,7 @@
'src/transform-sse1.c',
],
}],
- ['OS == "win" and (MSVS_VERSION == "2013" or MSVS_VERSION == "2013e")', {
+ ['OS == "win"', {
'msvs_disabled_warnings': [
4056, # overflow in floating-point constant arithmetic (INFINITY)
4756, # overflow in constant arithmetic (INFINITY)
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index 5dbec0f..d07fd9a 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -12,11 +12,10 @@
cflags = [ "-msse2", "-msse4.2", "-mpclmul" ]
} else {
sources = [ "simd_stub.c"]
- if (is_win) {
- # TODO(GYP): crbug.com/431462 disable warning about structure padding.
- cflags = [ "/wd4324" ]
- }
}
+
+ configs -= [ "//build/config/compiler:chromium_code" ]
+ configs += [ "//build/config/compiler:no_chromium_code" ]
}
static_library("zlib") {
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index 3cd6ca0..ca3d29a 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1871,3 +1871,15 @@
MSWSOCK.dll!*
content.dll!content::AppCacheStorageImpl::DatabaseTask::CallRun
+UNINITIALIZED READ
+name=bug_434033
+*!`anonymous namespace'::TOutputTraverser::visitConstantUnion
+*!TIntermBinary::traverse
+*!TIntermBinary::traverse
+*!TIntermAggregate::traverse
+*!TIntermAggregate::traverse
+*!TIntermAggregate::traverse
+*!TIntermediate::outputTree
+*!TCompiler::compile
+*!TypeTrackingTest::compile
+*!TypeTrackingTest_StructConstructorResultNoPrecision_Test::TestBody
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt
index 154e4e9..4ae5e47 100644
--- a/tools/valgrind/memcheck/suppressions_mac.txt
+++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -194,6 +194,19 @@
fun:_ZN3gfx9GLSurface24InitializeOneOffForTestsEv
}
{
+ bug_380568
+ Memcheck:Leak
+ fun:calloc
+ fun:_internal_class_createInstanceFromZone
+ fun:_internal_class_createInstance
+ fun:NSAllocateObject
+ fun:+[NSObject(NSObject) alloc]
+ fun:-[VideoCaptureDeviceQTKit initWithFrameReceiver:]
+ fun:_ZN5media21VideoCaptureDeviceMac4InitENS_18VideoCaptureDevice4Name14CaptureApiTypeE
+ fun:_ZN5media28VideoCaptureDeviceFactoryMac6CreateERKNS_18VideoCaptureDevice4NameE
+ fun:_ZN5media45VideoCaptureDeviceTest_OpenInvalidDevice_Test8TestBodyEv
+}
+{
bug_385604_b
Memcheck:Leak
fun:calloc
@@ -220,4 +233,12 @@
fun:_ZN15tracked_objects10ThreadData11TallyADeathERKNS_6BirthsEiRKNS_13TaskStopwatchE
fun:_ZN15tracked_objects10ThreadData31TallyRunOnNamedThreadIfTrackingERKN4base12TrackingInfoERKNS_13TaskStopwatchE
}
-
+{
+ bug_431906
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN7content21PluginLoaderPosixTestC2Ev
+ fun:_ZN7content45PluginLoaderPosixTest_PluginLaunchFailed_TestC2Ev
+ fun:_ZN7content45PluginLoaderPosixTest_PluginLaunchFailed_TestC1Ev
+ fun:_ZN7testing8internal15TestFactoryImplIN7content45PluginLoaderPosixTest_PluginLaunchFailed_TestEE10CreateTestEv
+}
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 0156806..da668ec 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -595,9 +595,15 @@
'names': ['glMapBufferOES', 'glMapBuffer'],
'arguments': 'GLenum target, GLenum access', },
{ 'return_type': 'void*',
- 'names': ['glMapBufferRange'],
+ 'known_as': 'glMapBufferRange',
+ 'versions': [{ 'name': 'glMapBufferRange',
+ 'gl_versions': ['gl3', 'gl4', 'es3'] },
+ { 'name': 'glMapBufferRange',
+ 'extensions': ['GL_ARB_map_buffer_range'] },
+ { 'name': 'glMapBufferRangeEXT',
+ 'extensions': ['GL_EXT_map_buffer_range'] }],
'arguments':
- 'GLenum target, GLintptr offset, GLsizeiptr length, GLenum access', },
+ 'GLenum target, GLintptr offset, GLsizeiptr length, GLbitfield access', },
{ 'return_type': 'void',
'known_as': 'glMatrixLoadfEXT',
'versions': [{ 'name': 'glMatrixLoadfEXT',
diff --git a/ui/gl/gl_implementation_win.cc b/ui/gl/gl_implementation_win.cc
index b4dd38c..fff9018 100644
--- a/ui/gl/gl_implementation_win.cc
+++ b/ui/gl/gl_implementation_win.cc
@@ -33,7 +33,7 @@
namespace {
-const wchar_t kD3DCompiler[] = L"D3DCompiler_46.dll";
+const wchar_t kD3DCompiler[] = L"D3DCompiler_47.dll";
void GL_BINDING_CALL MarshalClearDepthToClearDepthf(GLclampd depth) {
glClearDepthf(static_cast<GLclampf>(depth));