Update from https://crrev.com/304121
Includes DEPS updates and port of
https://codereview.chromium.org/665223004 to accomodate skia API change
on android.
Review URL: https://codereview.chromium.org/723343002
diff --git a/DEPS b/DEPS
index 6eadb5b..58fb063 100644
--- a/DEPS
+++ b/DEPS
@@ -22,27 +22,27 @@
'libcxx_revision': '48198f9110397fff47fe7c37cbfa296be7d44d3d',
'libcxxabi_revision': '4ad1009ab3a59fa7a6896d74d5e4de5885697f95',
'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
- 'skia_revision': '7a10fb6bead0f63623307a7ff71b1dd323534a7f',
+ 'skia_revision': 'bc97c9378bf8b89cc17280a2a04a5c3a9405e6ab',
# 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': '11b7b24c91c903ee08b2b6b94f0bbb17b966dd92', # from svn revision 25090
+ 'v8_revision': '43ced1bd1528ea8b4d9299d2c8f7c6a81921457b',
# 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": "657cd684a615da648df6a851a916f11bb6f9a70e",
+ "angle_revision": "560eef1627abdef65f71021b906e57dc609f47fa",
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling build tools
# and whatever else without interference from each other.
- 'buildtools_revision': '51ca1f25a2ecea34069cb3ff35394dc53b6fd657',
+ 'buildtools_revision': 'c27f95bd1d9baaef70c879dea375090dd1496147',
# 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': '4dc95e74e1acc75f4eab08bc771874cd2a9c3a9b',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling BoringSSL
# and whatever else without interference from each other.
- 'boringssl_revision': '03a739d8d2cdc2560531a7446ead0f705409670a',
+ 'boringssl_revision': '2f3ba910a2bdb9e7d19e712a827cdc80c8d8c777',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling lss
# and whatever else without interference from each other.
@@ -50,7 +50,7 @@
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling nss
# and whatever else without interference from each other.
- 'nss_revision': '87b96db4268293187d7cf741907a6d5d1d8080e0',
+ 'nss_revision': '258342ecf9c65105189092ef6339dc4e7779a7ae',
}
# Only these hosts are allowed for dependencies in this DEPS file.
@@ -87,7 +87,7 @@
Var('chromium_git') + '/chromium/llvm-project/libcxxabi.git' + '@' + Var('libcxxabi_revision'),
'src/tools/grit':
- Var('chromium_git') + '/external/grit-i18n.git' + '@' + '740badd5e3e44434a9a47b5d16749daac1e8ea80', # from svn revision 176
+ Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a24a0e647bb718b3540db89864cf586b12331e82', # from svn revision 182
'src/v8':
Var('chromium_git') + '/v8/v8.git' + '@' + Var('v8_revision'),
@@ -126,7 +126,7 @@
'https://boringssl.googlesource.com/boringssl.git' + '@' + Var('boringssl_revision'),
'src/tools/gyp':
- Var('chromium_git') + '/external/gyp.git' + '@' + '487c0b6ae8b44932e45347211bca0e8387718436', # from svn revision 1998
+ Var('chromium_git') + '/external/gyp.git' + '@' + 'b13d8f243da15ded051e87e663c4f2c2fcc5804c', # from svn revision 1994
}
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index 510c3d3..d9ff4c5 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -37,7 +37,7 @@
}
}
-if (!is_android) {
+if (use_allocator == "tcmalloc") {
# tcmalloc currently won't compile on Android.
source_set("tcmalloc") {
tcmalloc_dir = "//third_party/tcmalloc/chromium"
diff --git a/base/android/java/src/org/chromium/base/SystemMessageHandler.java b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
index 10f8d55..fd3dc5a 100644
--- a/base/android/java/src/org/chromium/base/SystemMessageHandler.java
+++ b/base/android/java/src/org/chromium/base/SystemMessageHandler.java
@@ -5,12 +5,9 @@
package org.chromium.base;
import android.os.Handler;
-import android.os.Looper;
import android.os.Message;
-import android.os.MessageQueue;
import android.util.Log;
-import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -25,23 +22,31 @@
private long mMessagePumpDelegateNative = 0;
private long mDelayedScheduledTimeTicks = 0;
- // The following members are used to detect and trace the presence of sync
- // barriers in Android's MessageQueue. Note that this detection is
- // experimental, temporary and intended only for diagnostic purposes.
- private MessageQueue mMessageQueue;
- private Field mMessageQueueMessageField;
- private Field mMessageTargetField;
- private boolean mQueueHasSyncBarrier;
- private long mSyncBarrierTraceId;
+ // Reflected API for marking a message as asynchronous. This is a workaround
+ // to provide fair Chromium task dispatch when served by the Android UI
+ // thread's Looper, avoiding stalls when the Looper has a sync barrier.
+ // Note: Use of this API is experimental and likely to evolve in the future.
+ private Method mMessageMethodSetAsynchronous;
private SystemMessageHandler(long messagePumpDelegateNative) {
mMessagePumpDelegateNative = messagePumpDelegateNative;
- tryEnableSyncBarrierDetection();
+
+ try {
+ Class<?> messageClass = Class.forName("android.os.Message");
+ mMessageMethodSetAsynchronous = messageClass.getMethod(
+ "setAsynchronous", new Class[]{boolean.class});
+ } catch (ClassNotFoundException e) {
+ Log.e(TAG, "Failed to find android.os.Message class:" + e);
+ } catch (NoSuchMethodException e) {
+ Log.e(TAG, "Failed to load Message.setAsynchronous method:" + e);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Exception while loading Message.setAsynchronous method: " + e);
+ }
+
}
@Override
public void handleMessage(Message msg) {
- updateWhetherQueueHasBlockingSyncBarrier();
if (msg.what == DELAYED_SCHEDULED_WORK) {
mDelayedScheduledTimeTicks = 0;
}
@@ -51,9 +56,7 @@
@SuppressWarnings("unused")
@CalledByNative
private void scheduleWork() {
- updateWhetherQueueHasBlockingSyncBarrier();
- if (mQueueHasSyncBarrier) TraceEvent.instant("SystemMessageHandler:immediateWorkBlocked");
- sendEmptyMessage(SCHEDULED_WORK);
+ sendMessage(obtainAsyncMessage(SCHEDULED_WORK));
}
@SuppressWarnings("unused")
@@ -63,97 +66,39 @@
removeMessages(DELAYED_SCHEDULED_WORK);
}
mDelayedScheduledTimeTicks = delayedTimeTicks;
- updateWhetherQueueHasBlockingSyncBarrier();
- if (mQueueHasSyncBarrier) TraceEvent.instant("SystemMessageHandler:delayedWorkBlocked");
- sendEmptyMessageDelayed(DELAYED_SCHEDULED_WORK, millis);
+ sendMessageDelayed(obtainAsyncMessage(DELAYED_SCHEDULED_WORK), millis);
}
@SuppressWarnings("unused")
@CalledByNative
private void removeAllPendingMessages() {
- updateWhetherQueueHasBlockingSyncBarrier();
removeMessages(SCHEDULED_WORK);
removeMessages(DELAYED_SCHEDULED_WORK);
}
- private void updateWhetherQueueHasBlockingSyncBarrier() {
- if (mMessageQueue == null) return;
- // As barrier detection is only used for tracing, early out when tracing
- // is disabled to avoid any potential performance penalties.
- if (!TraceEvent.enabled()) {
- mQueueHasSyncBarrier = false;
- return;
+ private Message obtainAsyncMessage(int what) {
+ Message msg = Message.obtain();
+ msg.what = what;
+ if (mMessageMethodSetAsynchronous != null) {
+ // If invocation fails, assume this is indicative of future
+ // failures, and avoid log spam by nulling the reflected method.
+ try {
+ mMessageMethodSetAsynchronous.invoke(msg, true);
+ } catch (IllegalAccessException e) {
+ Log.e(TAG, "Illegal access to asynchronous message creation, disabling.");
+ mMessageMethodSetAsynchronous = null;
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Illegal argument for asynchronous message creation, disabling.");
+ mMessageMethodSetAsynchronous = null;
+ } catch (InvocationTargetException e) {
+ Log.e(TAG, "Invocation exception during asynchronous message creation, disabling.");
+ mMessageMethodSetAsynchronous = null;
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Runtime exception during asynchronous message creation, disabling.");
+ mMessageMethodSetAsynchronous = null;
+ }
}
- Message queueHead = (Message) getField(mMessageQueue, mMessageQueueMessageField);
- setqueueHasSyncBarrier(isSyncBarrierMessage(queueHead));
- }
-
- private boolean isSyncBarrierMessage(Message message) {
- if (message == null) return false;
- // Sync barrier messages have null targets.
- return getField(message, mMessageTargetField) == null;
- }
-
- private void tryEnableSyncBarrierDetection() {
- assert mMessageQueue == null;
-
- boolean success = false;
- try {
- Method getQueueMethod = Looper.class.getMethod("getQueue", new Class[]{});
- mMessageQueue = (MessageQueue) getQueueMethod.invoke(getLooper());
-
- mMessageQueueMessageField = mMessageQueue.getClass().getDeclaredField("mMessages");
- mMessageQueueMessageField.setAccessible(true);
-
- mMessageTargetField = Message.class.getDeclaredField("target");
- mMessageTargetField.setAccessible(true);
-
- mSyncBarrierTraceId = hashCode();
-
- success = true;
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "Failed to load method: " + e);
- } catch (NoSuchFieldException e) {
- Log.e(TAG, "Failed to load field: " + e);
- } catch (InvocationTargetException e) {
- Log.e(TAG, "Failed invocation: " + e);
- } catch (IllegalAccessException e) {
- Log.e(TAG, "Illegal access to reflected invocation: " + e);
- } catch (IllegalArgumentException e) {
- Log.e(TAG, "Illegal argument to reflected invocation: " + e);
- } catch (RuntimeException e) {
- Log.e(TAG, e.toString());
- } finally {
- if (!success) disableSyncBarrierDetection();
- }
- }
-
- private void disableSyncBarrierDetection() {
- Log.e(TAG, "Unexpected error with sync barrier detection, disabling.");
- mMessageQueue = null;
- mMessageQueueMessageField = null;
- mMessageTargetField = null;
- setqueueHasSyncBarrier(false);
- }
-
- private void setqueueHasSyncBarrier(boolean queueHasSyncBarrier) {
- if (queueHasSyncBarrier == mQueueHasSyncBarrier) return;
- mQueueHasSyncBarrier = queueHasSyncBarrier;
- if (mQueueHasSyncBarrier) {
- TraceEvent.startAsync("SyncBarrier", mSyncBarrierTraceId);
- } else {
- TraceEvent.finishAsync("SyncBarrier", mSyncBarrierTraceId);
- }
- }
-
- private Object getField(Object object, Field field) {
- try {
- return field.get(object);
- } catch (IllegalAccessException e) {
- Log.e(TAG, "Failed field access: " + e);
- disableSyncBarrierDetection();
- }
- return null;
+ return msg;
}
@CalledByNative
diff --git a/base/android/linker/linker_jni.cc b/base/android/linker/linker_jni.cc
index b3ed651..1a11639 100644
--- a/base/android/linker/linker_jni.cc
+++ b/base/android/linker/linker_jni.cc
@@ -664,7 +664,7 @@
__FUNCTION__, library_name_c_str, apkfile_name_c_str);
jboolean mappable = crazy_linker_check_library_is_mappable_in_zip_file(
apkfile_name_c_str, library_name_c_str) == CRAZY_STATUS_SUCCESS;
- LOG_INFO("%s: %s\n", __FUNCTION__, aligned ? "Aligned" : "NOT aligned");
+ LOG_INFO("%s: %s\n", __FUNCTION__, mappable ? "Mappable" : "NOT mappable");
return mappable;
}
diff --git a/base/base64.h b/base/base64.h
index 43d8f76..def9b67 100644
--- a/base/base64.h
+++ b/base/base64.h
@@ -12,11 +12,12 @@
namespace base {
-// Encodes the input string in base64.
+// Encodes the input string in base64. The encoding can be done in-place.
BASE_EXPORT void Base64Encode(const StringPiece& input, std::string* output);
// Decodes the base64 input string. Returns true if successful and false
-// otherwise. The output string is only modified if successful.
+// otherwise. The output string is only modified if successful. The decoding can
+// be done in-place.
BASE_EXPORT bool Base64Decode(const StringPiece& input, std::string* output);
} // namespace base
diff --git a/base/base64_unittest.cc b/base/base64_unittest.cc
index 9b23194..91651f4 100644
--- a/base/base64_unittest.cc
+++ b/base/base64_unittest.cc
@@ -24,4 +24,17 @@
EXPECT_EQ(kText, decoded);
}
+TEST(Base64Test, InPlace) {
+ const std::string kText = "hello world";
+ const std::string kBase64Text = "aGVsbG8gd29ybGQ=";
+ std::string text(kText);
+
+ Base64Encode(text, &text);
+ EXPECT_EQ(kBase64Text, text);
+
+ bool ok = Base64Decode(text, &text);
+ EXPECT_TRUE(ok);
+ EXPECT_EQ(text, kText);
+}
+
} // namespace base
diff --git a/base/files/file.h b/base/files/file.h
index 4110d51..7b6366c 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -19,6 +19,7 @@
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/files/scoped_file.h"
+#include "base/gtest_prod_util.h"
#include "base/move.h"
#include "base/time/time.h"
@@ -26,6 +27,8 @@
#include "base/win/scoped_handle.h"
#endif
+FORWARD_DECLARE_TEST(FileTest, MemoryCorruption);
+
namespace base {
class FilePath;
@@ -296,12 +299,59 @@
static std::string ErrorToString(Error error);
private:
+ FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+#if defined(OS_POSIX)
+ // Encloses a single ScopedFD, saving a cheap tamper resistent memory checksum
+ // alongside it. This checksum is validated at every access, allowing early
+ // detection of memory corruption.
+
+ // TODO(gavinp): This is in place temporarily to help us debug
+ // https://crbug.com/424562 , which can't be reproduced in valgrind. Remove
+ // this code after we have fixed this issue.
+ class MemoryCheckingScopedFD {
+ public:
+ MemoryCheckingScopedFD();
+ MemoryCheckingScopedFD(int fd);
+ ~MemoryCheckingScopedFD();
+
+ bool is_valid() const { Check(); return file_.is_valid(); }
+ int get() const { Check(); return file_.get(); }
+
+ void reset() { Check(); file_.reset(); UpdateChecksum(); }
+ void reset(int fd) { Check(); file_.reset(fd); UpdateChecksum(); }
+ int release() {
+ Check();
+ int fd = file_.release();
+ UpdateChecksum();
+ return fd;
+ }
+
+ private:
+ FRIEND_TEST_ALL_PREFIXES(::FileTest, MemoryCorruption);
+
+ // Computes the checksum for the current value of |file_|. Returns via an
+ // out parameter to guard against implicit conversions of unsigned integral
+ // types.
+ void ComputeMemoryChecksum(unsigned int* out_checksum) const;
+
+ // Confirms that the current |file_| and |file_memory_checksum_| agree,
+ // failing a CHECK if they do not.
+ void Check() const;
+
+ void UpdateChecksum();
+
+ ScopedFD file_;
+ unsigned int file_memory_checksum_;
+ };
+#endif
+
void SetPlatformFile(PlatformFile file);
#if defined(OS_WIN)
win::ScopedHandle file_;
#elif defined(OS_POSIX)
- ScopedFD file_;
+ MemoryCheckingScopedFD file_;
#endif
Error error_details_;
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 43684b5..3d229e4 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -483,6 +483,49 @@
}
}
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD() {
+ UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::MemoryCheckingScopedFD(int fd) : file_(fd) {
+ UpdateChecksum();
+}
+
+File::MemoryCheckingScopedFD::~MemoryCheckingScopedFD() {}
+
+// static
+void File::MemoryCheckingScopedFD::ComputeMemoryChecksum(
+ unsigned int* out_checksum) const {
+ // Use a single iteration of a linear congruentional generator (lcg) to
+ // provide a cheap checksum unlikely to be accidentally matched by a random
+ // memory corruption.
+
+ // By choosing constants that satisfy the Hull-Duebell Theorem on lcg cycle
+ // length, we insure that each distinct fd value maps to a distinct checksum,
+ // which maximises the utility of our checksum.
+
+ // This code uses "unsigned int" throughout for its defined modular semantics,
+ // which implicitly gives us a divisor that is a power of two.
+
+ const unsigned int kMultiplier = 13035 * 4 + 1;
+ COMPILE_ASSERT(((kMultiplier - 1) & 3) == 0, pred_must_be_multiple_of_four);
+ const unsigned int kIncrement = 1595649551;
+ COMPILE_ASSERT(kIncrement & 1, must_be_coprime_to_powers_of_two);
+
+ *out_checksum =
+ static_cast<unsigned int>(file_.get()) * kMultiplier + kIncrement;
+}
+
+void File::MemoryCheckingScopedFD::Check() const {
+ unsigned int computed_checksum;
+ ComputeMemoryChecksum(&computed_checksum);
+ CHECK_EQ(file_memory_checksum_, computed_checksum) << "corrupted fd memory";
+}
+
+void File::MemoryCheckingScopedFD::UpdateChecksum() {
+ ComputeMemoryChecksum(&file_memory_checksum_);
+}
+
void File::SetPlatformFile(PlatformFile file) {
DCHECK(!file_.is_valid());
file_.reset(file);
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
index 6616f6a..3bc2db6 100644
--- a/base/files/file_unittest.cc
+++ b/base/files/file_unittest.cc
@@ -5,6 +5,7 @@
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
+#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -466,3 +467,71 @@
EXPECT_EQ(0, info.size);
}
#endif // defined(OS_WIN)
+
+#if defined(OS_POSIX) && defined(GTEST_HAS_DEATH_TEST)
+TEST(FileTest, MemoryCorruption) {
+ {
+ // Test that changing the checksum value is detected.
+ base::File file;
+ EXPECT_NE(file.file_.file_memory_checksum_,
+ implicit_cast<unsigned int>(file.GetPlatformFile()));
+ file.file_.file_memory_checksum_ = file.GetPlatformFile();
+ EXPECT_DEATH(file.IsValid(), "");
+
+ file.file_.UpdateChecksum(); // Do not crash on File::~File().
+ }
+
+ {
+ // Test that changing the file descriptor value is detected.
+ base::File file;
+ file.file_.file_.reset(17);
+ EXPECT_DEATH(file.IsValid(), "");
+
+ // Do not crash on File::~File().
+ ignore_result(file.file_.file_.release());
+ file.file_.UpdateChecksum();
+ }
+
+ {
+ // Test that GetPlatformFile() checks for corruption.
+ base::File file;
+ file.file_.file_memory_checksum_ = file.GetPlatformFile();
+ EXPECT_DEATH(file.GetPlatformFile(), "");
+
+ file.file_.UpdateChecksum(); // Do not crash on File::~File().
+ }
+
+ {
+ // Test that the base::File destructor checks for corruption.
+ scoped_ptr<base::File> file(new File());
+ file->file_.file_memory_checksum_ = file->GetPlatformFile();
+ EXPECT_DEATH(file.reset(), "");
+
+ // Do not crash on this thread's destructor call.
+ file->file_.UpdateChecksum();
+ }
+
+ {
+ // Test that the base::File constructor checks for corruption.
+ base::File file;
+ file.file_.file_memory_checksum_ = file.GetPlatformFile();
+ EXPECT_DEATH(File f(file.Pass()), "");
+
+ file.file_.UpdateChecksum(); // Do not crash on File::~File().
+ }
+
+ {
+ // Test that doing IO checks for corruption.
+ base::File file;
+ file.file_.file_.reset(17); // A fake open FD value.
+
+ EXPECT_DEATH(file.Seek(File::FROM_BEGIN, 0), "");
+ EXPECT_DEATH(file.Read(0, NULL, 0), "");
+ EXPECT_DEATH(file.ReadAtCurrentPos(NULL, 0), "");
+ EXPECT_DEATH(file.Write(0, NULL, 0), "");
+
+ ignore_result(file.file_.file_.release());
+ file.file_.UpdateChecksum();
+ }
+}
+#endif // defined(OS_POSIX)
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc
index b8c0eeb..0bf41a5 100644
--- a/base/files/file_util_posix.cc
+++ b/base/files/file_util_posix.cc
@@ -28,8 +28,6 @@
#include <glib.h> // for g_get_home_dir()
#endif
-#include <fstream>
-
#include "base/basictypes.h"
#include "base/files/file_enumerator.h"
#include "base/files/file_path.h"
@@ -428,7 +426,7 @@
bool SetPosixFilePermissions(const FilePath& path,
int mode) {
ThreadRestrictions::AssertIOAllowed();
- DCHECK((mode & ~FILE_PERMISSION_MASK) == 0);
+ DCHECK_EQ(mode & ~FILE_PERMISSION_MASK, 0);
// Calls stat() so that we can preserve the higher bits like S_ISGID.
stat_wrapper_t stat_buf;
diff --git a/base/json/json_reader.cc b/base/json/json_reader.cc
index ad5a9d5..e17d450 100644
--- a/base/json/json_reader.cc
+++ b/base/json/json_reader.cc
@@ -31,7 +31,7 @@
"Dictionary keys must be quoted.";
JSONReader::JSONReader()
- : parser_(new internal::JSONParser(JSON_PARSE_RFC)) {
+ : JSONReader(JSON_PARSE_RFC) {
}
JSONReader::JSONReader(int options)
diff --git a/base/mac/bind_objc_block.h b/base/mac/bind_objc_block.h
index 9deb2d2..c31f26e 100644
--- a/base/mac/bind_objc_block.h
+++ b/base/mac/bind_objc_block.h
@@ -21,51 +21,32 @@
// BindBlock(^(const std::string& arg0, const std::string& arg1) {
// ...
// });
+//
+// These variadic templates will accommodate any number of arguments, however
+// the underlying templates in bind_internal.h and callback.h are limited to
+// seven total arguments, and the bound block itself is used as one of these
+// arguments, so functionally the templates are limited to binding blocks with
+// zero through six arguments.
namespace base {
namespace internal {
-// Helper functions to run the block contained in the parameter.
-template<typename R>
-R RunBlock(base::mac::ScopedBlock<R(^)()> block) {
- R(^extracted_block)() = block.get();
- return extracted_block();
-}
-
-template<typename R, typename A1>
-R RunBlock(base::mac::ScopedBlock<R(^)(A1)> block, A1 a) {
- R(^extracted_block)(A1) = block.get();
- return extracted_block(a);
-}
-
-template<typename R, typename A1, typename A2>
-R RunBlock(base::mac::ScopedBlock<R(^)(A1, A2)> block, A1 a, A2 b) {
- R(^extracted_block)(A1, A2) = block.get();
- return extracted_block(a, b);
+// Helper function to run the block contained in the parameter.
+template<typename R, typename... Args>
+R RunBlock(base::mac::ScopedBlock<R(^)(Args...)> block, Args... args) {
+ R(^extracted_block)(Args...) = block.get();
+ return extracted_block(args...);
}
} // namespace internal
-// Construct a callback with no argument from an objective-C block.
-template<typename R>
-base::Callback<R(void)> BindBlock(R(^block)()) {
- return base::Bind(&base::internal::RunBlock<R>,
- base::mac::ScopedBlock<R(^)()>(Block_copy(block)));
-}
-
-// Construct a callback with one argument from an objective-C block.
-template<typename R, typename A1>
-base::Callback<R(A1)> BindBlock(R(^block)(A1)) {
- return base::Bind(&base::internal::RunBlock<R, A1>,
- base::mac::ScopedBlock<R(^)(A1)>(Block_copy(block)));
-}
-
-// Construct a callback with two arguments from an objective-C block.
-template<typename R, typename A1, typename A2>
-base::Callback<R(A1, A2)> BindBlock(R(^block)(A1, A2)) {
- return base::Bind(&base::internal::RunBlock<R, A1, A2>,
- base::mac::ScopedBlock<R(^)(A1, A2)>(Block_copy(block)));
+// Construct a callback from an objective-C block with up to six arguments (see
+// note above).
+template<typename R, typename... Args>
+base::Callback<R(Args...)> BindBlock(R(^block)(Args...)) {
+ return base::Bind(&base::internal::RunBlock<R, Args...>,
+ base::mac::ScopedBlock<R(^)(Args...)>(Block_copy(block)));
}
} // namespace base
diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm
index c72fd4a..5d15eba 100644
--- a/base/mac/bind_objc_block_unittest.mm
+++ b/base/mac/bind_objc_block_unittest.mm
@@ -64,4 +64,36 @@
EXPECT_EQ(result, "fortytwo");
}
+TEST(BindObjcBlockTest, TestThreeArguments) {
+ std::string result;
+ std::string* ptr = &result;
+ base::Callback<void(const std::string&,
+ const std::string&,
+ const std::string&)> c =
+ base::BindBlock(^(const std::string& a,
+ const std::string& b,
+ const std::string& c) {
+ *ptr = a + b + c;
+ });
+ c.Run("six", "times", "nine");
+ EXPECT_EQ(result, "sixtimesnine");
+}
+
+TEST(BindObjcBlockTest, TestSixArguments) {
+ std::string result1;
+ std::string* ptr = &result1;
+ int result2;
+ int* ptr2 = &result2;
+ base::Callback<void(int, int, const std::string&, const std::string&,
+ int, const std::string&)> c =
+ base::BindBlock(^(int a, int b, const std::string& c,
+ const std::string& d, int e, const std::string& f) {
+ *ptr = c + d + f;
+ *ptr2 = a + b + e;
+ });
+ c.Run(1, 2, "infinite", "improbability", 3, "drive");
+ EXPECT_EQ(result1, "infiniteimprobabilitydrive");
+ EXPECT_EQ(result2, 6);
+}
+
} // namespace
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 3f169a7..ca7cfbf 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -669,7 +669,9 @@
TEST(ScopedPtrTest, SelfResetWithCustomDeleterOptOut) {
// A custom deleter should be able to opt out of self-reset abort behavior.
struct NoOpDeleter {
+#if !defined(NDEBUG)
typedef void AllowSelfReset;
+#endif
inline void operator()(int*) {}
};
scoped_ptr<int> owner(new int);
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index 01402d0..2f4a03c 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -106,9 +106,11 @@
typedef MessagePumpLibevent MessagePumpForIO;
#endif
+#if !defined(OS_NACL_SFI)
MessagePumpForIO* ToPumpIO(MessagePump* pump) {
return static_cast<MessagePumpForIO*>(pump);
}
+#endif // !defined(OS_NACL_SFI)
} // namespace
diff --git a/base/metrics/histogram.h b/base/metrics/histogram.h
index 5ed9d9e..43e7462 100644
--- a/base/metrics/histogram.h
+++ b/base/metrics/histogram.h
@@ -286,7 +286,7 @@
base::HistogramBase::kUmaTargetedHistogramFlag))
// The samples should always be strictly less than |boundary_value|. For more
-// details, see the comment for the |HISTOGRAM_ENUMERATION| macro, above.
+// 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)
diff --git a/base/observer_list.h b/base/observer_list.h
index c77ec15..ef45269 100644
--- a/base/observer_list.h
+++ b/base/observer_list.h
@@ -100,7 +100,8 @@
// Remove an observer from the list if it is in the list.
void RemoveObserver(ObserverType* obs);
- bool HasObserver(ObserverType* observer) const;
+ // Determine whether a particular observer is in the list.
+ bool HasObserver(const ObserverType* observer) const;
void Clear();
@@ -176,7 +177,8 @@
}
template <class ObserverType>
-bool ObserverListBase<ObserverType>::HasObserver(ObserverType* observer) const {
+bool ObserverListBase<ObserverType>::HasObserver(
+ const ObserverType* observer) const {
for (size_t i = 0; i < observers_.size(); ++i) {
if (observers_[i] == observer)
return true;
diff --git a/base/observer_list_unittest.cc b/base/observer_list_unittest.cc
index 11f59be..65ef934 100644
--- a/base/observer_list_unittest.cc
+++ b/base/observer_list_unittest.cc
@@ -182,6 +182,9 @@
observer_list.AddObserver(&a);
observer_list.AddObserver(&b);
+ EXPECT_TRUE(observer_list.HasObserver(&a));
+ EXPECT_FALSE(observer_list.HasObserver(&c));
+
FOR_EACH_OBSERVER(Foo, observer_list, Observe(10));
observer_list.AddObserver(&evil);
diff --git a/base/profiler/scoped_profile.cc b/base/profiler/scoped_profile.cc
index 8b0ae59..4f8bc2d 100644
--- a/base/profiler/scoped_profile.cc
+++ b/base/profiler/scoped_profile.cc
@@ -11,15 +11,6 @@
namespace tracked_objects {
-ScopedProfile::ScopedProfile(const Location& location)
- : birth_(ThreadData::TallyABirthIfActive(location)) {
- if (!birth_)
- return;
-
- ThreadData::PrepareForStartOfRun(birth_);
- stopwatch_.Start();
-}
-
ScopedProfile::ScopedProfile(const Location& location, Mode mode)
: birth_(NULL) {
if (mode == DISABLED)
diff --git a/base/profiler/scoped_profile.h b/base/profiler/scoped_profile.h
index 6a76486..c1e2830 100644
--- a/base/profiler/scoped_profile.h
+++ b/base/profiler/scoped_profile.h
@@ -25,10 +25,10 @@
// Defines the containing scope as a profiled region. This allows developers to
// profile their code and see results on their about:profiler page, as well as
// on the UMA dashboard.
-#define TRACK_RUN_IN_THIS_SCOPED_REGION(dispatch_function_name) \
- ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
- FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name))
-
+#define TRACK_RUN_IN_THIS_SCOPED_REGION(dispatch_function_name) \
+ ::tracked_objects::ScopedProfile LINE_BASED_VARIABLE_NAME_FOR_PROFILING( \
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(#dispatch_function_name), \
+ ::tracked_objects::ScopedProfile::ENABLED)
namespace tracked_objects {
class Births;
@@ -42,8 +42,6 @@
ENABLED // Create and tally a task.
};
- // TODO(vadimt): Remove this constructor.
- explicit ScopedProfile(const Location& location);
ScopedProfile(const Location& location, Mode mode);
~ScopedProfile();
diff --git a/base/profiler/scoped_tracker.cc b/base/profiler/scoped_tracker.cc
index 1d4f0bf..26b17c0 100644
--- a/base/profiler/scoped_tracker.cc
+++ b/base/profiler/scoped_tracker.cc
@@ -15,7 +15,7 @@
// Executes |callback|, augmenting it with provided |location|.
void ExecuteAndTrackCallback(const Location& location,
const base::Closure& callback) {
- ScopedProfile tracking_profile(location);
+ ScopedProfile tracking_profile(location, ScopedProfile::ENABLED);
callback.Run();
}
diff --git a/base/test/launcher/unit_test_launcher.cc b/base/test/launcher/unit_test_launcher.cc
index 44846a1..a49e777 100644
--- a/base/test/launcher/unit_test_launcher.cc
+++ b/base/test/launcher/unit_test_launcher.cc
@@ -479,15 +479,6 @@
fflush(stdout);
force_single_process = true;
}
-
- if (RunningOnValgrind()) {
- fprintf(stdout,
- "Valgrind detected, switching to single process mode.\n"
- "Pass --test-launcher-debug-launcher to valgrind the launcher "
- "itself.\n");
- fflush(stdout);
- force_single_process = true;
- }
}
if (CommandLine::ForCurrentProcess()->HasSwitch(kGTestHelpFlag) ||
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index d9e2bd9..d97a3f4 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -27,6 +27,7 @@
namespace {
+#if !defined(OS_NACL)
int ThreadNiceValue(ThreadPriority priority) {
switch (priority) {
case kThreadPriority_RealtimeAudio:
@@ -42,6 +43,7 @@
return 0;
}
}
+#endif // !defined(OS_NACL)
} // namespace
diff --git a/base/time/time.h b/base/time/time.h
index 641f465..9cb007e 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -232,6 +232,10 @@
static const int64 kNanosecondsPerSecond = kNanosecondsPerMicrosecond *
kMicrosecondsPerSecond;
+ // The representation of Jan 1, 1970 UTC in microseconds since the
+ // platform-dependent epoch.
+ static const int64 kTimeTToMicrosecondsOffset;
+
#if !defined(OS_WIN)
// On Mac & Linux, this value is the delta from the Windows epoch of 1601 to
// the Posix delta of 1970. This is used for migrating between the old
@@ -492,10 +496,6 @@
bool is_local,
Time* parsed_time);
- // The representation of Jan 1, 1970 UTC in microseconds since the
- // platform-dependent epoch.
- static const int64 kTimeTToMicrosecondsOffset;
-
// Time in microseconds in UTC.
int64 us_;
};
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc
index c69fada..5e30762 100644
--- a/base/tracked_objects.cc
+++ b/base/tracked_objects.cc
@@ -116,7 +116,7 @@
void DeathData::RecordDeath(const int32 queue_duration,
const int32 run_duration,
- int32 random_number) {
+ const uint32 random_number) {
// We'll just clamp at INT_MAX, but we should note this in the UI as such.
if (count_ < INT_MAX)
++count_;
@@ -307,7 +307,7 @@
(void)VALGRIND_MAKE_MEM_DEFINED_IF_ADDRESSABLE(&random_number_,
sizeof(random_number_));
MSAN_UNPOISON(&random_number_, sizeof(random_number_));
- random_number_ += static_cast<int32>(this - static_cast<ThreadData*>(0));
+ random_number_ += static_cast<uint32>(this - static_cast<ThreadData*>(0));
random_number_ ^= (Now() - TrackedTime()).InMilliseconds();
DCHECK(!next_);
@@ -453,10 +453,10 @@
int32 run_duration = stopwatch.RunDurationMs();
// Stir in some randomness, plus add constant in case durations are zero.
- const int32 kSomePrimeNumber = 2147483647;
+ const uint32 kSomePrimeNumber = 2147483647;
random_number_ += queue_duration + run_duration + kSomePrimeNumber;
// An address is going to have some randomness to it as well ;-).
- random_number_ ^= static_cast<int32>(&birth - reinterpret_cast<Births*>(0));
+ random_number_ ^= static_cast<uint32>(&birth - reinterpret_cast<Births*>(0));
// We don't have queue durations without OS timer. OS timer is automatically
// used for task-post-timing, so the use of an alternate timer implies all
diff --git a/base/tracked_objects.h b/base/tracked_objects.h
index 50bea47..723fb91 100644
--- a/base/tracked_objects.h
+++ b/base/tracked_objects.h
@@ -273,7 +273,7 @@
// |duration|, and has had a queueing delay of |queue_duration|.
void RecordDeath(const int32 queue_duration,
const int32 run_duration,
- int random_number);
+ const uint32 random_number);
// Metrics accessors, used only for serialization and in tests.
int count() const;
@@ -685,7 +685,7 @@
// representative sample in each DeathData instance. We can't start off with
// much randomness (because we can't call RandInt() on all our threads), so
// we stir in more and more as we go.
- int32 random_number_;
+ uint32 random_number_;
// Record of what the incarnation_counter_ was when this instance was created.
// If the incarnation_counter_ has changed, then we avoid pushing into the
diff --git a/base/win/scoped_comptr_unittest.cc b/base/win/scoped_comptr_unittest.cc
index d8d12be..711c52f 100644
--- a/base/win/scoped_comptr_unittest.cc
+++ b/base/win/scoped_comptr_unittest.cc
@@ -41,8 +41,8 @@
EXPECT_TRUE(SUCCEEDED(unk.CreateInstance(CLSID_ShellLink)));
ScopedComPtr<IUnknown> unk2;
unk2.Attach(unk.Detach());
- EXPECT_TRUE(unk == NULL);
- EXPECT_TRUE(unk2 != NULL);
+ EXPECT_TRUE(unk.get() == NULL);
+ EXPECT_TRUE(unk2.get() != NULL);
ScopedComPtr<IMalloc> mem_alloc;
EXPECT_TRUE(SUCCEEDED(CoGetMalloc(1, mem_alloc.Receive())));
@@ -55,26 +55,26 @@
// test ScopedComPtr& constructor
ScopedComPtr<IMalloc> copy1(mem_alloc);
- EXPECT_TRUE(copy1.IsSameObject(mem_alloc));
- EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid but different
- EXPECT_FALSE(copy1.IsSameObject(unk)); // unk is NULL
+ EXPECT_TRUE(copy1.IsSameObject(mem_alloc.get()));
+ EXPECT_FALSE(copy1.IsSameObject(unk2.get())); // unk2 is valid but different
+ EXPECT_FALSE(copy1.IsSameObject(unk.get())); // unk is NULL
IMalloc* naked_copy = copy1.Detach();
copy1 = naked_copy; // Test the =(T*) operator.
naked_copy->Release();
copy1.Release();
- EXPECT_FALSE(copy1.IsSameObject(unk2)); // unk2 is valid, copy1 is not
+ EXPECT_FALSE(copy1.IsSameObject(unk2.get())); // unk2 is valid, copy1 is not
// test Interface* constructor
- ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc));
- EXPECT_TRUE(copy2.IsSameObject(mem_alloc));
+ ScopedComPtr<IMalloc> copy2(static_cast<IMalloc*>(mem_alloc.get()));
+ EXPECT_TRUE(copy2.IsSameObject(mem_alloc.get()));
- EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc)));
- EXPECT_TRUE(unk != NULL);
+ EXPECT_TRUE(SUCCEEDED(unk.QueryFrom(mem_alloc.get())));
+ EXPECT_TRUE(unk.get() != NULL);
unk.Release();
- EXPECT_TRUE(unk == NULL);
- EXPECT_TRUE(unk.IsSameObject(copy1)); // both are NULL
+ EXPECT_TRUE(unk.get() == NULL);
+ EXPECT_TRUE(unk.IsSameObject(copy1.get())); // both are NULL
}
TEST(ScopedComPtrTest, ScopedComPtrVector) {
@@ -98,7 +98,7 @@
bleh.push_back(p2);
EXPECT_EQ(p->adds, 4);
EXPECT_EQ(p->releases, 1);
- EXPECT_EQ(bleh[0], p.get());
+ EXPECT_EQ(bleh[0].get(), p.get());
bleh.pop_back();
EXPECT_EQ(p->adds, 4);
EXPECT_EQ(p->releases, 2);
diff --git a/build/all.gyp b/build/all.gyp
index 22f0d26..d47fc79 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.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_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_system_impl',
- '../mojo/edk/mojo_edk.gyp:mojo_system_unittests',
+ '../mojo/edk/mojo_edk_tests.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',
@@ -276,6 +276,11 @@
'../athena/main/athena_main.gyp:*',
],
}],
+ ['envoy==1', {
+ 'dependencies': [
+ '../envoy/envoy.gyp:*',
+ ],
+ }],
],
}, # target_name: All
{
@@ -354,6 +359,7 @@
['OS=="win"', {
'dependencies': [
'../chrome/chrome.gyp:app_installer',
+ '../chrome/chrome.gyp:app_installer_unittests',
'../chrome/chrome.gyp:crash_service',
'../chrome/chrome.gyp:installer_util_unittests',
# ../chrome/test/mini_installer requires mini_installer.
@@ -844,9 +850,10 @@
'../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
],
'conditions': [
- ['"<(libpeer_target_type)"=="static_library"', {
+ ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', {
'dependencies': [
'../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
+ '../components/devtools_bridge.gyp:devtools_bridge_tests2_apk',
],
}],
],
@@ -1180,6 +1187,7 @@
'dependencies': [
'../base/base.gyp:base_unittests',
'../chrome/chrome.gyp:app_installer',
+ '../chrome/chrome.gyp:app_installer_unittests',
'../chrome/chrome.gyp:browser_tests',
'../chrome/chrome.gyp:sync_integration_tests',
'../chrome/chrome.gyp:crash_service',
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index f641e15..ee27544 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -24,3 +24,4 @@
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 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/java_cpp_enum.py b/build/android/gyp/java_cpp_enum.py
index 8ae5f36..b10e7c5 100755
--- a/build/android/gyp/java_cpp_enum.py
+++ b/build/android/gyp/java_cpp_enum.py
@@ -13,14 +13,21 @@
from util import build_utils
+# List of C++ types that are compatible with the Java code generated by this
+# script.
+ENUM_FIXED_TYPE_WHITELIST = ['char', 'unsigned char',
+ 'short', 'unsigned short',
+ 'int', 'int8_t', 'int16_t', 'int32_t', 'uint8_t', 'uint16_t']
+
class EnumDefinition(object):
def __init__(self, original_enum_name=None, class_name_override=None,
- enum_package=None, entries=None):
+ enum_package=None, entries=None, fixed_type=None):
self.original_enum_name = original_enum_name
self.class_name_override = class_name_override
self.enum_package = enum_package
self.entries = collections.OrderedDict(entries or [])
self.prefix_to_strip = None
+ self.fixed_type = fixed_type
def AppendEntry(self, key, value):
if key in self.entries:
@@ -40,6 +47,9 @@
assert self.class_name
assert self.enum_package
assert self.entries
+ if self.fixed_type and self.fixed_type not in ENUM_FIXED_TYPE_WHITELIST:
+ raise Exception('Fixed type %s for enum %s not whitelisted.' %
+ (self.fixed_type, self.class_name))
def _AssignEntryIndices(self):
# Enums, if given no value, are given the value of the previous enum + 1.
@@ -110,12 +120,17 @@
class HeaderParser(object):
single_line_comment_re = re.compile(r'\s*//')
multi_line_comment_start_re = re.compile(r'\s*/\*')
- enum_start_re = re.compile(r'^\s*enum\s+(\w+)\s+{\s*$')
enum_line_re = re.compile(r'^\s*(\w+)(\s*\=\s*([^,\n]+))?,?')
enum_end_re = re.compile(r'^\s*}\s*;\.*$')
generator_directive_re = re.compile(
r'^\s*//\s+GENERATED_JAVA_(\w+)\s*:\s*([\.\w]+)$')
+ optional_class_or_struct_re = r'(class|struct)?'
+ enum_name_re = r'(\w+)'
+ optional_fixed_type_re = r'(\:\s*(\w+\s*\w+?))?'
+ enum_start_re = re.compile(r'^\s*enum\s+' + optional_class_or_struct_re +
+ '\s*' + enum_name_re + '\s*' + optional_fixed_type_re + '\s*{\s*$')
+
def __init__(self, lines):
self._lines = lines
self._enum_definitions = []
@@ -162,7 +177,8 @@
if self._generator_directives.empty:
return
self._current_definition = EnumDefinition(
- original_enum_name=enum_start.groups()[0])
+ original_enum_name=enum_start.groups()[1],
+ fixed_type=enum_start.groups()[3])
self._in_enum = True
elif generator_directive:
directive_name = generator_directive.groups()[0]
diff --git a/build/android/gyp/java_cpp_enum_tests.py b/build/android/gyp/java_cpp_enum_tests.py
index bb8150d..3aa386e 100755
--- a/build/android/gyp/java_cpp_enum_tests.py
+++ b/build/android/gyp/java_cpp_enum_tests.py
@@ -14,7 +14,8 @@
import sys
import unittest
-from java_cpp_enum import EnumDefinition, GenerateOutput, HeaderParser
+from java_cpp_enum import EnumDefinition, GenerateOutput, GetScriptName
+from java_cpp_enum import HeaderParser
sys.path.append(os.path.join(os.path.dirname(__file__), "gyp"))
from util import build_utils
@@ -31,7 +32,7 @@
// found in the LICENSE file.
// This file is autogenerated by
-// build/android/gyp/java_cpp_enum_tests.py
+// %s
// From
// path/to/file
@@ -42,7 +43,7 @@
public static final int E2 = 2 << 2;
}
"""
- self.assertEqual(expected, output)
+ self.assertEqual(expected % GetScriptName(), output)
def testParseSimpleEnum(self):
test_data = """
@@ -150,6 +151,78 @@
with self.assertRaises(Exception):
HeaderParser(test_data).ParseDefinitions()
+ def testParseEnumClass(self):
+ test_data = """
+ // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+ enum class Foo {
+ FOO_A,
+ };
+ """.split('\n')
+ definitions = HeaderParser(test_data).ParseDefinitions()
+ self.assertEqual(1, len(definitions))
+ definition = definitions[0]
+ self.assertEqual('Foo', definition.class_name)
+ self.assertEqual('test.namespace', definition.enum_package)
+ self.assertEqual(collections.OrderedDict([('A', 0)]),
+ definition.entries)
+
+ def testParseEnumStruct(self):
+ test_data = """
+ // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+ enum struct Foo {
+ FOO_A,
+ };
+ """.split('\n')
+ definitions = HeaderParser(test_data).ParseDefinitions()
+ self.assertEqual(1, len(definitions))
+ definition = definitions[0]
+ self.assertEqual('Foo', definition.class_name)
+ self.assertEqual('test.namespace', definition.enum_package)
+ self.assertEqual(collections.OrderedDict([('A', 0)]),
+ definition.entries)
+
+ def testParseFixedTypeEnum(self):
+ test_data = """
+ // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+ enum Foo : int {
+ FOO_A,
+ };
+ """.split('\n')
+ definitions = HeaderParser(test_data).ParseDefinitions()
+ self.assertEqual(1, len(definitions))
+ definition = definitions[0]
+ self.assertEqual('Foo', definition.class_name)
+ self.assertEqual('test.namespace', definition.enum_package)
+ self.assertEqual('int', definition.fixed_type)
+ self.assertEqual(collections.OrderedDict([('A', 0)]),
+ definition.entries)
+
+ def testParseFixedTypeEnumClass(self):
+ test_data = """
+ // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+ enum class Foo: unsigned short {
+ FOO_A,
+ };
+ """.split('\n')
+ definitions = HeaderParser(test_data).ParseDefinitions()
+ self.assertEqual(1, len(definitions))
+ definition = definitions[0]
+ self.assertEqual('Foo', definition.class_name)
+ self.assertEqual('test.namespace', definition.enum_package)
+ self.assertEqual('unsigned short', definition.fixed_type)
+ self.assertEqual(collections.OrderedDict([('A', 0)]),
+ definition.entries)
+
+ def testParseUnknownFixedTypeRaises(self):
+ test_data = """
+ // GENERATED_JAVA_ENUM_PACKAGE: test.namespace
+ enum class Foo: foo_type {
+ FOO_A,
+ };
+ """.split('\n')
+ with self.assertRaises(Exception):
+ HeaderParser(test_data).ParseDefinitions()
+
def testEnumValueAssignmentNoneDefined(self):
definition = EnumDefinition(original_enum_name='c', enum_package='p')
definition.AppendEntry('A', None)
diff --git a/build/android/gyp/package_resources.py b/build/android/gyp/package_resources.py
index 6444ed9..9b6ec68 100755
--- a/build/android/gyp/package_resources.py
+++ b/build/android/gyp/package_resources.py
@@ -37,6 +37,11 @@
parser.add_option('--android-manifest', help='AndroidManifest.xml path')
parser.add_option('--version-code', help='Version code for apk.')
parser.add_option('--version-name', help='Version name for apk.')
+ parser.add_option(
+ '--shared-resources',
+ action='store_true',
+ help='Make a resource package that can be loaded by a different'
+ 'application at runtime to access the package\'s resources.')
parser.add_option('--resource-zips',
help='zip files containing resources to be packaged')
parser.add_option('--asset-dir',
@@ -132,6 +137,8 @@
if options.no_compress:
for ext in options.no_compress.split(','):
package_command += ['-0', ext]
+ if options.shared_resources:
+ package_command.append('--shared-lib')
if os.path.exists(options.asset_dir):
package_command += ['-A', options.asset_dir]
diff --git a/build/android/gyp/process_resources.py b/build/android/gyp/process_resources.py
index 6bf71f3..45b0947 100755
--- a/build/android/gyp/process_resources.py
+++ b/build/android/gyp/process_resources.py
@@ -38,6 +38,11 @@
parser.add_option('--android-manifest', help='AndroidManifest.xml path')
parser.add_option('--custom-package', help='Java package for R.java')
+ parser.add_option(
+ '--shared-resources',
+ action='store_true',
+ help='Make a resource package that can be loaded by a different'
+ 'application at runtime to access the package\'s resources.')
parser.add_option('--resource-dirs',
help='Directories containing resources of this target.')
@@ -236,6 +241,8 @@
package_command += ['--custom-package', options.custom_package]
if options.proguard_file:
package_command += ['-G', options.proguard_file]
+ if options.shared_resources:
+ package_command.append('--shared-lib')
build_utils.CheckOutput(package_command, print_stderr=False)
if options.extra_res_packages:
diff --git a/build/android/pylib/base/base_test_result.py b/build/android/pylib/base/base_test_result.py
index 1f45214..f9e61a9 100644
--- a/build/android/pylib/base/base_test_result.py
+++ b/build/android/pylib/base/base_test_result.py
@@ -23,18 +23,20 @@
class BaseTestResult(object):
"""Base class for a single test result."""
- def __init__(self, name, test_type, log=''):
+ def __init__(self, name, test_type, duration=0, log=''):
"""Construct a BaseTestResult.
Args:
name: Name of the test which defines uniqueness.
test_type: Type of the test result as defined in ResultType.
+ duration: Time it took for the test to run in milliseconds.
log: An optional string listing any errors.
"""
assert name
assert test_type in ResultType.GetTypes()
self._name = name
self._test_type = test_type
+ self._duration = duration
self._log = log
def __str__(self):
@@ -66,6 +68,10 @@
"""Get the test result type."""
return self._test_type
+ def GetDuration(self):
+ """Get the test duration."""
+ return self._duration
+
def GetLog(self):
"""Get the test log."""
return self._log
diff --git a/build/android/pylib/base/base_test_runner.py b/build/android/pylib/base/base_test_runner.py
index 1f76149..6e51b43 100644
--- a/build/android/pylib/base/base_test_runner.py
+++ b/build/android/pylib/base/base_test_runner.py
@@ -9,10 +9,8 @@
# model.
import logging
-import time
from pylib import ports
-from pylib.chrome_test_server_spawner import SpawningServer
from pylib.device import device_utils
from pylib.forwarder import Forwarder
from pylib.valgrind_tools import CreateTool
@@ -42,7 +40,6 @@
self._forwarder_device_port = 8000
self.forwarder_base_url = ('http://localhost:%d' %
self._forwarder_device_port)
- self._spawning_server = None
# We will allocate port for test server spawner when calling method
# LaunchChromeTestServerSpawner and allocate port for test server when
# starting it in TestServerThread.
@@ -146,45 +143,4 @@
if self._http_server:
self._UnmapPorts([(self._forwarder_device_port, self._http_server.port)])
self._http_server.ShutdownHttpServer()
- if self._spawning_server:
- self._spawning_server.Stop()
- def CleanupSpawningServerState(self):
- """Tells the spawning server to clean up any state.
-
- If the spawning server is reused for multiple tests, this should be called
- after each test to prevent tests affecting each other.
- """
- if self._spawning_server:
- self._spawning_server.CleanupState()
-
- def LaunchChromeTestServerSpawner(self):
- """Launches test server spawner."""
- server_ready = False
- error_msgs = []
- # TODO(pliard): deflake this function. The for loop should be removed as
- # well as IsHttpServerConnectable(). spawning_server.Start() should also
- # block until the server is ready.
- # Try 3 times to launch test spawner server.
- for _ in xrange(0, 3):
- self.test_server_spawner_port = ports.AllocateTestServerPort()
- self._ForwardPorts(
- [(self.test_server_spawner_port, self.test_server_spawner_port)])
- self._spawning_server = SpawningServer(self.test_server_spawner_port,
- self.device,
- self.tool)
- self._spawning_server.Start()
- server_ready, error_msg = ports.IsHttpServerConnectable(
- '127.0.0.1', self.test_server_spawner_port, path='/ping',
- expected_read='ready')
- if server_ready:
- break
- else:
- error_msgs.append(error_msg)
- self._spawning_server.Stop()
- # Wait for 2 seconds then restart.
- time.sleep(2)
- if not server_ready:
- logging.error(';'.join(error_msgs))
- raise Exception('Can not start the test spawner server.')
- self._PushTestServerPortInfoToDevice()
diff --git a/build/android/pylib/base/test_collection.py b/build/android/pylib/base/test_collection.py
new file mode 100644
index 0000000..e914652
--- /dev/null
+++ b/build/android/pylib/base/test_collection.py
@@ -0,0 +1,80 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import threading
+
+class TestCollection(object):
+ """A threadsafe collection of tests.
+
+ Args:
+ tests: List of tests to put in the collection.
+ """
+
+ def __init__(self, tests=None):
+ if not tests:
+ tests = []
+ self._lock = threading.Lock()
+ self._tests = []
+ self._tests_in_progress = 0
+ # Used to signal that an item is available or all items have been handled.
+ self._item_available_or_all_done = threading.Event()
+ for t in tests:
+ self.add(t)
+
+ def _pop(self):
+ """Pop a test from the collection.
+
+ Waits until a test is available or all tests have been handled.
+
+ Returns:
+ A test or None if all tests have been handled.
+ """
+ while True:
+ # Wait for a test to be available or all tests to have been handled.
+ self._item_available_or_all_done.wait()
+ with self._lock:
+ # Check which of the two conditions triggered the signal.
+ if self._tests_in_progress == 0:
+ return None
+ try:
+ return self._tests.pop(0)
+ except IndexError:
+ # Another thread beat us to the available test, wait again.
+ self._item_available_or_all_done.clear()
+
+ def add(self, test):
+ """Add an test to the collection.
+
+ Args:
+ test: A test to add.
+ """
+ with self._lock:
+ self._tests.append(test)
+ self._item_available_or_all_done.set()
+ self._tests_in_progress += 1
+
+ def test_completed(self):
+ """Indicate that a test has been fully handled."""
+ with self._lock:
+ self._tests_in_progress -= 1
+ if self._tests_in_progress == 0:
+ # All tests have been handled, signal all waiting threads.
+ self._item_available_or_all_done.set()
+
+ def __iter__(self):
+ """Iterate through tests in the collection until all have been handled."""
+ while True:
+ r = self._pop()
+ if r is None:
+ break
+ yield r
+
+ def __len__(self):
+ """Return the number of tests currently in the collection."""
+ return len(self._tests)
+
+ def test_names(self):
+ """Return a list of the names of the tests currently in the collection."""
+ with self._lock:
+ return list(t.test for t in self._tests)
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
index 7b00ccd..929c408 100644
--- a/build/android/pylib/base/test_dispatcher.py
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -24,6 +24,7 @@
from pylib import android_commands
from pylib import constants
from pylib.base import base_test_result
+from pylib.base import test_collection
from pylib.device import device_errors
from pylib.utils import reraiser_thread
from pylib.utils import watchdog_timer
@@ -65,92 +66,16 @@
self.tries = tries
-class _TestCollection(object):
- """A threadsafe collection of tests.
-
- Args:
- tests: List of tests to put in the collection.
- """
-
- def __init__(self, tests=None):
- if not tests:
- tests = []
- self._lock = threading.Lock()
- self._tests = []
- self._tests_in_progress = 0
- # Used to signal that an item is available or all items have been handled.
- self._item_available_or_all_done = threading.Event()
- for t in tests:
- self.add(t)
-
- def _pop(self):
- """Pop a test from the collection.
-
- Waits until a test is available or all tests have been handled.
-
- Returns:
- A test or None if all tests have been handled.
- """
- while True:
- # Wait for a test to be available or all tests to have been handled.
- self._item_available_or_all_done.wait()
- with self._lock:
- # Check which of the two conditions triggered the signal.
- if self._tests_in_progress == 0:
- return None
- try:
- return self._tests.pop(0)
- except IndexError:
- # Another thread beat us to the available test, wait again.
- self._item_available_or_all_done.clear()
-
- def add(self, test):
- """Add an test to the collection.
-
- Args:
- test: A test to add.
- """
- with self._lock:
- self._tests.append(test)
- self._item_available_or_all_done.set()
- self._tests_in_progress += 1
-
- def test_completed(self):
- """Indicate that a test has been fully handled."""
- with self._lock:
- self._tests_in_progress -= 1
- if self._tests_in_progress == 0:
- # All tests have been handled, signal all waiting threads.
- self._item_available_or_all_done.set()
-
- def __iter__(self):
- """Iterate through tests in the collection until all have been handled."""
- while True:
- r = self._pop()
- if r is None:
- break
- yield r
-
- def __len__(self):
- """Return the number of tests currently in the collection."""
- return len(self._tests)
-
- def test_names(self):
- """Return a list of the names of the tests currently in the collection."""
- with self._lock:
- return list(t.test for t in self._tests)
-
-
-def _RunTestsFromQueue(runner, test_collection, out_results, watcher,
+def _RunTestsFromQueue(runner, collection, out_results, watcher,
num_retries, tag_results_with_device=False):
- """Runs tests from the test_collection until empty using the given runner.
+ """Runs tests from the collection until empty using the given runner.
Adds TestRunResults objects to the out_results list and may add tests to the
out_retry list.
Args:
runner: A TestRunner object used to run the tests.
- test_collection: A _TestCollection from which to get _Test objects to run.
+ collection: A TestCollection from which to get _Test objects to run.
out_results: A list to add TestRunResults to.
watcher: A watchdog_timer.WatchdogTimer object, used as a shared timeout.
num_retries: Number of retries for a test.
@@ -174,7 +99,7 @@
new_test_run_results.AddResult(test_result)
return new_test_run_results
- for test in test_collection:
+ for test in collection:
watcher.Reset()
try:
if runner.device_serial not in android_commands.GetAttachedDevices():
@@ -192,18 +117,18 @@
pass_results.AddResults(result.GetPass())
out_results.append(pass_results)
logging.warning('Will retry test, try #%s.' % test.tries)
- test_collection.add(_Test(test=retry, tries=test.tries))
+ collection.add(_Test(test=retry, tries=test.tries))
else:
# All tests passed or retry limit reached. Either way, record results.
out_results.append(result)
except:
# An unhandleable exception, ensure tests get run by another device and
# reraise this exception on the main thread.
- test_collection.add(test)
+ collection.add(test)
raise
finally:
# Retries count as separate tasks so always mark the popped test as done.
- test_collection.test_completed()
+ collection.test_completed()
def _SetUp(runner_factory, device, out_runners, threadsafe_counter):
@@ -238,7 +163,7 @@
Args:
runners: A list of TestRunner objects.
- test_collection_factory: A callable to generate a _TestCollection object for
+ test_collection_factory: A callable to generate a TestCollection object for
each test runner.
num_retries: Number of retries for a test.
timeout: Watchdog timeout in seconds.
@@ -384,16 +309,17 @@
tests_expanded = ApplyMaxPerRun(tests, max_per_run)
if shard:
- # Generate a shared _TestCollection object for all test runners, so they
+ # Generate a shared TestCollection object for all test runners, so they
# draw from a common pool of tests.
- shared_test_collection = _TestCollection([_Test(t) for t in tests_expanded])
+ shared_test_collection = test_collection.TestCollection(
+ [_Test(t) for t in tests_expanded])
test_collection_factory = lambda: shared_test_collection
tag_results_with_device = False
log_string = 'sharded across devices'
else:
- # Generate a unique _TestCollection object for each test runner, but use
+ # Generate a unique TestCollection object for each test runner, but use
# the same set of tests.
- test_collection_factory = lambda: _TestCollection(
+ test_collection_factory = lambda: test_collection.TestCollection(
[_Test(t) for t in tests_expanded])
tag_results_with_device = True
log_string = 'replicated on each device'
diff --git a/build/android/pylib/base/test_dispatcher_unittest.py b/build/android/pylib/base/test_dispatcher_unittest.py
index d349f32..b57cca9 100644
--- a/build/android/pylib/base/test_dispatcher_unittest.py
+++ b/build/android/pylib/base/test_dispatcher_unittest.py
@@ -18,6 +18,7 @@
android_commands.GetAttachedDevices = lambda: ['0', '1']
from pylib import constants
from pylib.base import base_test_result
+from pylib.base import test_collection
from pylib.base import test_dispatcher
from pylib.utils import watchdog_timer
@@ -83,7 +84,7 @@
@staticmethod
def _RunTests(mock_runner, tests):
results = []
- tests = test_dispatcher._TestCollection(
+ tests = test_collection.TestCollection(
[test_dispatcher._Test(t) for t in tests])
test_dispatcher._RunTestsFromQueue(mock_runner, tests, results,
watchdog_timer.WatchdogTimer(None), 2)
@@ -129,7 +130,7 @@
"""Tests test_dispatcher._RunAllTests and test_dispatcher._CreateRunners."""
def setUp(self):
self.tests = ['a', 'b', 'c', 'd', 'e', 'f', 'g']
- shared_test_collection = test_dispatcher._TestCollection(
+ shared_test_collection = test_collection.TestCollection(
[test_dispatcher._Test(t) for t in self.tests])
self.test_collection_factory = lambda: shared_test_collection
diff --git a/build/android/pylib/base/test_server.py b/build/android/pylib/base/test_server.py
new file mode 100644
index 0000000..085a51e
--- /dev/null
+++ b/build/android/pylib/base/test_server.py
@@ -0,0 +1,19 @@
+# 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.
+
+class TestServer(object):
+ """Base class for any server that needs to be set up for the tests."""
+
+ def __init__(self, *args, **kwargs):
+ pass
+
+ def SetUp(self):
+ raise NotImplementedError
+
+ def Reset(self):
+ raise NotImplementedError
+
+ def TearDown(self):
+ raise NotImplementedError
+
diff --git a/build/android/pylib/constants.py b/build/android/pylib/constants.py
index cef098f..29da601 100644
--- a/build/android/pylib/constants.py
+++ b/build/android/pylib/constants.py
@@ -189,13 +189,12 @@
'pylib.device.device_utils_test',
]
},
-# TODO(mkosiba) Enable after fixing these tests.
-# 'gyp_py_unittests': {
-# 'path': os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'android', 'gyp'),
-# 'test_modules': [
-# 'java_cpp_enum_tests'
-# ]
-# },
+ 'gyp_py_unittests': {
+ 'path': os.path.join(DIR_SOURCE_ROOT, 'build', 'android', 'gyp'),
+ 'test_modules': [
+ 'java_cpp_enum_tests',
+ ]
+ },
}
LOCAL_MACHINE_TESTS = ['junit', 'python']
@@ -217,6 +216,10 @@
os.environ['CHROMIUM_OUT_DIR'] = build_directory
+def SetOutputDirectort(output_directory):
+ os.environ['CHROMIUM_OUTPUT_DIR'] = output_directory
+
+
def GetOutDirectory(build_type=None):
"""Returns the out directory where the output binaries are built.
@@ -224,6 +227,10 @@
build_type: Build type, generally 'Debug' or 'Release'. Defaults to the
globally set build type environment variable BUILDTYPE.
"""
+ if 'CHROMIUM_OUTPUT_DIR' in os.environ:
+ return os.path.abspath(os.path.join(
+ DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUTPUT_DIR')))
+
return os.path.abspath(os.path.join(
DIR_SOURCE_ROOT, os.environ.get('CHROMIUM_OUT_DIR', 'out'),
GetBuildType() if build_type is None else build_type))
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index 97f387a..e7a8418 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -152,14 +152,14 @@
self._DeviceAdbCmd(['pull', remote, local], timeout, retries)
_VerifyLocalFileExists(local)
- def Shell(self, command, expect_rc=None, timeout=_DEFAULT_TIMEOUT,
+ def Shell(self, command, expect_rc=0, timeout=_DEFAULT_TIMEOUT,
retries=_DEFAULT_RETRIES):
"""Runs a shell command on the device.
Args:
command: The shell command to run.
- expect_rc: (optional) If set checks that the command's return code matches
- this value.
+ expect_rc: (optional) Check that the command's return code matches this
+ value. Default is 0. If set to None the test is skipped.
timeout: (optional) Timeout per try in seconds.
retries: (optional) Number of retries to attempt.
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index f4bce41..f6bebce 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -215,9 +215,6 @@
CommandTimeoutError on timeout.
DeviceUnreachableError on missing device.
"""
- return self._GetExternalStoragePathImpl()
-
- def _GetExternalStoragePathImpl(self):
if 'external_storage' in self._cache:
return self._cache['external_storage']
@@ -285,7 +282,8 @@
return self.GetProp('sys.boot_completed') == '1'
def wifi_enabled():
- return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'])
+ return 'Wi-Fi is enabled' in self.RunShellCommand(['dumpsys', 'wifi'],
+ check_return=False)
self.adb.WaitForDevice()
timeout_retry.WaitFor(sd_card_ready)
@@ -442,7 +440,7 @@
timeout = self._default_timeout
try:
- output = self.adb.Shell(cmd, expect_rc=0)
+ output = self.adb.Shell(cmd)
except device_errors.AdbShellCommandFailedError as e:
if check_return:
raise
@@ -531,6 +529,22 @@
raise device_errors.CommandFailedError(l, device=str(self))
@decorators.WithTimeoutAndRetriesFromInstance()
+ def StartInstrumentation(self, component, finish=True, raw=False,
+ extras=None, timeout=None, retries=None):
+ if extras is None:
+ extras = {}
+
+ cmd = ['am', 'instrument']
+ if finish:
+ cmd.append('-w')
+ if raw:
+ cmd.append('-r')
+ for k, v in extras.iteritems():
+ cmd.extend(['-e', k, v])
+ cmd.append(component)
+ return self.RunShellCommand(cmd, check_return=True)
+
+ @decorators.WithTimeoutAndRetriesFromInstance()
def BroadcastIntent(self, intent, timeout=None, retries=None):
"""Send a broadcast intent.
@@ -768,7 +782,7 @@
zip_proc.start()
zip_proc.join()
- zip_on_device = '%s/tmp.zip' % self._GetExternalStoragePathImpl()
+ zip_on_device = '%s/tmp.zip' % self.GetExternalStoragePath()
try:
self.adb.Push(zip_file.name, zip_on_device)
self.RunShellCommand(
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index fa4ffaa..65547d4 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -26,6 +26,7 @@
from pylib.device import device_errors
from pylib.device import device_utils
from pylib.device import intent
+from pylib.utils import mock_calls
# RunCommand from third_party/android_testrunner/run_command.py is mocked
# below, so its path needs to be in sys.path.
@@ -218,82 +219,7 @@
'0123456789abcdef', default_timeout=1, default_retries=0)
-class Args:
- def __init__(self, *args, **kwargs):
- self.args = args
- self.kwargs = kwargs
-
- def __eq__(self, other):
- return (self.args, self.kwargs) == (other.args, other.kwargs)
-
- def __repr__(self):
- return '%s(%s)' % (type(self).__name__, str(self))
-
- def __str__(self):
- toks = (['%r' % v for v in self.args] +
- ['%s=%r' % (k, self.kwargs[k]) for k in sorted(self.kwargs)])
- return ', '.join(toks)
-
-
-class MockCallSequence(object):
- def __init__(self, test_case, obj, method, calls):
- def assert_and_return(*args, **kwargs):
- received_args = Args(*args, **kwargs)
- test_case.assertTrue(
- self._calls,
- msg=('Unexpected call\n'
- ' received: %s(%s)\n' % (self._method, received_args)))
- expected_args, return_value = self._calls.pop(0)
- test_case.assertTrue(
- received_args == expected_args,
- msg=('Call does not match expected args\n'
- ' received: %s(%s)\n'
- ' expected: %s(%s)\n'
- % (self._method, received_args,
- self._method, expected_args)))
- if isinstance(return_value, Exception):
- raise return_value
- else:
- return return_value
-
- self._calls = list(calls)
- self._test_case = test_case
- self._method = method
- self._patched = mock.patch.object(obj, self._method,
- side_effect=assert_and_return)
-
- def __enter__(self):
- return self._patched.__enter__()
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._patched.__exit__(exc_type, exc_val, exc_tb)
- if exc_type is None:
- missing = ''.join(' expected: %s(%s)\n'
- % (self._method, expected_args)
- for expected_args, _ in self._calls)
- self._test_case.assertTrue(
- not missing,
- msg=('Expected calls not found\n' + missing))
-
-
-class _ShellError:
- def __init__(self, output=None, return_code=1):
- if output is None:
- self.output = 'Permission denied\r\n'
- else:
- self.output = output
- self.return_code = return_code
-
-
-class _CmdTimeout:
- def __init__(self, msg=None):
- if msg is None:
- self.msg = 'Operation timed out'
- else:
- self.msg = msg
-
-
-class DeviceUtilsNewImplTest(unittest.TestCase):
+class DeviceUtilsNewImplTest(mock_calls.TestCase):
def setUp(self):
test_serial = '0123456789abcdef'
@@ -302,66 +228,52 @@
self.adb.GetDeviceSerial.return_value = test_serial
self.device = device_utils.DeviceUtils(
self.adb, default_timeout=10, default_retries=0)
+ self.watchMethodCalls(self.call.adb)
- def assertShellCallSequence(self, calls):
- '''Assert that we expect a sequence of calls to adb.Shell.
+ def ShellError(self, output=None, exit_code=1):
+ def action(cmd, *args, **kwargs):
+ raise device_errors.AdbShellCommandFailedError(
+ cmd, exit_code, output, str(self.device))
+ if output is None:
+ output = 'Permission denied\n'
+ return action
- Args:
- calls: a sequence of (cmd, return_value) pairs, where |cmd| is the
- expected shell command to run on the device (with any quoting already
- applied), and |return_value| is either a string to give as mock output
- or a _ShellError object to raise an AdbShellCommandFailedError.
- '''
- def mk_expected_call(cmd, return_value):
- expected_args = Args(cmd, expect_rc=0)
- if isinstance(return_value, _ShellError):
- return_value = device_errors.AdbShellCommandFailedError(cmd,
- return_value.return_code, return_value.output, str(self.device))
- elif isinstance(return_value, _CmdTimeout):
- return_value = device_errors.CommandTimeoutError(return_value.msg,
- str(self.device))
- return (expected_args, return_value)
+ def TimeoutError(self, msg=None):
+ if msg is None:
+ msg = 'Operation timed out'
+ return mock.Mock(side_effect=device_errors.CommandTimeoutError(
+ msg, str(self.device)))
- expected_calls = (mk_expected_call(a, r) for a, r in calls)
- return MockCallSequence(self, self.adb, 'Shell', expected_calls)
-
- def assertShellCall(self, cmd, return_value=''):
- return self.assertShellCallSequence([(cmd, return_value)])
-
-
-class DeviceUtilsHybridImplTest(DeviceUtilsOldImplTest):
-
- def setUp(self):
- super(DeviceUtilsHybridImplTest, self).setUp()
- self.device.adb = self.adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
+ def CommandError(self, msg=None):
+ if msg is None:
+ msg = 'Command failed'
+ return mock.Mock(side_effect=device_errors.CommandFailedError(
+ msg, str(self.device)))
class DeviceUtilsIsOnlineTest(DeviceUtilsNewImplTest):
def testIsOnline_true(self):
- self.adb.GetState = mock.Mock(return_value='device')
- self.assertTrue(self.device.IsOnline())
- self.adb.GetState.assert_called_once_with()
+ with self.assertCall(self.call.adb.GetState(), 'device'):
+ self.assertTrue(self.device.IsOnline())
def testIsOnline_false(self):
- self.adb.GetState = mock.Mock(return_value='offline')
- self.assertFalse(self.device.IsOnline())
- self.adb.GetState.assert_called_once_with()
+ with self.assertCall(self.call.adb.GetState(), 'offline'):
+ self.assertFalse(self.device.IsOnline())
def testIsOnline_error(self):
- self.adb.GetState = mock.Mock(
- side_effect=device_errors.CommandFailedError('falied'))
- self.assertFalse(self.device.IsOnline())
- self.adb.GetState.assert_called_once_with()
+ with self.assertCall(self.call.adb.GetState(), self.CommandError()):
+ self.assertFalse(self.device.IsOnline())
+
class DeviceUtilsHasRootTest(DeviceUtilsNewImplTest):
def testHasRoot_true(self):
- with self.assertShellCall('ls /root', 'foo\r\n'):
+ with self.assertCall(self.call.adb.Shell('ls /root'), 'foo\n'):
self.assertTrue(self.device.HasRoot())
def testHasRoot_false(self):
- with self.assertShellCall('ls /root', _ShellError()):
+ with self.assertCall(self.call.adb.Shell('ls /root'), self.ShellError()):
self.assertFalse(self.device.HasRoot())
@@ -395,25 +307,26 @@
class DeviceUtilsIsUserBuildTest(DeviceUtilsNewImplTest):
def testIsUserBuild_yes(self):
- with self.assertShellCall('getprop ro.build.type', 'user\r\n'):
+ with self.assertCall(
+ self.call.device.GetProp('ro.build.type', cache=True), 'user'):
self.assertTrue(self.device.IsUserBuild())
def testIsUserBuild_no(self):
- with self.assertShellCall('getprop ro.build.type', 'userdebug\r\n'):
+ with self.assertCall(
+ self.call.device.GetProp('ro.build.type', cache=True), 'userdebug'):
self.assertFalse(self.device.IsUserBuild())
class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsNewImplTest):
def testGetExternalStoragePath_succeeds(self):
- fakeStoragePath = '/fake/storage/path'
- with self.assertShellCall('echo $EXTERNAL_STORAGE',
- '%s\r\n' % fakeStoragePath):
- self.assertEquals(fakeStoragePath,
+ with self.assertCall(
+ self.call.adb.Shell('echo $EXTERNAL_STORAGE'), '/fake/storage/path\n'):
+ self.assertEquals('/fake/storage/path',
self.device.GetExternalStoragePath())
def testGetExternalStoragePath_fails(self):
- with self.assertShellCall('echo $EXTERNAL_STORAGE', '\r\n'):
+ with self.assertCall(self.call.adb.Shell('echo $EXTERNAL_STORAGE'), '\n'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.GetExternalStoragePath()
@@ -421,148 +334,150 @@
class DeviceUtilsGetApplicationPathTest(DeviceUtilsNewImplTest):
def testGetApplicationPath_exists(self):
- with self.assertShellCall('pm path android',
- 'package:/path/to/android.apk\n'):
+ with self.assertCall(self.call.adb.Shell('pm path android'),
+ 'package:/path/to/android.apk\n'):
self.assertEquals('/path/to/android.apk',
self.device.GetApplicationPath('android'))
def testGetApplicationPath_notExists(self):
- with self.assertShellCall('pm path not.installed.app',
- ''):
+ with self.assertCall(self.call.adb.Shell('pm path not.installed.app'), ''):
self.assertEquals(None,
self.device.GetApplicationPath('not.installed.app'))
def testGetApplicationPath_fails(self):
- with self.assertShellCall('pm path android',
- 'ERROR. Is package manager running?\n'):
+ with self.assertCall(self.call.adb.Shell('pm path android'),
+ self.CommandError('ERROR. Is package manager running?\n')):
with self.assertRaises(device_errors.CommandFailedError):
self.device.GetApplicationPath('android')
+@mock.patch('time.sleep', mock.Mock())
class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsNewImplTest):
def testWaitUntilFullyBooted_succeedsNoWifi(self):
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
- ('test -d /fake/storage/path', ''),
+ with self.assertCalls(
+ self.call.adb.WaitForDevice(),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'), ''),
# pm_ready
- ('pm path android', 'package:this.is.a.test.package\r\n'),
+ (self.call.device.GetApplicationPath('android'),
+ 'package:/some/fake/path'),
# boot_completed
- ('getprop sys.boot_completed', '1\r\n')]):
+ (self.call.device.GetProp('sys.boot_completed'), '1')):
self.device.WaitUntilFullyBooted(wifi=False)
- self.adb.WaitForDevice.assert_called_once_with()
def testWaitUntilFullyBooted_succeedsWithWifi(self):
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
- ('test -d /fake/storage/path', ''),
+ with self.assertCalls(
+ self.call.adb.WaitForDevice(),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'), ''),
# pm_ready
- ('pm path android', 'package:this.is.a.test.package\r\n'),
+ (self.call.device.GetApplicationPath('android'),
+ 'package:/some/fake/path'),
# boot_completed
- ('getprop sys.boot_completed', '1\r\n'),
+ (self.call.device.GetProp('sys.boot_completed'), '1'),
# wifi_enabled
- ('dumpsys wifi', 'stuff\r\nWi-Fi is enabled\r\nmore stuff\r\n')]):
+ (self.call.adb.Shell('dumpsys wifi'),
+ 'stuff\nWi-Fi is enabled\nmore stuff\n')):
self.device.WaitUntilFullyBooted(wifi=True)
- self.adb.WaitForDevice.assert_called_once_with()
def testWaitUntilFullyBooted_sdCardReadyFails_noPath(self):
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '\r\n')]):
+ with self.assertCalls(
+ self.call.adb.WaitForDevice(),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), self.CommandError())):
with self.assertRaises(device_errors.CommandFailedError):
self.device.WaitUntilFullyBooted(wifi=False)
- def testWaitUntilFullyBooted_sdCardReadyFails_emptyPath(self):
- with mock.patch('time.sleep'):
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
- ('test -d /fake/storage/path', _ShellError()),
- # sc_card_ready
- ('test -d /fake/storage/path', _ShellError()),
- # sc_card_ready
- ('test -d /fake/storage/path', _CmdTimeout())]):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=False)
+ def testWaitUntilFullyBooted_sdCardReadyFails_notExists(self):
+ with self.assertCalls(
+ self.call.adb.WaitForDevice(),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'), self.ShellError()),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'),
+ self.TimeoutError())):
+ with self.assertRaises(device_errors.CommandTimeoutError):
+ self.device.WaitUntilFullyBooted(wifi=False)
def testWaitUntilFullyBooted_devicePmFails(self):
- with mock.patch('time.sleep'):
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
- ('test -d /fake/storage/path', ''),
- # pm_ready
- ('pm path android', 'Error. Is package manager running?\r\n'),
- # pm_ready
- ('pm path android', 'Error. Is package manager running?\r\n'),
- # pm_ready
- ('pm path android', _CmdTimeout())]):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=False)
+ with self.assertCalls(
+ self.call.adb.WaitForDevice(),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+ # pm_ready
+ (self.call.device.GetApplicationPath('android'), self.CommandError()),
+ # pm_ready
+ (self.call.device.GetApplicationPath('android'), self.CommandError()),
+ # pm_ready
+ (self.call.device.GetApplicationPath('android'), self.TimeoutError())):
+ with self.assertRaises(device_errors.CommandTimeoutError):
+ self.device.WaitUntilFullyBooted(wifi=False)
def testWaitUntilFullyBooted_bootFails(self):
- with mock.patch('time.sleep'):
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
- ('test -d /fake/storage/path', ''),
- # pm_ready
- ('pm path android', 'package:this.is.a.test.package\r\n'),
- # boot_completed
- ('getprop sys.boot_completed', '0\r\n'),
- # boot_completed
- ('getprop sys.boot_completed', '0\r\n'),
- # boot_completed
- ('getprop sys.boot_completed', _CmdTimeout())]):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=False)
+ with self.assertCalls(
+ self.call.adb.WaitForDevice(),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+ # pm_ready
+ (self.call.device.GetApplicationPath('android'),
+ 'package:/some/fake/path'),
+ # boot_completed
+ (self.call.device.GetProp('sys.boot_completed'), '0'),
+ # boot_completed
+ (self.call.device.GetProp('sys.boot_completed'), '0'),
+ # boot_completed
+ (self.call.device.GetProp('sys.boot_completed'), self.TimeoutError())):
+ with self.assertRaises(device_errors.CommandTimeoutError):
+ self.device.WaitUntilFullyBooted(wifi=False)
def testWaitUntilFullyBooted_wifiFails(self):
- with mock.patch('time.sleep'):
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
- ('test -d /fake/storage/path', ''),
- # pm_ready
- ('pm path android', 'package:this.is.a.test.package\r\n'),
- # boot_completed
- ('getprop sys.boot_completed', '1\r\n'),
- # wifi_enabled
- ('dumpsys wifi', 'stuff\r\nmore stuff\r\n'),
- # wifi_enabled
- ('dumpsys wifi', 'stuff\r\nmore stuff\r\n'),
- # wifi_enabled
- ('dumpsys wifi', _CmdTimeout())]):
- with self.assertRaises(device_errors.CommandTimeoutError):
- self.device.WaitUntilFullyBooted(wifi=True)
+ with self.assertCalls(
+ self.call.adb.WaitForDevice(),
+ # sd_card_ready
+ (self.call.device.GetExternalStoragePath(), '/fake/storage/path'),
+ (self.call.adb.Shell('test -d /fake/storage/path'), ''),
+ # pm_ready
+ (self.call.device.GetApplicationPath('android'),
+ 'package:/some/fake/path'),
+ # boot_completed
+ (self.call.device.GetProp('sys.boot_completed'), '1'),
+ # wifi_enabled
+ (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
+ # wifi_enabled
+ (self.call.adb.Shell('dumpsys wifi'), 'stuff\nmore stuff\n'),
+ # wifi_enabled
+ (self.call.adb.Shell('dumpsys wifi'), self.TimeoutError())):
+ with self.assertRaises(device_errors.CommandTimeoutError):
+ self.device.WaitUntilFullyBooted(wifi=True)
+@mock.patch('time.sleep', mock.Mock())
class DeviceUtilsRebootTest(DeviceUtilsNewImplTest):
def testReboot_nonBlocking(self):
- self.adb.Reboot = mock.Mock()
- self.device.IsOnline = mock.Mock(return_value=False)
- self.device.Reboot(block=False)
- self.adb.Reboot.assert_called_once_with()
- self.device.IsOnline.assert_called_once_with()
+ with self.assertCalls(
+ self.call.adb.Reboot(),
+ (self.call.device.IsOnline(), True),
+ (self.call.device.IsOnline(), False)):
+ self.device.Reboot(block=False)
def testReboot_blocking(self):
- self.adb.Reboot = mock.Mock()
- self.device.IsOnline = mock.Mock(return_value=False)
- with self.assertShellCallSequence([
- # sc_card_ready
- ('echo $EXTERNAL_STORAGE', '/fake/storage/path\r\n'),
- ('test -d /fake/storage/path', ''),
- # pm_ready
- ('pm path android', 'package:this.is.a.test.package\r\n'),
- # boot_completed
- ('getprop sys.boot_completed', '1\r\n')]):
+ with self.assertCalls(
+ self.call.adb.Reboot(),
+ (self.call.device.IsOnline(), True),
+ (self.call.device.IsOnline(), False),
+ self.call.device.WaitUntilFullyBooted()):
self.device.Reboot(block=True)
- self.adb.Reboot.assert_called_once_with()
- self.device.IsOnline.assert_called_once_with()
- self.adb.WaitForDevice.assert_called_once_with()
class DeviceUtilsInstallTest(DeviceUtilsOldImplTest):
@@ -656,24 +571,31 @@
class DeviceUtilsRunShellCommandTest(DeviceUtilsNewImplTest):
+
+ def setUp(self):
+ super(DeviceUtilsRunShellCommandTest, self).setUp()
+ self.device.NeedsSU = mock.Mock(return_value=False)
+
def testRunShellCommand_commandAsList(self):
- with self.assertShellCall('pm list packages'):
+ with self.assertCall(self.call.adb.Shell('pm list packages'), ''):
self.device.RunShellCommand(['pm', 'list', 'packages'])
def testRunShellCommand_commandAsListQuoted(self):
- with self.assertShellCall("echo 'hello world' '$10'"):
+ with self.assertCall(self.call.adb.Shell("echo 'hello world' '$10'"), ''):
self.device.RunShellCommand(['echo', 'hello world', '$10'])
def testRunShellCommand_commandAsString(self):
- with self.assertShellCall('echo "$VAR"'):
+ with self.assertCall(self.call.adb.Shell('echo "$VAR"'), ''):
self.device.RunShellCommand('echo "$VAR"')
def testNewRunShellImpl_withEnv(self):
- with self.assertShellCall('VAR=some_string echo "$VAR"'):
+ with self.assertCall(
+ self.call.adb.Shell('VAR=some_string echo "$VAR"'), ''):
self.device.RunShellCommand('echo "$VAR"', env={'VAR': 'some_string'})
def testNewRunShellImpl_withEnvQuoted(self):
- with self.assertShellCall('PATH="$PATH:/other/path" run_this'):
+ with self.assertCall(
+ self.call.adb.Shell('PATH="$PATH:/other/path" run_this'), ''):
self.device.RunShellCommand('run_this', env={'PATH': '$PATH:/other/path'})
def testNewRunShellImpl_withEnv_failure(self):
@@ -681,132 +603,129 @@
self.device.RunShellCommand('some_cmd', env={'INVALID NAME': 'value'})
def testNewRunShellImpl_withCwd(self):
- with self.assertShellCall('cd /some/test/path && ls'):
+ with self.assertCall(self.call.adb.Shell('cd /some/test/path && ls'), ''):
self.device.RunShellCommand('ls', cwd='/some/test/path')
def testNewRunShellImpl_withCwdQuoted(self):
- with self.assertShellCall("cd '/some test/path with/spaces' && ls"):
+ with self.assertCall(
+ self.call.adb.Shell("cd '/some test/path with/spaces' && ls"), ''):
self.device.RunShellCommand('ls', cwd='/some test/path with/spaces')
def testRunShellCommand_withSu(self):
- with self.assertShellCallSequence([
- ('su -c ls /root && ! ls /root', ''),
- ('su -c setprop service.adb.root 0', '')]):
- self.device.RunShellCommand('setprop service.adb.root 0', as_root=True)
-
- def testRunShellCommand_withRoot(self):
- with self.assertShellCallSequence([
- ('su -c ls /root && ! ls /root', _ShellError()),
- ('setprop service.adb.root 0', '')]):
+ with self.assertCalls(
+ (self.call.device.NeedsSU(), True),
+ (self.call.adb.Shell('su -c setprop service.adb.root 0'), '')):
self.device.RunShellCommand('setprop service.adb.root 0', as_root=True)
def testRunShellCommand_manyLines(self):
cmd = 'ls /some/path'
- with self.assertShellCall(cmd, 'file1\r\nfile2\r\nfile3\r\n'):
+ with self.assertCall(self.call.adb.Shell(cmd), 'file1\nfile2\nfile3\n'):
self.assertEquals(['file1', 'file2', 'file3'],
self.device.RunShellCommand(cmd))
def testRunShellCommand_singleLine_success(self):
cmd = 'echo $VALUE'
- with self.assertShellCall(cmd, 'some value\r\n'):
+ with self.assertCall(self.call.adb.Shell(cmd), 'some value\n'):
self.assertEquals('some value',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_successEmptyLine(self):
cmd = 'echo $VALUE'
- with self.assertShellCall(cmd, '\r\n'):
+ with self.assertCall(self.call.adb.Shell(cmd), '\n'):
self.assertEquals('',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_successWithoutEndLine(self):
cmd = 'echo -n $VALUE'
- with self.assertShellCall(cmd, 'some value'):
+ with self.assertCall(self.call.adb.Shell(cmd), 'some value'):
self.assertEquals('some value',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_successNoOutput(self):
cmd = 'echo -n $VALUE'
- with self.assertShellCall(cmd, ''):
+ with self.assertCall(self.call.adb.Shell(cmd), ''):
self.assertEquals('',
self.device.RunShellCommand(cmd, single_line=True))
def testRunShellCommand_singleLine_failTooManyLines(self):
cmd = 'echo $VALUE'
- with self.assertShellCall(cmd, 'some value\r\nanother value\r\n'):
+ with self.assertCall(self.call.adb.Shell(cmd),
+ 'some value\nanother value\n'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.RunShellCommand(cmd, single_line=True)
def testRunShellCommand_checkReturn_success(self):
cmd = 'echo $ANDROID_DATA'
- output = '/data\r\n'
- with self.assertShellCall(cmd, output):
+ output = '/data\n'
+ with self.assertCall(self.call.adb.Shell(cmd), output):
self.assertEquals([output.rstrip()],
self.device.RunShellCommand(cmd, check_return=True))
def testRunShellCommand_checkReturn_failure(self):
cmd = 'ls /root'
- output = 'opendir failed, Permission denied\r\n'
- with self.assertShellCall(cmd, _ShellError(output)):
+ output = 'opendir failed, Permission denied\n'
+ with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
with self.assertRaises(device_errors.AdbShellCommandFailedError):
self.device.RunShellCommand(cmd, check_return=True)
def testRunShellCommand_checkReturn_disabled(self):
cmd = 'ls /root'
- output = 'opendir failed, Permission denied\r\n'
- with self.assertShellCall(cmd, _ShellError(output)):
+ output = 'opendir failed, Permission denied\n'
+ with self.assertCall(self.call.adb.Shell(cmd), self.ShellError(output)):
self.assertEquals([output.rstrip()],
self.device.RunShellCommand(cmd, check_return=False))
+@mock.patch('time.sleep', mock.Mock())
class DeviceUtilsKillAllTest(DeviceUtilsNewImplTest):
def testKillAll_noMatchingProcesses(self):
- output = 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- with self.assertShellCallSequence([('ps', output)]):
+ with self.assertCall(self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'):
with self.assertRaises(device_errors.CommandFailedError):
self.device.KillAll('test_process')
def testKillAll_nonblocking(self):
- with self.assertShellCallSequence([
- ('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
- 'this.is.a.test.process\r\n'),
- ('kill -9 1234', '')]):
+ with self.assertCalls(
+ (self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
+ (self.call.adb.Shell('kill -9 1234'), '')):
self.assertEquals(1,
- self.device.KillAll('this.is.a.test.process', blocking=False))
+ self.device.KillAll('some.process', blocking=False))
def testKillAll_blocking(self):
- with mock.patch('time.sleep'):
- with self.assertShellCallSequence([
- ('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
- 'this.is.a.test.process\r\n'),
- ('kill -9 1234', ''),
- ('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
- 'this.is.a.test.process\r\n'),
- ('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n')]):
- self.assertEquals(1,
- self.device.KillAll('this.is.a.test.process', blocking=True))
+ with self.assertCalls(
+ (self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
+ (self.call.adb.Shell('kill -9 1234'), ''),
+ (self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
+ (self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n')):
+ self.assertEquals(1,
+ self.device.KillAll('some.process', blocking=True))
def testKillAll_root(self):
- with self.assertShellCallSequence([
- ('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
- 'this.is.a.test.process\r\n'),
- ('su -c ls /root && ! ls /root', ''),
- ('su -c kill -9 1234', '')]):
+ with self.assertCalls(
+ (self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
+ (self.call.device.NeedsSU(), True),
+ (self.call.adb.Shell('su -c kill -9 1234'), '')):
self.assertEquals(1,
- self.device.KillAll('this.is.a.test.process', as_root=True))
+ self.device.KillAll('some.process', as_root=True))
def testKillAll_sigterm(self):
- with self.assertShellCallSequence([
- ('ps', 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'u0_a1 1234 174 123456 54321 ffffffff 456789ab '
- 'this.is.a.test.process\r\n'),
- ('kill -15 1234', '')]):
+ with self.assertCalls(
+ (self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'u0_a1 1234 174 123456 54321 ffffffff 456789ab some.process\n'),
+ (self.call.adb.Shell('kill -15 1234'), '')):
self.assertEquals(1,
- self.device.KillAll('this.is.a.test.process', signum=signal.SIGTERM))
+ self.device.KillAll('some.process', signum=signal.SIGTERM))
class DeviceUtilsStartActivityTest(DeviceUtilsOldImplTest):
@@ -974,6 +893,48 @@
self.device.StartActivity(test_intent)
+class DeviceUtilsStartInstrumentationTest(DeviceUtilsNewImplTest):
+
+ def testStartInstrumentation_nothing(self):
+ with self.assertCalls(
+ self.call.device.RunShellCommand(
+ ['am', 'instrument', 'test.package/.TestInstrumentation'],
+ check_return=True)):
+ self.device.StartInstrumentation(
+ 'test.package/.TestInstrumentation',
+ finish=False, raw=False, extras=None)
+
+ def testStartInstrumentation_finish(self):
+ with self.assertCalls(
+ (self.call.device.RunShellCommand(
+ ['am', 'instrument', '-w', 'test.package/.TestInstrumentation'],
+ check_return=True),
+ ['OK (1 test)'])):
+ output = self.device.StartInstrumentation(
+ 'test.package/.TestInstrumentation',
+ finish=True, raw=False, extras=None)
+ self.assertEquals(['OK (1 test)'], output)
+
+ def testStartInstrumentation_raw(self):
+ with self.assertCalls(
+ self.call.device.RunShellCommand(
+ ['am', 'instrument', '-r', 'test.package/.TestInstrumentation'],
+ check_return=True)):
+ self.device.StartInstrumentation(
+ 'test.package/.TestInstrumentation',
+ finish=False, raw=True, extras=None)
+
+ def testStartInstrumentation_extras(self):
+ with self.assertCalls(
+ self.call.device.RunShellCommand(
+ ['am', 'instrument', '-e', 'foo', 'Foo', '-e', 'bar', 'Bar',
+ 'test.package/.TestInstrumentation'],
+ check_return=True)):
+ self.device.StartInstrumentation(
+ 'test.package/.TestInstrumentation',
+ finish=False, raw=False, extras={'foo': 'Foo', 'bar': 'Bar'})
+
+
class DeviceUtilsBroadcastIntentTest(DeviceUtilsOldImplTest):
def testBroadcastIntent_noExtras(self):
@@ -1056,93 +1017,61 @@
def testPushChangedFilesIndividually_empty(self):
test_files = []
- self.device._PushChangedFilesIndividually(test_files)
- self.assertEqual(0, self.adb.Push.call_count)
+ with self.assertCalls():
+ self.device._PushChangedFilesIndividually(test_files)
def testPushChangedFilesIndividually_single(self):
test_files = [('/test/host/path', '/test/device/path')]
- self.device._PushChangedFilesIndividually(test_files)
- self.adb.Push.assert_called_once_with(
- '/test/host/path', '/test/device/path')
+ with self.assertCalls(self.call.adb.Push(*test_files[0])):
+ self.device._PushChangedFilesIndividually(test_files)
def testPushChangedFilesIndividually_multiple(self):
test_files = [
('/test/host/path/file1', '/test/device/path/file1'),
('/test/host/path/file2', '/test/device/path/file2')]
- self.device._PushChangedFilesIndividually(test_files)
- self.assertEqual(2, self.adb.Push.call_count)
- self.adb.Push.assert_any_call(
- '/test/host/path/file1', '/test/device/path/file1')
- self.adb.Push.assert_any_call(
- '/test/host/path/file2', '/test/device/path/file2')
+ with self.assertCalls(
+ self.call.adb.Push(*test_files[0]),
+ self.call.adb.Push(*test_files[1])):
+ self.device._PushChangedFilesIndividually(test_files)
-@mock.patch('pylib.device.commands.install_commands.Installed', new=None)
-@mock.patch('pylib.device.commands.install_commands.InstallCommands', new=None)
-class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsHybridImplTest):
-
- def setUp(self):
- super(DeviceUtilsPushChangedFilesZippedTest, self).setUp()
+class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsNewImplTest):
def testPushChangedFilesZipped_empty(self):
test_files = []
- self.device._PushChangedFilesZipped(test_files)
- self.assertEqual(0, self.adb.Push.call_count)
+ with self.assertCalls():
+ self.device._PushChangedFilesZipped(test_files)
+
+ def _testPushChangedFilesZipped_spec(self, test_files):
+ mock_zip_temp = mock.mock_open()
+ mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
+ with self.assertCalls(
+ (mock.call.tempfile.NamedTemporaryFile(suffix='.zip'), mock_zip_temp),
+ (mock.call.multiprocessing.Process(
+ target=device_utils.DeviceUtils._CreateDeviceZip,
+ args=('/test/temp/file/tmp.zip', test_files)), mock.Mock()),
+ (self.call.device.GetExternalStoragePath(),
+ '/test/device/external_dir'),
+ self.call.adb.Push(
+ '/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip'),
+ self.call.device.RunShellCommand(
+ ['unzip', '/test/device/external_dir/tmp.zip'],
+ as_root=True,
+ env={'PATH': '$PATH:/data/local/tmp/bin'},
+ check_return=True),
+ (self.call.device.IsOnline(), True),
+ self.call.device.RunShellCommand(
+ ['rm', '/test/device/external_dir/tmp.zip'], check_return=True)):
+ self.device._PushChangedFilesZipped(test_files)
def testPushChangedFilesZipped_single(self):
- test_files = [('/test/host/path/file1', '/test/device/path/file1')]
-
- self.device._GetExternalStoragePathImpl = mock.Mock(
- return_value='/test/device/external_dir')
- self.device.IsOnline = mock.Mock(return_value=True)
- self.device.RunShellCommand = mock.Mock()
- mock_zip_temp = mock.mock_open()
- mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
- with mock.patch('multiprocessing.Process') as mock_zip_proc, (
- mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
- self.device._PushChangedFilesZipped(test_files)
-
- mock_zip_proc.assert_called_once_with(
- target=device_utils.DeviceUtils._CreateDeviceZip,
- args=('/test/temp/file/tmp.zip', test_files))
- self.adb.Push.assert_called_once_with(
- '/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
- self.assertEqual(2, self.device.RunShellCommand.call_count)
- self.device.RunShellCommand.assert_any_call(
- ['unzip', '/test/device/external_dir/tmp.zip'],
- as_root=True,
- env={'PATH': '$PATH:/data/local/tmp/bin'},
- check_return=True)
- self.device.RunShellCommand.assert_any_call(
- ['rm', '/test/device/external_dir/tmp.zip'], check_return=True)
+ self._testPushChangedFilesZipped_spec(
+ [('/test/host/path/file1', '/test/device/path/file1')])
def testPushChangedFilesZipped_multiple(self):
- test_files = [('/test/host/path/file1', '/test/device/path/file1'),
- ('/test/host/path/file2', '/test/device/path/file2')]
-
- self.device._GetExternalStoragePathImpl = mock.Mock(
- return_value='/test/device/external_dir')
- self.device.IsOnline = mock.Mock(return_value=True)
- self.device.RunShellCommand = mock.Mock()
- mock_zip_temp = mock.mock_open()
- mock_zip_temp.return_value.name = '/test/temp/file/tmp.zip'
- with mock.patch('multiprocessing.Process') as mock_zip_proc, (
- mock.patch('tempfile.NamedTemporaryFile', mock_zip_temp)):
- self.device._PushChangedFilesZipped(test_files)
-
- mock_zip_proc.assert_called_once_with(
- target=device_utils.DeviceUtils._CreateDeviceZip,
- args=('/test/temp/file/tmp.zip', test_files))
- self.adb.Push.assert_called_once_with(
- '/test/temp/file/tmp.zip', '/test/device/external_dir/tmp.zip')
- self.assertEqual(2, self.device.RunShellCommand.call_count)
- self.device.RunShellCommand.assert_any_call(
- ['unzip', '/test/device/external_dir/tmp.zip'],
- as_root=True,
- env={'PATH': '$PATH:/data/local/tmp/bin'},
- check_return=True)
- self.device.RunShellCommand.assert_any_call(
- ['rm', '/test/device/external_dir/tmp.zip'], check_return=True)
+ self._testPushChangedFilesZipped_spec(
+ [('/test/host/path/file1', '/test/device/path/file1'),
+ ('/test/host/path/file2', '/test/device/path/file2')])
class DeviceUtilsFileExistsTest(DeviceUtilsOldImplTest):
@@ -1370,23 +1299,27 @@
self.device.WriteFile('/test/file/no.permissions.to.write',
'new test file contents', as_root=True)
+
class DeviceUtilsWriteTextFileTest(DeviceUtilsNewImplTest):
def testWriteTextFileTest_basic(self):
- with self.assertShellCall('echo some.string > /test/file/to.write'):
+ with self.assertCall(
+ self.call.adb.Shell('echo some.string > /test/file/to.write'), ''):
self.device.WriteTextFile('/test/file/to.write', 'some.string')
def testWriteTextFileTest_quoted(self):
- with self.assertShellCall(
- "echo 'some other string' > '/test/file/to write'"):
+ with self.assertCall(
+ self.call.adb.Shell("echo 'some other string' > '/test/file/to write'"),
+ ''):
self.device.WriteTextFile('/test/file/to write', 'some other string')
- def testWriteTextFileTest_asRoot(self):
- with self.assertShellCallSequence([
- ('su -c ls /root && ! ls /root', ''),
- ('su -c echo string > /test/file', '')]):
+ def testWriteTextFileTest_withSU(self):
+ with self.assertCalls(
+ (self.call.device.NeedsSU(), True),
+ (self.call.adb.Shell('su -c echo string > /test/file'), '')):
self.device.WriteTextFile('/test/file', 'string', as_root=True)
+
class DeviceUtilsLsTest(DeviceUtilsOldImplTest):
def testLs_nothing(self):
@@ -1512,29 +1445,29 @@
class DeviceUtilsGetPropTest(DeviceUtilsNewImplTest):
def testGetProp_exists(self):
- with self.assertShellCall('getprop this.is.a.test.property',
- 'test_property_value\r\n'):
- self.assertEqual('test_property_value',
- self.device.GetProp('this.is.a.test.property'))
+ with self.assertCall(
+ self.call.adb.Shell('getprop test.property'), 'property_value\n'):
+ self.assertEqual('property_value',
+ self.device.GetProp('test.property'))
def testGetProp_doesNotExist(self):
- with self.assertShellCall('getprop this.property.does.not.exist',
- '\r\n'):
- self.assertEqual('', self.device.GetProp('this.property.does.not.exist'))
+ with self.assertCall(
+ self.call.adb.Shell('getprop property.does.not.exist'), '\n'):
+ self.assertEqual('', self.device.GetProp('property.does.not.exist'))
def testGetProp_cachedRoProp(self):
- with self.assertShellCall('getprop ro.build.type',
- 'userdebug\r\n'):
+ with self.assertCall(
+ self.call.adb.Shell('getprop ro.build.type'), 'userdebug\n'):
self.assertEqual('userdebug',
self.device.GetProp('ro.build.type', cache=True))
self.assertEqual('userdebug',
self.device.GetProp('ro.build.type', cache=True))
def testGetProp_retryAndCache(self):
- with self.assertShellCallSequence([
- ('getprop ro.build.type', _ShellError()),
- ('getprop ro.build.type', _ShellError()),
- ('getprop ro.build.type', 'userdebug\r\n')]):
+ with self.assertCalls(
+ (self.call.adb.Shell('getprop ro.build.type'), self.ShellError()),
+ (self.call.adb.Shell('getprop ro.build.type'), self.ShellError()),
+ (self.call.adb.Shell('getprop ro.build.type'), 'userdebug\n')):
self.assertEqual('userdebug',
self.device.GetProp('ro.build.type',
cache=True, retries=3))
@@ -1546,46 +1479,55 @@
class DeviceUtilsSetPropTest(DeviceUtilsNewImplTest):
def testSetProp(self):
- with self.assertShellCall(
- "setprop this.is.a.test.property 'test property value'"):
- self.device.SetProp('this.is.a.test.property', 'test property value')
+ with self.assertCall(
+ self.call.adb.Shell("setprop test.property 'test value'"), ''):
+ self.device.SetProp('test.property', 'test value')
+
+ def testSetProp_check_succeeds(self):
+ with self.assertCalls(
+ (self.call.adb.Shell('setprop test.property new_value'), ''),
+ (self.call.adb.Shell('getprop test.property'), 'new_value')):
+ self.device.SetProp('test.property', 'new_value', check=True)
+
+ def testSetProp_check_fails(self):
+ with self.assertCalls(
+ (self.call.adb.Shell('setprop test.property new_value'), ''),
+ (self.call.adb.Shell('getprop test.property'), 'old_value')):
+ with self.assertRaises(device_errors.CommandFailedError):
+ self.device.SetProp('test.property', 'new_value', check=True)
class DeviceUtilsGetPidsTest(DeviceUtilsNewImplTest):
def testGetPids_noMatches(self):
- with self.assertShellCall(
- 'ps',
- 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'user 1000 100 1024 1024 ffffffff 00000000 no.match\r\n'):
+ with self.assertCall(self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'user 1000 100 1024 1024 ffffffff 00000000 no.match\n'):
self.assertEqual({}, self.device.GetPids('does.not.match'))
def testGetPids_oneMatch(self):
- with self.assertShellCall(
- 'ps',
- 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'user 1000 100 1024 1024 ffffffff 00000000 not.a.match\r\n'
- 'user 1001 100 1024 1024 ffffffff 00000000 one.match\r\n'):
+ with self.assertCall(self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'user 1000 100 1024 1024 ffffffff 00000000 not.a.match\n'
+ 'user 1001 100 1024 1024 ffffffff 00000000 one.match\n'):
self.assertEqual({'one.match': '1001'}, self.device.GetPids('one.match'))
def testGetPids_mutlipleMatches(self):
- with self.assertShellCall(
- 'ps',
- 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'user 1000 100 1024 1024 ffffffff 00000000 not\r\n'
- 'user 1001 100 1024 1024 ffffffff 00000000 one.match\r\n'
- 'user 1002 100 1024 1024 ffffffff 00000000 two.match\r\n'
- 'user 1003 100 1024 1024 ffffffff 00000000 three.match\r\n'):
+ with self.assertCall(self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'user 1000 100 1024 1024 ffffffff 00000000 not\n'
+ 'user 1001 100 1024 1024 ffffffff 00000000 one.match\n'
+ 'user 1002 100 1024 1024 ffffffff 00000000 two.match\n'
+ 'user 1003 100 1024 1024 ffffffff 00000000 three.match\n'):
self.assertEqual(
{'one.match': '1001', 'two.match': '1002', 'three.match': '1003'},
self.device.GetPids('match'))
def testGetPids_exactMatch(self):
- with self.assertShellCall(
- 'ps',
- 'USER PID PPID VSIZE RSS WCHAN PC NAME\r\n'
- 'user 1000 100 1024 1024 ffffffff 00000000 not.exact.match\r\n'
- 'user 1234 100 1024 1024 ffffffff 00000000 exact.match\r\n'):
+ with self.assertCall(self.call.adb.Shell('ps'),
+ 'USER PID PPID VSIZE RSS WCHAN PC NAME\n'
+ 'user 1000 100 1024 1024 ffffffff 00000000 not.exact.match\n'
+ 'user 1234 100 1024 1024 ffffffff 00000000 exact.match\n'):
self.assertEqual(
{'not.exact.match': '1000', 'exact.match': '1234'},
self.device.GetPids('exact.match'))
@@ -1668,6 +1610,7 @@
class DeviceUtilsStrTest(DeviceUtilsOldImplTest):
+
def testStr_noAdbCalls(self):
with self.assertNoAdbCalls():
self.assertEqual('0123456789abcdef', str(self.device))
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
index 5e45043..5f40a94 100644
--- a/build/android/pylib/forwarder.py
+++ b/build/android/pylib/forwarder.py
@@ -270,6 +270,7 @@
pid_file.seek(0)
pid_file.write(
'%s:%s' % (pid_for_lock, str(_GetProcessStartTime(pid_for_lock))))
+ pid_file.truncate()
def _InitDeviceLocked(self, device, tool):
"""Initializes the device_forwarder daemon for a specific device (once).
diff --git a/build/android/pylib/gtest/test_runner.py b/build/android/pylib/gtest/test_runner.py
index 75892ee..56e7449 100644
--- a/build/android/pylib/gtest/test_runner.py
+++ b/build/android/pylib/gtest/test_runner.py
@@ -7,9 +7,11 @@
import re
from pylib import pexpect
+from pylib import ports
from pylib.base import base_test_result
from pylib.base import base_test_runner
from pylib.device import device_errors
+from pylib.local import local_test_server_spawner
from pylib.perf import perf_control
@@ -53,6 +55,13 @@
if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
self._perf_controller = perf_control.PerfControl(self.device)
+ if _TestSuiteRequiresMockTestServer(self.test_package.suite_name):
+ self._servers = [
+ local_test_server_spawner.LocalTestServerSpawner(
+ ports.AllocateTestServerPort(), self.device, self.tool)]
+ else:
+ self._servers = []
+
#override
def InstallTestPackage(self):
self.test_package.Install(self.device)
@@ -149,7 +158,8 @@
test_results = self._ParseTestOutput(
self.test_package.SpawnTestProcess(self.device))
finally:
- self.CleanupSpawningServerState()
+ for s in self._servers:
+ s.Reset()
# Calculate unknown test results.
all_tests = set(test.split(':'))
all_tests_ran = set([t.GetName() for t in test_results.GetAll()])
@@ -164,8 +174,8 @@
def SetUp(self):
"""Sets up necessary test enviroment for the test suite."""
super(TestRunner, self).SetUp()
- if _TestSuiteRequiresMockTestServer(self.test_package.suite_name):
- self.LaunchChromeTestServerSpawner()
+ for s in self._servers:
+ s.SetUp()
if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
self._perf_controller.SetHighPerfMode()
self.tool.SetupEnvironment()
@@ -173,6 +183,8 @@
#override
def TearDown(self):
"""Cleans up the test enviroment for the test suite."""
+ for s in self._servers:
+ s.TearDown()
if _TestSuiteRequiresHighPerfMode(self.test_package.suite_name):
self._perf_controller.SetDefaultPerfMode()
self.test_package.ClearApplicationState(self.device)
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py
index c81258f..d83d00a 100644
--- a/build/android/pylib/instrumentation/test_jar.py
+++ b/build/android/pylib/instrumentation/test_jar.py
@@ -23,7 +23,7 @@
import unittest_util # pylint: disable=F0401
# If you change the cached output of proguard, increment this number
-PICKLE_FORMAT_VERSION = 2
+PICKLE_FORMAT_VERSION = 3
class TestJar(object):
@@ -55,6 +55,16 @@
if not self._GetCachedProguardData():
self._GetProguardData()
+ @staticmethod
+ def _CalculateMd5(path):
+ # TODO(jbudorick): Move MD5sum calculations out of here and
+ # AndroidCommands to their own module.
+ out = cmd_helper.GetCmdOutput(
+ [os.path.join(constants.GetOutDirectory(),
+ 'md5sum_bin_host'),
+ path])
+ return out
+
def _GetCachedProguardData(self):
if (os.path.exists(self._pickled_proguard_name) and
(os.path.getmtime(self._pickled_proguard_name) >
@@ -64,7 +74,9 @@
try:
with open(self._pickled_proguard_name, 'r') as r:
d = pickle.loads(r.read())
- if d['VERSION'] == PICKLE_FORMAT_VERSION:
+ jar_md5 = self._CalculateMd5(self._jar_path)
+ if (d['JAR_MD5SUM'] == jar_md5 and
+ d['VERSION'] == PICKLE_FORMAT_VERSION):
self._test_methods = d['TEST_METHODS']
return True
except:
@@ -182,7 +194,8 @@
logging.info('Storing proguard output to %s', self._pickled_proguard_name)
d = {'VERSION': PICKLE_FORMAT_VERSION,
- 'TEST_METHODS': self._test_methods}
+ 'TEST_METHODS': self._test_methods,
+ 'JAR_MD5SUM': self._CalculateMd5(self._jar_path)}
with open(self._pickled_proguard_name, 'w') as f:
f.write(pickle.dumps(d))
diff --git a/build/android/pylib/instrumentation/test_result.py b/build/android/pylib/instrumentation/test_result.py
index a0eea65..24e80a8 100644
--- a/build/android/pylib/instrumentation/test_result.py
+++ b/build/android/pylib/instrumentation/test_result.py
@@ -18,7 +18,8 @@
dur: Duration of the test run in milliseconds.
log: A string listing any errors.
"""
- super(InstrumentationTestResult, self).__init__(full_name, test_type, log)
+ super(InstrumentationTestResult, self).__init__(
+ full_name, test_type, dur, log)
name_pieces = full_name.rsplit('#')
if len(name_pieces) > 1:
self._test_name = name_pieces[1]
@@ -27,8 +28,3 @@
self._class_name = full_name
self._test_name = full_name
self._start_date = start_date
- self._dur = dur
-
- def GetDur(self):
- """Get the test duration."""
- return self._dur
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 3bac503..60e00f3 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -369,16 +369,11 @@
Returns:
The raw output of am instrument as a list of lines.
"""
- # Build the 'am instrument' command
- instrumentation_path = (
- '%s/%s' % (self.test_pkg.GetPackageName(), self.options.test_runner))
-
- cmd = ['am', 'instrument', '-r']
- for k, v in self._GetInstrumentationArgs().iteritems():
- cmd.extend(['-e', k, v])
- cmd.extend(['-e', 'class', test])
- cmd.extend(['-w', instrumentation_path])
- return self.device.RunShellCommand(cmd, timeout=timeout, retries=0)
+ extras = self._GetInstrumentationArgs()
+ extras['class'] = test
+ return self.device.StartInstrumentation(
+ '%s/%s' % (self.test_pkg.GetPackageName(), self.options.test_runner),
+ raw=True, extras=extras, timeout=timeout, retries=0)
@staticmethod
def _ParseAmInstrumentRawOutput(raw_output):
@@ -506,7 +501,7 @@
self.tool.GetTimeoutScale())
if (self.device.GetProp('ro.build.version.sdk')
< constants.ANDROID_SDK_VERSION_CODES.JELLY_BEAN):
- timeout *= 4
+ timeout *= 10
start_ms = 0
duration_ms = 0
diff --git a/build/android/pylib/instrumentation/test_runner_test.py b/build/android/pylib/instrumentation/test_runner_test.py
index 039bb03..0f2845e 100755
--- a/build/android/pylib/instrumentation/test_runner_test.py
+++ b/build/android/pylib/instrumentation/test_runner_test.py
@@ -144,7 +144,7 @@
self.assertEqual('test.package.TestClass#testMethod', result.GetName())
self.assertEqual(base_test_result.ResultType.UNKNOWN, result.GetType())
self.assertEqual('', result.GetLog())
- self.assertEqual(1000, result.GetDur())
+ self.assertEqual(1000, result.GetDuration())
def testGenerateTestResult_testPassed(self):
statuses = [
@@ -253,17 +253,18 @@
def test_RunTest_verifyAdbShellCommand(self):
self.instance.options.test_runner = 'MyTestRunner'
- self.instance.device.RunShellCommand = mock.Mock()
+ self.instance.device.StartInstrumentation = mock.Mock()
self.instance.test_pkg.GetPackageName = mock.Mock(
return_value='test.package')
self.instance._GetInstrumentationArgs = mock.Mock(
return_value={'test_arg_key': 'test_arg_value'})
self.instance._RunTest('test.package.TestClass#testMethod', 100)
- self.instance.device.RunShellCommand.assert_called_with(
- ['am', 'instrument', '-r',
- '-e', 'test_arg_key', 'test_arg_value',
- '-e', 'class', 'test.package.TestClass#testMethod',
- '-w', 'test.package/MyTestRunner'],
+ self.instance.device.StartInstrumentation.assert_called_with(
+ 'test.package/MyTestRunner', raw=True,
+ extras={
+ 'test_arg_key': 'test_arg_value',
+ 'class': 'test.package.TestClass#testMethod'
+ },
timeout=100, retries=0)
if __name__ == '__main__':
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
index 446bc84..f64a58b 100644
--- a/build/android/pylib/linker/test_case.py
+++ b/build/android/pylib/linker/test_case.py
@@ -340,7 +340,7 @@
base_test_result.BaseTestResult(
self.tagged_name,
status,
- logs))
+ log=logs))
return results
diff --git a/build/android/pylib/local/__init__.py b/build/android/pylib/local/__init__.py
new file mode 100644
index 0000000..4d6aabb
--- /dev/null
+++ b/build/android/pylib/local/__init__.py
@@ -0,0 +1,3 @@
+# 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.
diff --git a/build/android/pylib/local/local_test_server_spawner.py b/build/android/pylib/local/local_test_server_spawner.py
new file mode 100644
index 0000000..77f552e
--- /dev/null
+++ b/build/android/pylib/local/local_test_server_spawner.py
@@ -0,0 +1,45 @@
+# 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.
+
+from pylib import chrome_test_server_spawner
+from pylib import forwarder
+from pylib.base import test_server
+
+
+class LocalTestServerSpawner(test_server.TestServer):
+
+ def __init__(self, port, device, tool):
+ super(LocalTestServerSpawner, self).__init__()
+ self._device = device
+ self._spawning_server = chrome_test_server_spawner.SpawningServer(
+ port, device, tool)
+ self._tool = tool
+
+ @property
+ def server_address(self):
+ return self._spawning_server.server.server_address
+
+ @property
+ def port(self):
+ return self.server_address[1]
+
+ #override
+ def SetUp(self):
+ self._device.WriteFile(
+ '%s/net-test-server-ports' % self._device.GetExternalStoragePath(),
+ '%s:0' % str(self.port))
+ forwarder.Forwarder.Map(
+ [(self.port, self.port)], self._device, self._tool)
+ self._spawning_server.Start()
+
+ #override
+ def Reset(self):
+ self._spawning_server.CleanupState()
+
+ #override
+ def TearDown(self):
+ self.Reset()
+ self._spawning_server.Stop()
+ forwarder.Forwarder.UnmapDevicePort(self.port, self._device)
+
diff --git a/build/android/pylib/uiautomator/test_package.py b/build/android/pylib/uiautomator/test_package.py
index fd9120e..cb51fdf 100644
--- a/build/android/pylib/uiautomator/test_package.py
+++ b/build/android/pylib/uiautomator/test_package.py
@@ -11,6 +11,11 @@
class TestPackage(test_jar.TestJar):
+
+ UIAUTOMATOR_PATH = 'uiautomator/'
+ UIAUTOMATOR_DEVICE_DIR = os.path.join(constants.TEST_EXECUTABLE_DIR,
+ UIAUTOMATOR_PATH)
+
def __init__(self, jar_path, jar_info_path):
test_jar.TestJar.__init__(self, jar_info_path)
@@ -24,4 +29,5 @@
# Override.
def Install(self, device):
- device.PushChangedFiles([(self._jar_path, constants.TEST_EXECUTABLE_DIR)])
+ device.PushChangedFiles([(self._jar_path, self.UIAUTOMATOR_DEVICE_DIR +
+ self.GetPackageName())])
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
index c0f8f15..f4e5730 100644
--- a/build/android/pylib/uiautomator/test_runner.py
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -73,7 +73,8 @@
package=self._package),
blocking=True,
force_stop=True)
- cmd = ['uiautomator', 'runtest', self.test_pkg.GetPackageName(),
+ cmd = ['uiautomator', 'runtest',
+ self.test_pkg.UIAUTOMATOR_PATH + self.test_pkg.GetPackageName(),
'-e', 'class', test]
return self.device.RunShellCommand(cmd, timeout=timeout, retries=0)
diff --git a/build/android/pylib/utils/flakiness_dashboard_results_uploader.py b/build/android/pylib/utils/flakiness_dashboard_results_uploader.py
index 246c83b..ff286b6 100644
--- a/build/android/pylib/utils/flakiness_dashboard_results_uploader.py
+++ b/build/android/pylib/utils/flakiness_dashboard_results_uploader.py
@@ -131,7 +131,7 @@
test_result = json_results_generator.TestResult(
test=single_test_result.GetName(),
failed=failed,
- elapsed_time=single_test_result.GetDur() / 1000)
+ elapsed_time=single_test_result.GetDuration() / 1000)
# The WebKit TestResult object sets the modifier it based on test name.
# Since we don't use the same test naming convention as WebKit the
# modifier will be wrong, so we need to overwrite it.
diff --git a/build/android/pylib/utils/isolator.py b/build/android/pylib/utils/isolator.py
index 9ee5671..afbee2a 100644
--- a/build/android/pylib/utils/isolator.py
+++ b/build/android/pylib/utils/isolator.py
@@ -32,7 +32,6 @@
'component': 'static_library',
'fastbuild': '0',
'icu_use_data_file_flag': '1',
- 'libpeer_target_type': 'static_library',
'lsan': '0',
# TODO(maruel): This may not always be true.
'target_arch': 'arm',
diff --git a/build/android/pylib/utils/mock_calls.py b/build/android/pylib/utils/mock_calls.py
new file mode 100755
index 0000000..1f9d8e3
--- /dev/null
+++ b/build/android/pylib/utils/mock_calls.py
@@ -0,0 +1,175 @@
+#!/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.
+
+"""
+A test facility to assert call sequences while mocking their behavior.
+"""
+
+import os
+import sys
+import unittest
+
+from pylib import constants
+
+sys.path.append(os.path.join(
+ constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class TestCase(unittest.TestCase):
+ """Adds assertCalls to TestCase objects."""
+ class _AssertCalls(object):
+ def __init__(self, test_case, expected_calls, watched):
+ def call_action(pair):
+ if isinstance(pair, type(mock.call)):
+ return (pair, None)
+ else:
+ return pair
+
+ def do_check(call):
+ def side_effect(*args, **kwargs):
+ received_call = call(*args, **kwargs)
+ self._test_case.assertTrue(
+ self._expected_calls,
+ msg=('Unexpected call: %s' % str(received_call)))
+ expected_call, action = self._expected_calls.pop(0)
+ self._test_case.assertTrue(
+ received_call == expected_call,
+ msg=('Expected call missmatch:\n'
+ ' expected: %s\n'
+ ' received: %s\n'
+ % (str(expected_call), str(received_call))))
+ if callable(action):
+ return action(*args, **kwargs)
+ else:
+ return action
+ return side_effect
+
+ self._test_case = test_case
+ self._expected_calls = [call_action(pair) for pair in expected_calls]
+ watched = watched.copy() # do not pollute the caller's dict
+ watched.update((call.parent.name, call.parent)
+ for call, _ in self._expected_calls)
+ self._patched = [test_case.patch_call(call, side_effect=do_check(call))
+ for call in watched.itervalues()]
+
+ def __enter__(self):
+ for patch in self._patched:
+ patch.__enter__()
+ return self
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ for patch in self._patched:
+ patch.__exit__(exc_type, exc_val, exc_tb)
+ if exc_type is None:
+ missing = ''.join(' expected: %s\n' % str(call)
+ for call, _ in self._expected_calls)
+ self._test_case.assertFalse(
+ missing,
+ msg='Expected calls not found:\n' + missing)
+
+ def __init__(self, *args, **kwargs):
+ super(TestCase, self).__init__(*args, **kwargs)
+ self.call = mock.call.self
+ self._watched = {}
+
+ def call_target(self, call):
+ """Resolve a self.call instance to the target it represents.
+
+ Args:
+ call: a self.call instance, e.g. self.call.adb.Shell
+
+ Returns:
+ The target object represented by the call, e.g. self.adb.Shell
+
+ Raises:
+ ValueError if the path of the call does not start with "self", i.e. the
+ target of the call is external to the self object.
+ AttributeError if the path of the call does not specify a valid
+ chain of attributes (without any calls) starting from "self".
+ """
+ path = call.name.split('.')
+ if path.pop(0) != 'self':
+ raise ValueError("Target %r outside of 'self' object" % call.name)
+ target = self
+ for attr in path:
+ target = getattr(target, attr)
+ return target
+
+ def patch_call(self, call, **kwargs):
+ """Patch the target of a mock.call instance.
+
+ Args:
+ call: a mock.call instance identifying a target to patch
+ Extra keyword arguments are processed by mock.patch
+
+ Returns:
+ A context manager to mock/unmock the target of the call
+ """
+ if call.name.startswith('self.'):
+ target = self.call_target(call.parent)
+ _, attribute = call.name.rsplit('.', 1)
+ return mock.patch.object(target, attribute, **kwargs)
+ else:
+ return mock.patch(call.name, **kwargs)
+
+ def watchCalls(self, calls):
+ """Add calls to the set of watched calls.
+
+ Args:
+ calls: a sequence of mock.call instances identifying targets to watch
+ """
+ self._watched.update((call.name, call) for call in calls)
+
+ def watchMethodCalls(self, call):
+ """Watch all public methods of the target identified by a self.call.
+
+ Args:
+ call: a self.call instance indetifying an object
+ """
+ target = self.call_target(call)
+ self.watchCalls(getattr(call, method)
+ for method in dir(target.__class__)
+ if not method.startswith('_'))
+
+ def clearWatched(self):
+ """Clear the set of watched calls."""
+ self._watched = {}
+
+ def assertCalls(self, *calls):
+ """A context manager to assert that a sequence of calls is made.
+
+ During the assertion, a number of functions and methods will be "watched",
+ and any calls made to them is expected to appear---in the exact same order,
+ and with the exact same arguments---as specified by the argument |calls|.
+
+ By default, the targets of all expected calls are watched. Further targets
+ to watch may be added using watchCalls and watchMethodCalls.
+
+ Optionaly, each call may be accompanied by an action. If the action is a
+ (non-callable) value, this value will be used as the return value given to
+ the caller when the matching call is found. Alternatively, if the action is
+ a callable, the action will be then called with the same arguments as the
+ intercepted call, so that it can provide a return value or perform other
+ side effects. If the action is missing, a return value of None is assumed.
+
+ Note that mock.Mock objects are often convenient to use as a callable
+ action, e.g. to raise exceptions or return other objects which are
+ themselves callable.
+
+ Args:
+ calls: each argument is either a pair (expected_call, action) or just an
+ expected_call, where expected_call is a mock.call instance.
+
+ Raises:
+ AssertionError if the watched targets do not receive the exact sequence
+ of calls specified. Missing calls, extra calls, and calls with
+ mismatching arguments, all cause the assertion to fail.
+ """
+ return self._AssertCalls(self, calls, self._watched)
+
+ def assertCall(self, call, action=None):
+ return self.assertCalls((call, action))
+
diff --git a/build/android/pylib/utils/mock_calls_test.py b/build/android/pylib/utils/mock_calls_test.py
new file mode 100755
index 0000000..1b474af
--- /dev/null
+++ b/build/android/pylib/utils/mock_calls_test.py
@@ -0,0 +1,159 @@
+#!/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.
+
+"""
+Unit tests for the contents of mock_calls.py.
+"""
+
+import logging
+import os
+import sys
+import unittest
+
+from pylib import constants
+from pylib.utils import mock_calls
+
+sys.path.append(os.path.join(
+ constants.DIR_SOURCE_ROOT, 'third_party', 'pymock'))
+import mock # pylint: disable=F0401
+
+
+class _DummyAdb(object):
+ def __str__(self):
+ return '0123456789abcdef'
+
+ def Push(self, host_path, device_path):
+ logging.debug('(device %s) pushing %r to %r', self, host_path, device_path)
+
+ def IsOnline(self):
+ logging.debug('(device %s) checking device online', self)
+ return True
+
+ def Shell(self, cmd):
+ logging.debug('(device %s) running command %r', self, cmd)
+ return "nice output\n"
+
+ def Reboot(self):
+ logging.debug('(device %s) rebooted!', self)
+
+
+class TestCaseWithAssertCallsTest(mock_calls.TestCase):
+ def setUp(self):
+ self.adb = _DummyAdb()
+
+ def ShellError(self):
+ def action(cmd):
+ raise ValueError('(device %s) command %r is not nice' % (self.adb, cmd))
+ return action
+
+ def get_answer(self):
+ logging.debug("called 'get_answer' of %r object", self)
+ return 42
+
+ def echo(self, thing):
+ logging.debug("called 'echo' of %r object", self)
+ return thing
+
+ def testCallTarget_succeds(self):
+ self.assertEquals(self.adb.Shell,
+ self.call_target(self.call.adb.Shell))
+
+ def testCallTarget_failsExternal(self):
+ with self.assertRaises(ValueError):
+ self.call_target(mock.call.sys.getcwd)
+
+ def testCallTarget_failsUnknownAttribute(self):
+ with self.assertRaises(AttributeError):
+ self.call_target(self.call.adb.Run)
+
+ def testCallTarget_failsIntermediateCalls(self):
+ with self.assertRaises(AttributeError):
+ self.call_target(self.call.adb.RunShell('cmd').append)
+
+ def testPatchCall_method(self):
+ self.assertEquals(42, self.get_answer())
+ with self.patch_call(self.call.get_answer, return_value=123):
+ self.assertEquals(123, self.get_answer())
+ self.assertEquals(42, self.get_answer())
+
+ def testPatchCall_attribute_method(self):
+ with self.patch_call(self.call.adb.Shell, return_value='hello'):
+ self.assertEquals('hello', self.adb.Shell('echo hello'))
+
+ def testPatchCall_global(self):
+ with self.patch_call(mock.call.os.getcwd, return_value='/some/path'):
+ self.assertEquals('/some/path', os.getcwd())
+
+ def testPatchCall_withSideEffect(self):
+ with self.patch_call(self.call.adb.Shell, side_effect=ValueError):
+ with self.assertRaises(ValueError):
+ self.adb.Shell('echo hello')
+
+ def testAssertCalls_succeeds_simple(self):
+ self.assertEquals(42, self.get_answer())
+ with self.assertCall(self.call.get_answer(), 123):
+ self.assertEquals(123, self.get_answer())
+ self.assertEquals(42, self.get_answer())
+
+ def testAssertCalls_succeeds_multiple(self):
+ with self.assertCalls(
+ (mock.call.os.getcwd(), '/some/path'),
+ (self.call.echo('hello'), 'hello'),
+ (self.call.get_answer(), 11),
+ self.call.adb.Push('this_file', 'that_file'),
+ (self.call.get_answer(), 12)):
+ self.assertEquals(os.getcwd(), '/some/path')
+ self.assertEquals('hello', self.echo('hello'))
+ self.assertEquals(11, self.get_answer())
+ self.adb.Push('this_file', 'that_file')
+ self.assertEquals(12, self.get_answer())
+
+ def testAsserCalls_succeeds_withAction(self):
+ with self.assertCall(
+ self.call.adb.Shell('echo hello'), self.ShellError()):
+ with self.assertRaises(ValueError):
+ self.adb.Shell('echo hello')
+
+ def testAssertCalls_fails_tooManyCalls(self):
+ with self.assertRaises(AssertionError):
+ with self.assertCalls(self.call.adb.IsOnline()):
+ self.adb.IsOnline()
+ self.adb.IsOnline()
+
+ def testAssertCalls_fails_tooFewCalls(self):
+ with self.assertRaises(AssertionError):
+ with self.assertCalls(self.call.adb.IsOnline()):
+ pass
+
+ def testAssertCalls_succeeds_extraCalls(self):
+ # we are not watching Reboot, so the assertion succeeds
+ with self.assertCalls(self.call.adb.IsOnline()):
+ self.adb.IsOnline()
+ self.adb.Reboot()
+
+ def testAssertCalls_fails_extraCalls(self):
+ self.watchCalls([self.call.adb.Reboot])
+ # this time we are also watching Reboot, so the assertion fails
+ with self.assertRaises(AssertionError):
+ with self.assertCalls(self.call.adb.IsOnline()):
+ self.adb.IsOnline()
+ self.adb.Reboot()
+
+ def testAssertCalls_succeeds_NoCalls(self):
+ self.watchMethodCalls(self.call.adb) # we are watching all adb methods
+ with self.assertCalls():
+ pass
+
+ def testAssertCalls_fails_NoCalls(self):
+ self.watchMethodCalls(self.call.adb)
+ with self.assertRaises(AssertionError):
+ with self.assertCalls():
+ self.adb.IsOnline()
+
+
+if __name__ == '__main__':
+ logging.getLogger().setLevel(logging.DEBUG)
+ unittest.main(verbosity=2)
+
diff --git a/build/android/test_runner.py b/build/android/test_runner.py
index 2e39c3c..d5c9b35 100755
--- a/build/android/test_runner.py
+++ b/build/android/test_runner.py
@@ -64,6 +64,11 @@
group.add_option('--build-directory', dest='build_directory',
help=('Path to the directory in which build files are'
' located (should not include build type)'))
+ group.add_option('--output-directory', dest='output_directory',
+ help=('Path to the directory in which build files are'
+ ' located (must include build type). This will take'
+ ' precedence over --debug, --release and'
+ ' --build-directory'))
group.add_option('--num_retries', dest='num_retries', type='int',
default=2,
help=('Number of retries for a test before '
@@ -95,6 +100,8 @@
constants.SetBuildType(options.build_type)
if options.build_directory:
constants.SetBuildDirectory(options.build_directory)
+ if options.output_directory:
+ constants.SetOutputDirectort(options.output_directory)
if options.environment not in constants.VALID_ENVIRONMENTS:
error_func('--environment must be one of: %s' %
', '.join(constants.VALID_ENVIRONMENTS))
diff --git a/build/common.gypi b/build/common.gypi
index 753abfe..3ddb01a 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -505,25 +505,9 @@
# tool explicitly.
# See third_party/cld_2/cld_2.gyp for more information.
# 0: Small tables, lower accuracy
- # 1: Medium tables, medium accuracy
# 2: Large tables, high accuracy
'cld2_table_size%': 2,
- # The data acquisition mode for CLD2. Possible values are:
- # static: CLD2 data is statically linked to the executable.
- # standalone: CLD2 data is provided in a standalone file that is
- # bundled with the executable.
- # component: CLD2 data is provided as a Chrome "component" and is
- # downloaded via the component updater.
- #
- # For more information on switching the CLD2 data source, see:
- # https://sites.google.com/a/chromium.org/dev/developers/how-tos/compact-language-detector-cld-data-source-configuration
- #
- # This string will be exposed in chrome://translate-internals under the
- # heading "CLD Data Source". This allows easy determination of which
- # data source the browser was built with.
- 'cld2_data_source%': 'static',
-
# Enable spell checker.
'enable_spellcheck%': 1,
@@ -564,12 +548,6 @@
# components.
'use_icu_alternatives_on_android%': 0,
- # XInput2 multitouch support is enabled by default (use_xi2_mt=2).
- # Setting to zero value disables XI2 MT. When XI2 MT is enabled,
- # the input value also defines the required XI2 minor minimum version.
- # For example, use_xi2_mt=2 means XI2.2 or above version is required.
- 'use_xi2_mt%': 2,
-
# Use of precompiled headers on Windows.
#
# This variable may be explicitly set to 1 (enabled) or 0
@@ -813,6 +791,7 @@
'enable_basic_printing%': 0,
'enable_print_preview%': 0,
'enable_session_service%': 0,
+ 'enable_spellcheck%': 0,
'enable_themes%': 0,
'enable_webrtc%': 0,
'notifications%': 0,
@@ -1113,7 +1092,6 @@
'chromecast%': '<(chromecast)',
'enable_viewport%': '<(enable_viewport)',
'enable_hidpi%': '<(enable_hidpi)',
- 'use_xi2_mt%':'<(use_xi2_mt)',
'image_loader_extension%': '<(image_loader_extension)',
'fastbuild%': '<(fastbuild)',
'dont_embed_build_metadata%': '<(dont_embed_build_metadata)',
@@ -1186,7 +1164,6 @@
'enable_google_now%': '<(enable_google_now)',
'cld_version%': '<(cld_version)',
'cld2_table_size%': '<(cld2_table_size)',
- 'cld2_data_source%': '<(cld2_data_source)',
'enable_captive_portal_detection%': '<(enable_captive_portal_detection)',
'disable_file_support%': '<(disable_file_support)',
'disable_ftp_support%': '<(disable_ftp_support)',
@@ -1488,7 +1465,6 @@
# IPC fuzzer is disabled by default.
'enable_ipc_fuzzer%': 0,
-
# Force disable libstdc++ debug mode.
'disable_glibcxx_debug%': 0,
@@ -1509,6 +1485,12 @@
'ozone_platform_ozonex%': 0,
'ozone_platform_test%': 0,
+ # Whether the browser is non-native (using Views Toolkit) on Mac.
+ 'mac_views_browser%': 0,
+
+ # Experiment: http://crbug.com/426914
+ 'envoy%': 0,
+
'conditions': [
['buildtype=="Official"', {
# Continue to embed build meta data in Official builds, basically the
@@ -2070,8 +2052,11 @@
],
}],
['OS=="android"', {
- 'grit_defines': ['-t', 'android',
- '-E', 'ANDROID_JAVA_TAGGED_ONLY=true'],
+ 'grit_defines': [
+ '-t', 'android',
+ '-E', 'ANDROID_JAVA_TAGGED_ONLY=true',
+ '--no-output-all-resource-defines',
+ ],
}],
['OS=="mac" or OS=="ios"', {
'grit_defines': ['-D', 'scale_factors=2x'],
@@ -2080,7 +2065,8 @@
'grit_defines': [
'-t', 'ios',
# iOS uses a whitelist to filter resources.
- '-w', '<(DEPTH)/build/ios/grit_whitelist.txt'
+ '-w', '<(DEPTH)/build/ios/grit_whitelist.txt',
+ '--no-output-all-resource-defines',
],
# Enable host builds when generating with ninja-ios.
@@ -2489,7 +2475,7 @@
'mac_debug_optimization%': '0', # Use -O0 unless overridden
}, {
# See http://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Optimize-Options.html
- 'mac_release_optimization%': '3', # Use -O3 unless overridden
+ 'mac_release_optimization%': '2', # Use -O2 unless overridden
'mac_debug_optimization%': '0', # Use -O0 unless overridden
}],
['OS=="android"', {
@@ -2527,9 +2513,6 @@
# code generated by flex (used in angle) contains that keyword.
# http://crbug.com/255186
'-Wno-deprecated-register',
-
- # TODO(hans): Clean this up. Or disable with finer granularity.
- '-Wno-unused-local-typedef',
],
},
'includes': [ 'set_clang_warning_flags.gypi', ],
@@ -2635,9 +2618,6 @@
['enable_pre_sync_backup==1', {
'defines': ['ENABLE_PRE_SYNC_BACKUP'],
}],
- ['use_xi2_mt!=0 and use_x11==1', {
- 'defines': ['USE_XI2_MT=<(use_xi2_mt)'],
- }],
['image_loader_extension==1', {
'defines': ['IMAGE_LOADER_EXTENSION=1'],
}],
@@ -2925,11 +2905,6 @@
['cld_version!=0', {
'defines': ['CLD_VERSION=<(cld_version)'],
}],
- ['cld_version==2', {
- # This is used to populate the "CLD Data Source" field in:
- # chrome://translate-internals
- 'defines': ['CLD2_DATA_SOURCE=<(cld2_data_source)'],
- }],
['enable_basic_printing==1 or enable_print_preview==1', {
# Convenience define for ENABLE_BASIC_PRINTING || ENABLE_PRINT_PREVIEW.
'defines': ['ENABLE_PRINTING=1'],
@@ -4209,6 +4184,13 @@
'-fsanitize=undefined',
# -fsanitize=vptr is incompatible with -fno-rtti.
'-fno-sanitize=vptr',
+ # Employ the experimental PBQP register allocator to avoid
+ # slow compilation on files with too many basic blocks.
+ # See http://crbug.com/426271.
+ '-mllvm -regalloc=pbqp',
+ # Speculatively use coalescing to slightly improve the code
+ # generated by PBQP regallocator. May increase compile time.
+ '-mllvm -pbqp-coalescing',
],
'ldflags': [
'-fsanitize=undefined',
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index ecbef88..c51709c 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -121,9 +121,6 @@
}
if (use_x11) {
defines += [ "USE_X11=1" ]
- if (use_xi2_mt > 0) {
- defines += [ "USE_XI2_MT=$use_xi2_mt" ]
- }
}
if (use_allocator != "tcmalloc") {
defines += [ "NO_TCMALLOC" ]
diff --git a/build/config/allocator.gni b/build/config/allocator.gni
index acc21d1..2d2fed1 100644
--- a/build/config/allocator.gni
+++ b/build/config/allocator.gni
@@ -1,8 +1,9 @@
# 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.
-
-if (is_android || cpu_arch == "mipsel" || is_mac || is_asan) {
+
+# TODO(GYP): Make tcmalloc work on win.
+if (is_android || cpu_arch == "mipsel" || is_mac || is_asan || is_win) {
_default_allocator = "none"
} else {
_default_allocator = "tcmalloc"
diff --git a/build/config/android/internal_rules.gni b/build/config/android/internal_rules.gni
index de29cce..d6711b8 100644
--- a/build/config/android/internal_rules.gni
+++ b/build/config/android/internal_rules.gni
@@ -260,6 +260,7 @@
_resource_packaged_apk_path = _base_apk_path + ".ap_"
_packaged_apk_path = _base_apk_path + ".unfinished.apk"
+ _shared_resources = defined(invoker.shared_resources) && invoker.shared_resources
_configuration_name = "Release"
@@ -295,6 +296,10 @@
"--apk-path", rebase_path(_resource_packaged_apk_path, root_build_dir),
]
+
+ if (_shared_resources) {
+ args += ["--shared-resources"]
+ }
}
action("${target_name}__package") {
@@ -718,6 +723,11 @@
args += ["--v14-verify-only"]
}
+ if (defined(invoker.shared_resources) &&
+ invoker.shared_resources) {
+ args += ["--shared-resources"]
+ }
+
if (defined(invoker.all_resources_zip_path)) {
all_resources_zip = invoker.all_resources_zip_path
outputs += [ all_resources_zip ]
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 9c9287d..d28c481 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -477,6 +477,8 @@
# that the resources are v14-compliant (see
# build/android/gyp/generate_v14_compatible_resources.py). Defaults to
# false.
+# shared_resources: If true make a resource package that can be loaded by a
+# different application at runtime to access the package's resources.
#
# Example
# android_resources("foo_resources") {
@@ -518,6 +520,10 @@
if (defined(invoker.v14_verify_only)) {
v14_verify_only = invoker.v14_verify_only
}
+
+ if (defined(invoker.shared_resources)) {
+ shared_resources = invoker.shared_resources
+ }
}
group(target_name) {
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 3d1b341..1c51cd0 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -745,9 +745,6 @@
# TODO(thakis): Remove, http://crbug.com/263960
"-Wno-reserved-user-defined-literal",
-
- # TODO(hans): Clean this up. Or disable with finer granularity.
- "-Wno-unused-local-typedef",
]
}
if (gcc_version >= 48) {
@@ -918,15 +915,28 @@
cflags = common_optimize_on_cflags
ldflags = common_optimize_on_ldflags
if (is_win) {
+ cflags -= [
+ "/Os",
+ ]
cflags += [
"/Ot", # Favor speed over size.
- "/GL", # Whole program optimization.
- # Disable Warning 4702 ("Unreachable code") for the WPO/PGO builds.
- # Probably anything that this would catch that wouldn't be caught in a
- # normal build isn't going to actually be a bug, so the incremental value
- # of C4702 for PGO builds is likely very small.
- "/wd4702",
]
+ if (is_official_build) {
+ # TODO(GYP): TODO(dpranke): Should these only be on in an official
+ # build, or on all the time? For now we'll require official build so
+ # that the compile is clean.
+ cflags += [
+ "/GL", # Whole program optimization.
+ # Disable Warning 4702 ("Unreachable code") for the WPO/PGO builds.
+ # Probably anything that this would catch that wouldn't be caught in a
+ # normal build isn't going to actually be a bug, so the incremental
+ # value of C4702 for PGO builds is likely very small.
+ "/wd4702",
+ ]
+ ldflags += [
+ "/LTCG",
+ ]
+ }
} else {
cflags += [
"-O2",
diff --git a/build/config/features.gni b/build/config/features.gni
index a395b40..575a89c 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -77,9 +77,8 @@
use_seccomp_bpf = (is_linux || is_android) &&
(cpu_arch == "x86" || cpu_arch == "x64" || cpu_arch == "arm")
-# Enable notifications everywhere except Android/iOS.
-# Android is http://crbug.com/115320
-enable_notifications = !is_android && !is_ios
+# Enable notifications everywhere except iOS.
+enable_notifications = !is_ios
# TODO(brettw) this should be moved to net and only dependents get this define.
disable_ftp_support = is_ios
@@ -105,17 +104,6 @@
enable_configuration_policy = true
-# The data acquisition mode for CLD2. Possible values are:
-# static: CLD2 data is statically linked to the executable.
-# standalone: CLD2 data is provided in a standalone file that is
-# bundled with the executable.
-# component: CLD2 data is provided as a Chrome "component" and is
-# downloaded via the component updater.
-#
-# For more information on switching the CLD2 data source, see:
-# https://sites.google.com/a/chromium.org/dev/developers/how-tos/compact-language-detector-cld-data-source-configuration
-cld2_data_source = "static"
-
# Enables support for background apps.
enable_background = !is_ios && !is_android
diff --git a/build/config/linux/pkg-config.py b/build/config/linux/pkg-config.py
index 60304d4..a4f4703 100644
--- a/build/config/linux/pkg-config.py
+++ b/build/config/linux/pkg-config.py
@@ -25,6 +25,10 @@
#
# When using a sysroot, you must also specify the architecture via
# "-a <arch>" where arch is either "x86" or "x64".
+#
+# Additionally, you can specify the option --atleast-version. This will skip
+# the normal outputting of a dictionary and instead print true or false,
+# depending on the return value of pkg-config for the given package.
# If this is run on non-Linux platforms, just return nothing and indicate
# success. This allows us to "kind of emulate" a Linux build from other
@@ -106,6 +110,8 @@
parser.add_option('-v', action='append', dest='strip_out', type='string')
parser.add_option('-s', action='store', dest='sysroot', type='string')
parser.add_option('-a', action='store', dest='arch', type='string')
+parser.add_option('--atleast-version', action='store',
+ dest='atleast_version', type='string')
(options, args) = parser.parse_args()
# Make a list of regular expressions to strip out.
@@ -120,6 +126,18 @@
else:
prefix = ''
+if options.atleast_version:
+ # When asking for the return value, just run pkg-config and print the return
+ # value, no need to do other work.
+ if not subprocess.call([options.pkg_config,
+ "--atleast-version=" + options.atleast_version] +
+ args,
+ env=os.environ):
+ print "true"
+ else:
+ print "false"
+ sys.exit(0)
+
try:
flag_string = subprocess.check_output(
[ options.pkg_config, "--cflags", "--libs-only-l", "--libs-only-L" ] +
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni
index 378863e..687afc5 100644
--- a/build/config/linux/pkg_config.gni
+++ b/build/config/linux/pkg_config.gni
@@ -33,25 +33,29 @@
pkg_config = ""
}
+pkg_config_script = "//build/config/linux/pkg-config.py"
+
+# Define the args we pass to the pkg-config script for other build files that
+# need to invoke it manually.
+if (sysroot != "") {
+ # Pass the sysroot if we're using one (it requires the CPU arch also).
+ pkg_config_args = ["-s", sysroot, "-a", cpu_arch]
+} else if (pkg_config != "") {
+ pkg_config_args = ["-p", pkg_config]
+} else {
+ pkg_config_args = []
+}
+
template("pkg_config") {
assert(defined(invoker.packages),
"Variable |packages| must be defined to be a list in pkg_config.")
config(target_name) {
- if (sysroot != "") {
- # Pass the sysroot if we're using one (it requires the CPU arch also).
- args = ["-s", sysroot, "-a", cpu_arch] + invoker.packages
- } else if (pkg_config != "") {
- args = ["-p", pkg_config] + invoker.packages
- } else {
- args = invoker.packages
- }
-
+ args = pkg_config_args + invoker.packages
if (defined(invoker.extra_args)) {
args += invoker.extra_args
}
- pkgresult = exec_script("//build/config/linux/pkg-config.py",
- args, "value")
+ pkgresult = exec_script(pkg_config_script, args, "value")
include_dirs = pkgresult[0]
cflags = pkgresult[1]
diff --git a/build/config/ui.gni b/build/config/ui.gni
index f23cd00..dc7a059 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -27,10 +27,6 @@
# of a replacement for GDI or GTK.
use_aura = is_win || is_linux
- # XInput2 multitouch support. Zero means disabled, nonzero indicates the
- # minimum XI2 version. For example, use_xi2_mt=2 means XI2.2 or above.
- use_xi2_mt = 2
-
# True means the UI is built using the "views" framework.
toolkit_views = is_win || is_chromeos || use_aura
}
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index 39e5628..aa579ce 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -1,17 +1,11 @@
IDR_ABOUT_DOM_DISTILLER_CSS
IDR_ABOUT_DOM_DISTILLER_HTML
IDR_ABOUT_DOM_DISTILLER_JS
+IDR_ABOUT_STATS_HTML
+IDR_ABOUT_STATS_JS
IDR_ABOUT_VERSION_CSS
IDR_ABOUT_VERSION_HTML
IDR_ABOUT_VERSION_JS
-IDR_APPLE_FLAGS_HTML
-IDR_AUTOFILL_CC_AMEX
-IDR_AUTOFILL_CC_DINERS
-IDR_AUTOFILL_CC_DISCOVER
-IDR_AUTOFILL_CC_GENERIC
-IDR_AUTOFILL_CC_JCB
-IDR_AUTOFILL_CC_MASTERCARD
-IDR_AUTOFILL_CC_VISA
IDR_CONTEXTUAL_SEARCH_PROMO_HTML
IDR_CONTROLLED_SETTING_MANDATORY
IDR_CRASHES_HTML
@@ -22,6 +16,10 @@
IDR_DEFAULT_FAVICON_32
IDR_DEFAULT_FAVICON_64
IDR_DIR_HEADER_HTML
+IDR_DISTILLER_CSS
+IDR_DISTILLER_JS
+IDR_DOM_DISTILLER_VIEWER_HTML
+IDR_DOM_DISTILLER_VIEWER_JS
IDR_FLAGS_FAVICON
IDR_FLAGS_HTML
IDR_FLAGS_JS
@@ -34,11 +32,11 @@
IDR_INCOGNITO_TAB_HTML
IDR_INFOBAR_AUTOFILL_CC
IDR_INFOBAR_AUTOLOGIN
-IDR_INFOBAR_GEOLOCATION
IDR_INFOBAR_RESTORE_SESSION
IDR_INFOBAR_SAVE_PASSWORD
IDR_INFOBAR_TRANSLATE_IOS
IDR_INFOBAR_WARNING
+IDR_IS_DISTILLABLE_JS
IDR_LOCATION_BAR_HTTP
IDR_NET_ERROR_HTML
IDR_NET_EXPORT_HTML
@@ -51,6 +49,7 @@
IDR_OMNIBOX_CLEAR_OTR_IOS
IDR_OMNIBOX_CLEAR_OTR_PRESSED_IOS
IDR_OMNIBOX_CLEAR_PRESSED_IOS
+IDR_OMNIBOX_EXTENSION_APP
IDR_OMNIBOX_HISTORY
IDR_OMNIBOX_HISTORY_INCOGNITO
IDR_OMNIBOX_HTTP
@@ -68,6 +67,7 @@
IDR_OMNIBOX_SEARCH_SECURED
IDR_OMNIBOX_STAR
IDR_OMNIBOX_STAR_INCOGNITO
+IDR_OTHER_DEVICES_JS
IDR_PAGEINFO_BAD
IDR_PAGEINFO_GOOD
IDR_PAGEINFO_INFO
@@ -76,7 +76,6 @@
IDR_POLICY_CSS
IDR_POLICY_HTML
IDR_POLICY_JS
-IDR_PRERENDER
IDR_PRINTER_FAVICON
IDR_PRODUCT_LOGO_26
IDR_SAD_FAVICON
@@ -84,8 +83,6 @@
IDR_SECURITY_INTERSTITIAL_HTML
IDR_SIGNIN_INTERNALS_INDEX_HTML
IDR_SIGNIN_INTERNALS_INDEX_JS
-IDR_SSL_BLOCKING_HTML
-IDR_SSL_ROAD_BLOCK_HTML
IDR_SYNC_INTERNALS_ABOUT_JS
IDR_SYNC_INTERNALS_CHROME_SYNC_JS
IDR_SYNC_INTERNALS_DATA_JS
@@ -100,84 +97,9 @@
IDR_TOOLBAR_SHADOW_FULL_BLEED
IDR_TRANSLATE_JS
IDR_UBER_UTILS_JS
-IDR_WEBUI_CSS_ALERT_OVERLAY
-IDR_WEBUI_CSS_APPS_COMMON
-IDR_WEBUI_CSS_APPS_TOPBUTTON_BAR
-IDR_WEBUI_CSS_BUBBLE
-IDR_WEBUI_CSS_BUBBLE_BUTTON
-IDR_WEBUI_CSS_BUTTER_BAR
-IDR_WEBUI_CSS_CHROME
-IDR_WEBUI_CSS_DIALOGS
-IDR_WEBUI_CSS_LIST
-IDR_WEBUI_CSS_MENU
-IDR_WEBUI_CSS_MENU_BUTTON
-IDR_WEBUI_CSS_OVERLAY
-IDR_WEBUI_CSS_SPINNER
-IDR_WEBUI_CSS_TABLE
-IDR_WEBUI_CSS_TABS
-IDR_WEBUI_CSS_THROBBER
-IDR_WEBUI_CSS_TRASH
-IDR_WEBUI_CSS_TREE
-IDR_WEBUI_CSS_TREE_JS
-IDR_WEBUI_CSS_UI_ACCOUNT_TWEAKS
-IDR_WEBUI_CSS_WIDGETS
-IDR_WEBUI_I18N_PROCESS_JS
IDR_WEBUI_I18N_TEMPLATE2_JS
-IDR_WEBUI_I18N_TEMPLATE_JS
-IDR_WEBUI_IMAGES_SELECT
IDR_WEBUI_JSTEMPLATE_JS
-IDR_WEBUI_JS_ASSERT
-IDR_WEBUI_JS_CR
-IDR_WEBUI_JS_CR_EVENT_TARGET
-IDR_WEBUI_JS_CR_LINK_CONTROLLER
-IDR_WEBUI_JS_CR_UI
-IDR_WEBUI_JS_CR_UI_ALERT_OVERLAY
-IDR_WEBUI_JS_CR_UI_ARRAY_DATA_MODEL
-IDR_WEBUI_JS_CR_UI_AUTOCOMPLETE_LIST
-IDR_WEBUI_JS_CR_UI_BUBBLE
-IDR_WEBUI_JS_CR_UI_BUBBLE_BUTTON
-IDR_WEBUI_JS_CR_UI_CARD_SLIDER
-IDR_WEBUI_JS_CR_UI_COMMAND
-IDR_WEBUI_JS_CR_UI_CONTEXT_MENU_BUTTON
-IDR_WEBUI_JS_CR_UI_CONTEXT_MENU_HANDLER
-IDR_WEBUI_JS_CR_UI_DIALOGS
-IDR_WEBUI_JS_CR_UI_DRAG_WRAPPER
-IDR_WEBUI_JS_CR_UI_FOCUS_GRID
-IDR_WEBUI_JS_CR_UI_FOCUS_MANAGER
-IDR_WEBUI_JS_CR_UI_FOCUS_OUTLINE_MANAGER
-IDR_WEBUI_JS_CR_UI_FOCUS_ROW
-IDR_WEBUI_JS_CR_UI_GRID
-IDR_WEBUI_JS_CR_UI_LIST
-IDR_WEBUI_JS_CR_UI_LIST_ITEM
-IDR_WEBUI_JS_CR_UI_LIST_SELECTION_CONTROLLER
-IDR_WEBUI_JS_CR_UI_LIST_SELECTION_MODEL
-IDR_WEBUI_JS_CR_UI_LIST_SINGLE_SELECTION_MODEL
-IDR_WEBUI_JS_CR_UI_MENU
-IDR_WEBUI_JS_CR_UI_MENU_BUTTON
-IDR_WEBUI_JS_CR_UI_MENU_ITEM
-IDR_WEBUI_JS_CR_UI_OVERLAY
-IDR_WEBUI_JS_CR_UI_PAGE_MANAGER_PAGE
-IDR_WEBUI_JS_CR_UI_PAGE_MANAGER_PAGE_MANAGER
-IDR_WEBUI_JS_CR_UI_POSITION_UTIL
-IDR_WEBUI_JS_CR_UI_REPEATING_BUTTON
-IDR_WEBUI_JS_CR_UI_SPLITTER
-IDR_WEBUI_JS_CR_UI_TABLE
-IDR_WEBUI_JS_CR_UI_TABLE_COLUMN
-IDR_WEBUI_JS_CR_UI_TABLE_COLUMN_MODEL
-IDR_WEBUI_JS_CR_UI_TABLE_HEADER
-IDR_WEBUI_JS_CR_UI_TABLE_LIST
-IDR_WEBUI_JS_CR_UI_TABLE_SPLITTER
-IDR_WEBUI_JS_CR_UI_TABS
-IDR_WEBUI_JS_CR_UI_TOUCH_HANDLER
-IDR_WEBUI_JS_CR_UI_TREE
-IDR_WEBUI_JS_EVENT_TRACKER
-IDR_WEBUI_JS_I18N_TEMPLATE_NO_PROCESS
IDR_WEBUI_JS_LOAD_TIME_DATA
-IDR_WEBUI_JS_MEDIA_COMMON
-IDR_WEBUI_JS_PARSE_HTML_SUBSET
-IDR_WEBUI_JS_UI_ACCOUNT_TWEAKS
-IDR_WEBUI_JS_UTIL
-IDR_WEBUI_JS_WEBUI_RESOURCE_TEST
IDS_ABOUT_MAC
IDS_ABOUT_VERSION_COMMAND_LINE
IDS_ABOUT_VERSION_COMPANY_NAME
@@ -1151,6 +1073,7 @@
IDS_SYNC_UNRECOVERABLE_ERROR_HELP_URL
IDS_SYNC_UPGRADE_CLIENT
IDS_SYSTEM_FLAGS_OWNER_ONLY
+IDS_TERMS_HTML
IDS_TIME_DAYS_1ST_DEFAULT
IDS_TIME_DAYS_1ST_FEW
IDS_TIME_DAYS_1ST_MANY
diff --git a/build/java_apk.gypi b/build/java_apk.gypi
index 18e6ccf..4243554 100644
--- a/build/java_apk.gypi
+++ b/build/java_apk.gypi
@@ -44,6 +44,8 @@
# shared library to be included in this apk. A stripped copy of the
# library will be included in the apk.
# resource_dir - The directory for resources.
+# shared_resources - Make a resource package that can be loaded by a different
+# application at runtime to access the package's resources.
# R_package - A custom Java package to generate the resource file R.java in.
# By default, the package given in AndroidManifest.xml will be used.
# use_chromium_linker - Enable the content dynamic linker that allows sharing the
@@ -126,6 +128,7 @@
'resource_zip_path': '<(intermediate_dir)/<(_target_name).resources.zip',
'resource_packaged_apk_name': '<(apk_name)-resources.ap_',
'resource_packaged_apk_path': '<(intermediate_dir)/<(resource_packaged_apk_name)',
+ 'shared_resources%': 0,
'unsigned_apk_path': '<(intermediate_dir)/<(apk_name)-unsigned.apk',
'final_apk_path%': '<(PRODUCT_DIR)/apks/<(apk_name).apk',
'incomplete_apk_path': '<(intermediate_dir)/<(apk_name)-incomplete.apk',
@@ -575,7 +578,10 @@
'additional_res_packages=': [],
}],
['res_v14_verify_only == 1', {
- 'process_resources_options': ['--v14-verify-only']
+ 'process_resources_options+': ['--v14-verify-only']
+ }],
+ ['shared_resources == 1', {
+ 'process_resources_options+': ['--shared-resources']
}],
],
},
@@ -825,10 +831,16 @@
'action_name': 'package_resources',
'message': 'packaging resources for <(_target_name)',
'variables': {
+ 'package_resources_options': [],
'package_resource_zip_input_paths': [
'<(resource_zip_path)',
'>@(dependencies_res_zip_paths)',
],
+ 'conditions': [
+ ['shared_resources == 1', {
+ 'package_resources_options+': ['--shared-resources']
+ }],
+ ],
},
'conditions': [
['is_test_apk == 1', {
@@ -868,6 +880,8 @@
'--no-compress', '<(extensions_to_not_compress)',
'--apk-path', '<(resource_packaged_apk_path)',
+
+ '<@(package_resources_options)',
],
},
{
diff --git a/build/landmines.py b/build/landmines.py
index 2ddf346..cb3bdab 100755
--- a/build/landmines.py
+++ b/build/landmines.py
@@ -54,6 +54,79 @@
return os.path.abspath(ret)
+def extract_gn_build_commands(build_ninja_file):
+ """Extracts from a build.ninja the commands to run GN.
+
+ The commands to run GN are the gn rule and build.ninja build step at the
+ top of the build.ninja file. We want to keep these when deleting GN builds
+ since we want to preserve the command-line flags to GN.
+
+ On error, returns the empty string."""
+ result = ""
+ with open(build_ninja_file, 'r') as f:
+ # Read until the second blank line. The first thing GN writes to the file
+ # is the "rule gn" and the second is the section for "build build.ninja",
+ # separated by blank lines.
+ num_blank_lines = 0
+ while num_blank_lines < 2:
+ line = f.readline()
+ if len(line) == 0:
+ return '' # Unexpected EOF.
+ result += line
+ if line[0] == '\n':
+ num_blank_lines = num_blank_lines + 1
+ return result
+
+def delete_build_dir(build_dir):
+ # GN writes a build.ninja.d file. Note that not all GN builds have args.gn.
+ build_ninja_d_file = os.path.join(build_dir, 'build.ninja.d')
+ if not os.path.exists(build_ninja_d_file):
+ shutil.rmtree(build_dir)
+ return
+
+ # GN builds aren't automatically regenerated when you sync. To avoid
+ # messing with the GN workflow, erase everything but the args file, and
+ # write a dummy build.ninja file that will automatically rerun GN the next
+ # time Ninja is run.
+ build_ninja_file = os.path.join(build_dir, 'build.ninja')
+ build_commands = extract_gn_build_commands(build_ninja_file)
+
+ try:
+ gn_args_file = os.path.join(build_dir, 'args.gn')
+ with open(gn_args_file, 'r') as f:
+ args_contents = f.read()
+ except IOError:
+ args_contents = ''
+
+ shutil.rmtree(build_dir)
+
+ # Put back the args file (if any).
+ os.mkdir(build_dir)
+ if args_contents != '':
+ with open(gn_args_file, 'w') as f:
+ f.write(args_contents)
+
+ # Write the build.ninja file sufficiently to regenerate itself.
+ with open(os.path.join(build_dir, 'build.ninja'), 'w') as f:
+ if build_commands != '':
+ f.write(build_commands)
+ else:
+ # Couldn't parse the build.ninja file, write a default thing.
+ f.write('''rule gn
+command = gn -q gen //out/%s/
+description = Regenerating ninja files
+
+build build.ninja: gn
+generator = 1
+depfile = build.ninja.d
+''' % (os.path.split(build_dir)[1]))
+
+ # Write a .d file for the build which references a nonexistant file. This
+ # will make Ninja always mark the build as dirty.
+ with open(build_ninja_d_file, 'w') as f:
+ f.write('build.ninja: nonexistant_file.gn\n')
+
+
def clobber_if_necessary(new_landmines):
"""Does the work of setting, planting, and triggering landmines."""
out_dir = get_build_dir(landmine_utils.builder())
@@ -82,7 +155,7 @@
if os.path.isfile(path):
os.unlink(path)
elif os.path.isdir(path):
- shutil.rmtree(path)
+ delete_build_dir(path)
# Save current set of landmines for next time.
with open(landmines_path, 'w') as f:
diff --git a/build/secondary/third_party/nss/BUILD.gn b/build/secondary/third_party/nss/BUILD.gn
index 30364d1..a285ca1 100644
--- a/build/secondary/third_party/nss/BUILD.gn
+++ b/build/secondary/third_party/nss/BUILD.gn
@@ -1159,6 +1159,10 @@
"USE_HW_AES",
"INTEL_GCM",
]
+ sources -= [
+ "nss/lib/freebl/mpi/mpi_amd64.c",
+ ]
+
} else if (cpu_arch == "x64") {
sources -= [
"nss/lib/freebl/intel-aes-x86-masm.asm",
diff --git a/build/tree_truth.sh b/build/tree_truth.sh
index 03d0523..617092d 100755
--- a/build/tree_truth.sh
+++ b/build/tree_truth.sh
@@ -87,9 +87,10 @@
# Print a summary of the last 10 commits for each repo.
tt_brief_summary() {
echo "@@@BUILD_STEP Brief summary of recent CLs in every branch@@@"
- for p in $@; do
- echo $project
- (cd $CHROME_SRC/../$p && git log -n 10 --format=" %H %s %an, %ad" | cat)
+ for project in $@; do
+ echo $project:
+ local full_path=$CHROME_SRC/../$project
+ (cd $full_path && git log -n 10 --format=" %H %s %an, %ad" | cat)
echo "================================================================="
done
}
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 78ed34c..526203f 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -145,4 +145,3 @@
Oh god the bots are red! I'm blind! Mmmm, cronuts.
If you stand on your head, you will get footprints in your hair.
-
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index f753895..3b3ed6d 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -64,6 +64,7 @@
"base/switches.h",
"base/tiling_data.cc",
"base/tiling_data.h",
+ "base/time_util.h",
"base/unique_notifier.cc",
"base/unique_notifier.h",
"base/util.h",
@@ -112,11 +113,14 @@
"debug/unittest_only_benchmark.h",
"debug/unittest_only_benchmark_impl.cc",
"debug/unittest_only_benchmark_impl.h",
+ "input/input_handler.cc",
"input/input_handler.h",
"input/page_scale_animation.cc",
"input/page_scale_animation.h",
"input/layer_selection_bound.cc",
"input/layer_selection_bound.h",
+ "input/scroll_elasticity_helper.cc",
+ "input/scroll_elasticity_helper.h",
"input/selection_bound_type.h",
"input/top_controls_manager.cc",
"input/top_controls_manager.h",
@@ -346,8 +350,6 @@
"resources/picture_layer_tiling_set.h",
"resources/picture_pile.cc",
"resources/picture_pile.h",
- "resources/picture_pile_base.cc",
- "resources/picture_pile_base.h",
"resources/picture_pile_impl.cc",
"resources/picture_pile_impl.h",
"resources/pixel_buffer_raster_worker_pool.cc",
@@ -532,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.h",
"test/fake_picture_pile_impl.cc",
"test/fake_picture_pile_impl.h",
"test/fake_proxy.cc",
diff --git a/cc/animation/animation.cc b/cc/animation/animation.cc
index e49cf1e..f5abfa0 100644
--- a/cc/animation/animation.cc
+++ b/cc/animation/animation.cc
@@ -9,6 +9,7 @@
#include "base/debug/trace_event.h"
#include "base/strings/string_util.h"
#include "cc/animation/animation_curve.h"
+#include "cc/base/time_util.h"
namespace {
@@ -154,17 +155,18 @@
return false;
return run_state_ == Running && iterations_ >= 0 &&
- iterations_ * curve_->Duration() / std::abs(playback_rate_) <=
- (monotonic_time + time_offset_ - start_time_ - total_paused_time_)
- .InSecondsF();
+ TimeUtil::Scale(curve_->Duration(),
+ iterations_ / std::abs(playback_rate_)) <=
+ (monotonic_time + time_offset_ - start_time_ - total_paused_time_);
}
bool Animation::InEffect(base::TimeTicks monotonic_time) const {
- return ConvertToActiveTime(monotonic_time) >= 0 ||
+ return ConvertToActiveTime(monotonic_time) >= base::TimeDelta() ||
(fill_mode_ == FillModeBoth || fill_mode_ == FillModeBackwards);
}
-double Animation::ConvertToActiveTime(base::TimeTicks monotonic_time) const {
+base::TimeDelta Animation::ConvertToActiveTime(
+ base::TimeTicks monotonic_time) const {
base::TimeTicks trimmed = monotonic_time + time_offset_;
// If we're paused, time is 'stuck' at the pause time.
@@ -181,56 +183,60 @@
needs_synchronized_start_time())
trimmed = base::TimeTicks() + time_offset_;
- return (trimmed - base::TimeTicks()).InSecondsF();
+ return (trimmed - base::TimeTicks());
}
-double Animation::TrimTimeToCurrentIteration(
+base::TimeDelta Animation::TrimTimeToCurrentIteration(
base::TimeTicks monotonic_time) const {
// Check for valid parameters
DCHECK(playback_rate_);
DCHECK_GE(iteration_start_, 0);
- double active_time = ConvertToActiveTime(monotonic_time);
- double start_offset = iteration_start_ * curve_->Duration();
+ base::TimeDelta active_time = ConvertToActiveTime(monotonic_time);
+ base::TimeDelta start_offset =
+ TimeUtil::Scale(curve_->Duration(), iteration_start_);
// Return start offset if we are before the start of the animation
- if (active_time < 0)
+ if (active_time < base::TimeDelta())
return start_offset;
-
// Always return zero if we have no iterations.
if (!iterations_)
- return 0;
+ return base::TimeDelta();
// Don't attempt to trim if we have no duration.
- if (curve_->Duration() <= 0)
- return 0;
+ if (curve_->Duration() <= base::TimeDelta())
+ return base::TimeDelta();
- double repeated_duration = iterations_ * curve_->Duration();
- double active_duration = repeated_duration / std::abs(playback_rate_);
+ base::TimeDelta repeated_duration =
+ TimeUtil::Scale(curve_->Duration(), iterations_);
+ base::TimeDelta active_duration =
+ TimeUtil::Scale(repeated_duration, 1.0 / std::abs(playback_rate_));
// Check if we are past active duration
if (iterations_ > 0 && active_time >= active_duration)
active_time = active_duration;
// Calculate the scaled active time
- double scaled_active_time;
+ base::TimeDelta scaled_active_time;
if (playback_rate_ < 0)
scaled_active_time =
- (active_time - active_duration) * playback_rate_ + start_offset;
+ TimeUtil::Scale((active_time - active_duration), playback_rate_) +
+ start_offset;
else
- scaled_active_time = active_time * playback_rate_ + start_offset;
+ scaled_active_time =
+ TimeUtil::Scale(active_time, playback_rate_) + start_offset;
// Calculate the iteration time
- double iteration_time;
+ base::TimeDelta iteration_time;
if (scaled_active_time - start_offset == repeated_duration &&
fmod(iterations_ + iteration_start_, 1) == 0)
iteration_time = curve_->Duration();
else
- iteration_time = fmod(scaled_active_time, curve_->Duration());
+ iteration_time = TimeUtil::Mod(scaled_active_time, curve_->Duration());
// Calculate the current iteration
int iteration;
- if (scaled_active_time <= 0)
+ if (scaled_active_time <= base::TimeDelta())
iteration = 0;
else if (iteration_time == curve_->Duration())
iteration = ceil(iteration_start_ + iterations_ - 1);
diff --git a/cc/animation/animation.h b/cc/animation/animation.h
index 7856497..80c0763 100644
--- a/cc/animation/animation.h
+++ b/cc/animation/animation.h
@@ -142,7 +142,8 @@
// Takes the given absolute time, and using the start time and the number
// of iterations, returns the relative time in the current iteration.
- double TrimTimeToCurrentIteration(base::TimeTicks monotonic_time) const;
+ base::TimeDelta TrimTimeToCurrentIteration(
+ base::TimeTicks monotonic_time) const;
scoped_ptr<Animation> CloneAndInitialize(RunState initial_run_state) const;
@@ -169,7 +170,7 @@
int group_id,
TargetProperty target_property);
- double ConvertToActiveTime(base::TimeTicks monotonic_time) const;
+ base::TimeDelta ConvertToActiveTime(base::TimeTicks monotonic_time) const;
scoped_ptr<AnimationCurve> curve_;
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h
index 57c42c7..c03feb8 100644
--- a/cc/animation/animation_curve.h
+++ b/cc/animation/animation_curve.h
@@ -6,6 +6,7 @@
#define CC_ANIMATION_ANIMATION_CURVE_H_
#include "base/memory/scoped_ptr.h"
+#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/filter_operations.h"
#include "ui/gfx/transform.h"
@@ -30,7 +31,7 @@
virtual ~AnimationCurve() {}
- virtual double Duration() const = 0;
+ virtual base::TimeDelta Duration() const = 0;
virtual CurveType Type() const = 0;
virtual scoped_ptr<AnimationCurve> Clone() const = 0;
diff --git a/cc/animation/animation_unittest.cc b/cc/animation/animation_unittest.cc
index b1592d6..2522f19 100644
--- a/cc/animation/animation_unittest.cc
+++ b/cc/animation/animation_unittest.cc
@@ -41,166 +41,257 @@
TEST(AnimationTest, TrimTimeZeroIterations) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeOneHalfIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1.5));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.9, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.9)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.9, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.9))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
anim->set_direction(Animation::Reverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ EXPECT_EQ(
+ 1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2));
anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoHalfIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2.5));
anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.50)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.50))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateReverseInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateReverseOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateReverseTwoIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2));
anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_start_time(TicksFromSecondsF(4));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeStartTimeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_start_time(TicksFromSecondsF(4));
anim->set_direction(Animation::Reverse);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(6.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
anim->set_start_time(TicksFromSecondsF(4));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeTimeOffsetReverse) {
@@ -208,20 +299,28 @@
anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
anim->set_start_time(TicksFromSecondsF(4));
anim->set_direction(Animation::Reverse);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeNegativeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeNegativeTimeOffsetReverse) {
@@ -229,103 +328,149 @@
anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
anim->set_direction(Animation::Reverse);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(5.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePauseResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.5));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimePauseResumeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_direction(Animation::Reverse);
anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.25));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75)));
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeSuspendResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
anim->Suspend(TicksFromSecondsF(0.5));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
anim->Resume(TicksFromSecondsF(1024));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeSuspendResumeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_direction(Animation::Reverse);
anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
anim->Suspend(TicksFromSecondsF(0.75));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
anim->Resume(TicksFromSecondsF(1024));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.25)));
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
+ .InSecondsF());
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeZeroDuration) {
scoped_ptr<Animation> anim(CreateAnimation(0, 0));
anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimeStarting) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
anim->SetRunState(Animation::Starting, TicksFromSecondsF(0.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_start_time(TicksFromSecondsF(1.0));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeNeedsSynchronizedStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
anim->set_needs_synchronized_start_time(true);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_time_offset(TimeDelta::FromMilliseconds(2000));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
anim->set_start_time(TicksFromSecondsF(1.0));
anim->set_needs_synchronized_start_time(false);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(3.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
}
TEST(AnimationTest, IsFinishedAtZeroIterations) {
@@ -437,223 +582,362 @@
TEST(AnimationTest, TrimTimePlaybackNormal) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, 1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackSlow) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, 0.5));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFast) {
scoped_ptr<Animation> anim(CreateAnimation(1, 4, 2));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackNormalReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 2, -1));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackSlowReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 2, -0.5));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(1.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3)));
- EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(1.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3)).InSecondsF());
+ EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFastReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 2, -2));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFastInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1, 4, 4));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.0)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.5)));
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.0))
+ .InSecondsF());
+ EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1000.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackNormalDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, -1));
anim->set_direction(Animation::Reverse);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
}
TEST(AnimationTest, TrimTimePlaybackFastDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 4, -2));
anim->set_direction(Animation::Reverse);
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(
+ 0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
+ EXPECT_EQ(
+ 1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)).InSecondsF());
+ EXPECT_EQ(
+ 2, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)).InSecondsF());
+ EXPECT_EQ(
+ 3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)).InSecondsF());
+ EXPECT_EQ(
+ 4, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)).InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFast) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastReverse) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, -2));
anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
}
TEST(AnimationTest,
TrimTimeAlternateReverseThreeIterationsPlaybackFastAlternateReverse) {
scoped_ptr<Animation> anim(CreateAnimation(3, 2, -2));
anim->set_direction(Animation::AlternateReverse);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.25)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.75))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.25))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.75))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.25))
+ .InSecondsF());
}
TEST(AnimationTest,
TrimTimeAlternateReverseTwoIterationsPlaybackNormalAlternate) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, -1));
anim->set_direction(Animation::Alternate);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeIterationStart) {
scoped_ptr<Animation> anim(CreateAnimation(2, 1, 1));
anim->set_iteration_start(0.5);
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeIterationStartAlternate) {
scoped_ptr<Animation> anim(CreateAnimation(2, 1, 1));
anim->set_direction(Animation::Alternate);
anim->set_iteration_start(0.3);
- EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.8, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.7)));
- EXPECT_EQ(0.7, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.2)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.7)));
+ EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.8, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.7))
+ .InSecondsF());
+ EXPECT_EQ(0.7, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.2))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.7))
+ .InSecondsF());
}
TEST(AnimationTest, TrimTimeIterationStartAlternateThreeIterations) {
scoped_ptr<Animation> anim(CreateAnimation(3, 1, 1));
anim->set_direction(Animation::Alternate);
anim->set_iteration_start(1);
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.5))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.5))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
}
TEST(AnimationTest,
@@ -661,11 +945,16 @@
scoped_ptr<Animation> anim(CreateAnimation(3, 1, -1));
anim->set_direction(Animation::Alternate);
anim->set_iteration_start(1);
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0)));
- EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0)));
- EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5)));
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1.0))
+ .InSecondsF());
+ EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(2.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.0))
+ .InSecondsF());
+ EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(3.5))
+ .InSecondsF());
}
TEST(AnimationTest, InEffectFillMode) {
diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc
index 333a5c9..a6dc8c5 100644
--- a/cc/animation/keyframed_animation_curve.cc
+++ b/cc/animation/keyframed_animation_curve.cc
@@ -205,8 +205,9 @@
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedColorAnimationCurve::Duration() const {
- return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedColorAnimationCurve::Duration() const {
+ return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+ keyframes_.front()->Time());
}
scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
@@ -252,8 +253,9 @@
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedFloatAnimationCurve::Duration() const {
- return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedFloatAnimationCurve::Duration() const {
+ return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+ keyframes_.front()->Time());
}
scoped_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const {
@@ -297,8 +299,9 @@
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedTransformAnimationCurve::Duration() const {
- return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedTransformAnimationCurve::Duration() const {
+ return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+ keyframes_.front()->Time());
}
scoped_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone() const {
@@ -408,8 +411,9 @@
InsertKeyframe(keyframe.Pass(), &keyframes_);
}
-double KeyframedFilterAnimationCurve::Duration() const {
- return keyframes_.back()->Time() - keyframes_.front()->Time();
+base::TimeDelta KeyframedFilterAnimationCurve::Duration() const {
+ return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
+ keyframes_.front()->Time());
}
scoped_ptr<AnimationCurve> KeyframedFilterAnimationCurve::Clone() const {
diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h
index a6e6740..ff746fe 100644
--- a/cc/animation/keyframed_animation_curve.h
+++ b/cc/animation/keyframed_animation_curve.h
@@ -5,6 +5,7 @@
#ifndef CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
#define CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
+#include "base/time/time.h"
#include "cc/animation/animation_curve.h"
#include "cc/animation/timing_function.h"
#include "cc/animation/transform_operations.h"
@@ -126,7 +127,7 @@
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// BackgrounColorAnimationCurve implementation
@@ -156,7 +157,7 @@
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// FloatAnimationCurve implementation
@@ -187,7 +188,7 @@
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// TransformAnimationCurve implementation
@@ -224,7 +225,7 @@
}
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
// FilterAnimationCurve implementation
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc
index b779a37..f621ad3 100644
--- a/cc/animation/layer_animation_controller.cc
+++ b/cc/animation/layer_animation_controller.cc
@@ -148,7 +148,8 @@
if (!animation->InEffect(monotonic_time))
continue;
- double trimmed = animation->TrimTimeToCurrentIteration(monotonic_time);
+ double trimmed =
+ animation->TrimTimeToCurrentIteration(monotonic_time).InSecondsF();
switch (animation->target_property()) {
case Animation::Opacity: {
AnimationEvent event(AnimationEvent::PropertyUpdate,
@@ -212,7 +213,11 @@
if (!HasActiveValueObserver())
return;
- DCHECK(last_tick_time_ != base::TimeTicks());
+ // Animate hasn't been called, this happens if an observer has been added
+ // between the Commit and Draw phases.
+ if (last_tick_time_ == base::TimeTicks())
+ return;
+
if (start_ready_animations)
PromoteStartedAnimations(last_tick_time_, events);
@@ -856,8 +861,9 @@
if (!animations_[i]->InEffect(monotonic_time))
continue;
- double trimmed =
- animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
+ double trimmed = animations_[i]
+ ->TrimTimeToCurrentIteration(monotonic_time)
+ .InSecondsF();
switch (animations_[i]->target_property()) {
case Animation::Transform: {
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc
index 49ac0a5..4fa3d84 100644
--- a/cc/animation/layer_animation_controller_unittest.cc
+++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -673,14 +673,11 @@
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- double duration_in_seconds =
- controller_impl->GetAnimation(Animation::ScrollOffset)
- ->curve()
- ->Duration();
- TimeDelta duration = TimeDelta::FromMicroseconds(
- duration_in_seconds * base::Time::kMicrosecondsPerSecond);
+ TimeDelta duration = controller_impl->GetAnimation(Animation::ScrollOffset)
+ ->curve()
+ ->Duration();
EXPECT_EQ(
- duration_in_seconds,
+ duration,
controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
controller->Animate(kInitialTickTime);
@@ -755,12 +752,11 @@
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- double duration_in_seconds =
- controller_impl->GetAnimation(Animation::ScrollOffset)
- ->curve()
- ->Duration();
+ TimeDelta duration = controller_impl->GetAnimation(Animation::ScrollOffset)
+ ->curve()
+ ->Duration();
EXPECT_EQ(
- duration_in_seconds,
+ duration,
controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
controller->Animate(kInitialTickTime);
@@ -776,8 +772,6 @@
const AnimationEvent* event = GetMostRecentPropertyUpdateEvent(events.get());
EXPECT_FALSE(event);
- TimeDelta duration = TimeDelta::FromMicroseconds(
- duration_in_seconds * base::Time::kMicrosecondsPerSecond);
controller->NotifyAnimationStarted((*events)[0]);
controller->Animate(kInitialTickTime + duration / 2);
@@ -820,7 +814,7 @@
target_value,
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- double duration_in_seconds = curve->Duration();
+ double duration_in_seconds = curve->Duration().InSecondsF();
scoped_ptr<Animation> animation(
Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc
index 641c9e0..e0b1a3b 100644
--- a/cc/animation/scroll_offset_animation_curve.cc
+++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -83,8 +83,8 @@
progress, initial_value_.y(), target_value_.y()));
}
-double ScrollOffsetAnimationCurve::Duration() const {
- return total_animation_duration_.InSecondsF();
+base::TimeDelta ScrollOffsetAnimationCurve::Duration() const {
+ return total_animation_duration_;
}
AnimationCurve::CurveType ScrollOffsetAnimationCurve::Type() const {
diff --git a/cc/animation/scroll_offset_animation_curve.h b/cc/animation/scroll_offset_animation_curve.h
index 0c8692a..50dfb17 100644
--- a/cc/animation/scroll_offset_animation_curve.h
+++ b/cc/animation/scroll_offset_animation_curve.h
@@ -29,7 +29,7 @@
void UpdateTarget(double t, const gfx::ScrollOffset& new_target);
// AnimationCurve implementation
- double Duration() const override;
+ base::TimeDelta Duration() const override;
CurveType Type() const override;
scoped_ptr<AnimationCurve> Clone() const override;
diff --git a/cc/animation/scroll_offset_animation_curve_unittest.cc b/cc/animation/scroll_offset_animation_curve_unittest.cc
index d89784a..d57814e 100644
--- a/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -19,39 +19,39 @@
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(target_value);
- EXPECT_DOUBLE_EQ(0.0, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.0, curve->Duration().InSecondsF());
// x decreases, y stays the same.
curve->SetInitialValue(gfx::ScrollOffset(136.f, 200.f));
- EXPECT_DOUBLE_EQ(0.1, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.1, curve->Duration().InSecondsF());
// x increases, y stays the same.
curve->SetInitialValue(gfx::ScrollOffset(19.f, 200.f));
- EXPECT_DOUBLE_EQ(0.15, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.15, curve->Duration().InSecondsF());
// x stays the same, y decreases.
curve->SetInitialValue(gfx::ScrollOffset(100.f, 344.f));
- EXPECT_DOUBLE_EQ(0.2, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.2, curve->Duration().InSecondsF());
// x stays the same, y increases.
curve->SetInitialValue(gfx::ScrollOffset(100.f, 191.f));
- EXPECT_DOUBLE_EQ(0.05, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.05, curve->Duration().InSecondsF());
// x decreases, y decreases.
curve->SetInitialValue(gfx::ScrollOffset(32500.f, 500.f));
- EXPECT_DOUBLE_EQ(3.0, curve->Duration());
+ EXPECT_DOUBLE_EQ(3.0, curve->Duration().InSecondsF());
// x decreases, y increases.
curve->SetInitialValue(gfx::ScrollOffset(150.f, 119.f));
- EXPECT_DOUBLE_EQ(0.15, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.15, curve->Duration().InSecondsF());
// x increases, y decreases.
curve->SetInitialValue(gfx::ScrollOffset(0.f, 14600.f));
- EXPECT_DOUBLE_EQ(2.0, curve->Duration());
+ EXPECT_DOUBLE_EQ(2.0, curve->Duration().InSecondsF());
// x increases, y increases.
curve->SetInitialValue(gfx::ScrollOffset(95.f, 191.f));
- EXPECT_DOUBLE_EQ(0.05, curve->Duration());
+ EXPECT_DOUBLE_EQ(0.05, curve->Duration().InSecondsF());
}
TEST(ScrollOffsetAnimationCurveTest, GetValue) {
@@ -63,22 +63,22 @@
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- double duration = curve->Duration();
- EXPECT_GT(curve->Duration(), 0);
- EXPECT_LT(curve->Duration(), 0.1);
+ double duration_in_seconds = curve->Duration().InSecondsF();
+ EXPECT_GT(curve->Duration().InSecondsF(), 0);
+ EXPECT_LT(curve->Duration().InSecondsF(), 0.1);
EXPECT_EQ(AnimationCurve::ScrollOffset, curve->Type());
- EXPECT_EQ(duration, curve->Duration());
+ EXPECT_EQ(duration_in_seconds, curve->Duration().InSecondsF());
EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(-1.0));
EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(0.0));
EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(6.f, 30.f),
- curve->GetValue(duration/2.0));
- EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration));
- EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration+1.0));
+ curve->GetValue(duration_in_seconds / 2.0));
+ EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration_in_seconds));
+ EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration_in_seconds + 1.0));
// Verify that GetValue takes the timing function into account.
- gfx::ScrollOffset value = curve->GetValue(duration/4.0);
+ gfx::ScrollOffset value = curve->GetValue(duration_in_seconds / 4.0);
EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
}
@@ -92,30 +92,30 @@
target_value,
EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- double duration = curve->Duration();
+ double duration_in_seconds = curve->Duration().InSecondsF();
scoped_ptr<AnimationCurve> clone(curve->Clone().Pass());
EXPECT_EQ(AnimationCurve::ScrollOffset, clone->Type());
- EXPECT_EQ(duration, clone->Duration());
+ EXPECT_EQ(duration_in_seconds, clone->Duration().InSecondsF());
EXPECT_VECTOR2DF_EQ(initial_value,
clone->ToScrollOffsetAnimationCurve()->GetValue(-1.0));
EXPECT_VECTOR2DF_EQ(initial_value,
clone->ToScrollOffsetAnimationCurve()->GetValue(0.0));
- EXPECT_VECTOR2DF_EQ(
- gfx::ScrollOffset(6.f, 30.f),
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 2.0));
+ EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(6.f, 30.f),
+ clone->ToScrollOffsetAnimationCurve()->GetValue(
+ duration_in_seconds / 2.0));
EXPECT_VECTOR2DF_EQ(
target_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration));
- EXPECT_VECTOR2DF_EQ(
- target_value,
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration + 1.0));
+ clone->ToScrollOffsetAnimationCurve()->GetValue(duration_in_seconds));
+ EXPECT_VECTOR2DF_EQ(target_value,
+ clone->ToScrollOffsetAnimationCurve()->GetValue(
+ duration_in_seconds + 1.0));
// Verify that the timing function was cloned correctly.
- gfx::ScrollOffset value =
- clone->ToScrollOffsetAnimationCurve()->GetValue(duration / 4.0);
+ gfx::ScrollOffset value = clone->ToScrollOffsetAnimationCurve()->GetValue(
+ duration_in_seconds / 4.0);
EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
}
@@ -127,20 +127,20 @@
ScrollOffsetAnimationCurve::Create(
target_value, EaseInOutTimingFunction::Create().Pass()));
curve->SetInitialValue(initial_value);
- EXPECT_EQ(1.0, curve->Duration());
+ EXPECT_EQ(1.0, curve->Duration().InSecondsF());
EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
EXPECT_EQ(3600.0, curve->GetValue(1.0).y());
curve->UpdateTarget(0.5, gfx::ScrollOffset(0.0, 9900.0));
- EXPECT_EQ(2.0, curve->Duration());
+ EXPECT_EQ(2.0, curve->Duration().InSecondsF());
EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
EXPECT_EQ(9900.0, curve->GetValue(2.0).y());
curve->UpdateTarget(1.0, gfx::ScrollOffset(0.0, 7200.0));
- EXPECT_NEAR(1.674, curve->Duration(), 0.01);
+ EXPECT_NEAR(1.674, curve->Duration().InSecondsF(), 0.01);
EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
EXPECT_EQ(7200.0, curve->GetValue(1.674).y());
}
diff --git a/cc/base/time_util.h b/cc/base/time_util.h
new file mode 100644
index 0000000..dc07e74
--- /dev/null
+++ b/cc/base/time_util.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_BASE_TIME_UTIL_H_
+#define CC_BASE_TIME_UTIL_H_
+
+namespace base {
+class TimeDelta;
+}
+
+namespace cc {
+
+class CC_EXPORT TimeUtil {
+ public:
+ static base::TimeDelta Scale(base::TimeDelta time_delta, double value) {
+ return base::TimeDelta::FromInternalValue(static_cast<int64>(
+ static_cast<double>(time_delta.ToInternalValue()) * value));
+ }
+
+ static base::TimeDelta Mod(base::TimeDelta dividend,
+ base::TimeDelta divisor) {
+ return base::TimeDelta::FromInternalValue(dividend.ToInternalValue() %
+ divisor.ToInternalValue());
+ }
+};
+
+} // namespace cc
+
+#endif // CC_BASE_TIME_UTIL_H_
diff --git a/cc/blink/web_scroll_offset_animation_curve_impl.cc b/cc/blink/web_scroll_offset_animation_curve_impl.cc
index e789631..ba55d5b 100644
--- a/cc/blink/web_scroll_offset_animation_curve_impl.cc
+++ b/cc/blink/web_scroll_offset_animation_curve_impl.cc
@@ -39,7 +39,7 @@
}
double WebScrollOffsetAnimationCurveImpl::duration() const {
- return curve_->Duration();
+ return curve_->Duration().InSecondsF();
}
scoped_ptr<cc::AnimationCurve>
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 308a61d..fac01a7 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -92,6 +92,7 @@
'base/switches.h',
'base/tiling_data.cc',
'base/tiling_data.h',
+ 'base/time_util.h',
'base/unique_notifier.cc',
'base/unique_notifier.h',
'base/util.h',
@@ -140,11 +141,14 @@
'debug/unittest_only_benchmark.h',
'debug/unittest_only_benchmark_impl.cc',
'debug/unittest_only_benchmark_impl.h',
+ 'input/input_handler.cc',
'input/input_handler.h',
'input/page_scale_animation.cc',
'input/page_scale_animation.h',
'input/layer_selection_bound.cc',
'input/layer_selection_bound.h',
+ 'input/scroll_elasticity_helper.cc',
+ 'input/scroll_elasticity_helper.h',
'input/selection_bound_type.h',
'input/top_controls_manager.cc',
'input/top_controls_manager.h',
@@ -381,8 +385,6 @@
'resources/picture_layer_tiling_set.h',
'resources/picture_pile.cc',
'resources/picture_pile.h',
- 'resources/picture_pile_base.cc',
- 'resources/picture_pile_base.h',
'resources/picture_pile_impl.cc',
'resources/picture_pile_impl.h',
'resources/pixel_buffer_raster_worker_pool.cc',
@@ -403,6 +405,7 @@
'resources/raster_worker_pool.h',
'resources/rasterizer.cc',
'resources/rasterizer.h',
+ 'resources/recording_source.h',
'resources/release_callback.h',
'resources/resource.cc',
'resources/resource.h',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 75267ef..db58318 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.h',
'test/fake_picture_pile_impl.cc',
'test/fake_picture_pile_impl.h',
'test/fake_proxy.cc',
diff --git a/cc/debug/benchmark_instrumentation.cc b/cc/debug/benchmark_instrumentation.cc
index 74caae8..1cb5bc3 100644
--- a/cc/debug/benchmark_instrumentation.cc
+++ b/cc/debug/benchmark_instrumentation.cc
@@ -12,16 +12,7 @@
// tools/perf/measurements/rendering_stats.py accordingly.
// The benchmarks search for events and their arguments by name.
-void IssueMainThreadRenderingStatsEvent(
- const RenderingStats::MainThreadRenderingStats& stats) {
- TRACE_EVENT_INSTANT1("benchmark",
- "BenchmarkInstrumentation::MainThreadRenderingStats",
- TRACE_EVENT_SCOPE_THREAD,
- "data", stats.AsTraceableData());
-}
-
-void IssueImplThreadRenderingStatsEvent(
- const RenderingStats::ImplThreadRenderingStats& stats) {
+void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats) {
TRACE_EVENT_INSTANT1("benchmark",
"BenchmarkInstrumentation::ImplThreadRenderingStats",
TRACE_EVENT_SCOPE_THREAD,
diff --git a/cc/debug/benchmark_instrumentation.h b/cc/debug/benchmark_instrumentation.h
index bd524b9..944ac66 100644
--- a/cc/debug/benchmark_instrumentation.h
+++ b/cc/debug/benchmark_instrumentation.h
@@ -42,10 +42,7 @@
DISALLOW_COPY_AND_ASSIGN(ScopedBeginFrameTask);
};
-void IssueMainThreadRenderingStatsEvent(
- const RenderingStats::MainThreadRenderingStats& stats);
-void IssueImplThreadRenderingStatsEvent(
- const RenderingStats::ImplThreadRenderingStats& stats);
+void IssueImplThreadRenderingStatsEvent(const RenderingStats& stats);
void CC_EXPORT IssueDisplayRenderingStatsEvent();
} // namespace benchmark_instrumentation
diff --git a/cc/debug/picture_record_benchmark.cc b/cc/debug/picture_record_benchmark.cc
index 5f832ae..ab50c7c 100644
--- a/cc/debug/picture_record_benchmark.cc
+++ b/cc/debug/picture_record_benchmark.cc
@@ -10,8 +10,10 @@
#include "base/values.h"
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
+#include "cc/resources/picture.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
+#include "third_party/skia/include/core/SkBBHFactory.h"
#include "ui/gfx/geometry/rect.h"
namespace cc {
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc
index f24dce3..a2052ab 100644
--- a/cc/debug/rasterize_and_record_benchmark.cc
+++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -15,6 +15,7 @@
#include "cc/debug/rasterize_and_record_benchmark_impl.h"
#include "cc/layers/layer.h"
#include "cc/layers/picture_layer.h"
+#include "cc/resources/picture_pile.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_host_common.h"
#include "ui/gfx/geometry/rect.h"
@@ -106,7 +107,7 @@
gfx::Size tile_grid_size = host_->settings().default_tile_size;
SkTileGridFactory::TileGridInfo tile_grid_info;
- PicturePileBase::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
+ PicturePile::ComputeTileGridInfo(tile_grid_size, &tile_grid_info);
gfx::Rect visible_content_rect = gfx::ScaleToEnclosingRect(
layer->visible_content_rect(), 1.f / layer->contents_scale_x());
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index 2ffac1b..07058d0 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -121,6 +121,10 @@
return base_client_->GetRecycledTwinTiling(tiling);
}
+ TilePriority::PriorityBin GetMaxTilePriorityBin() const override {
+ return base_client_->GetMaxTilePriorityBin();
+ }
+
size_t GetMaxTilesForInterestArea() const override {
return base_client_->GetMaxTilesForInterestArea();
}
diff --git a/cc/debug/rendering_stats.cc b/cc/debug/rendering_stats.cc
index 558c882..9c62a3c 100644
--- a/cc/debug/rendering_stats.cc
+++ b/cc/debug/rendering_stats.cc
@@ -18,9 +18,8 @@
void RenderingStats::TimeDeltaList::AddToTracedValue(
base::debug::TracedValue* list_value) const {
- std::list<base::TimeDelta>::const_iterator iter;
- for (iter = values.begin(); iter != values.end(); ++iter) {
- list_value->AppendDouble(iter->InMillisecondsF());
+ for (const auto& value : values) {
+ list_value->AppendDouble(value.InMillisecondsF());
}
}
@@ -32,43 +31,17 @@
return values.empty() ? base::TimeDelta() : values.back();
}
-RenderingStats::MainThreadRenderingStats::MainThreadRenderingStats()
- : painted_pixel_count(0), recorded_pixel_count(0) {
-}
-
-RenderingStats::MainThreadRenderingStats::~MainThreadRenderingStats() {
-}
-
-scoped_refptr<base::debug::ConvertableToTraceFormat>
-RenderingStats::MainThreadRenderingStats::AsTraceableData() const {
- scoped_refptr<base::debug::TracedValue> record_data =
- new base::debug::TracedValue();
- record_data->SetDouble("paint_time", paint_time.InSecondsF());
- record_data->SetInteger("painted_pixel_count", painted_pixel_count);
- record_data->SetDouble("record_time", record_time.InSecondsF());
- record_data->SetInteger("recorded_pixel_count", recorded_pixel_count);
- return record_data;
-}
-
-void RenderingStats::MainThreadRenderingStats::Add(
- const MainThreadRenderingStats& other) {
- paint_time += other.paint_time;
- painted_pixel_count += other.painted_pixel_count;
- record_time += other.record_time;
- recorded_pixel_count += other.recorded_pixel_count;
-}
-
-RenderingStats::ImplThreadRenderingStats::ImplThreadRenderingStats()
+RenderingStats::RenderingStats()
: frame_count(0),
visible_content_area(0),
approximated_visible_content_area(0) {
}
-RenderingStats::ImplThreadRenderingStats::~ImplThreadRenderingStats() {
+RenderingStats::~RenderingStats() {
}
scoped_refptr<base::debug::ConvertableToTraceFormat>
-RenderingStats::ImplThreadRenderingStats::AsTraceableData() const {
+RenderingStats::AsTraceableData() const {
scoped_refptr<base::debug::TracedValue> record_data =
new base::debug::TracedValue();
record_data->SetInteger("frame_count", frame_count);
@@ -102,8 +75,7 @@
return record_data;
}
-void RenderingStats::ImplThreadRenderingStats::Add(
- const ImplThreadRenderingStats& other) {
+void RenderingStats::Add(const RenderingStats& other) {
frame_count += other.frame_count;
visible_content_area += other.visible_content_area;
approximated_visible_content_area += other.approximated_visible_content_area;
@@ -119,9 +91,4 @@
other.commit_to_activate_duration_estimate);
}
-void RenderingStats::Add(const RenderingStats& other) {
- main_stats.Add(other.main_stats);
- impl_stats.Add(other.impl_stats);
-}
-
} // namespace cc
diff --git a/cc/debug/rendering_stats.h b/cc/debug/rendering_stats.h
index 7b1898a..193454c 100644
--- a/cc/debug/rendering_stats.h
+++ b/cc/debug/rendering_stats.h
@@ -31,51 +31,27 @@
base::TimeDelta GetLastTimeDelta() const;
private:
- std::list<base::TimeDelta> values;
+ std::vector<base::TimeDelta> values;
};
- struct CC_EXPORT MainThreadRenderingStats {
- // Note: when adding new members, please remember to update Add in
- // rendering_stats.cc.
+ RenderingStats();
+ ~RenderingStats();
- base::TimeDelta paint_time;
- int64 painted_pixel_count;
- base::TimeDelta record_time;
- int64 recorded_pixel_count;
+ // Note: when adding new members, please remember to update Add in
+ // rendering_stats.cc.
- MainThreadRenderingStats();
- ~MainThreadRenderingStats();
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData()
- const;
- void Add(const MainThreadRenderingStats& other);
- };
+ int64 frame_count;
+ int64 visible_content_area;
+ int64 approximated_visible_content_area;
- struct CC_EXPORT ImplThreadRenderingStats {
- // Note: when adding new members, please remember to update Add in
- // rendering_stats.cc.
+ TimeDeltaList draw_duration;
+ TimeDeltaList draw_duration_estimate;
+ TimeDeltaList begin_main_frame_to_commit_duration;
+ TimeDeltaList begin_main_frame_to_commit_duration_estimate;
+ TimeDeltaList commit_to_activate_duration;
+ TimeDeltaList commit_to_activate_duration_estimate;
- int64 frame_count;
- int64 visible_content_area;
- int64 approximated_visible_content_area;
-
- TimeDeltaList draw_duration;
- TimeDeltaList draw_duration_estimate;
- TimeDeltaList begin_main_frame_to_commit_duration;
- TimeDeltaList begin_main_frame_to_commit_duration_estimate;
- TimeDeltaList commit_to_activate_duration;
- TimeDeltaList commit_to_activate_duration_estimate;
-
- ImplThreadRenderingStats();
- ~ImplThreadRenderingStats();
- scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData()
- const;
- void Add(const ImplThreadRenderingStats& other);
- };
-
- MainThreadRenderingStats main_stats;
- ImplThreadRenderingStats impl_stats;
-
- // Add fields of |other| to the fields in this structure.
+ scoped_refptr<base::debug::ConvertableToTraceFormat> AsTraceableData() const;
void Add(const RenderingStats& other);
};
diff --git a/cc/debug/rendering_stats_instrumentation.cc b/cc/debug/rendering_stats_instrumentation.cc
index f5f2e07..c707e23 100644
--- a/cc/debug/rendering_stats_instrumentation.cc
+++ b/cc/debug/rendering_stats_instrumentation.cc
@@ -18,14 +18,7 @@
RenderingStatsInstrumentation::~RenderingStatsInstrumentation() {}
-RenderingStats::MainThreadRenderingStats
-RenderingStatsInstrumentation::main_thread_rendering_stats() {
- base::AutoLock scoped_lock(lock_);
- return main_thread_rendering_stats_;
-}
-
-RenderingStats::ImplThreadRenderingStats
-RenderingStatsInstrumentation::impl_thread_rendering_stats() {
+RenderingStats RenderingStatsInstrumentation::impl_thread_rendering_stats() {
base::AutoLock scoped_lock(lock_);
return impl_thread_rendering_stats_;
}
@@ -33,23 +26,15 @@
RenderingStats RenderingStatsInstrumentation::GetRenderingStats() {
base::AutoLock scoped_lock(lock_);
RenderingStats rendering_stats;
- rendering_stats.main_stats = main_thread_rendering_stats_accu_;
- rendering_stats.main_stats.Add(main_thread_rendering_stats_);
- rendering_stats.impl_stats = impl_thread_rendering_stats_accu_;
- rendering_stats.impl_stats.Add(impl_thread_rendering_stats_);
+ rendering_stats = impl_thread_rendering_stats_accu_;
+ rendering_stats.Add(impl_thread_rendering_stats_);
return rendering_stats;
}
-void RenderingStatsInstrumentation::AccumulateAndClearMainThreadStats() {
- base::AutoLock scoped_lock(lock_);
- main_thread_rendering_stats_accu_.Add(main_thread_rendering_stats_);
- main_thread_rendering_stats_ = RenderingStats::MainThreadRenderingStats();
-}
-
void RenderingStatsInstrumentation::AccumulateAndClearImplThreadStats() {
base::AutoLock scoped_lock(lock_);
impl_thread_rendering_stats_accu_.Add(impl_thread_rendering_stats_);
- impl_thread_rendering_stats_ = RenderingStats::ImplThreadRenderingStats();
+ impl_thread_rendering_stats_ = RenderingStats();
}
base::TimeTicks RenderingStatsInstrumentation::StartRecording() const {
@@ -79,26 +64,6 @@
impl_thread_rendering_stats_.frame_count += count;
}
-void RenderingStatsInstrumentation::AddPaint(base::TimeDelta duration,
- int64 pixels) {
- if (!record_rendering_stats_)
- return;
-
- base::AutoLock scoped_lock(lock_);
- main_thread_rendering_stats_.paint_time += duration;
- main_thread_rendering_stats_.painted_pixel_count += pixels;
-}
-
-void RenderingStatsInstrumentation::AddRecord(base::TimeDelta duration,
- int64 pixels) {
- if (!record_rendering_stats_)
- return;
-
- base::AutoLock scoped_lock(lock_);
- main_thread_rendering_stats_.record_time += duration;
- main_thread_rendering_stats_.recorded_pixel_count += pixels;
-}
-
void RenderingStatsInstrumentation::AddVisibleContentArea(int64 area) {
if (!record_rendering_stats_)
return;
diff --git a/cc/debug/rendering_stats_instrumentation.h b/cc/debug/rendering_stats_instrumentation.h
index 734583a..8d95929 100644
--- a/cc/debug/rendering_stats_instrumentation.h
+++ b/cc/debug/rendering_stats_instrumentation.h
@@ -18,19 +18,12 @@
static scoped_ptr<RenderingStatsInstrumentation> Create();
virtual ~RenderingStatsInstrumentation();
- // Return copy of current main thread rendering stats.
- RenderingStats::MainThreadRenderingStats main_thread_rendering_stats();
-
// Return copy of current impl thread rendering stats.
- RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats();
+ RenderingStats impl_thread_rendering_stats();
// Return the accumulated, combined rendering stats.
RenderingStats GetRenderingStats();
- // Add current main thread rendering stats to accumulator and
- // clear current stats.
- void AccumulateAndClearMainThreadStats();
-
// Add current impl thread rendering stats to accumulator and
// clear current stats.
void AccumulateAndClearImplThreadStats();
@@ -48,8 +41,6 @@
base::TimeDelta EndRecording(base::TimeTicks start_time) const;
void IncrementFrameCount(int64 count);
- void AddPaint(base::TimeDelta duration, int64 pixels);
- void AddRecord(base::TimeDelta duration, int64 pixels);
void AddVisibleContentArea(int64 area);
void AddApproximatedVisibleContentArea(int64 area);
void AddDrawDuration(base::TimeDelta draw_duration,
@@ -65,10 +56,8 @@
RenderingStatsInstrumentation();
private:
- RenderingStats::MainThreadRenderingStats main_thread_rendering_stats_;
- RenderingStats::MainThreadRenderingStats main_thread_rendering_stats_accu_;
- RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats_;
- RenderingStats::ImplThreadRenderingStats impl_thread_rendering_stats_accu_;
+ RenderingStats impl_thread_rendering_stats_;
+ RenderingStats impl_thread_rendering_stats_accu_;
bool record_rendering_stats_;
diff --git a/cc/input/input_handler.cc b/cc/input/input_handler.cc
new file mode 100644
index 0000000..336d0d4
--- /dev/null
+++ b/cc/input/input_handler.cc
@@ -0,0 +1,13 @@
+// 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/input/input_handler.h"
+
+namespace cc {
+
+InputHandlerScrollResult::InputHandlerScrollResult()
+ : did_scroll(false), did_overscroll_root(false) {
+}
+
+} // namespace cc
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index b3205a8..7b83e4b 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -6,6 +6,7 @@
#define CC_INPUT_INPUT_HANDLER_H_
#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/base/swap_promise_monitor.h"
@@ -23,6 +24,22 @@
namespace cc {
class LayerScrollOffsetDelegate;
+class ScrollElasticityHelper;
+
+struct CC_EXPORT InputHandlerScrollResult {
+ InputHandlerScrollResult();
+ // Did any layer scroll as a result this ScrollBy call?
+ bool did_scroll;
+ // Was any of the scroll delta argument to this ScrollBy call not used?
+ bool did_overscroll_root;
+ // The total overscroll that has been accumulated by all ScrollBy calls that
+ // have had overscroll since the last ScrollBegin call. This resets upon a
+ // ScrollBy with no overscroll.
+ gfx::Vector2dF accumulated_root_overscroll;
+ // The amount of the scroll delta argument to this ScrollBy call that was not
+ // used for scrolling.
+ gfx::Vector2dF unused_scroll_delta;
+};
class CC_EXPORT InputHandlerClient {
public:
@@ -32,13 +49,6 @@
virtual void Animate(base::TimeTicks time) = 0;
virtual void MainThreadHasStoppedFlinging() = 0;
- // Called when scroll deltas reaching the root scrolling layer go unused.
- // The accumulated overscroll is scoped by the most recent call to
- // InputHandler::ScrollBegin.
- virtual void DidOverscroll(const gfx::PointF& causal_event_viewport_point,
- const gfx::Vector2dF& accumulated_overscroll,
- const gfx::Vector2dF& latest_overscroll_delta) = 0;
-
protected:
InputHandlerClient() {}
@@ -85,15 +95,16 @@
// should be in viewport (logical pixel) coordinates. Otherwise they are in
// scrolling layer's (logical pixel) space. If there is no room to move the
// layer in the requested direction, its first ancestor layer that can be
- // scrolled will be moved instead. If no layer can be moved in the requested
- // direction at all, then false is returned. If any layer is moved, then
- // true is returned.
+ // scrolled will be moved instead. The return value's |did_scroll| field is
+ // set to false if no layer can be moved in the requested direction at all,
+ // and set to true if any layer is moved.
// If the scroll delta hits the root layer, and the layer can no longer move,
// the root overscroll accumulated within this ScrollBegin() scope is reported
- // to the client.
+ // in the return value's |accumulated_overscroll| field.
// Should only be called if ScrollBegin() returned ScrollStarted.
- virtual bool ScrollBy(const gfx::Point& viewport_point,
- const gfx::Vector2dF& scroll_delta) = 0;
+ virtual InputHandlerScrollResult ScrollBy(
+ const gfx::Point& viewport_point,
+ const gfx::Vector2dF& scroll_delta) = 0;
virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
ScrollDirection direction) = 0;
@@ -140,6 +151,8 @@
virtual scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) = 0;
+ virtual ScrollElasticityHelper* CreateScrollElasticityHelper() = 0;
+
protected:
InputHandler() {}
virtual ~InputHandler() {}
diff --git a/cc/input/scroll_elasticity_helper.cc b/cc/input/scroll_elasticity_helper.cc
new file mode 100644
index 0000000..54da888
--- /dev/null
+++ b/cc/input/scroll_elasticity_helper.cc
@@ -0,0 +1,101 @@
+// 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/input/scroll_elasticity_helper.h"
+
+#include "cc/layers/layer_impl.h"
+#include "cc/trees/layer_tree_host_impl.h"
+#include "cc/trees/layer_tree_impl.h"
+
+namespace cc {
+
+ScrollElasticityHelper::ScrollElasticityHelper(LayerTreeHostImpl* layer_tree)
+ : layer_tree_host_impl_(layer_tree), timer_active_(false) {
+}
+
+ScrollElasticityHelper::~ScrollElasticityHelper() {
+}
+
+bool ScrollElasticityHelper::AllowsHorizontalStretching() {
+ // The WebKit implementation has this interface because it is written in terms
+ // of overscrolling on a per-layer basis, not for the whole layer tree. In
+ // that implementation, this always returns true for the frame view's
+ // scrollable area.
+ // TODO(ccameron): This is function is redundant and may be removed.
+ return true;
+}
+
+bool ScrollElasticityHelper::AllowsVerticalStretching() {
+ // TODO(ccameron): This is function is redundant and may be removed.
+ return true;
+}
+
+gfx::Vector2dF ScrollElasticityHelper::StretchAmount() {
+ return stretch_offset_;
+}
+
+bool ScrollElasticityHelper::PinnedInDirection(
+ const gfx::Vector2dF& direction) {
+ gfx::ScrollOffset scroll_offset =
+ layer_tree_host_impl_->active_tree()->TotalScrollOffset();
+ gfx::ScrollOffset max_scroll_offset =
+ layer_tree_host_impl_->active_tree()->TotalMaxScrollOffset();
+ bool result = false;
+ if (direction.x() < 0)
+ result |= scroll_offset.x() <= 0;
+ if (direction.x() > 0)
+ result |= scroll_offset.x() >= max_scroll_offset.x();
+ if (direction.y() < 0)
+ result |= scroll_offset.y() <= 0;
+ if (direction.y() > 0)
+ result |= scroll_offset.y() >= max_scroll_offset.y();
+ return result;
+}
+
+bool ScrollElasticityHelper::CanScrollHorizontally() {
+ return layer_tree_host_impl_->active_tree()->TotalMaxScrollOffset().x() > 0;
+}
+
+bool ScrollElasticityHelper::CanScrollVertically() {
+ return layer_tree_host_impl_->active_tree()->TotalMaxScrollOffset().y() > 0;
+}
+
+gfx::Vector2dF ScrollElasticityHelper::AbsoluteScrollPosition() {
+ // TODO(ccameron): This is function is redundant and may be removed.
+ return stretch_offset_;
+}
+
+void ScrollElasticityHelper::ImmediateScrollBy(const gfx::Vector2dF& scroll) {
+ // TODO(ccameron): This is function is redundant and may be removed.
+}
+
+void ScrollElasticityHelper::ImmediateScrollByWithoutContentEdgeConstraints(
+ const gfx::Vector2dF& scroll) {
+ stretch_offset_ += scroll;
+
+ // TODO(ccameron): Update the transform of the appropriate layer in the
+ // LayerTreeHostImpl, and request that a frame be drawn.
+}
+
+void ScrollElasticityHelper::StartSnapRubberbandTimer() {
+ if (timer_active_)
+ return;
+ timer_active_ = true;
+ layer_tree_host_impl_->SetNeedsAnimate();
+}
+
+void ScrollElasticityHelper::StopSnapRubberbandTimer() {
+ timer_active_ = false;
+}
+
+void ScrollElasticityHelper::SnapRubberbandTimerFired() {
+ if (timer_active_)
+ layer_tree_host_impl_->SetNeedsAnimate();
+}
+
+void ScrollElasticityHelper::AdjustScrollPositionToBoundsIfNecessary() {
+ // TODO(ccameron): This is function is redundant and may be removed.
+}
+
+} // namespace cc
diff --git a/cc/input/scroll_elasticity_helper.h b/cc/input/scroll_elasticity_helper.h
new file mode 100644
index 0000000..645b20c
--- /dev/null
+++ b/cc/input/scroll_elasticity_helper.h
@@ -0,0 +1,84 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
+#define CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
+
+#include "base/time/time.h"
+#include "cc/base/cc_export.h"
+#include "ui/gfx/geometry/vector2d_f.h"
+
+namespace cc {
+
+class LayerTreeHostImpl;
+
+// ScrollElasticityHelper is based on
+// WebKit/Source/platform/mac/ScrollElasticityController.h
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+// Interface between a LayerTreeHostImpl and the ScrollElasticityController. It
+// would be possible, in principle, for LayerTreeHostImpl to implement this
+// interface itself. This artificial boundary is introduced to reduce the amount
+// of logic and state held directly inside LayerTreeHostImpl.
+class CC_EXPORT ScrollElasticityHelper {
+ public:
+ explicit ScrollElasticityHelper(LayerTreeHostImpl* layer_tree);
+ ~ScrollElasticityHelper();
+
+ bool AllowsHorizontalStretching();
+ bool AllowsVerticalStretching();
+ // The amount that the view is stretched past the normal allowable bounds.
+ // The "overhang" amount.
+ gfx::Vector2dF StretchAmount();
+ bool PinnedInDirection(const gfx::Vector2dF& direction);
+ bool CanScrollHorizontally();
+ bool CanScrollVertically();
+
+ // Return the absolute scroll position, not relative to the scroll origin.
+ gfx::Vector2dF AbsoluteScrollPosition();
+
+ void ImmediateScrollBy(const gfx::Vector2dF& scroll);
+ void ImmediateScrollByWithoutContentEdgeConstraints(
+ const gfx::Vector2dF& scroll);
+ void StartSnapRubberbandTimer();
+ void StopSnapRubberbandTimer();
+ void SnapRubberbandTimerFired();
+
+ // If the current scroll position is within the overhang area, this function
+ // will cause
+ // the page to scroll to the nearest boundary point.
+ void AdjustScrollPositionToBoundsIfNecessary();
+
+ private:
+ LayerTreeHostImpl* layer_tree_host_impl_;
+ gfx::Vector2dF stretch_offset_;
+ bool timer_active_;
+};
+
+} // namespace cc
+
+#endif // CC_INPUT_SCROLL_ELASTICITY_HELPER_H_
diff --git a/cc/layers/content_layer.cc b/cc/layers/content_layer.cc
index d3e9a28..88031e4 100644
--- a/cc/layers/content_layer.cc
+++ b/cc/layers/content_layer.cc
@@ -57,13 +57,6 @@
if (!updater_.get())
return;
-
- if (host) {
- updater_->set_rendering_stats_instrumentation(
- host->rendering_stats_instrumentation());
- } else {
- updater_->set_rendering_stats_instrumentation(nullptr);
- }
}
void ContentLayer::SetTexturePriorities(
@@ -108,7 +101,6 @@
} else {
updater_ = BitmapContentLayerUpdater::Create(
painter.Pass(),
- rendering_stats_instrumentation(),
id());
}
updater_->SetOpaque(contents_opaque());
diff --git a/cc/layers/draw_properties.h b/cc/layers/draw_properties.h
index 403393e..2e54083 100644
--- a/cc/layers/draw_properties.h
+++ b/cc/layers/draw_properties.h
@@ -6,6 +6,7 @@
#define CC_LAYERS_DRAW_PROPERTIES_H_
#include "base/memory/scoped_ptr.h"
+#include "third_party/skia/include/core/SkXfermode.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/transform.h"
@@ -17,6 +18,7 @@
struct CC_EXPORT DrawProperties {
DrawProperties()
: opacity(0.f),
+ blend_mode(SkXfermode::kSrcOver_Mode),
opacity_is_animating(false),
screen_space_opacity_is_animating(false),
target_space_transform_is_animating(false),
@@ -53,6 +55,10 @@
// opacity, or when opacity is compounded by the hierarchy.
float opacity;
+ // DrawProperties::blend_mode may be different than LayerType::blend_mode,
+ // when a RenderSurface re-parents the layer's blend_mode.
+ SkXfermode::Mode blend_mode;
+
// xxx_is_animating flags are used to indicate whether the DrawProperties
// are actually meaningful on the main thread. When the properties are
// animating, the main thread may not have the same values that are used
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index f09761b..a99ede8 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -255,14 +255,11 @@
}
void LayerImpl::PopulateSharedQuadState(SharedQuadState* state) const {
- state->SetAll(draw_properties_.target_space_transform,
- draw_properties_.content_bounds,
- draw_properties_.visible_content_rect,
- draw_properties_.clip_rect,
- draw_properties_.is_clipped,
- draw_properties_.opacity,
- blend_mode_,
- sorting_context_id_);
+ state->SetAll(
+ draw_properties_.target_space_transform, draw_properties_.content_bounds,
+ draw_properties_.visible_content_rect, draw_properties_.clip_rect,
+ draw_properties_.is_clipped, draw_properties_.opacity,
+ draw_properties_.blend_mode, sorting_context_id_);
}
bool LayerImpl::WillDraw(DrawMode draw_mode,
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 5fe679c..12f1dca 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -323,6 +323,9 @@
return draw_properties_.screen_space_transform;
}
float draw_opacity() const { return draw_properties_.opacity; }
+ SkXfermode::Mode draw_blend_mode() const {
+ return draw_properties_.blend_mode;
+ }
bool draw_opacity_is_animating() const {
return draw_properties_.opacity_is_animating;
}
diff --git a/cc/layers/layer_perftest.cc b/cc/layers/layer_perftest.cc
index fcd0844..f42e228 100644
--- a/cc/layers/layer_perftest.cc
+++ b/cc/layers/layer_perftest.cc
@@ -40,7 +40,7 @@
virtual void SetUp() override {
layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
layer_tree_host_->InitializeSingleThreaded(
- &fake_client_, base::MessageLoopProxy::current());
+ &fake_client_, base::MessageLoopProxy::current(), nullptr);
}
virtual void TearDown() override {
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index ecdd916..246a658 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -42,7 +42,9 @@
public:
explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
: LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
- InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+ InitializeSingleThreaded(client,
+ base::MessageLoopProxy::current(),
+ nullptr);
}
MOCK_METHOD0(SetNeedsCommit, void());
@@ -935,7 +937,8 @@
shared_bitmap_manager_.get(),
gpu_memory_buffer_manager_.get(),
LayerTreeSettings(),
- base::MessageLoopProxy::current()).Pass();
+ base::MessageLoopProxy::current(),
+ nullptr);
}
scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) {
@@ -945,7 +948,8 @@
shared_bitmap_manager_.get(),
gpu_memory_buffer_manager_.get(),
settings,
- base::MessageLoopProxy::current()).Pass();
+ base::MessageLoopProxy::current(),
+ nullptr);
}
private:
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index fcaacc7..1c766ba 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -60,9 +60,9 @@
}
TestablePictureImageLayerImpl* layer =
new TestablePictureImageLayerImpl(tree, id);
- layer->pile_ = FakePicturePileImpl::CreateInfiniteFilledPile();
- layer->SetBounds(layer->pile_->tiling_size());
- layer->SetContentBounds(layer->pile_->tiling_size());
+ layer->raster_source_ = FakePicturePileImpl::CreateInfiniteFilledPile();
+ layer->SetBounds(layer->raster_source_->GetSize());
+ layer->SetContentBounds(layer->raster_source_->GetSize());
return make_scoped_ptr(layer);
}
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index c56ff8b..5d45cae 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -7,6 +7,7 @@
#include "base/auto_reset.h"
#include "cc/layers/content_layer_client.h"
#include "cc/layers/picture_layer_impl.h"
+#include "cc/resources/picture_pile.h"
#include "cc/trees/layer_tree_impl.h"
#include "third_party/skia/include/core/SkPictureRecorder.h"
#include "ui/gfx/geometry/rect_conversions.h"
@@ -19,6 +20,7 @@
PictureLayer::PictureLayer(ContentLayerClient* client)
: client_(client),
+ recording_source_(new PicturePile),
instrumentation_object_tracker_(id()),
update_source_frame_number_(-1),
can_use_lcd_text_last_frame_(can_use_lcd_text()) {
@@ -37,38 +39,39 @@
int source_frame_number = layer_tree_host()->source_frame_number();
gfx::Size impl_bounds = layer_impl->bounds();
- gfx::Size pile_bounds = pile_.tiling_size();
+ gfx::Size recording_source_bounds = recording_source_->GetSize();
- // If update called, then pile size must match bounds pushed to impl layer.
+ // If update called, then recording source size must match bounds pushed to
+ // impl layer.
DCHECK_IMPLIES(update_source_frame_number_ == source_frame_number,
- impl_bounds == pile_bounds)
- << " bounds " << impl_bounds.ToString() << " pile "
- << pile_bounds.ToString();
+ impl_bounds == recording_source_bounds)
+ << " bounds " << impl_bounds.ToString() << " recording source "
+ << recording_source_bounds.ToString();
if (update_source_frame_number_ != source_frame_number &&
- pile_bounds != impl_bounds) {
+ recording_source_bounds != impl_bounds) {
// Update may not get called for the layer (if it's not in the viewport
- // for example, even though it has resized making the pile no longer
- // valid. In this case just destroy the pile.
- pile_.SetEmptyBounds();
+ // for example, even though it has resized making the recording source no
+ // longer valid. In this case just destroy the recording source.
+ recording_source_->SetEmptyBounds();
}
// Unlike other properties, invalidation must always be set on layer_impl.
// See PictureLayerImpl::PushPropertiesTo for more details.
layer_impl->invalidation_.Clear();
- layer_impl->invalidation_.Swap(&pile_invalidation_);
- layer_impl->UpdatePile(PicturePileImpl::CreateFromOther(&pile_));
+ layer_impl->invalidation_.Swap(&recording_invalidation_);
+ layer_impl->UpdateRasterSource(recording_source_->CreateRasterSource());
}
void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
Layer::SetLayerTreeHost(host);
if (host) {
- pile_.SetMinContentsScale(host->settings().minimum_contents_scale);
- pile_.SetTileGridSize(host->settings().default_tile_grid_size);
- pile_.set_slow_down_raster_scale_factor(
+ // 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);
+ recording_source_->SetSlowdownRasterScaleFactor(
host->debug_state().slow_down_raster_scale_factor);
- pile_.set_show_debug_picture_borders(
- host->debug_state().show_picture_borders);
}
}
@@ -97,7 +100,8 @@
gfx::Size layer_size = paint_properties().bounds;
if (last_updated_visible_content_rect_ == visible_content_rect() &&
- pile_.tiling_size() == layer_size && pending_invalidation_.IsEmpty()) {
+ recording_source_->GetSize() == layer_size &&
+ pending_invalidation_.IsEmpty()) {
// Only early out if the visible content rect of this layer hasn't changed.
return updated;
}
@@ -110,7 +114,7 @@
// Calling paint in WebKit can sometimes cause invalidations, so save
// off the invalidation prior to calling update.
- pending_invalidation_.Swap(&pile_invalidation_);
+ pending_invalidation_.Swap(&recording_invalidation_);
pending_invalidation_.Clear();
if (layer_tree_host()->settings().record_full_layer) {
@@ -124,32 +128,26 @@
// to the impl side so that it drops tiles that may not have a recording
// for them.
DCHECK(client_);
- updated |=
- pile_.UpdateAndExpandInvalidation(client_,
- &pile_invalidation_,
- SafeOpaqueBackgroundColor(),
- contents_opaque(),
- client_->FillsBoundsCompletely(),
- layer_size,
- visible_layer_rect,
- update_source_frame_number_,
- Picture::RECORD_NORMALLY,
- rendering_stats_instrumentation());
+ updated |= recording_source_->UpdateAndExpandInvalidation(
+ client_, &recording_invalidation_, SafeOpaqueBackgroundColor(),
+ contents_opaque(), client_->FillsBoundsCompletely(), layer_size,
+ visible_layer_rect, update_source_frame_number_,
+ Picture::RECORD_NORMALLY);
last_updated_visible_content_rect_ = visible_content_rect();
if (updated) {
SetNeedsPushProperties();
} else {
- // If this invalidation did not affect the pile, then it can be cleared as
- // an optimization.
- pile_invalidation_.Clear();
+ // If this invalidation did not affect the recording source, then it can be
+ // cleared as an optimization.
+ recording_invalidation_.Clear();
}
return updated;
}
void PictureLayer::SetIsMask(bool is_mask) {
- pile_.set_is_mask(is_mask);
+ recording_source_->SetIsMask(is_mask);
}
bool PictureLayer::SupportsLCDText() const {
@@ -166,7 +164,7 @@
}
skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
- // We could either flatten the PicturePile into a single SkPicture,
+ // We could either flatten the RecordingSource into a single SkPicture,
// or paint a fresh one depending on what we intend to do with the
// picture. For now we just paint a fresh one to get consistent results.
if (!DrawsContent())
@@ -185,7 +183,7 @@
}
bool PictureLayer::IsSuitableForGpuRasterization() const {
- return pile_.is_suitable_for_gpu_rasterization();
+ return recording_source_->IsSuitableForGpuRasterization();
}
void PictureLayer::ClearClient() {
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 232dba2..2969ee1 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -9,12 +9,12 @@
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/micro_benchmark_controller.h"
#include "cc/layers/layer.h"
-#include "cc/resources/picture_pile.h"
#include "cc/trees/occlusion_tracker.h"
namespace cc {
class ContentLayerClient;
+class RecordingSource;
class ResourceUpdateQueue;
class CC_EXPORT PictureLayer : public Layer {
@@ -39,7 +39,9 @@
ContentLayerClient* client() { return client_; }
- PicturePile* GetPicturePileForTesting() { return &pile_; }
+ RecordingSource* GetRecordingSourceForTesting() {
+ return recording_source_.get();
+ }
protected:
explicit PictureLayer(ContentLayerClient* client);
@@ -50,13 +52,13 @@
private:
ContentLayerClient* client_;
- PicturePile pile_;
+ scoped_ptr<RecordingSource> recording_source_;
devtools_instrumentation::
ScopedLayerObjectTracker instrumentation_object_tracker_;
// Invalidation to use the next time update is called.
InvalidationRegion pending_invalidation_;
// Invalidation from the last time update was called.
- Region pile_invalidation_;
+ Region recording_invalidation_;
gfx::Rect last_updated_visible_content_rect_;
int update_source_frame_number_;
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index f9678cc..6d89140 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -71,7 +71,7 @@
PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
twin_layer_(nullptr),
- pile_(PicturePileImpl::Create()),
+ raster_source_(PicturePileImpl::Create()),
ideal_page_scale_(0.f),
ideal_device_scale_(0.f),
ideal_source_scale_(0.f),
@@ -122,9 +122,9 @@
twin_layer_ = layer_impl;
layer_impl->twin_layer_ = this;
- layer_impl->UpdatePile(pile_);
+ layer_impl->UpdateRasterSource(raster_source_);
- DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
+ DCHECK(!raster_source_->IsSolidColor() || !tilings_->num_tilings());
// Tilings would be expensive to push, so we swap.
layer_impl->tilings_.swap(tilings_);
layer_impl->tilings_->SetClient(layer_impl);
@@ -132,7 +132,7 @@
tilings_->SetClient(this);
// Ensure that the recycle tree doesn't have any unshared tiles.
- if (tilings_ && pile_->is_solid_color())
+ if (tilings_ && raster_source_->IsSolidColor())
tilings_->RemoveAllTilings();
// Remove invalidated tiles from what will become a recycle tree.
@@ -158,9 +158,10 @@
needs_push_properties_ = true;
}
-void PictureLayerImpl::UpdatePile(scoped_refptr<PicturePileImpl> pile) {
+void PictureLayerImpl::UpdateRasterSource(
+ scoped_refptr<RasterSource> raster_source) {
bool could_have_tilings = CanHaveTilings();
- pile_.swap(pile);
+ raster_source_.swap(raster_source);
// Need to call UpdateTiles again if CanHaveTilings changed.
if (could_have_tilings != CanHaveTilings()) {
@@ -174,26 +175,24 @@
DCHECK(!needs_post_commit_initialization_);
// The bounds and the pile size may differ if the pile wasn't updated (ie.
// PictureLayer::Update didn't happen). In that case the pile will be empty.
- DCHECK_IMPLIES(!pile_->tiling_size().IsEmpty(),
- bounds() == pile_->tiling_size())
+ DCHECK_IMPLIES(!raster_source_->GetSize().IsEmpty(),
+ bounds() == raster_source_->GetSize())
<< " bounds " << bounds().ToString() << " pile "
- << pile_->tiling_size().ToString();
+ << raster_source_->GetSize().ToString();
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- if (pile_->is_solid_color()) {
+ if (raster_source_->IsSolidColor()) {
PopulateSharedQuadState(shared_quad_state);
AppendDebugBorderQuad(
render_pass, bounds(), shared_quad_state, append_quads_data);
- SolidColorLayerImpl::AppendSolidQuads(render_pass,
- occlusion_in_content_space,
- shared_quad_state,
- visible_content_rect(),
- pile_->solid_color(),
- append_quads_data);
+ SolidColorLayerImpl::AppendSolidQuads(
+ render_pass, occlusion_in_content_space, shared_quad_state,
+ visible_content_rect(), raster_source_->GetSolidColor(),
+ append_quads_data);
return;
}
@@ -210,14 +209,11 @@
occlusion_in_content_space.GetOcclusionWithGivenDrawTransform(
scaled_draw_transform);
- shared_quad_state->SetAll(scaled_draw_transform,
- scaled_content_bounds,
- scaled_visible_content_rect,
- draw_properties().clip_rect,
- draw_properties().is_clipped,
- draw_properties().opacity,
- blend_mode(),
- sorting_context_id_);
+ shared_quad_state->SetAll(
+ scaled_draw_transform, scaled_content_bounds, scaled_visible_content_rect,
+ draw_properties().clip_rect, draw_properties().is_clipped,
+ draw_properties().opacity, draw_properties().blend_mode,
+ sorting_context_id_);
if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) {
AppendDebugBorderQuad(
@@ -241,16 +237,9 @@
PictureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- visible_geometry_rect,
- texture_rect,
- texture_size,
- RGBA_8888,
- quad_content_rect,
- max_contents_scale,
- pile_);
+ quad->SetNew(shared_quad_state, geometry_rect, opaque_rect,
+ visible_geometry_rect, texture_rect, texture_size, RGBA_8888,
+ quad_content_rect, max_contents_scale, raster_source_);
return;
}
@@ -382,16 +371,10 @@
resource_provider->memory_efficient_texture_format();
PictureDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- visible_geometry_rect,
- texture_rect,
- iter.texture_size(),
- format,
- iter->content_rect(),
- iter->contents_scale(),
- pile_);
+ quad->SetNew(shared_quad_state, geometry_rect, opaque_rect,
+ visible_geometry_rect, texture_rect, iter.texture_size(),
+ format, iter->content_rect(), iter->contents_scale(),
+ raster_source_);
has_draw_quad = true;
break;
}
@@ -506,7 +489,7 @@
draw_properties().screen_space_transform_is_animating;
if (draw_transform_is_animating())
- pile_->set_likely_to_be_used_for_transform_animation();
+ raster_source_->SetShouldAttemptToUseDistanceFieldText();
should_update_tile_priorities_ = true;
@@ -515,7 +498,7 @@
void PictureLayerImpl::UpdateTilePriorities(
const Occlusion& occlusion_in_content_space) {
- DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
+ DCHECK(!raster_source_->IsSolidColor() || !tilings_->num_tilings());
double current_frame_time_in_seconds =
(layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
base::TimeTicks()).InSecondsF();
@@ -607,7 +590,7 @@
}
void PictureLayerImpl::DidBeginTracing() {
- pile_->DidBeginTracing();
+ raster_source_->DidBeginTracing();
}
void PictureLayerImpl::ReleaseResources() {
@@ -623,13 +606,13 @@
}
skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() {
- return pile_->GetFlattenedPicture();
+ return raster_source_->GetFlattenedPicture();
}
scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling,
const gfx::Rect& content_rect) {
- DCHECK(!pile_->is_solid_color());
- if (!pile_->CanRaster(tiling->contents_scale(), content_rect))
+ DCHECK(!raster_source_->IsSolidColor());
+ if (!raster_source_->CoversRect(content_rect, tiling->contents_scale()))
return scoped_refptr<Tile>();
int flags = 0;
@@ -640,21 +623,17 @@
// 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 (!pile_->is_mask())
+ if (!raster_source_->IsMask())
flags = Tile::USE_PICTURE_ANALYSIS;
return layer_tree_impl()->tile_manager()->CreateTile(
- pile_.get(),
- content_rect.size(),
- content_rect,
- tiling->contents_scale(),
- id(),
- layer_tree_impl()->source_frame_number(),
+ raster_source_.get(), content_rect.size(), content_rect,
+ tiling->contents_scale(), id(), layer_tree_impl()->source_frame_number(),
flags);
}
RasterSource* PictureLayerImpl::GetRasterSource() {
- return pile_.get();
+ return raster_source_.get();
}
const Region* PictureLayerImpl::GetPendingInvalidation() {
@@ -685,6 +664,12 @@
return recycled_twin->tilings_->TilingAtScale(tiling->contents_scale());
}
+TilePriority::PriorityBin PictureLayerImpl::GetMaxTilePriorityBin() const {
+ if (!HasValidTilePriorities())
+ return TilePriority::EVENTUALLY;
+ return TilePriority::NOW;
+}
+
size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
return layer_tree_impl()->settings().max_tiles_for_interest_area;
}
@@ -714,7 +699,7 @@
int max_texture_size =
layer_tree_impl()->resource_provider()->max_texture_size();
- if (pile_->is_mask()) {
+ if (raster_source_->IsMask()) {
// 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 ||
@@ -803,10 +788,9 @@
bool synced_high_res_tiling = false;
if (CanHaveTilings()) {
- synced_high_res_tiling = tilings_->SyncTilings(*other->tilings_,
- pile_->tiling_size(),
- invalidation_,
- MinimumContentsScale());
+ synced_high_res_tiling =
+ tilings_->SyncTilings(*other->tilings_, raster_source_->GetSize(),
+ invalidation_, MinimumContentsScale());
} else {
RemoveAllTilings();
}
@@ -830,7 +814,7 @@
return;
if (!CanHaveTilingWithScale(tiling->contents_scale()))
return;
- tilings_->AddTiling(tiling->contents_scale(), pile_->tiling_size());
+ tilings_->AddTiling(tiling->contents_scale(), raster_source_->GetSize());
// If this tree needs update draw properties, then the tiling will
// get updated prior to drawing or activation. If this tree does not
@@ -849,7 +833,7 @@
void PictureLayerImpl::GetContentsResourceId(
ResourceProvider::ResourceId* resource_id,
gfx::Size* resource_size) const {
- DCHECK_EQ(bounds().ToString(), pile_->tiling_size().ToString());
+ DCHECK_EQ(bounds().ToString(), raster_source_->GetSize().ToString());
gfx::Rect content_rect(bounds());
PictureLayerTilingSet::CoverageIterator iter(
tilings_.get(), 1.f, content_rect, ideal_contents_scale_);
@@ -899,9 +883,9 @@
"contents_scale: " << contents_scale;
PictureLayerTiling* tiling =
- tilings_->AddTiling(contents_scale, pile_->tiling_size());
+ tilings_->AddTiling(contents_scale, raster_source_->GetSize());
- DCHECK(pile_->HasRecordings());
+ DCHECK(raster_source_->HasRecordings());
if (PictureLayerImpl* twin_layer = GetPendingOrActiveTwinLayer())
twin_layer->SyncTiling(tiling);
@@ -1100,7 +1084,7 @@
float maximum_scale = draw_properties().maximum_animation_contents_scale;
if (maximum_scale) {
gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(
- gfx::ScaleSize(pile_->tiling_size(), maximum_scale));
+ gfx::ScaleSize(raster_source_->GetSize(), maximum_scale));
if (bounds_at_maximum_scale.GetArea() <=
layer_tree_impl()->device_viewport_size().GetArea())
can_raster_at_maximum_scale = true;
@@ -1120,7 +1104,7 @@
// If this layer would create zero or one tiles at this content scale,
// don't create a low res tiling.
gfx::Size raster_bounds = gfx::ToCeiledSize(
- gfx::ScaleSize(pile_->tiling_size(), raster_contents_scale_));
+ gfx::ScaleSize(raster_source_->GetSize(), raster_contents_scale_));
gfx::Size tile_size = CalculateTileSize(raster_bounds);
bool tile_covers_bounds = tile_size.width() >= raster_bounds.width() &&
tile_size.height() >= raster_bounds.height();
@@ -1227,8 +1211,8 @@
// then it will end up having less than one pixel of content in that
// dimension. Bump the minimum contents scale up in this case to prevent
// this from happening.
- int min_dimension =
- std::min(pile_->tiling_size().width(), pile_->tiling_size().height());
+ int min_dimension = std::min(raster_source_->GetSize().width(),
+ raster_source_->GetSize().height());
if (!min_dimension)
return setting_min;
@@ -1249,11 +1233,11 @@
}
bool PictureLayerImpl::CanHaveTilings() const {
- if (pile_->is_solid_color())
+ if (raster_source_->IsSolidColor())
return false;
if (!DrawsContent())
return false;
- if (!pile_->HasRecordings())
+ if (!raster_source_->HasRecordings())
return false;
return true;
}
@@ -1353,7 +1337,7 @@
state->EndArray();
state->BeginArray("pictures");
- pile_->AsValueInto(state);
+ raster_source_->AsValueInto(state);
state->EndArray();
state->BeginArray("invalidation");
@@ -1362,12 +1346,9 @@
state->BeginArray("coverage_tiles");
for (PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(),
- 1.f,
- gfx::Rect(pile_->tiling_size()),
+ tilings_.get(), 1.f, gfx::Rect(raster_source_->GetSize()),
ideal_contents_scale_);
- iter;
- ++iter) {
+ iter; ++iter) {
state->BeginDictionary();
state->BeginArray("geometry_rect");
@@ -1403,10 +1384,8 @@
return IsOnActiveOrPendingTree() && IsDrawnRenderSurfaceLayerListMember();
}
-bool PictureLayerImpl::AllTilesRequiredForActivationAreReadyToDraw() const {
- if (!layer_tree_impl()->IsPendingTree())
- return true;
-
+bool PictureLayerImpl::AllTilesRequiredAreReadyToDraw(
+ TileRequirementCheck is_tile_required_callback) const {
if (!HasValidTilePriorities())
return true;
@@ -1438,11 +1417,9 @@
// be out of date. It is updated in the raster/eviction iterators.
// TODO(vmpstr): Remove the comment once you can't access this information
// from the tile.
- if (tiling->IsTileRequiredForActivation(tile) && !tile->IsReadyToDraw()) {
- TRACE_EVENT_INSTANT0("cc",
- "PictureLayerImpl::"
- "AllTilesRequiredForActivationAreReadyToDraw not "
- "ready to activate",
+ if ((tiling->*is_tile_required_callback)(tile) &&
+ !tile->IsReadyToDraw()) {
+ TRACE_EVENT_INSTANT0("cc", "Tile required, but not ready to draw.",
TRACE_EVENT_SCOPE_THREAD);
return false;
}
@@ -1452,6 +1429,22 @@
return true;
}
+bool PictureLayerImpl::AllTilesRequiredForActivationAreReadyToDraw() const {
+ if (!layer_tree_impl()->IsPendingTree())
+ return true;
+
+ return AllTilesRequiredAreReadyToDraw(
+ &PictureLayerTiling::IsTileRequiredForActivationIfVisible);
+}
+
+bool PictureLayerImpl::AllTilesRequiredForDrawAreReadyToDraw() const {
+ if (!layer_tree_impl()->IsActiveTree())
+ return true;
+
+ return AllTilesRequiredAreReadyToDraw(
+ &PictureLayerTiling::IsTileRequiredForDrawIfVisible);
+}
+
PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator()
: layer_(nullptr), current_stage_(arraysize(stages_)) {
}
@@ -1586,11 +1579,12 @@
tree_priority_(tree_priority),
current_category_(PictureLayerTiling::EVENTUALLY),
current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
- current_tiling_(CurrentTilingRange().start - 1u) {
- // TODO(vmpstr): Once tile priorities are determined by the iterators, ensure
- // that layers that don't have valid tile priorities have lowest priorities so
- // they evict their tiles first (crbug.com/381704)
- DCHECK(layer_->tilings_);
+ current_tiling_(0u) {
+ // Early out if the layer has no tilings.
+ if (!layer_->tilings_ || !layer_->tilings_->num_tilings())
+ return;
+
+ current_tiling_ = CurrentTilingRange().start - 1u;
do {
if (!AdvanceToNextTiling())
break;
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 024e315..b341bde 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -126,6 +126,7 @@
const PictureLayerTiling* tiling) const override;
PictureLayerTiling* GetRecycledTwinTiling(
const PictureLayerTiling* tiling) override;
+ TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
size_t GetMaxTilesForInterestArea() const override;
float GetSkewportTargetTimeInSeconds() const override;
int GetSkewportExtrapolationLimitInContentPixels() const override;
@@ -149,9 +150,11 @@
// Virtual for testing.
virtual bool HasValidTilePriorities() const;
bool AllTilesRequiredForActivationAreReadyToDraw() const;
+ bool AllTilesRequiredForDrawAreReadyToDraw() const;
protected:
friend class LayerRasterTileIterator;
+ using TileRequirementCheck = bool (PictureLayerTiling::*)(const Tile*) const;
PictureLayerImpl(LayerTreeImpl* tree_impl, int id);
PictureLayerTiling* AddTiling(float contents_scale);
@@ -169,7 +172,7 @@
void ResetRasterScale();
gfx::Rect GetViewportForTilePriorityInContentSpace() const;
PictureLayerImpl* GetRecycledTwinLayer() const;
- void UpdatePile(scoped_refptr<PicturePileImpl> pile);
+ void UpdateRasterSource(scoped_refptr<RasterSource> raster_source);
void DoPostCommitInitializationIfNeeded() {
if (needs_post_commit_initialization_)
@@ -180,6 +183,11 @@
bool CanHaveTilings() const;
bool CanHaveTilingWithScale(float contents_scale) const;
void SanityCheckTilingState() const;
+ // Checks if all tiles required for a certain action (e.g. activation) are
+ // ready to draw. is_tile_required_callback gets called on all candidate
+ // tiles and returns true if the tile is required for the action.
+ bool AllTilesRequiredAreReadyToDraw(
+ TileRequirementCheck is_tile_required_callback) const;
bool ShouldAdjustRasterScaleDuringScaleAnimations() const;
@@ -193,7 +201,7 @@
PictureLayerImpl* twin_layer_;
scoped_ptr<PictureLayerTilingSet> tilings_;
- scoped_refptr<PicturePileImpl> pile_;
+ scoped_refptr<RasterSource> raster_source_;
Region invalidation_;
float ideal_page_scale_;
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index aeea2bb..7f1ce85 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -58,7 +58,7 @@
pending_tree->DetachLayerTree();
scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, 7, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, 7, pile);
pending_layer->SetDrawsContent(true);
pending_tree->SetRootLayer(pending_layer.Pass());
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index a46386c..a75feb0 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -134,7 +134,7 @@
pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
}
- void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
+ void SetupPendingTree(scoped_refptr<RasterSource> raster_source) {
host_impl_.CreatePendingTree();
host_impl_.pending_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
LayerTreeImpl* pending_tree = host_impl_.pending_tree();
@@ -147,14 +147,14 @@
if (old_pending_root) {
pending_layer.reset(
static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
- pending_layer->SetPile(pile);
+ pending_layer->SetRasterSource(raster_source);
} else {
- pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+ pending_layer = FakePictureLayerImpl::CreateWithRasterSource(
+ pending_tree, id_, raster_source);
pending_layer->SetDrawsContent(true);
}
// The bounds() just mirror the pile size.
- pending_layer->SetBounds(pending_layer->pile()->tiling_size());
+ pending_layer->SetBounds(pending_layer->raster_source()->GetSize());
pending_tree->SetRootLayer(pending_layer.Pass());
pending_layer_ = static_cast<FakePictureLayerImpl*>(
@@ -268,8 +268,8 @@
std::vector<SkRect>::const_iterator rect_iter = rects.begin();
for (tile_iter = tiles.begin(); tile_iter < tiles.end(); tile_iter++) {
MockCanvas mock_canvas(1000, 1000);
- active_pile->RasterDirect(&mock_canvas, (*tile_iter)->content_rect(),
- 1.0f);
+ active_pile->PlaybackToSharedCanvas(&mock_canvas,
+ (*tile_iter)->content_rect(), 1.0f);
// This test verifies that when drawing the contents of a specific tile
// at content scale 1.0, the playback canvas never receives content from
@@ -658,10 +658,10 @@
++iter) {
EXPECT_FALSE(iter.full_tile_geometry_rect().IsEmpty());
// Ensure there is a recording for this tile.
- bool in_pending = pending_pile->CanRaster(tiling->contents_scale(),
- iter.full_tile_geometry_rect());
- bool in_active = active_pile->CanRaster(tiling->contents_scale(),
- iter.full_tile_geometry_rect());
+ bool in_pending = pending_pile->CoversRect(iter.full_tile_geometry_rect(),
+ tiling->contents_scale());
+ bool in_active = active_pile->CoversRect(iter.full_tile_geometry_rect(),
+ tiling->contents_scale());
if (in_pending && !in_active)
EXPECT_EQ(pending_pile.get(), iter->raster_source());
@@ -1132,8 +1132,15 @@
}
TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
- gfx::Size tile_size(host_impl_.settings().default_tile_size);
- SetupDefaultTrees(tile_size);
+ gfx::Size layer_bounds(host_impl_.settings().default_tile_size);
+ gfx::Size tile_size(100, 100);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
float device_scale = 1.f;
@@ -1181,8 +1188,8 @@
ResetTilingsAndRasterScales();
// Mask layers dont create low res since they always fit on one tile.
- pending_layer_->pile()->set_is_mask(true);
- active_layer_->pile()->set_is_mask(true);
+ pending_pile->SetIsMask(true);
+ active_pile->SetIsMask(true);
SetContentsScaleOnBothLayers(contents_scale,
device_scale,
page_scale,
@@ -1197,7 +1204,7 @@
scoped_refptr<FakePicturePileImpl> valid_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
- valid_pile->set_is_mask(true);
+ valid_pile->SetIsMask(true);
SetupPendingTree(valid_pile);
SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
@@ -1224,7 +1231,7 @@
scoped_refptr<FakePicturePileImpl> huge_pile =
FakePicturePileImpl::CreateFilledPile(
tile_size, gfx::Size(max_texture_size + 1, 10));
- huge_pile->set_is_mask(true);
+ huge_pile->SetIsMask(true);
SetupPendingTree(huge_pile);
SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
@@ -1249,7 +1256,7 @@
scoped_refptr<FakePicturePileImpl> valid_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
- valid_pile->set_is_mask(true);
+ valid_pile->SetIsMask(true);
SetupPendingTree(valid_pile);
float ideal_contents_scale = 1.3f;
@@ -1499,7 +1506,7 @@
EXPECT_EQ(0.f, active_layer_->ideal_contents_scale());
// Push non-solid-color pending pile makes active layer can have tilings.
- active_layer_->UpdatePile(pending_pile);
+ active_layer_->UpdateRasterSource(pending_pile);
ASSERT_TRUE(active_layer_->CanHaveTilings());
// Update properties with non-solid color pile should allow tilings.
@@ -2044,7 +2051,8 @@
LayerTreeImpl* pending_tree = host_impl_.pending_tree();
scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pending_pile);
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_,
+ pending_pile);
pending_layer->SetDrawsContent(true);
pending_tree->SetRootLayer(pending_layer.Pass());
@@ -3708,9 +3716,10 @@
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
- pending_pile->set_is_mask(true);
- scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateWithPile(
- host_impl_.pending_tree(), 3, pending_pile);
+ pending_pile->SetIsMask(true);
+ scoped_ptr<FakePictureLayerImpl> mask =
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 3,
+ pending_pile);
mask->SetBounds(bounds);
mask->SetContentBounds(bounds);
@@ -4485,31 +4494,23 @@
FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
host->SetRootLayer(layer);
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
host_impl_.SetViewportSize(layer_bounds);
int frame_number = 0;
- FakeRenderingStatsInstrumentation stats_instrumentation;
client.set_fill_with_nonsolid_color(!test_for_solid);
Region invalidation(layer_rect);
- pile->UpdateAndExpandInvalidation(&client,
- &invalidation,
- SK_ColorWHITE,
- false,
- false,
- layer_bounds,
- layer_rect,
- frame_number++,
- Picture::RECORD_NORMALLY,
- &stats_instrumentation);
+ recording_source->UpdateAndExpandInvalidation(
+ &client, &invalidation, SK_ColorWHITE, false, false, layer_bounds,
+ layer_rect, frame_number++, Picture::RECORD_NORMALLY);
- scoped_refptr<PicturePileImpl> pending_pile =
- PicturePileImpl::CreateFromOther(pile);
+ scoped_refptr<RasterSource> pending_raster_source =
+ recording_source->CreateRasterSource();
- SetupPendingTree(pending_pile);
+ SetupPendingTree(pending_raster_source);
ActivateTree();
active_layer_->set_fixed_tile_size(tile_size);
@@ -4560,31 +4561,23 @@
FakeLayerTreeHostClient host_client(FakeLayerTreeHostClient::DIRECT_3D);
scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&host_client);
host->SetRootLayer(layer);
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
host_impl_.SetViewportSize(layer_bounds);
int frame_number = 0;
- FakeRenderingStatsInstrumentation stats_instrumentation;
client.set_fill_with_nonsolid_color(true);
Region invalidation1(layer_rect);
- pile->UpdateAndExpandInvalidation(&client,
- &invalidation1,
- SK_ColorWHITE,
- false,
- false,
- layer_bounds,
- layer_rect,
- frame_number++,
- Picture::RECORD_NORMALLY,
- &stats_instrumentation);
+ recording_source->UpdateAndExpandInvalidation(
+ &client, &invalidation1, SK_ColorWHITE, false, false, layer_bounds,
+ layer_rect, frame_number++, Picture::RECORD_NORMALLY);
- scoped_refptr<PicturePileImpl> pending_pile1 =
- PicturePileImpl::CreateFromOther(pile);
+ scoped_refptr<RasterSource> raster_source1 =
+ recording_source->CreateRasterSource();
- SetupPendingTree(pending_pile1);
+ SetupPendingTree(raster_source1);
ActivateTree();
host_impl_.active_tree()->UpdateDrawProperties();
@@ -4595,21 +4588,14 @@
client.set_fill_with_nonsolid_color(false);
Region invalidation2(layer_rect);
- pile->UpdateAndExpandInvalidation(&client,
- &invalidation2,
- SK_ColorWHITE,
- false,
- false,
- layer_bounds,
- layer_rect,
- frame_number++,
- Picture::RECORD_NORMALLY,
- &stats_instrumentation);
+ recording_source->UpdateAndExpandInvalidation(
+ &client, &invalidation2, SK_ColorWHITE, false, false, layer_bounds,
+ layer_rect, frame_number++, Picture::RECORD_NORMALLY);
- scoped_refptr<PicturePileImpl> pending_pile2 =
- PicturePileImpl::CreateFromOther(pile);
+ scoped_refptr<RasterSource> raster_source2 =
+ recording_source->CreateRasterSource();
- SetupPendingTree(pending_pile2);
+ SetupPendingTree(raster_source2);
ActivateTree();
// We've switched to a solid color, so we should end up with no tilings.
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index ca622aa..7873b48 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -66,23 +66,23 @@
layer->PushPropertiesTo(layer_impl.get());
EXPECT_FALSE(layer_impl->CanHaveTilings());
EXPECT_TRUE(layer_impl->bounds() == gfx::Size(0, 0));
- EXPECT_EQ(gfx::Size(), layer_impl->pile()->tiling_size());
- EXPECT_FALSE(layer_impl->pile()->HasRecordings());
+ EXPECT_EQ(gfx::Size(), layer_impl->raster_source()->GetSize());
+ EXPECT_FALSE(layer_impl->raster_source()->HasRecordings());
}
}
TEST(PictureLayerTest, SuitableForGpuRasterization) {
MockContentLayerClient client;
scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Layer is suitable for gpu rasterization by default.
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
// Veto gpu rasterization.
- pile->SetUnsuitableForGpuRasterizationForTesting();
- EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ recording_source->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
}
@@ -99,7 +99,7 @@
// Tile-grid is set according to its setting.
SkTileGridFactory::TileGridInfo info =
- layer->GetPicturePileForTesting()->GetTileGridInfoForTesting();
+ layer->GetRecordingSourceForTesting()->GetTileGridInfoForTesting();
EXPECT_EQ(info.fTileInterval.width(), 123 - 2 * info.fMargin.width());
EXPECT_EQ(info.fTileInterval.height(), 123 - 2 * info.fMargin.height());
}
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc
index 68398fe..8175efa 100644
--- a/cc/layers/render_surface_unittest.cc
+++ b/cc/layers/render_surface_unittest.cc
@@ -92,6 +92,9 @@
owning_layer->CreateRenderSurface();
ASSERT_TRUE(owning_layer->render_surface());
owning_layer->draw_properties().render_target = owning_layer.get();
+
+ SkXfermode::Mode blend_mode = SkXfermode::kSoftLight_Mode;
+ owning_layer->SetBlendMode(blend_mode);
RenderSurfaceImpl* render_surface = owning_layer->render_surface();
root_layer->AddChild(owning_layer.Pass());
@@ -131,6 +134,7 @@
EXPECT_RECT_EQ(content_rect,
gfx::Rect(shared_quad_state->visible_content_rect));
EXPECT_EQ(1.f, shared_quad_state->opacity);
+ EXPECT_EQ(blend_mode, shared_quad_state->blend_mode);
}
class TestRenderPassSink : public RenderPassSink {
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 25fa708..8a998f3 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -632,7 +632,9 @@
next_id_(1),
total_ui_resource_created_(0),
total_ui_resource_deleted_(0) {
- InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+ InitializeSingleThreaded(client,
+ base::MessageLoopProxy::current(),
+ nullptr);
}
UIResourceId CreateUIResource(UIResourceClient* content) override {
diff --git a/cc/layers/solid_color_layer_impl_unittest.cc b/cc/layers/solid_color_layer_impl_unittest.cc
index 768fae4..320345f 100644
--- a/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/cc/layers/solid_color_layer_impl_unittest.cc
@@ -102,6 +102,31 @@
->opacity());
}
+TEST(SolidColorLayerImplTest, VerifyCorrectBlendModeInQuad) {
+ const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
+
+ scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+
+ gfx::Size layer_size = gfx::Size(100, 100);
+ gfx::Rect visible_content_rect = gfx::Rect(layer_size);
+
+ FakeImplProxy proxy;
+ TestSharedBitmapManager shared_bitmap_manager;
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ scoped_ptr<SolidColorLayerImpl> layer =
+ SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
+ layer->SetBounds(layer_size);
+ layer->SetContentBounds(layer_size);
+ layer->draw_properties().blend_mode = blend_mode;
+
+ AppendQuadsData data;
+ layer->AppendQuads(render_pass.get(), Occlusion(), &data);
+
+ ASSERT_EQ(render_pass->quad_list.size(), 1U);
+ EXPECT_EQ(blend_mode,
+ render_pass->quad_list.front()->shared_quad_state->blend_mode);
+}
+
TEST(SolidColorLayerImplTest, VerifyOpaqueRect) {
gfx::Size layer_size = gfx::Size(100, 100);
gfx::Rect visible_content_rect = gfx::Rect(layer_size);
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc
index f1909b4..ab6289e 100644
--- a/cc/layers/surface_layer.cc
+++ b/cc/layers/surface_layer.cc
@@ -44,6 +44,7 @@
SurfaceLayer::SurfaceLayer(const SatisfyCallback& satisfy_callback,
const RequireCallback& require_callback)
: Layer(),
+ surface_scale_(1.f),
satisfy_callback_(satisfy_callback),
require_callback_(require_callback) {
}
@@ -53,9 +54,13 @@
DCHECK(destroy_sequence_.is_null());
}
-void SurfaceLayer::SetSurfaceId(SurfaceId surface_id) {
+void SurfaceLayer::SetSurfaceId(SurfaceId surface_id,
+ float scale,
+ const gfx::Size& size) {
SatisfyDestroySequence();
surface_id_ = surface_id;
+ surface_size_ = size;
+ surface_scale_ = scale;
CreateNewDestroySequence();
UpdateDrawsContent(HasDrawableContent());
@@ -88,6 +93,15 @@
layer_impl->SetSurfaceId(surface_id_);
}
+void SurfaceLayer::CalculateContentsScale(float ideal_contents_scale,
+ float* contents_scale_x,
+ float* contents_scale_y,
+ gfx::Size* content_bounds) {
+ *content_bounds = surface_size_;
+ *contents_scale_x = surface_scale_;
+ *contents_scale_y = surface_scale_;
+}
+
void SurfaceLayer::CreateNewDestroySequence() {
DCHECK(destroy_sequence_.is_null());
if (layer_tree_host()) {
diff --git a/cc/layers/surface_layer.h b/cc/layers/surface_layer.h
index 4292549..9b73589 100644
--- a/cc/layers/surface_layer.h
+++ b/cc/layers/surface_layer.h
@@ -9,6 +9,7 @@
#include "cc/layers/layer.h"
#include "cc/surfaces/surface_id.h"
#include "cc/surfaces/surface_sequence.h"
+#include "ui/gfx/size.h"
namespace cc {
@@ -29,12 +30,16 @@
const SatisfyCallback& satisfy_callback,
const RequireCallback& require_callback);
- void SetSurfaceId(SurfaceId surface_id);
+ void SetSurfaceId(SurfaceId surface_id, float scale, const gfx::Size& size);
// Layer overrides.
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
void SetLayerTreeHost(LayerTreeHost* host) override;
void PushPropertiesTo(LayerImpl* layer) override;
+ void CalculateContentsScale(float ideal_contents_scale,
+ float* contents_scale_x,
+ float* contents_scale_y,
+ gfx::Size* content_bounds) override;
protected:
SurfaceLayer(const SatisfyCallback& satisfy_callback,
@@ -47,6 +52,8 @@
void SatisfyDestroySequence();
SurfaceId surface_id_;
+ gfx::Size surface_size_;
+ float surface_scale_;
SurfaceSequence destroy_sequence_;
SatisfyCallback satisfy_callback_;
RequireCallback require_callback_;
diff --git a/cc/layers/surface_layer_unittest.cc b/cc/layers/surface_layer_unittest.cc
index 99d0e17..73415c0 100644
--- a/cc/layers/surface_layer_unittest.cc
+++ b/cc/layers/surface_layer_unittest.cc
@@ -65,7 +65,7 @@
scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create(
base::Bind(&SatisfyCallback, &blank_change),
base::Bind(&RequireCallback, &required_id, &required_seq)));
- layer->SetSurfaceId(SurfaceId(1));
+ layer->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
layer_tree_host_->set_surface_id_namespace(1);
layer_tree_host_->SetRootLayer(layer);
@@ -74,7 +74,7 @@
scoped_refptr<SurfaceLayer> layer2(SurfaceLayer::Create(
base::Bind(&SatisfyCallback, &blank_change),
base::Bind(&RequireCallback, &required_id, &required_seq)));
- layer2->SetSurfaceId(SurfaceId(1));
+ layer2->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
layer_tree_host2->set_surface_id_namespace(2);
layer_tree_host2->SetRootLayer(layer2);
@@ -110,6 +110,36 @@
EXPECT_EQ(2u, required_seq.size());
}
+static void CalcDrawProps(FakeLayerTreeHost* host, float device_scale_factor) {
+ RenderSurfaceLayerList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ host->root_layer(), gfx::Size(500, 500), &render_surface_layer_list);
+ inputs.device_scale_factor = device_scale_factor;
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+}
+
+// Check that setting content scale on the surface works.
+TEST_F(SurfaceLayerTest, ScaleSurface) {
+ SurfaceSequence blank_change;
+ SurfaceId required_id;
+ std::set<SurfaceSequence> required_seq;
+ scoped_refptr<SurfaceLayer> layer(SurfaceLayer::Create(
+ base::Bind(&SatisfyCallback, &blank_change),
+ base::Bind(&RequireCallback, &required_id, &required_seq)));
+ gfx::Size surface_size(10, 15);
+ layer->SetSurfaceId(SurfaceId(1), 2.f, surface_size);
+ layer->SetBounds(gfx::Size(25, 45));
+ layer_tree_host_->SetRootLayer(layer);
+
+ CalcDrawProps(layer_tree_host_.get(), 5.f);
+ EXPECT_EQ(2.f, layer->contents_scale_x());
+ EXPECT_EQ(2.f, layer->contents_scale_y());
+ EXPECT_EQ(surface_size.ToString(), layer->content_bounds().ToString());
+
+ layer_tree_host_->SetRootLayer(nullptr);
+ layer_tree_host_.reset();
+}
+
// Check that SurfaceSequence is sent through swap promise.
class SurfaceLayerSwapPromise : public LayerTreeTest {
public:
@@ -121,7 +151,7 @@
layer_ = SurfaceLayer::Create(
base::Bind(&SatisfyCallback, &satisfied_sequence_),
base::Bind(&RequireCallback, &required_id_, &required_set_));
- layer_->SetSurfaceId(SurfaceId(1));
+ layer_->SetSurfaceId(SurfaceId(1), 1.f, gfx::Size(1, 1));
// Layer hasn't been added to tree so no SurfaceSequence generated yet.
EXPECT_EQ(0u, required_set_.size());
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index d355b62..f2ee269 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -52,7 +52,9 @@
public:
explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
: LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
- InitializeSingleThreaded(client, base::MessageLoopProxy::current());
+ InitializeSingleThreaded(client,
+ base::MessageLoopProxy::current(),
+ nullptr);
}
MOCK_METHOD0(SetNeedsCommit, void());
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 9c814be..7433a14 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -82,7 +82,8 @@
: LayerTreeHost(client, manager, NULL, settings),
output_surface_created_(false) {
LayerTreeHost::InitializeThreaded(base::MessageLoopProxy::current(),
- impl_task_runner);
+ impl_task_runner,
+ nullptr);
}
bool output_surface_created_;
@@ -1663,8 +1664,7 @@
: FakeTiledLayer(manager) {
scoped_ptr<TrackingLayerPainter> painter(TrackingLayerPainter::Create());
tracking_layer_painter_ = painter.get();
- layer_updater_ = BitmapContentLayerUpdater::Create(
- painter.Pass(), &stats_instrumentation_, 0);
+ layer_updater_ = BitmapContentLayerUpdater::Create(painter.Pass(), 0);
}
TrackingLayerPainter* tracking_layer_painter() const {
@@ -1677,7 +1677,6 @@
TrackingLayerPainter* tracking_layer_painter_;
scoped_refptr<BitmapContentLayerUpdater> layer_updater_;
- FakeRenderingStatsInstrumentation stats_instrumentation_;
};
TEST_F(TiledLayerTest, NonIntegerContentsScaleIsNotDistortedDuringPaint) {
diff --git a/cc/layers/ui_resource_layer_unittest.cc b/cc/layers/ui_resource_layer_unittest.cc
index 784ff35..09d57a9 100644
--- a/cc/layers/ui_resource_layer_unittest.cc
+++ b/cc/layers/ui_resource_layer_unittest.cc
@@ -36,7 +36,9 @@
virtual void SetUp() {
layer_tree_host_ = FakeLayerTreeHost::Create(&fake_client_);
layer_tree_host_->InitializeSingleThreaded(
- &fake_client_, base::MessageLoopProxy::current());
+ &fake_client_,
+ base::MessageLoopProxy::current(),
+ nullptr);
}
virtual void TearDown() {
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index 8251a09..a7e1bde 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -159,14 +159,9 @@
SharedQuadState* shared_quad_state =
render_pass->CreateAndAppendSharedQuadState();
- shared_quad_state->SetAll(transform,
- rotated_size,
- visible_content_rect(),
- clip_rect(),
- is_clipped(),
- draw_opacity(),
- blend_mode(),
- sorting_context_id());
+ shared_quad_state->SetAll(transform, rotated_size, visible_content_rect(),
+ clip_rect(), is_clipped(), draw_opacity(),
+ draw_blend_mode(), sorting_context_id());
AppendDebugBorderQuad(
render_pass, rotated_size, shared_quad_state, append_quads_data);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 4eb1324..cb6189e 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -98,6 +98,8 @@
switch (mode) {
case SkXfermode::kSrcOver_Mode:
return BlendModeNormal;
+ case SkXfermode::kScreen_Mode:
+ return BlendModeScreen;
case SkXfermode::kOverlay_Mode:
return BlendModeOverlay;
case SkXfermode::kDarken_Mode:
@@ -128,7 +130,7 @@
return BlendModeLuminosity;
default:
NOTREACHED();
- return BlendModeNormal;
+ return BlendModeNone;
}
}
@@ -865,99 +867,8 @@
return background_with_filters;
}
-scoped_ptr<ScopedResource>
-GLRenderer::ApplyInverseTransformForBackgroundFilters(
- DrawingFrame* frame,
- const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform,
- skia::RefPtr<SkImage> filtered_device_background,
- const gfx::Rect& backdrop_bounding_rect) {
- // This method draws a background filter, which applies a filter to any pixels
- // behind the quad and seen through its background. The algorithm works as
- // follows:
- // 1. Read the pixels in the bounding box into a buffer.
- // Moved to GLRenderer::GetBackdropBoundingBoxForRenderPassQuad().
- // 2. Read the pixels in the bounding box into a buffer R.
- // Moved to GLRenderer::GetBackdropTexture().
- // 3. Apply the background filter to R, so that it is applied in the pixels'
- // coordinate space. Moved to GLRenderer::ApplyBackgroundFilters().
- // 4. Apply the quad's inverse transform to map the pixels in R into the
- // quad's content space. This implicitly clips R by the content bounds of the
- // quad since the destination texture has bounds matching the quad's content.
- // 5. Draw the background texture for the contents using the same transform as
- // used to draw the contents itself. This is done without blending to replace
- // the current background pixels with the new filtered background.
- // 6. Draw the contents of the quad over drop of the new background with
- // blending, as per usual. The filtered background pixels will show through
- // any non-opaque pixels in this draws.
- //
- // Pixel copies in this algorithm occur at steps 2, 3, 4, and 5.
-
- // TODO(danakj): When this algorithm changes, update
- // LayerTreeHost::PrioritizeTextures() accordingly.
-
- DCHECK(filtered_device_background);
-
- GrTexture* texture = filtered_device_background->getTexture();
-
- scoped_ptr<ScopedResource> background_texture =
- ScopedResource::Create(resource_provider_);
- background_texture->Allocate(
- quad->rect.size(),
- ResourceProvider::TextureHintImmutableFramebuffer,
- RGBA_8888);
-
- const RenderPass* target_render_pass = frame->current_render_pass;
- bool using_background_texture =
- UseScopedTexture(frame, background_texture.get(), quad->rect);
-
- if (using_background_texture) {
- // Copy the readback pixels from device to the background texture for the
- // surface.
-
- gfx::Transform contents_device_transform_inverse(
- gfx::Transform::kSkipInitialization);
- bool did_invert = contents_device_transform.GetInverse(
- &contents_device_transform_inverse);
- DCHECK(did_invert);
- gfx::Transform device_to_framebuffer_transform;
- QuadRectTransform(
- &device_to_framebuffer_transform, gfx::Transform(), quad->rect);
- device_to_framebuffer_transform.PreconcatTransform(
- contents_device_transform_inverse);
-
-#ifndef NDEBUG
- GLC(gl_, gl_->ClearColor(0, 0, 1, 1));
- gl_->Clear(GL_COLOR_BUFFER_BIT);
-#endif
-
- // The background_texture is oriented the same as the frame buffer.
- // The transform we are copying with has a vertical flip, as well as
- // the |device_to_framebuffer_transform|, which cancel each other out. So do
- // not flip the contents in the shader to maintain orientation.
- bool flip_vertically = false;
-
- CopyTextureToFramebuffer(frame,
- texture->getTextureHandle(),
- backdrop_bounding_rect,
- device_to_framebuffer_transform,
- flip_vertically);
- }
-
- UseRenderPass(frame, target_render_pass);
-
- if (!using_background_texture)
- return nullptr;
- return background_texture.Pass();
-}
-
void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
const RenderPassDrawQuad* quad) {
- SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
- SetBlendEnabled(
- CanApplyBlendModeUsingBlendFunc(blend_mode) &&
- (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
-
ScopedResource* contents_texture =
render_pass_textures_.get(quad->render_pass_id);
if (!contents_texture || !contents_texture->id())
@@ -983,62 +894,59 @@
SetupQuadForAntialiasing(contents_device_transform, quad,
&surface_quad, edge);
- bool need_background_texture = !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
- ShouldApplyBackgroundFilters(frame, quad);
+ SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
+ bool use_shaders_for_blending =
+ !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
+ ShouldApplyBackgroundFilters(frame, quad) ||
+ settings_->force_blending_with_shaders;
scoped_ptr<ScopedResource> background_texture;
skia::RefPtr<SkImage> background_image;
gfx::Rect background_rect;
- if (need_background_texture) {
+ if (use_shaders_for_blending) {
// Compute a bounding box around the pixels that will be visible through
// the quad.
background_rect = GetBackdropBoundingBoxForRenderPassQuad(
frame, quad, contents_device_transform, use_aa);
- }
- if (!background_rect.IsEmpty()) {
- // The pixels from the filtered background should completely replace the
- // current pixel values.
- bool disable_blending = blend_enabled();
- if (disable_blending)
- SetBlendEnabled(false);
+ if (!background_rect.IsEmpty()) {
+ // The pixels from the filtered background should completely replace the
+ // current pixel values.
+ if (blend_enabled())
+ SetBlendEnabled(false);
- // Read the pixels in the bounding box into a buffer R.
- scoped_ptr<ScopedResource> scoped_background_texture =
- GetBackdropTexture(background_rect);
+ // Read the pixels in the bounding box into a buffer R.
+ // This function allocates a texture, which should contribute to the
+ // amount of memory used by render surfaces:
+ // LayerTreeHost::CalculateMemoryForRenderSurfaces.
+ background_texture = GetBackdropTexture(background_rect);
- skia::RefPtr<SkImage> background_with_filters;
- if (ShouldApplyBackgroundFilters(frame, quad) &&
- scoped_background_texture) {
- // Apply the background filters to R, so that it is applied in the pixels'
- // coordinate space.
- background_with_filters =
- ApplyBackgroundFilters(frame, quad, scoped_background_texture.get());
- }
-
- if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
- background_with_filters) {
- // The background with filters will be copied to the frame buffer.
- // Apply the quad's inverse transform to map the pixels in R into the
- // quad's content space. This implicitly clips R by the content bounds of
- // the quad since the destination texture has bounds matching the quad's
- // content.
- background_texture = ApplyInverseTransformForBackgroundFilters(
- frame, quad, contents_device_transform, background_with_filters,
- background_rect);
- } else if (!CanApplyBlendModeUsingBlendFunc(blend_mode)) {
- if (background_with_filters) {
- // The background with filters will be used as backdrop for blending.
- background_image = background_with_filters;
- } else {
- background_texture = scoped_background_texture.Pass();
+ if (ShouldApplyBackgroundFilters(frame, quad) && background_texture) {
+ // Apply the background filters to R, so that it is applied in the
+ // pixels' coordinate space.
+ background_image =
+ ApplyBackgroundFilters(frame, quad, background_texture.get());
}
}
- if (disable_blending)
- SetBlendEnabled(true);
+ if (!background_texture) {
+ // Something went wrong with reading the backdrop.
+ DCHECK(!background_image);
+ use_shaders_for_blending = false;
+ } else if (background_image) {
+ background_texture.reset();
+ } else if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+ ShouldApplyBackgroundFilters(frame, quad)) {
+ // Something went wrong with applying background filters to the backdrop.
+ use_shaders_for_blending = false;
+ background_texture.reset();
+ }
}
+ SetBlendEnabled(
+ !use_shaders_for_blending &&
+ (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
+
// TODO(senorblanco): Cache this value so that we don't have to do it for both
// the surface and its replica. Apply filters to the contents texture.
skia::RefPtr<SkImage> filter_image;
@@ -1071,25 +979,6 @@
}
}
- if (background_texture && ShouldApplyBackgroundFilters(frame, quad)) {
- // Draw the background texture if it has some filters applied.
- DCHECK(CanApplyBlendModeUsingBlendFunc(blend_mode));
- DCHECK(background_texture->size() == quad->rect.size());
- ResourceProvider::ScopedReadLockGL lock(resource_provider_,
- background_texture->id());
-
- // The background_texture is oriented the same as the frame buffer. The
- // transform we are copying with has a vertical flip, so flip the contents
- // in the shader to maintain orientation
- bool flip_vertically = true;
-
- CopyTextureToFramebuffer(frame,
- lock.texture_id(),
- quad->rect,
- quad->quadTransform(),
- flip_vertically);
- }
-
scoped_ptr<ResourceProvider::ScopedSamplerGL> mask_resource_lock;
unsigned mask_texture_id = 0;
SamplerType mask_sampler = SamplerTypeNA;
@@ -1100,9 +989,6 @@
mask_sampler = SamplerTypeFromTextureTarget(mask_resource_lock->target());
}
- // TODO(danakj): use the background_texture and blend the background in with
- // this draw instead of having a separate copy of the background texture.
-
scoped_ptr<ResourceProvider::ScopedSamplerGL> contents_resource_lock;
if (filter_image) {
GrTexture* texture = filter_image->getTexture();
@@ -1116,7 +1002,7 @@
contents_resource_lock->target());
}
- if (CanApplyBlendModeUsingBlendFunc(blend_mode)) {
+ if (!use_shaders_for_blending) {
if (!use_blend_equation_advanced_coherent_ && use_blend_equation_advanced_)
GLC(gl_, gl_->BlendBarrierKHR());
@@ -1143,10 +1029,10 @@
int shader_backdrop_location = -1;
int shader_backdrop_rect_location = -1;
- BlendMode shader_blend_mode = ((background_texture || background_image) &&
- !CanApplyBlendModeUsingBlendFunc(blend_mode))
+ DCHECK_EQ(background_texture || background_image, use_shaders_for_blending);
+ BlendMode shader_blend_mode = use_shaders_for_blending
? BlendModeFromSkXfermode(blend_mode)
- : BlendModeNormal;
+ : BlendModeNone;
if (use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(
@@ -1423,7 +1309,7 @@
if (filter_image)
GLC(gl_, gl_->Flush());
- if (CanApplyBlendModeUsingBlendFunc(blend_mode))
+ if (!use_shaders_for_blending)
RestoreBlendFuncToDefault(blend_mode);
}
@@ -2096,8 +1982,8 @@
}
SkCanvas canvas(on_demand_tile_raster_bitmap_);
- quad->picture_pile->PlaybackToCanvas(&canvas, quad->content_rect,
- quad->contents_scale);
+ quad->raster_source->PlaybackToCanvas(&canvas, quad->content_rect,
+ quad->contents_scale);
uint8_t* bitmap_pixels = NULL;
SkBitmap on_demand_tile_raster_bitmap_dest;
@@ -2451,43 +2337,6 @@
GLC(gl_, gl_->DrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, 0));
}
-void GLRenderer::CopyTextureToFramebuffer(const DrawingFrame* frame,
- int texture_id,
- const gfx::Rect& rect,
- const gfx::Transform& draw_matrix,
- bool flip_vertically) {
- TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
- gl_, &highp_threshold_cache_, highp_threshold_min_, rect.bottom_right());
-
- const RenderPassProgram* program =
- GetRenderPassProgram(tex_coord_precision, BlendModeNormal);
- SetUseProgram(program->program());
-
- GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
-
- if (flip_vertically) {
- GLC(gl_,
- gl_->Uniform4f(program->vertex_shader().tex_transform_location(),
- 0.f,
- 1.f,
- 1.f,
- -1.f));
- } else {
- GLC(gl_,
- gl_->Uniform4f(program->vertex_shader().tex_transform_location(),
- 0.f,
- 0.f,
- 1.f,
- 1.f));
- }
-
- SetShaderOpacity(1.f, program->fragment_shader().alpha_location());
- DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(gl_));
- GLC(gl_, gl_->BindTexture(GL_TEXTURE_2D, texture_id));
- DrawQuadGeometry(
- frame, draw_matrix, rect, program->vertex_shader().matrix_location());
-}
-
void GLRenderer::Finish() {
TRACE_EVENT0("cc", "GLRenderer::Finish");
GLC(gl_, gl_->Finish());
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 4930204..ecadebb 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -167,12 +167,6 @@
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
ScopedResource* background_texture);
- scoped_ptr<ScopedResource> ApplyInverseTransformForBackgroundFilters(
- DrawingFrame* frame,
- const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform,
- skia::RefPtr<SkImage> backdrop_bitmap,
- const gfx::Rect& backdrop_bounding_rect);
void DrawRenderPassQuad(DrawingFrame* frame, const RenderPassDrawQuad* quad);
void DrawSolidColorQuad(const DrawingFrame* frame,
@@ -208,12 +202,6 @@
int matrix_location);
void SetUseProgram(unsigned program);
- void CopyTextureToFramebuffer(const DrawingFrame* frame,
- int texture_id,
- const gfx::Rect& rect,
- const gfx::Transform& draw_matrix,
- bool flip_vertically);
-
bool UseScopedTexture(DrawingFrame* frame,
const ScopedResource* resource,
const gfx::Rect& viewport_rect);
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index dc68675..2af953e 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -57,8 +57,11 @@
static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
switch (blend_mode) {
+ case BlendModeNone:
case BlendModeNormal:
return SkXfermode::kSrcOver_Mode;
+ case BlendModeScreen:
+ return SkXfermode::kScreen_Mode;
case BlendModeOverlay:
return SkXfermode::kOverlay_Mode;
case BlendModeDarken:
@@ -1421,6 +1424,7 @@
for (int i = 0; i < NumBlendModes; ++i) {
BlendMode blend_mode = static_cast<BlendMode>(i);
SkXfermode::Mode xfer_mode = BlendModeToSkXfermode(blend_mode);
+ settings_.force_blending_with_shaders = (blend_mode != BlendModeNone);
// RenderPassProgram
render_passes_in_draw_order_.clear();
child_pass = AddRenderPass(&render_passes_in_draw_order_,
@@ -1690,7 +1694,7 @@
// If use_aa incorrectly ignores clipping, it will use the
// RenderPassProgramAA shader instead of the RenderPassProgram.
- TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNormal);
+ TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNone);
}
TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
diff --git a/cc/output/output_surface.h b/cc/output/output_surface.h
index 0a0d456..04bd4a3 100644
--- a/cc/output/output_surface.h
+++ b/cc/output/output_surface.h
@@ -125,11 +125,6 @@
// processing should be stopped, or lowered in priority.
virtual void UpdateSmoothnessTakesPriority(bool prefer_smoothness) {}
- // Requests a BeginFrame notification from the output surface. The
- // notification will be delivered by calling
- // OutputSurfaceClient::BeginFrame until the callback is disabled.
- virtual void SetNeedsBeginFrame(bool enable) {}
-
bool HasClient() { return !!client_; }
// Get the class capable of informing cc of hardware overlay capability.
diff --git a/cc/output/output_surface_client.h b/cc/output/output_surface_client.h
index 99b174b..60750b4 100644
--- a/cc/output/output_surface_client.h
+++ b/cc/output/output_surface_client.h
@@ -9,7 +9,6 @@
#include "base/memory/ref_counted.h"
#include "base/time/time.h"
#include "cc/base/cc_export.h"
-#include "cc/output/begin_frame_args.h"
#include "cc/output/context_provider.h"
#include "ui/gfx/geometry/rect.h"
@@ -33,7 +32,6 @@
virtual void CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) = 0;
virtual void SetNeedsRedrawRect(const gfx::Rect& damage_rect) = 0;
- virtual void BeginFrame(const BeginFrameArgs& args) = 0;
virtual void DidSwapBuffers() = 0;
virtual void DidSwapBuffersComplete() = 0;
virtual void ReclaimResources(const CompositorFrameAck* ack) = 0;
diff --git a/cc/output/output_surface_unittest.cc b/cc/output/output_surface_unittest.cc
index b1f4149..4336f07 100644
--- a/cc/output/output_surface_unittest.cc
+++ b/cc/output/output_surface_unittest.cc
@@ -49,10 +49,6 @@
CommitVSyncParameters(timebase, interval);
}
- void BeginFrameForTesting() {
- client_->BeginFrame(CreateExpiredBeginFrameArgsForTesting());
- }
-
void DidSwapBuffersForTesting() { client_->DidSwapBuffers(); }
void OnSwapBuffersCompleteForTesting() { client_->DidSwapBuffersComplete(); }
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h
index 722c782..a10d0ab 100644
--- a/cc/output/program_binding.h
+++ b/cc/output/program_binding.h
@@ -59,7 +59,7 @@
void Initialize(ContextProvider* context_provider,
TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode = BlendModeNormal) {
+ BlendMode blend_mode = BlendModeNone) {
DCHECK(context_provider);
DCHECK(!initialized_);
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index a0ce823..d112ed1 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -1418,14 +1418,9 @@
blue_quad->SetNew(blue_shared_state,
viewport, // Intentionally bigger than clip.
- gfx::Rect(),
- viewport,
- gfx::RectF(viewport),
- viewport.size(),
- texture_format,
- viewport,
- 1.f,
- PicturePileImpl::CreateFromOther(blue_pile.get()));
+ gfx::Rect(), viewport, gfx::RectF(viewport),
+ viewport.size(), texture_format, viewport, 1.f,
+ blue_pile.get());
// One viewport-filling green quad.
scoped_refptr<FakePicturePileImpl> green_pile =
@@ -1441,16 +1436,9 @@
PictureDrawQuad* green_quad =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- green_quad->SetNew(green_shared_state,
- viewport,
- gfx::Rect(),
- viewport,
- gfx::RectF(0.f, 0.f, 1.f, 1.f),
- viewport.size(),
- texture_format,
- viewport,
- 1.f,
- PicturePileImpl::CreateFromOther(green_pile.get()));
+ green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport,
+ gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
+ texture_format, viewport, 1.f, green_pile.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -1487,16 +1475,9 @@
PictureDrawQuad* green_quad =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- green_quad->SetNew(green_shared_state,
- viewport,
- gfx::Rect(),
- viewport,
- gfx::RectF(0, 0, 1, 1),
- viewport.size(),
- texture_format,
- viewport,
- 1.f,
- PicturePileImpl::CreateFromOther(green_pile.get()));
+ green_quad->SetNew(green_shared_state, viewport, gfx::Rect(), viewport,
+ gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format,
+ viewport, 1.f, green_pile.get());
// One viewport-filling white quad.
scoped_refptr<FakePicturePileImpl> white_pile =
@@ -1512,16 +1493,9 @@
PictureDrawQuad* white_quad =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- white_quad->SetNew(white_shared_state,
- viewport,
- gfx::Rect(),
- viewport,
- gfx::RectF(0, 0, 1, 1),
- viewport.size(),
- texture_format,
- viewport,
- 1.f,
- PicturePileImpl::CreateFromOther(white_pile.get()));
+ white_quad->SetNew(white_shared_state, viewport, gfx::Rect(), viewport,
+ gfx::RectF(0, 0, 1, 1), viewport.size(), texture_format,
+ viewport, 1.f, white_pile.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -1586,16 +1560,9 @@
content_to_target_transform, viewport, pass.get());
PictureDrawQuad* quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- quad->SetNew(shared_state,
- viewport,
- gfx::Rect(),
- viewport,
- gfx::RectF(0, 0, 2, 2),
- viewport.size(),
- texture_format,
- viewport,
- 1.f,
- PicturePileImpl::CreateFromOther(pile.get()));
+ quad->SetNew(shared_state, viewport, gfx::Rect(), viewport,
+ gfx::RectF(0, 0, 2, 2), viewport.size(), texture_format,
+ viewport, 1.f, pile.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
@@ -1643,29 +1610,17 @@
PictureDrawQuad* green_quad1 =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- green_quad1->SetNew(top_right_green_shared_quad_state,
- green_rect1,
- gfx::Rect(),
- green_rect1,
- gfx::RectF(green_rect1.size()),
- green_rect1.size(),
- texture_format,
- green_rect1,
- 1.f,
- PicturePileImpl::CreateFromOther(green_pile.get()));
+ green_quad1->SetNew(top_right_green_shared_quad_state, green_rect1,
+ gfx::Rect(), green_rect1, gfx::RectF(green_rect1.size()),
+ green_rect1.size(), texture_format, green_rect1, 1.f,
+ green_pile.get());
PictureDrawQuad* green_quad2 =
pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- green_quad2->SetNew(top_right_green_shared_quad_state,
- green_rect2,
- gfx::Rect(),
- green_rect2,
- gfx::RectF(green_rect2.size()),
- green_rect2.size(),
- texture_format,
- green_rect2,
- 1.f,
- PicturePileImpl::CreateFromOther(green_pile.get()));
+ green_quad2->SetNew(top_right_green_shared_quad_state, green_rect2,
+ gfx::Rect(), green_rect2, gfx::RectF(green_rect2.size()),
+ green_rect2.size(), texture_format, green_rect2, 1.f,
+ green_pile.get());
// Add a green clipped checkerboard in the bottom right to help test
// interleaving picture quad content and solid color content.
@@ -1731,16 +1686,10 @@
content_to_target_transform, quad_content_rect, pass.get());
PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- blue_quad->SetNew(blue_shared_state,
- quad_content_rect,
- gfx::Rect(),
- quad_content_rect,
- gfx::RectF(quad_content_rect),
- content_union_rect.size(),
- texture_format,
- content_union_rect,
- contents_scale,
- PicturePileImpl::CreateFromOther(pile.get()));
+ blue_quad->SetNew(blue_shared_state, quad_content_rect, gfx::Rect(),
+ quad_content_rect, gfx::RectF(quad_content_rect),
+ content_union_rect.size(), texture_format,
+ content_union_rect, contents_scale, pile.get());
// Fill left half of viewport with green.
gfx::Transform half_green_content_to_target_transform;
@@ -1943,16 +1892,9 @@
blue_content_to_target_transform, viewport, pass.get());
PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- blue_quad->SetNew(blue_shared_state,
- viewport,
- gfx::Rect(),
- viewport,
- gfx::RectF(0.f, 0.f, 1.f, 1.f),
- viewport.size(),
- texture_format,
- viewport,
- 1.f,
- PicturePileImpl::CreateFromOther(blue_pile.get()));
+ blue_quad->SetNew(blue_shared_state, viewport, gfx::Rect(), viewport,
+ gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
+ texture_format, viewport, 1.f, blue_pile.get());
RenderPassList pass_list;
pass_list.push_back(pass.Pass());
diff --git a/cc/output/shader.cc b/cc/output/shader.cc
index b962d4a..e22e446 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -669,9 +669,9 @@
}
#define BLEND_MODE_UNIFORMS "s_backdropTexture", "backdropRect"
-#define UNUSED_BLEND_MODE_UNIFORMS (is_default_blend_mode() ? 2 : 0)
+#define UNUSED_BLEND_MODE_UNIFORMS (!has_blend_mode() ? 2 : 0)
#define BLEND_MODE_SET_LOCATIONS(X, POS) \
- if (!is_default_blend_mode()) { \
+ if (has_blend_mode()) { \
DCHECK_LT(static_cast<size_t>(POS) + 1, arraysize(X)); \
backdrop_location_ = locations[POS]; \
backdrop_rect_location_ = locations[POS + 1]; \
@@ -680,7 +680,7 @@
FragmentTexBlendMode::FragmentTexBlendMode()
: backdrop_location_(-1),
backdrop_rect_location_(-1),
- blend_mode_(BlendModeNormal) {
+ blend_mode_(BlendModeNone) {
}
std::string FragmentTexBlendMode::SetBlendModeFunctions(
@@ -688,7 +688,7 @@
if (shader_string.find("ApplyBlendMode") == std::string::npos)
return shader_string;
- if (is_default_blend_mode()) {
+ if (!has_blend_mode()) {
return "#define ApplyBlendMode(X) (X)\n" + shader_string;
}
@@ -902,6 +902,10 @@
std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
switch (blend_mode_) {
+ case BlendModeNormal:
+ return "result.rgb = src.rgb + dst.rgb * (1.0 - src.a);";
+ case BlendModeScreen:
+ return "result.rgb = src.rgb + (1.0 - src.rgb) * dst.rgb;";
case BlendModeLighten:
return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
" (1.0 - dst.a) * src.rgb + dst.rgb);";
@@ -963,11 +967,11 @@
" srcDstAlpha.a,"
" srcDstAlpha.rgb);"
"result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- default:
+ case BlendModeNone:
+ case NumBlendModes:
NOTREACHED();
- // simple alpha compositing
- return "result.rgb = src.rgb * src.a + dst.rgb * dst.a * (1 - src.a)";
}
+ return "result = vec4(1.0, 0.0, 0.0, 1.0);";
}
FragmentTexAlphaBinding::FragmentTexAlphaBinding()
diff --git a/cc/output/shader.h b/cc/output/shader.h
index 0384366..8c1f264 100644
--- a/cc/output/shader.h
+++ b/cc/output/shader.h
@@ -39,7 +39,9 @@
};
enum BlendMode {
+ BlendModeNone,
BlendModeNormal,
+ BlendModeScreen,
BlendModeOverlay,
BlendModeDarken,
BlendModeLighten,
@@ -305,7 +307,7 @@
BlendMode blend_mode() const { return blend_mode_; }
void set_blend_mode(BlendMode blend_mode) { blend_mode_ = blend_mode; }
- bool is_default_blend_mode() const { return blend_mode_ == BlendModeNormal; }
+ bool has_blend_mode() const { return blend_mode_ != BlendModeNone; }
protected:
FragmentTexBlendMode();
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 06f1851..442cd8d 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -350,8 +350,8 @@
TRACE_EVENT0("cc",
"SoftwareRenderer::DrawPictureQuad");
- quad->picture_pile->RasterDirect(current_canvas_, quad->content_rect,
- quad->contents_scale);
+ quad->raster_source->PlaybackToSharedCanvas(
+ current_canvas_, quad->content_rect, quad->contents_scale);
current_canvas_->setDrawFilter(NULL);
}
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index d3753ca..5755ea8 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -670,18 +670,12 @@
ResourceFormat texture_format = RGBA_8888;
gfx::Rect content_rect(30, 40, 20, 30);
float contents_scale = 3.141592f;
- scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
+ scoped_refptr<RasterSource> raster_source = PicturePileImpl::Create();
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(PictureDrawQuad,
- opaque_rect,
- visible_rect,
- tex_coord_rect,
- texture_size,
- texture_format,
- content_rect,
- contents_scale,
- picture_pile);
+ CREATE_QUAD_8_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+ texture_size, texture_format, content_rect, contents_scale,
+ raster_source);
EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
EXPECT_RECT_EQ(opaque_rect, copy_quad->opaque_rect);
EXPECT_RECT_EQ(visible_rect, copy_quad->visible_rect);
@@ -690,22 +684,18 @@
EXPECT_EQ(texture_format, copy_quad->texture_format);
EXPECT_RECT_EQ(content_rect, copy_quad->content_rect);
EXPECT_EQ(contents_scale, copy_quad->contents_scale);
- EXPECT_EQ(picture_pile, copy_quad->picture_pile);
+ EXPECT_EQ(raster_source, copy_quad->raster_source);
- CREATE_QUAD_6_ALL(PictureDrawQuad,
- tex_coord_rect,
- texture_size,
- texture_format,
- content_rect,
- contents_scale,
- picture_pile);
+ CREATE_QUAD_6_ALL(PictureDrawQuad, tex_coord_rect, texture_size,
+ texture_format, content_rect, contents_scale,
+ raster_source);
EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
EXPECT_EQ(texture_size, copy_quad->texture_size);
EXPECT_EQ(texture_format, copy_quad->texture_format);
EXPECT_RECT_EQ(content_rect, copy_quad->content_rect);
EXPECT_EQ(contents_scale, copy_quad->contents_scale);
- EXPECT_EQ(picture_pile, copy_quad->picture_pile);
+ EXPECT_EQ(raster_source, copy_quad->raster_source);
}
class DrawQuadIteratorTest : public testing::Test {
@@ -922,18 +912,12 @@
ResourceFormat texture_format = RGBA_8888;
gfx::Rect content_rect(30, 40, 20, 30);
float contents_scale = 3.141592f;
- scoped_refptr<PicturePileImpl> picture_pile = PicturePileImpl::Create();
+ scoped_refptr<PicturePileImpl> raster_source = PicturePileImpl::Create();
CREATE_SHARED_STATE();
- CREATE_QUAD_8_NEW(PictureDrawQuad,
- opaque_rect,
- visible_rect,
- tex_coord_rect,
- texture_size,
- texture_format,
- content_rect,
- contents_scale,
- picture_pile);
+ CREATE_QUAD_8_NEW(PictureDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
+ texture_size, texture_format, content_rect, contents_scale,
+ raster_source);
EXPECT_EQ(0, IterateAndCount(quad_new));
}
diff --git a/cc/quads/picture_draw_quad.cc b/cc/quads/picture_draw_quad.cc
index af120a4..bf329c2 100644
--- a/cc/quads/picture_draw_quad.cc
+++ b/cc/quads/picture_draw_quad.cc
@@ -26,7 +26,7 @@
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile) {
+ scoped_refptr<RasterSource> raster_source) {
ContentDrawQuadBase::SetNew(
shared_quad_state,
DrawQuad::PICTURE_CONTENT,
@@ -38,7 +38,7 @@
!PlatformColor::SameComponentOrder(texture_format));
this->content_rect = content_rect;
this->contents_scale = contents_scale;
- this->picture_pile = picture_pile;
+ this->raster_source = raster_source;
this->texture_format = texture_format;
}
@@ -52,7 +52,7 @@
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile) {
+ scoped_refptr<RasterSource> raster_source) {
ContentDrawQuadBase::SetAll(shared_quad_state,
DrawQuad::PICTURE_CONTENT,
rect,
@@ -65,7 +65,7 @@
texture_format));
this->content_rect = content_rect;
this->contents_scale = contents_scale;
- this->picture_pile = picture_pile;
+ this->raster_source = raster_source;
this->texture_format = texture_format;
}
@@ -87,7 +87,7 @@
value->EndArray();
value->SetDouble("contents_scale", contents_scale);
value->SetInteger("texture_format", texture_format);
- // TODO(piman): picture_pile?
+ // TODO(piman): raster_source?
}
} // namespace cc
diff --git a/cc/quads/picture_draw_quad.h b/cc/quads/picture_draw_quad.h
index 1bea1a2..62c9f18 100644
--- a/cc/quads/picture_draw_quad.h
+++ b/cc/quads/picture_draw_quad.h
@@ -9,7 +9,7 @@
#include "base/memory/scoped_ptr.h"
#include "cc/base/cc_export.h"
#include "cc/quads/content_draw_quad_base.h"
-#include "cc/resources/picture_pile_impl.h"
+#include "cc/resources/raster_source.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/rect_f.h"
#include "ui/gfx/geometry/size.h"
@@ -31,7 +31,7 @@
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile);
+ scoped_refptr<RasterSource> raster_source);
void SetAll(const SharedQuadState* shared_quad_state,
const gfx::Rect& rect,
@@ -43,11 +43,11 @@
ResourceFormat texture_format,
const gfx::Rect& content_rect,
float contents_scale,
- scoped_refptr<PicturePileImpl> picture_pile);
+ scoped_refptr<RasterSource> raster_source);
gfx::Rect content_rect;
float contents_scale;
- scoped_refptr<PicturePileImpl> picture_pile;
+ scoped_refptr<RasterSource> raster_source;
ResourceFormat texture_format;
void IterateResources(const ResourceIteratorCallback& callback) override;
diff --git a/cc/resources/bitmap_content_layer_updater.cc b/cc/resources/bitmap_content_layer_updater.cc
index 63ba336..31a62c3 100644
--- a/cc/resources/bitmap_content_layer_updater.cc
+++ b/cc/resources/bitmap_content_layer_updater.cc
@@ -32,19 +32,17 @@
scoped_refptr<BitmapContentLayerUpdater> BitmapContentLayerUpdater::Create(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id) {
return make_scoped_refptr(
new BitmapContentLayerUpdater(painter.Pass(),
- stats_instrumentation,
layer_id));
}
BitmapContentLayerUpdater::BitmapContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id)
- : ContentLayerUpdater(painter.Pass(), stats_instrumentation, layer_id) {}
+ : ContentLayerUpdater(painter.Pass(), layer_id) {
+}
BitmapContentLayerUpdater::~BitmapContentLayerUpdater() {}
@@ -71,17 +69,11 @@
DCHECK_EQ(paint_rect.height(), canvas_->getBaseLayerSize().height());
}
- base::TimeTicks start_time =
- rendering_stats_instrumentation_->StartRecording();
PaintContents(canvas_.get(),
content_size,
paint_rect,
contents_width_scale,
contents_height_scale);
- base::TimeDelta duration =
- rendering_stats_instrumentation_->EndRecording(start_time);
- rendering_stats_instrumentation_->AddPaint(
- duration, paint_rect.width() * paint_rect.height());
}
void BitmapContentLayerUpdater::UpdateTexture(ResourceUpdateQueue* queue,
diff --git a/cc/resources/bitmap_content_layer_updater.h b/cc/resources/bitmap_content_layer_updater.h
index 5ddc35f..3477600 100644
--- a/cc/resources/bitmap_content_layer_updater.h
+++ b/cc/resources/bitmap_content_layer_updater.h
@@ -42,7 +42,6 @@
static scoped_refptr<BitmapContentLayerUpdater> Create(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumenation,
int layer_id);
scoped_ptr<LayerUpdater::Resource> CreateResource(
@@ -63,7 +62,6 @@
protected:
BitmapContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumenation,
int layer_id);
~BitmapContentLayerUpdater() override;
diff --git a/cc/resources/bitmap_skpicture_content_layer_updater.cc b/cc/resources/bitmap_skpicture_content_layer_updater.cc
index 5b8e5e4..a78a9df 100644
--- a/cc/resources/bitmap_skpicture_content_layer_updater.cc
+++ b/cc/resources/bitmap_skpicture_content_layer_updater.cc
@@ -53,9 +53,8 @@
scoped_ptr<LayerPainter> painter,
RenderingStatsInstrumentation* stats_instrumentation,
int layer_id)
- : SkPictureContentLayerUpdater(painter.Pass(),
- stats_instrumentation,
- layer_id) {}
+ : SkPictureContentLayerUpdater(painter.Pass(), layer_id) {
+}
BitmapSkPictureContentLayerUpdater::~BitmapSkPictureContentLayerUpdater() {}
diff --git a/cc/resources/content_layer_updater.cc b/cc/resources/content_layer_updater.cc
index 971362f..206d76b 100644
--- a/cc/resources/content_layer_updater.cc
+++ b/cc/resources/content_layer_updater.cc
@@ -5,7 +5,6 @@
#include "cc/resources/content_layer_updater.h"
#include "base/debug/trace_event.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/resources/layer_painter.h"
#include "third_party/skia/include/core/SkCanvas.h"
#include "third_party/skia/include/core/SkRect.h"
@@ -16,12 +15,9 @@
namespace cc {
-ContentLayerUpdater::ContentLayerUpdater(
- scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id)
- : rendering_stats_instrumentation_(stats_instrumentation),
- layer_id_(layer_id),
+ContentLayerUpdater::ContentLayerUpdater(scoped_ptr<LayerPainter> painter,
+ int layer_id)
+ : layer_id_(layer_id),
layer_is_opaque_(false),
layer_fills_bounds_completely_(false),
painter_(painter.Pass()),
@@ -30,11 +26,6 @@
ContentLayerUpdater::~ContentLayerUpdater() {}
-void ContentLayerUpdater::set_rendering_stats_instrumentation(
- RenderingStatsInstrumentation* rsi) {
- rendering_stats_instrumentation_ = rsi;
-}
-
void ContentLayerUpdater::PaintContents(SkCanvas* canvas,
const gfx::Size& layer_content_size,
const gfx::Rect& paint_rect,
diff --git a/cc/resources/content_layer_updater.h b/cc/resources/content_layer_updater.h
index 4ba18ba..0f26b82 100644
--- a/cc/resources/content_layer_updater.h
+++ b/cc/resources/content_layer_updater.h
@@ -21,15 +21,12 @@
// their respective PaintContents implementations.
class CC_EXPORT ContentLayerUpdater : public LayerUpdater {
public:
- void set_rendering_stats_instrumentation(RenderingStatsInstrumentation* rsi);
void SetOpaque(bool opaque) override;
void SetFillsBoundsCompletely(bool fills_bounds) override;
void SetBackgroundColor(SkColor background_color) override;
protected:
- ContentLayerUpdater(scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
- int layer_id);
+ ContentLayerUpdater(scoped_ptr<LayerPainter> painter, int layer_id);
~ContentLayerUpdater() override;
// Paints the contents. |content_size| size of the underlying layer in
@@ -49,7 +46,6 @@
SkColor background_color() const { return background_color_; }
- RenderingStatsInstrumentation* rendering_stats_instrumentation_;
int layer_id_;
// True when it is known that all output pixels will be opaque.
diff --git a/cc/resources/gpu_raster_worker_pool.cc b/cc/resources/gpu_raster_worker_pool.cc
index 04724f1..c913970 100644
--- a/cc/resources/gpu_raster_worker_pool.cc
+++ b/cc/resources/gpu_raster_worker_pool.cc
@@ -40,7 +40,7 @@
// Turn on distance fields for layers that have ever animated.
bool use_distance_field_text =
use_distance_field_text_ ||
- raster_source->SuitableForDistanceFieldText();
+ raster_source->ShouldAttemptToUseDistanceFieldText();
SkSurface* sk_surface = lock_.GetSkSurface(use_distance_field_text);
if (!sk_surface)
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index d8885e7..04b18c3 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -167,18 +167,16 @@
VerifyLiveTilesRect();
}
-void PictureLayerTiling::UpdateTilesToCurrentPile(
+void PictureLayerTiling::UpdateTilesToCurrentRasterSource(
const Region& layer_invalidation,
const gfx::Size& new_layer_bounds) {
DCHECK(!new_layer_bounds.IsEmpty());
- gfx::Size tile_size = tiling_data_.max_texture_size();
+ gfx::Size content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
+ gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
if (new_layer_bounds != layer_bounds_) {
- gfx::Size content_bounds =
- gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
-
- tile_size = client_->CalculateTileSize(content_bounds);
if (tile_size.IsEmpty()) {
layer_bounds_ = gfx::Size();
content_bounds = gfx::Size();
@@ -699,15 +697,13 @@
return current_occlusion_in_layer_space_.IsOccluded(tile_query_rect);
}
-bool PictureLayerTiling::IsTileRequiredForActivation(const Tile* tile) const {
+bool PictureLayerTiling::IsTileRequiredForActivationIfVisible(
+ const Tile* tile) const {
DCHECK_EQ(PENDING_TREE, client_->GetTree());
- // Note that although this function will determine whether tile is required
- // for activation assuming that it is in visible (ie in the viewport). That is
- // to say, even if the tile is outside of the viewport, it will be treated as
- // if it was inside (there are no explicit checks for this). Hence, this
- // function is only called for visible tiles to ensure we don't block
- // activation on tiles outside of the viewport.
+ // This function assumes that the tile is visible (i.e. in the viewport). The
+ // caller needs to make sure that this condition is met to ensure we don't
+ // block activation on tiles outside of the viewport.
// If we are not allowed to mark tiles as required for activation, then don't
// do it.
@@ -744,6 +740,21 @@
return true;
}
+bool PictureLayerTiling::IsTileRequiredForDrawIfVisible(
+ const Tile* tile) const {
+ DCHECK_EQ(ACTIVE_TREE, client_->GetTree());
+
+ // This function assumes that the tile is visible (i.e. in the viewport).
+
+ if (resolution_ != HIGH_RESOLUTION)
+ return false;
+
+ if (IsTileOccluded(tile))
+ return false;
+
+ return true;
+}
+
void PictureLayerTiling::UpdateTileAndTwinPriority(Tile* tile) const {
UpdateTilePriority(tile);
@@ -756,6 +767,8 @@
tile->set_is_occluded(twin_tree, false);
if (twin_tree == PENDING_TREE)
tile->set_required_for_activation(false);
+ else
+ tile->set_required_for_draw(false);
return;
}
@@ -766,22 +779,31 @@
// TODO(vmpstr): This code should return the priority instead of setting it on
// the tile. This should be a part of the change to move tile priority from
// tiles into iterators.
+ TilePriority::PriorityBin max_tile_priority_bin =
+ client_->GetMaxTilePriorityBin();
WhichTree tree = client_->GetTree();
DCHECK_EQ(TileAt(tile->tiling_i_index(), tile->tiling_j_index()), tile);
gfx::Rect tile_bounds =
tiling_data_.TileBounds(tile->tiling_i_index(), tile->tiling_j_index());
- if (current_visible_rect_.Intersects(tile_bounds)) {
+ if (max_tile_priority_bin <= TilePriority::NOW &&
+ current_visible_rect_.Intersects(tile_bounds)) {
tile->SetPriority(tree, TilePriority(resolution_, TilePriority::NOW, 0));
- if (tree == PENDING_TREE)
- tile->set_required_for_activation(IsTileRequiredForActivation(tile));
+ if (tree == PENDING_TREE) {
+ tile->set_required_for_activation(
+ IsTileRequiredForActivationIfVisible(tile));
+ } else {
+ tile->set_required_for_draw(IsTileRequiredForDrawIfVisible(tile));
+ }
tile->set_is_occluded(tree, IsTileOccluded(tile));
return;
}
if (tree == PENDING_TREE)
tile->set_required_for_activation(false);
+ else
+ tile->set_required_for_draw(false);
tile->set_is_occluded(tree, false);
DCHECK_GT(content_to_screen_scale_, 0.f);
@@ -789,8 +811,9 @@
current_visible_rect_.ManhattanInternalDistance(tile_bounds) *
content_to_screen_scale_;
- if (current_soon_border_rect_.Intersects(tile_bounds) ||
- current_skewport_rect_.Intersects(tile_bounds)) {
+ if (max_tile_priority_bin <= TilePriority::SOON &&
+ (current_soon_border_rect_.Intersects(tile_bounds) ||
+ current_skewport_rect_.Intersects(tile_bounds))) {
tile->SetPriority(
tree,
TilePriority(resolution_, TilePriority::SOON, distance_to_visible));
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index 17da548..eb47b60 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -29,7 +29,7 @@
namespace cc {
class PictureLayerTiling;
-class PicturePileImpl;
+class RasterSource;
class CC_EXPORT PictureLayerTilingClient {
public:
@@ -48,6 +48,7 @@
const PictureLayerTiling* tiling) const = 0;
virtual PictureLayerTiling* GetRecycledTwinTiling(
const PictureLayerTiling* tiling) = 0;
+ virtual TilePriority::PriorityBin GetMaxTilePriorityBin() const = 0;
virtual size_t GetMaxTilesForInterestArea() const = 0;
virtual float GetSkewportTargetTimeInSeconds() const = 0;
virtual int GetSkewportExtrapolationLimitInContentPixels() const = 0;
@@ -144,8 +145,8 @@
const gfx::Size& layer_bounds,
PictureLayerTilingClient* client);
gfx::Size layer_bounds() const { return layer_bounds_; }
- void UpdateTilesToCurrentPile(const Region& layer_invalidation,
- const gfx::Size& new_layer_bounds);
+ void UpdateTilesToCurrentRasterSource(const Region& layer_invalidation,
+ const gfx::Size& new_layer_bounds);
void CreateMissingTilesInLiveTilesRect();
void RemoveTilesInRegion(const Region& layer_region);
@@ -205,7 +206,8 @@
}
bool IsTileOccluded(const Tile* tile) const;
- bool IsTileRequiredForActivation(const Tile* tile) const;
+ bool IsTileRequiredForActivationIfVisible(const Tile* tile) const;
+ bool IsTileRequiredForDrawIfVisible(const Tile* tile) const;
// Iterate over all tiles to fill content_rect. Even if tiles are invalid
// (i.e. no valid resource) this tiling should still iterate over them.
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 8f91763..0d1443e 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -59,7 +59,7 @@
void RunInvalidateTest(const std::string& test_name, const Region& region) {
timer_.Reset();
do {
- picture_layer_tiling_->UpdateTilesToCurrentPile(
+ picture_layer_tiling_->UpdateTilesToCurrentRasterSource(
region, picture_layer_tiling_->tiling_size());
timer_.NextLap();
} while (!timer_.HasTimeLimitExpired());
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index b2b86b5..a0000b6 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -69,8 +69,8 @@
if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
this_tiling->set_resolution(other.tilings_[i]->resolution());
- this_tiling->UpdateTilesToCurrentPile(layer_invalidation,
- new_layer_bounds);
+ this_tiling->UpdateTilesToCurrentRasterSource(layer_invalidation,
+ new_layer_bounds);
this_tiling->CreateMissingTilesInLiveTilesRect();
if (this_tiling->resolution() == HIGH_RESOLUTION)
have_high_res_tiling = true;
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index f793097..786f943 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -211,7 +211,7 @@
Region invalidation =
SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
- tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200));
+ tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(200, 200));
EXPECT_FALSE(tiling_->TileAt(0, 0));
}
@@ -266,8 +266,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_->UpdateTilesToCurrentPile(invalidation,
- gfx::Size(right + 1, bottom + 1));
+ tiling_->UpdateTilesToCurrentRasterSource(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 +284,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_->UpdateTilesToCurrentPile(invalidation,
- gfx::Size(right + 2, bottom + 2));
+ tiling_->UpdateTilesToCurrentRasterSource(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 +421,7 @@
Region invalidation =
SubtractRegions(gfx::Rect(tile_size), gfx::Rect(original_layer_size));
- tiling_->UpdateTilesToCurrentPile(invalidation, gfx::Size(200, 200));
+ tiling_->UpdateTilesToCurrentRasterSource(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
@@ -2178,5 +2178,29 @@
EXPECT_FALSE(recycle_tiling->TileAt(0, 0));
}
+TEST_F(PictureLayerTilingIteratorTest, ResizeTilesAndUpdateToCurrent) {
+ // The tiling has four rows and three columns.
+ Initialize(gfx::Size(150, 100), 1, gfx::Size(250, 150));
+ tiling_->CreateAllTilesForTesting();
+ EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
+ EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
+ EXPECT_EQ(4u, tiling_->AllRefTilesForTesting().size());
+
+ client_.SetTileSize(gfx::Size(250, 200));
+ client_.set_tree(PENDING_TREE);
+
+ // Tile size in the tiling should still be 150x100.
+ EXPECT_EQ(150, tiling_->TilingDataForTesting().max_texture_size().width());
+ EXPECT_EQ(100, tiling_->TilingDataForTesting().max_texture_size().height());
+
+ Region invalidation;
+ tiling_->UpdateTilesToCurrentRasterSource(invalidation, gfx::Size(250, 150));
+
+ // Tile size in the tiling should be resized to 250x200.
+ EXPECT_EQ(250, tiling_->TilingDataForTesting().max_texture_size().width());
+ EXPECT_EQ(200, tiling_->TilingDataForTesting().max_texture_size().height());
+ EXPECT_EQ(0u, tiling_->AllRefTilesForTesting().size());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index 1ad673b..ab138ca 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -9,7 +9,7 @@
#include <vector>
#include "cc/base/region.h"
-#include "cc/debug/rendering_stats_instrumentation.h"
+#include "cc/resources/picture_pile_impl.h"
#include "cc/resources/raster_worker_pool.h"
#include "skia/ext/analysis_canvas.h"
@@ -22,6 +22,24 @@
// operations.
const int kOpCountThatIsOkToAnalyze = 10;
+// Dimensions of the tiles in this picture pile as well as the dimensions of
+// 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
+// indicates when to stop invalidating offscreen regions.
+// kFrequentInvalidationDistanceThreshold defines what it means to be
+// "offscreen" in terms of distance to visible in css pixels.
+const float kInvalidationFrequencyThreshold = 0.75f;
+const int kFrequentInvalidationDistanceThreshold = 512;
+
// TODO(humper): The density threshold here is somewhat arbitrary; need a
// way to set // this from the command line so we can write a benchmark
// script and find a sweet spot.
@@ -149,8 +167,21 @@
namespace cc {
PicturePile::PicturePile()
- : is_suitable_for_gpu_rasterization_(true),
- pixel_record_distance_(kPixelDistanceToRecord) {
+ : 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),
+ is_suitable_for_gpu_rasterization_(true) {
+ tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
+ tile_grid_info_.fTileInterval.setEmpty();
+ tile_grid_info_.fMargin.setEmpty();
+ tile_grid_info_.fOffset.setZero();
}
PicturePile::~PicturePile() {
@@ -165,8 +196,7 @@
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
- Picture::RecordingMode recording_mode,
- RenderingStatsInstrumentation* stats_instrumentation) {
+ Picture::RecordingMode recording_mode) {
background_color_ = background_color;
contents_opaque_ = contents_opaque;
contents_fill_bounds_completely_ = contents_fill_bounds_completely;
@@ -174,7 +204,7 @@
bool updated = false;
Region resize_invalidation;
- gfx::Size old_tiling_size = tiling_size();
+ gfx::Size old_tiling_size = GetSize();
if (old_tiling_size != layer_size) {
tiling_.SetTilingSize(layer_size);
updated = true;
@@ -183,26 +213,35 @@
gfx::Rect interest_rect = visible_layer_rect;
interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_);
recorded_viewport_ = interest_rect;
- recorded_viewport_.Intersect(gfx::Rect(tiling_size()));
+ recorded_viewport_.Intersect(gfx::Rect(GetSize()));
gfx::Rect interest_rect_over_tiles =
tiling_.ExpandRectToTileBounds(interest_rect);
+ gfx::Size min_tiling_size(
+ std::min(GetSize().width(), old_tiling_size.width()),
+ std::min(GetSize().height(), old_tiling_size.height()));
+ gfx::Size max_tiling_size(
+ std::max(GetSize().width(), old_tiling_size.width()),
+ std::max(GetSize().height(), old_tiling_size.height()));
+
if (old_tiling_size != layer_size) {
has_any_recordings_ = false;
- // Drop recordings that are outside the new layer bounds or that changed
- // size.
+ // Drop recordings that are outside the new or old layer bounds or that
+ // changed size. Newly exposed areas are considered invalidated.
+ // Previously exposed areas that are now outside of bounds also need to
+ // be invalidated, as they may become part of raster when scale < 1.
std::vector<PictureMapKey> to_erase;
int min_toss_x = tiling_.num_tiles_x();
- if (tiling_size().width() > old_tiling_size.width()) {
+ if (max_tiling_size.width() > min_tiling_size.width()) {
min_toss_x =
- tiling_.FirstBorderTileXIndexFromSrcCoord(old_tiling_size.width());
+ tiling_.FirstBorderTileXIndexFromSrcCoord(min_tiling_size.width());
}
int min_toss_y = tiling_.num_tiles_y();
- if (tiling_size().height() > old_tiling_size.height()) {
+ if (max_tiling_size.height() > min_tiling_size.height()) {
min_toss_y =
- tiling_.FirstBorderTileYIndexFromSrcCoord(old_tiling_size.height());
+ tiling_.FirstBorderTileYIndexFromSrcCoord(min_tiling_size.height());
}
for (PictureMap::const_iterator it = picture_map_.begin();
it != picture_map_.end();
@@ -221,20 +260,22 @@
// If a recording is dropped and not re-recorded below, invalidate that
// full recording to cause any raster tiles that would use it to be
// dropped.
- // If the recording will be replaced below, just invalidate newly exposed
- // areas to force raster tiles that include the old recording to know
- // there is new recording to display.
- gfx::Rect old_tiling_rect_over_tiles =
- tiling_.ExpandRectToTileBounds(gfx::Rect(old_tiling_size));
+ // If the recording will be replaced below, invalidate newly exposed
+ // areas and previously exposed areas to force raster tiles that include the
+ // old recording to know there is new recording to display.
+ gfx::Rect min_tiling_rect_over_tiles =
+ tiling_.ExpandRectToTileBounds(gfx::Rect(min_tiling_size));
if (min_toss_x < tiling_.num_tiles_x()) {
// The bounds which we want to invalidate are the tiles along the old
- // edge of the pile. We'll call this bounding box the OLD EDGE RECT.
+ // edge of the pile when expanding, or the new edge of the pile when
+ // shrinking. In either case, it's the difference of the two, so we'll
+ // call this bounding box the DELTA EDGE RECT.
//
- // In the picture below, the old edge rect would be the bounding box
- // of tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index
- // of the same tiles.
+ // In the picture below, the delta edge rect would be the bounding box of
+ // tiles {h,i,j}. |min_toss_x| would be equal to the horizontal index of
+ // the same tiles.
//
- // old pile edge-v new pile edge-v
+ // min pile edge-v max pile edge-v
// ---------------+ - - - - - - - -+
// mmppssvvyybbeeh|h .
// mmppssvvyybbeeh|h .
@@ -242,33 +283,33 @@
// nnqqttwwzzccffi|i .
// oorruuxxaaddggj|j .
// oorruuxxaaddggj|j .
- // ---------------+ - - - - - - - -+ <- old pile edge
+ // ---------------+ - - - - - - - -+ <- min pile edge
// .
- // - - - - - - - - - - - - - - - -+ <- new pile edge
+ // - - - - - - - - - - - - - - - -+ <- max pile edge
//
// If you were to slide a vertical beam from the left edge of the
- // old edge rect toward the right, it would either hit the right edge
- // of the old edge rect, or the interest rect (expanded to the bounds
+ // delta edge rect toward the right, it would either hit the right edge
+ // of the delta edge rect, or the interest rect (expanded to the bounds
// of the tiles it touches). The same is true for a beam parallel to
- // any of the four edges, sliding accross the old edge rect. We use
+ // any of the four edges, sliding across the delta edge rect. We use
// the union of these four rectangles generated by these beams to
- // determine which part of the old edge rect is outside of the expanded
+ // determine which part of the delta edge rect is outside of the expanded
// interest rect.
//
- // Case 1: Intersect rect is outside the old edge rect. It can be
+ // Case 1: Intersect rect is outside the delta edge rect. It can be
// either on the left or the right. The |left_rect| and |right_rect|,
// cover this case, one will be empty and one will cover the full
- // old edge rect. In the picture below, |left_rect| would cover the
- // old edge rect, and |right_rect| would be empty.
+ // delta edge rect. In the picture below, |left_rect| would cover the
+ // delta edge rect, and |right_rect| would be empty.
// +----------------------+ |^^^^^^^^^^^^^^^|
- // |===> OLD EDGE RECT | | |
+ // |===> DELTA EDGE RECT | | |
// |===> | | INTEREST RECT |
// |===> | | |
// |===> | | |
// +----------------------+ |vvvvvvvvvvvvvvv|
//
- // Case 2: Interest rect is inside the old edge rect. It will always
- // fill the entire old edge rect horizontally since the old edge rect
+ // Case 2: Interest rect is inside the delta edge rect. It will always
+ // fill the entire delta edge rect horizontally since the old edge rect
// is a single tile wide, and the interest rect has been expanded to the
// bounds of the tiles it touches. In this case the |left_rect| and
// |right_rect| will be empty, but the case is handled by the |top_rect|
@@ -285,19 +326,19 @@
// | |
// +-----------------+
// | |
- // | OLD EDGE RECT |
+ // | DELTA EDGE RECT |
// +-----------------+
//
// Lastly, we need to consider tiles inside the expanded interest rect.
// For those tiles, we want to invalidate exactly the newly exposed
- // pixels. In the picture below the tiles in the old edge rect have been
- // resized and the area covered by periods must be invalidated. The
+ // pixels. In the picture below the tiles in the delta edge rect have
+ // been resized and the area covered by periods must be invalidated. The
// |exposed_rect| will cover exactly that area.
- // v-old pile edge
+ // v-min pile edge
// +---------+-------+
// | ........|
// | ........|
- // | OLD EDGE.RECT..|
+ // | DELTA EDGE.RECT.|
// | ........|
// | ........|
// | ........|
@@ -308,18 +349,18 @@
int left = tiling_.TilePositionX(min_toss_x);
int right = left + tiling_.TileSizeX(min_toss_x);
- int top = old_tiling_rect_over_tiles.y();
- int bottom = old_tiling_rect_over_tiles.bottom();
+ int top = min_tiling_rect_over_tiles.y();
+ int bottom = min_tiling_rect_over_tiles.bottom();
int left_until = std::min(interest_rect_over_tiles.x(), right);
int right_until = std::max(interest_rect_over_tiles.right(), left);
int top_until = std::min(interest_rect_over_tiles.y(), bottom);
int bottom_until = std::max(interest_rect_over_tiles.bottom(), top);
- int exposed_left = old_tiling_size.width();
- int exposed_left_until = tiling_size().width();
+ int exposed_left = min_tiling_size.width();
+ int exposed_left_until = max_tiling_size.width();
int exposed_top = top;
- int exposed_bottom = tiling_size().height();
+ int exposed_bottom = max_tiling_size.height();
DCHECK_GE(exposed_left, left);
gfx::Rect left_rect(left, top, left_until - left, bottom - top);
@@ -339,23 +380,23 @@
}
if (min_toss_y < tiling_.num_tiles_y()) {
// The same thing occurs here as in the case above, but the invalidation
- // rect is the bounding box around the bottom row of tiles in the old
+ // rect is the bounding box around the bottom row of tiles in the min
// pile. This would be tiles {o,r,u,x,a,d,g,j} in the above picture.
int top = tiling_.TilePositionY(min_toss_y);
int bottom = top + tiling_.TileSizeY(min_toss_y);
- int left = old_tiling_rect_over_tiles.x();
- int right = old_tiling_rect_over_tiles.right();
+ int left = min_tiling_rect_over_tiles.x();
+ int right = min_tiling_rect_over_tiles.right();
int top_until = std::min(interest_rect_over_tiles.y(), bottom);
int bottom_until = std::max(interest_rect_over_tiles.bottom(), top);
int left_until = std::min(interest_rect_over_tiles.x(), right);
int right_until = std::max(interest_rect_over_tiles.right(), left);
- int exposed_top = old_tiling_size.height();
- int exposed_top_until = tiling_size().height();
+ int exposed_top = min_tiling_size.height();
+ int exposed_top_until = max_tiling_size.height();
int exposed_left = left;
- int exposed_right = tiling_size().width();
+ int exposed_right = max_tiling_size.width();
DCHECK_GE(exposed_top, top);
gfx::Rect left_rect(left, top, left_until - left, bottom - top);
@@ -378,7 +419,7 @@
// Detect cases where the full pile is invalidated, in this situation we
// can just drop/invalidate everything.
if (invalidation->Contains(gfx::Rect(old_tiling_size)) ||
- invalidation->Contains(gfx::Rect(tiling_size()))) {
+ invalidation->Contains(gfx::Rect(GetSize()))) {
for (auto& it : picture_map_)
updated = it.second.Invalidate(frame_number) || updated;
} else {
@@ -489,9 +530,7 @@
bool gather_pixel_refs = RasterWorkerPool::GetNumRasterThreads() > 1;
{
- base::TimeDelta best_duration = base::TimeDelta::Max();
for (int i = 0; i < repeat_count; i++) {
- base::TimeTicks start_time = stats_instrumentation->StartRecording();
picture = Picture::Create(record_rect,
painter,
tile_grid_info_,
@@ -505,13 +544,7 @@
// the pile after each invalidation.
is_suitable_for_gpu_rasterization_ &=
picture->IsSuitableForGpuRasterization();
- base::TimeDelta duration =
- stats_instrumentation->EndRecording(start_time);
- best_duration = std::min(duration, best_duration);
}
- int recorded_pixel_count =
- picture->LayerRect().width() * picture->LayerRect().height();
- stats_instrumentation->AddRecord(best_duration, recorded_pixel_count);
}
bool found_tile_for_recorded_picture = false;
@@ -536,11 +569,93 @@
return true;
}
+gfx::Size PicturePile::GetSize() const {
+ return tiling_.tiling_size();
+}
+
void PicturePile::SetEmptyBounds() {
tiling_.SetTilingSize(gfx::Size());
Clear();
}
+void PicturePile::SetMinContentsScale(float min_contents_scale) {
+ DCHECK(min_contents_scale);
+ if (min_contents_scale_ == min_contents_scale)
+ return;
+
+ // Picture contents are played back scaled. When the final contents scale is
+ // less than 1 (i.e. low res), then multiple recorded pixels will be used
+ // to raster one final pixel. To avoid splitting a final pixel across
+ // pictures (which would result in incorrect rasterization due to blending), a
+ // buffer margin is added so that any picture can be snapped to integral
+ // final pixels.
+ //
+ // For example, if a 1/4 contents scale is used, then that would be 3 buffer
+ // pixels, since that's the minimum number of pixels to add so that resulting
+ // content can be snapped to a four pixel aligned grid.
+ int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
+ buffer_pixels = std::max(0, buffer_pixels);
+ SetBufferPixels(buffer_pixels);
+ min_contents_scale_ = min_contents_scale;
+}
+
+// static
+void PicturePile::ComputeTileGridInfo(const gfx::Size& tile_grid_size,
+ SkTileGridFactory::TileGridInfo* info) {
+ DCHECK(info);
+ info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
+ tile_grid_size.height() - 2 * kTileGridBorderPixels);
+ DCHECK_GT(info->fTileInterval.width(), 0);
+ DCHECK_GT(info->fTileInterval.height(), 0);
+ info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
+ // Offset the tile grid coordinate space to take into account the fact
+ // that the top-most and left-most tiles do not have top and left borders
+ // respectively.
+ info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
+}
+
+void PicturePile::SetTileGridSize(const gfx::Size& tile_grid_size) {
+ 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_;
+}
+
+bool PicturePile::CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const {
+ bool include_borders = false;
+ for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+ tile_iter; ++tile_iter) {
+ PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+ if (map_iter == picture_map_.end())
+ return false;
+ if (!map_iter->second.GetPicture())
+ return false;
+ }
+ return true;
+}
+
void PicturePile::DetermineIfSolidColor() {
is_solid_color_ = false;
solid_color_ = SK_ColorTRANSPARENT;
@@ -573,4 +688,81 @@
is_solid_color_ = canvas.GetColorIfSolid(&solid_color_);
}
+gfx::Rect PicturePile::PaddedRect(const PictureMapKey& key) const {
+ gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
+ return PadRect(tile);
+}
+
+gfx::Rect PicturePile::PadRect(const gfx::Rect& rect) const {
+ gfx::Rect padded_rect = rect;
+ padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
+ -buffer_pixels());
+ return padded_rect;
+}
+
+void PicturePile::Clear() {
+ picture_map_.clear();
+ recorded_viewport_ = gfx::Rect();
+ has_any_recordings_ = false;
+ is_solid_color_ = false;
+}
+
+PicturePile::PictureInfo::PictureInfo() : last_frame_number_(0) {
+}
+
+PicturePile::PictureInfo::~PictureInfo() {
+}
+
+void PicturePile::PictureInfo::AdvanceInvalidationHistory(int frame_number) {
+ DCHECK_GE(frame_number, last_frame_number_);
+ if (frame_number == last_frame_number_)
+ return;
+
+ invalidation_history_ <<= (frame_number - last_frame_number_);
+ last_frame_number_ = frame_number;
+}
+
+bool PicturePile::PictureInfo::Invalidate(int frame_number) {
+ AdvanceInvalidationHistory(frame_number);
+ invalidation_history_.set(0);
+
+ bool did_invalidate = !!picture_.get();
+ picture_ = NULL;
+ return did_invalidate;
+}
+
+bool PicturePile::PictureInfo::NeedsRecording(int frame_number,
+ int distance_to_visible) {
+ AdvanceInvalidationHistory(frame_number);
+
+ // We only need recording if we don't have a picture. Furthermore, we only
+ // need a recording if we're within frequent invalidation distance threshold
+ // or the invalidation is not frequent enough (below invalidation frequency
+ // threshold).
+ return !picture_.get() &&
+ ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
+ (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
+}
+
+void PicturePile::SetBufferPixels(int new_buffer_pixels) {
+ if (new_buffer_pixels == buffer_pixels())
+ return;
+
+ Clear();
+ tiling_.SetBorderTexels(new_buffer_pixels);
+}
+
+void PicturePile::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
+ picture_ = picture;
+}
+
+const Picture* PicturePile::PictureInfo::GetPicture() const {
+ return picture_.get();
+}
+
+float PicturePile::PictureInfo::GetInvalidationFrequency() const {
+ return invalidation_history_.count() /
+ static_cast<float>(INVALIDATION_FRAMES_TRACKED);
+}
+
} // namespace cc
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index 7cd2229..ffd9b52 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -5,25 +5,21 @@
#ifndef CC_RESOURCES_PICTURE_PILE_H_
#define CC_RESOURCES_PICTURE_PILE_H_
+#include <bitset>
+
#include "base/memory/ref_counted.h"
-#include "cc/resources/picture_pile_base.h"
-#include "ui/gfx/geometry/rect.h"
+#include "cc/base/tiling_data.h"
+#include "cc/resources/recording_source.h"
namespace cc {
class PicturePileImpl;
-class Region;
-class RenderingStatsInstrumentation;
-class CC_EXPORT PicturePile : public PicturePileBase {
+class CC_EXPORT PicturePile : public RecordingSource {
public:
PicturePile();
~PicturePile() override;
- // Re-record parts of the picture that are invalid.
- // Invalidations are in layer space, and will be expanded to cover everything
- // that was either recorded/changed or that has no recording, leaving out only
- // pieces that we had a recording for and it was not changed.
- // Return true iff the pile was modified.
+ // RecordingSource overrides.
bool UpdateAndExpandInvalidation(
ContentLayerClient* painter,
Region* invalidation,
@@ -33,35 +29,92 @@
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
- Picture::RecordingMode recording_mode,
- RenderingStatsInstrumentation* stats_instrumentation);
+ Picture::RecordingMode recording_mode) 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 SetUnsuitableForGpuRasterizationForTesting() override;
+ SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const override;
- void SetEmptyBounds();
+ static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
+ SkTileGridFactory::TileGridInfo* info);
- void set_slow_down_raster_scale_factor(int factor) {
- slow_down_raster_scale_factor_for_debug_ = factor;
- }
+ protected:
+ class CC_EXPORT PictureInfo {
+ public:
+ enum { INVALIDATION_FRAMES_TRACKED = 32 };
- void set_show_debug_picture_borders(bool show) {
- show_debug_picture_borders_ = show;
- }
+ PictureInfo();
+ ~PictureInfo();
- bool is_suitable_for_gpu_rasterization() const {
- return is_suitable_for_gpu_rasterization_;
- }
- void SetUnsuitableForGpuRasterizationForTesting() {
- is_suitable_for_gpu_rasterization_ = false;
- }
+ bool Invalidate(int frame_number);
+ bool NeedsRecording(int frame_number, int distance_to_visible);
+ void SetPicture(scoped_refptr<Picture> picture);
+ const Picture* GetPicture() const;
- void SetPixelRecordDistanceForTesting(int d) { pixel_record_distance_ = d; }
+ float GetInvalidationFrequencyForTesting() const {
+ return GetInvalidationFrequency();
+ }
+
+ private:
+ void AdvanceInvalidationHistory(int frame_number);
+ float GetInvalidationFrequency() const;
+
+ int last_frame_number_;
+ scoped_refptr<const Picture> picture_;
+ std::bitset<INVALIDATION_FRAMES_TRACKED> invalidation_history_;
+ };
+
+ typedef std::pair<int, int> PictureMapKey;
+ typedef base::hash_map<PictureMapKey, PictureInfo> PictureMap;
+
+ // An internal CanRaster check that goes to the picture_map rather than
+ // using the recorded_viewport hint.
+ bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
+
+ void Clear();
+
+ gfx::Rect PaddedRect(const PictureMapKey& key) const;
+ gfx::Rect PadRect(const gfx::Rect& rect) const;
+
+ int buffer_pixels() const { return tiling_.border_texels(); }
+
+ // A picture pile is a tiled set of pictures. The picture map is a map of tile
+ // indices to picture infos.
+ PictureMap picture_map_;
+ TilingData tiling_;
+
+ // If non-empty, all pictures tiles inside this rect are recorded. There may
+ // be recordings outside this rect, but everything inside the rect is
+ // recorded.
+ 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_;
private:
friend class PicturePileImpl;
void DetermineIfSolidColor();
+ void SetBufferPixels(int buffer_pixels);
bool is_suitable_for_gpu_rasterization_;
- int pixel_record_distance_;
DISALLOW_COPY_AND_ASSIGN(PicturePile);
};
diff --git a/cc/resources/picture_pile_base.cc b/cc/resources/picture_pile_base.cc
deleted file mode 100644
index a145b6c..0000000
--- a/cc/resources/picture_pile_base.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/picture_pile_base.h"
-
-#include <algorithm>
-#include <set>
-#include <vector>
-
-#include "base/debug/trace_event_argument.h"
-#include "base/logging.h"
-#include "base/values.h"
-#include "cc/debug/traced_value.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/rect_conversions.h"
-
-namespace {
-// Dimensions of the tiles in this picture pile as well as the dimensions of
-// 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
-// indicates when to stop invalidating offscreen regions.
-// kFrequentInvalidationDistanceThreshold defines what it means to be
-// "offscreen" in terms of distance to visible in css pixels.
-const float kInvalidationFrequencyThreshold = 0.75f;
-const int kFrequentInvalidationDistanceThreshold = 512;
-
-} // namespace
-
-namespace cc {
-
-PicturePileBase::PicturePileBase()
- : min_contents_scale_(0),
- background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
- slow_down_raster_scale_factor_for_debug_(0),
- contents_opaque_(false),
- contents_fill_bounds_completely_(false),
- show_debug_picture_borders_(false),
- clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
- has_any_recordings_(false),
- is_mask_(false),
- is_solid_color_(false),
- solid_color_(SK_ColorTRANSPARENT) {
- tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
- tile_grid_info_.fTileInterval.setEmpty();
- tile_grid_info_.fMargin.setEmpty();
- tile_grid_info_.fOffset.setZero();
-}
-
-PicturePileBase::PicturePileBase(const PicturePileBase* other)
- : picture_map_(other->picture_map_),
- tiling_(other->tiling_),
- recorded_viewport_(other->recorded_viewport_),
- min_contents_scale_(other->min_contents_scale_),
- tile_grid_info_(other->tile_grid_info_),
- background_color_(other->background_color_),
- slow_down_raster_scale_factor_for_debug_(
- other->slow_down_raster_scale_factor_for_debug_),
- contents_opaque_(other->contents_opaque_),
- contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
- show_debug_picture_borders_(other->show_debug_picture_borders_),
- clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
- has_any_recordings_(other->has_any_recordings_),
- is_mask_(other->is_mask_),
- is_solid_color_(other->is_solid_color_),
- solid_color_(other->solid_color_) {
-}
-
-PicturePileBase::~PicturePileBase() {
-}
-
-void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
- DCHECK(min_contents_scale);
- if (min_contents_scale_ == min_contents_scale)
- return;
-
- // Picture contents are played back scaled. When the final contents scale is
- // less than 1 (i.e. low res), then multiple recorded pixels will be used
- // to raster one final pixel. To avoid splitting a final pixel across
- // pictures (which would result in incorrect rasterization due to blending), a
- // buffer margin is added so that any picture can be snapped to integral
- // final pixels.
- //
- // For example, if a 1/4 contents scale is used, then that would be 3 buffer
- // pixels, since that's the minimum number of pixels to add so that resulting
- // content can be snapped to a four pixel aligned grid.
- int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
- buffer_pixels = std::max(0, buffer_pixels);
- SetBufferPixels(buffer_pixels);
- min_contents_scale_ = min_contents_scale;
-}
-
-// static
-void PicturePileBase::ComputeTileGridInfo(
- const gfx::Size& tile_grid_size,
- SkTileGridFactory::TileGridInfo* info) {
- DCHECK(info);
- info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
- tile_grid_size.height() - 2 * kTileGridBorderPixels);
- DCHECK_GT(info->fTileInterval.width(), 0);
- DCHECK_GT(info->fTileInterval.height(), 0);
- info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
- // Offset the tile grid coordinate space to take into account the fact
- // that the top-most and left-most tiles do not have top and left borders
- // respectively.
- info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
-}
-
-void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
- ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
-}
-
-void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
- if (new_buffer_pixels == buffer_pixels())
- return;
-
- Clear();
- tiling_.SetBorderTexels(new_buffer_pixels);
-}
-
-void PicturePileBase::Clear() {
- picture_map_.clear();
- recorded_viewport_ = gfx::Rect();
- has_any_recordings_ = false;
- is_solid_color_ = false;
-}
-
-bool PicturePileBase::HasRecordingAt(int x, int y) {
- PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
- if (found == picture_map_.end())
- return false;
- return !!found->second.GetPicture();
-}
-
-bool PicturePileBase::CanRaster(float contents_scale,
- const gfx::Rect& content_rect) const {
- if (tiling_.tiling_size().IsEmpty())
- return false;
- gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
- content_rect, 1.f / contents_scale);
- layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
-
- // Common case inside of viewport to avoid the slower map lookups.
- if (recorded_viewport_.Contains(layer_rect)) {
- // Sanity check that there are no false positives in recorded_viewport_.
- DCHECK(CanRasterSlowTileCheck(layer_rect));
- return true;
- }
-
- return CanRasterSlowTileCheck(layer_rect);
-}
-
-bool PicturePileBase::CanRasterSlowTileCheck(
- const gfx::Rect& layer_rect) const {
- bool include_borders = false;
- for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
- tile_iter;
- ++tile_iter) {
- PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
- if (map_iter == picture_map_.end())
- return false;
- if (!map_iter->second.GetPicture())
- return false;
- }
- return true;
-}
-
-gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) const {
- gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
- return PadRect(tile);
-}
-
-gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) const {
- gfx::Rect padded_rect = rect;
- padded_rect.Inset(
- -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
- return padded_rect;
-}
-
-void PicturePileBase::AsValueInto(base::debug::TracedValue* pictures) const {
- gfx::Rect tiling_rect(tiling_.tiling_size());
- std::set<const void*> appended_pictures;
- bool include_borders = true;
- for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
- tile_iter;
- ++tile_iter) {
- PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
- if (map_iter == picture_map_.end())
- continue;
-
- const Picture* picture = map_iter->second.GetPicture();
- if (picture && (appended_pictures.count(picture) == 0)) {
- appended_pictures.insert(picture);
- TracedValue::AppendIDRef(picture, pictures);
- }
- }
-}
-
-PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
-
-PicturePileBase::PictureInfo::~PictureInfo() {}
-
-void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
- int frame_number) {
- DCHECK_GE(frame_number, last_frame_number_);
- if (frame_number == last_frame_number_)
- return;
-
- invalidation_history_ <<= (frame_number - last_frame_number_);
- last_frame_number_ = frame_number;
-}
-
-bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
- AdvanceInvalidationHistory(frame_number);
- invalidation_history_.set(0);
-
- bool did_invalidate = !!picture_.get();
- picture_ = NULL;
- return did_invalidate;
-}
-
-bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
- int distance_to_visible) {
- AdvanceInvalidationHistory(frame_number);
-
- // We only need recording if we don't have a picture. Furthermore, we only
- // need a recording if we're within frequent invalidation distance threshold
- // or the invalidation is not frequent enough (below invalidation frequency
- // threshold).
- return !picture_.get() &&
- ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
- (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
-}
-
-void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
- picture_ = picture;
-}
-
-const Picture* PicturePileBase::PictureInfo::GetPicture() const {
- return picture_.get();
-}
-
-float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
- return invalidation_history_.count() /
- static_cast<float>(INVALIDATION_FRAMES_TRACKED);
-}
-
-} // namespace cc
diff --git a/cc/resources/picture_pile_base.h b/cc/resources/picture_pile_base.h
deleted file mode 100644
index 71e5bad..0000000
--- a/cc/resources/picture_pile_base.h
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_PICTURE_PILE_BASE_H_
-#define CC_RESOURCES_PICTURE_PILE_BASE_H_
-
-#include <bitset>
-#include <list>
-#include <utility>
-
-#include "base/containers/hash_tables.h"
-#include "cc/base/cc_export.h"
-#include "cc/base/region.h"
-#include "cc/base/tiling_data.h"
-#include "cc/resources/picture.h"
-#include "ui/gfx/geometry/size.h"
-
-namespace base {
-namespace debug {
-class TracedValue;
-}
-class Value;
-}
-
-namespace cc {
-
-class CC_EXPORT PicturePileBase {
- public:
- PicturePileBase();
- explicit PicturePileBase(const PicturePileBase* other);
-
- gfx::Size tiling_size() const { return tiling_.tiling_size(); }
- void SetMinContentsScale(float min_contents_scale);
-
- // If non-empty, all pictures tiles inside this rect are recorded. There may
- // be recordings outside this rect, but everything inside the rect is
- // recorded.
- gfx::Rect recorded_viewport() const { return recorded_viewport_; }
-
- int num_tiles_x() const { return tiling_.num_tiles_x(); }
- int num_tiles_y() const { return tiling_.num_tiles_y(); }
- gfx::Rect tile_bounds(int x, int y) const { return tiling_.TileBounds(x, y); }
- bool HasRecordingAt(int x, int y);
- bool CanRaster(float contents_scale, const gfx::Rect& content_rect) const;
-
- // If this pile contains any valid recordings. May have false positives.
- bool HasRecordings() const { return has_any_recordings_; }
-
- bool is_solid_color() const { return is_solid_color_; }
- SkColor solid_color() const { return solid_color_; }
-
- void set_is_mask(bool is_mask) { is_mask_ = is_mask; }
- bool is_mask() const { return is_mask_; }
-
- static void ComputeTileGridInfo(const gfx::Size& tile_grid_size,
- SkTileGridFactory::TileGridInfo* info);
-
- void SetTileGridSize(const gfx::Size& tile_grid_size);
- TilingData& tiling() { return tiling_; }
-
- void AsValueInto(base::debug::TracedValue* array) const;
-
- SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const {
- return tile_grid_info_;
- }
-
- protected:
- class CC_EXPORT PictureInfo {
- public:
- enum {
- INVALIDATION_FRAMES_TRACKED = 32
- };
-
- PictureInfo();
- ~PictureInfo();
-
- bool Invalidate(int frame_number);
- bool NeedsRecording(int frame_number, int distance_to_visible);
- void SetPicture(scoped_refptr<Picture> picture);
- const Picture* GetPicture() const;
-
- float GetInvalidationFrequencyForTesting() const {
- return GetInvalidationFrequency();
- }
-
- private:
- void AdvanceInvalidationHistory(int frame_number);
- float GetInvalidationFrequency() const;
-
- int last_frame_number_;
- scoped_refptr<const Picture> picture_;
- std::bitset<INVALIDATION_FRAMES_TRACKED> invalidation_history_;
- };
-
- typedef std::pair<int, int> PictureMapKey;
- typedef base::hash_map<PictureMapKey, PictureInfo> PictureMap;
-
- virtual ~PicturePileBase();
-
- int buffer_pixels() const { return tiling_.border_texels(); }
- void Clear();
-
- gfx::Rect PaddedRect(const PictureMapKey& key) const;
- gfx::Rect PadRect(const gfx::Rect& rect) const;
-
- // An internal CanRaster check that goes to the picture_map rather than
- // using the recorded_viewport hint.
- bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
-
- // A picture pile is a tiled set of pictures. The picture map is a map of tile
- // indices to picture infos.
- PictureMap picture_map_;
- TilingData tiling_;
- 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 show_debug_picture_borders_;
- 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_;
-
- private:
- void SetBufferPixels(int buffer_pixels);
-
- DISALLOW_COPY_AND_ASSIGN(PicturePileBase);
-};
-
-} // namespace cc
-
-#endif // CC_RESOURCES_PICTURE_PILE_BASE_H_
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index 0ad746c..7ec9252 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -20,26 +20,49 @@
return make_scoped_refptr(new PicturePileImpl);
}
-scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromOther(
- const PicturePileBase* other) {
+scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromPicturePile(
+ const PicturePile* other) {
return make_scoped_refptr(new PicturePileImpl(other));
}
PicturePileImpl::PicturePileImpl()
- : likely_to_be_used_for_transform_animation_(false) {
+ : background_color_(SK_ColorTRANSPARENT),
+ contents_opaque_(false),
+ contents_fill_bounds_completely_(false),
+ is_solid_color_(false),
+ solid_color_(SK_ColorTRANSPARENT),
+ has_any_recordings_(false),
+ is_mask_(false),
+ clear_canvas_with_debug_color_(false),
+ min_contents_scale_(0.f),
+ slow_down_raster_scale_factor_for_debug_(0),
+ should_attempt_to_use_distance_field_text_(false) {
}
-PicturePileImpl::PicturePileImpl(const PicturePileBase* other)
- : PicturePileBase(other),
- likely_to_be_used_for_transform_animation_(false) {
+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_),
+ 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_),
+ min_contents_scale_(other->min_contents_scale_),
+ slow_down_raster_scale_factor_for_debug_(
+ other->slow_down_raster_scale_factor_for_debug_),
+ should_attempt_to_use_distance_field_text_(false) {
}
PicturePileImpl::~PicturePileImpl() {
}
-void PicturePileImpl::RasterDirect(SkCanvas* canvas,
- const gfx::Rect& canvas_rect,
- float contents_scale) const {
+void PicturePileImpl::PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
RasterCommon(canvas,
NULL,
canvas_rect,
@@ -320,11 +343,88 @@
bool PicturePileImpl::CoversRect(const gfx::Rect& content_rect,
float contents_scale) const {
- return CanRaster(contents_scale, content_rect);
+ if (tiling_.tiling_size().IsEmpty())
+ return false;
+ gfx::Rect layer_rect =
+ gfx::ScaleToEnclosingRect(content_rect, 1.f / contents_scale);
+ layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
+
+ // Common case inside of viewport to avoid the slower map lookups.
+ if (recorded_viewport_.Contains(layer_rect)) {
+ // Sanity check that there are no false positives in recorded_viewport_.
+ DCHECK(CanRasterSlowTileCheck(layer_rect));
+ return true;
+ }
+
+ return CanRasterSlowTileCheck(layer_rect);
}
-bool PicturePileImpl::SuitableForDistanceFieldText() const {
- return likely_to_be_used_for_transform_animation_;
+gfx::Size PicturePileImpl::GetSize() const {
+ return tiling_.tiling_size();
+}
+
+bool PicturePileImpl::IsSolidColor() const {
+ return is_solid_color_;
+}
+
+SkColor PicturePileImpl::GetSolidColor() const {
+ DCHECK(IsSolidColor());
+ return solid_color_;
+}
+
+bool PicturePileImpl::HasRecordings() const {
+ return has_any_recordings_;
+}
+
+gfx::Rect PicturePileImpl::PaddedRect(const PictureMapKey& key) const {
+ gfx::Rect padded_rect = tiling_.TileBounds(key.first, key.second);
+ padded_rect.Inset(-buffer_pixels(), -buffer_pixels(), -buffer_pixels(),
+ -buffer_pixels());
+ return padded_rect;
+}
+
+bool PicturePileImpl::CanRasterSlowTileCheck(
+ const gfx::Rect& layer_rect) const {
+ bool include_borders = false;
+ for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
+ tile_iter; ++tile_iter) {
+ PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+ if (map_iter == picture_map_.end())
+ return false;
+ if (!map_iter->second.GetPicture())
+ return false;
+ }
+ return true;
+}
+
+void PicturePileImpl::SetShouldAttemptToUseDistanceFieldText() {
+ should_attempt_to_use_distance_field_text_ = true;
+}
+
+bool PicturePileImpl::ShouldAttemptToUseDistanceFieldText() const {
+ return should_attempt_to_use_distance_field_text_;
+}
+
+void PicturePileImpl::AsValueInto(base::debug::TracedValue* pictures) const {
+ gfx::Rect tiling_rect(tiling_.tiling_size());
+ std::set<const void*> appended_pictures;
+ bool include_borders = true;
+ for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
+ tile_iter; ++tile_iter) {
+ PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
+ if (map_iter == picture_map_.end())
+ continue;
+
+ const Picture* picture = map_iter->second.GetPicture();
+ if (picture && (appended_pictures.count(picture) == 0)) {
+ appended_pictures.insert(picture);
+ TracedValue::AppendIDRef(picture, pictures);
+ }
+ }
+}
+
+bool PicturePileImpl::IsMask() const {
+ return is_mask_;
}
PicturePileImpl::PixelRefIterator::PixelRefIterator(
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index 9f350a9..6986db4 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -13,7 +13,7 @@
#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/debug/rendering_stats_instrumentation.h"
-#include "cc/resources/picture_pile_base.h"
+#include "cc/resources/picture_pile.h"
#include "cc/resources/raster_source.h"
#include "skia/ext/analysis_canvas.h"
#include "skia/ext/refptr.h"
@@ -21,12 +21,11 @@
namespace cc {
-// TODO(vmpstr): Clean up PicturePileBase and make it a member.
-class CC_EXPORT PicturePileImpl : public PicturePileBase, public RasterSource {
+class CC_EXPORT PicturePileImpl : public RasterSource {
public:
static scoped_refptr<PicturePileImpl> Create();
- static scoped_refptr<PicturePileImpl> CreateFromOther(
- const PicturePileBase* other);
+ static scoped_refptr<PicturePileImpl> CreateFromPicturePile(
+ const PicturePile* other);
// RasterSource overrides. See RasterSource header for full description.
// When slow-down-raster-scale-factor is set to a value greater than 1, the
@@ -35,6 +34,9 @@
void PlaybackToCanvas(SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const override;
+ void PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const override;
void PerformSolidColorAnalysis(
const gfx::Rect& content_rect,
float contents_scale,
@@ -44,20 +46,18 @@
std::vector<SkPixelRef*>* pixel_refs) const override;
bool CoversRect(const gfx::Rect& content_rect,
float contents_scale) const override;
- bool SuitableForDistanceFieldText() const override;
-
- // Raster into the canvas without applying clips.
- void RasterDirect(SkCanvas* canvas,
- const gfx::Rect& canvas_rect,
- float contents_scale) const;
+ void SetShouldAttemptToUseDistanceFieldText() 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();
- skia::RefPtr<SkPicture> GetFlattenedPicture();
-
- void set_likely_to_be_used_for_transform_animation() {
- likely_to_be_used_for_transform_animation_ = true;
- }
+ void DidBeginTracing() override;
+ void AsValueInto(base::debug::TracedValue* array) const override;
+ skia::RefPtr<SkPicture> GetFlattenedPicture() override;
// Iterator used to return SkPixelRefs from this picture pile.
// Public for testing.
@@ -87,10 +87,31 @@
friend class PicturePile;
friend class PixelRefIterator;
+ // TODO(vmpstr): Change this when pictures are split from invalidation info.
+ using PictureMapKey = PicturePile::PictureMapKey;
+ using PictureMap = PicturePile::PictureMap;
+ using PictureInfo = PicturePile::PictureInfo;
+
PicturePileImpl();
- explicit PicturePileImpl(const PicturePileBase* other);
+ explicit PicturePileImpl(const PicturePile* other);
~PicturePileImpl() override;
+ int buffer_pixels() const { return tiling_.border_texels(); }
+
+ PictureMap picture_map_;
+ TilingData tiling_;
+ SkColor background_color_;
+ bool contents_opaque_;
+ bool contents_fill_bounds_completely_;
+ 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_;
+
private:
typedef std::map<const Picture*, Region> PictureRegionMap;
@@ -112,7 +133,13 @@
float contents_scale,
bool is_analysis) const;
- bool likely_to_be_used_for_transform_animation_;
+ // An internal CanRaster check that goes to the picture_map rather than
+ // using the recorded_viewport hint.
+ bool CanRasterSlowTileCheck(const gfx::Rect& layer_rect) const;
+
+ gfx::Rect PaddedRect(const PictureMapKey& key) const;
+
+ bool should_attempt_to_use_distance_field_text_;
DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);
};
diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc
index 24bed3e..25e0d12 100644
--- a/cc/resources/picture_pile_unittest.cc
+++ b/cc/resources/picture_pile_unittest.cc
@@ -7,7 +7,7 @@
#include "cc/resources/picture_pile.h"
#include "cc/test/fake_content_layer_client.h"
-#include "cc/test/fake_rendering_stats_instrumentation.h"
+#include "cc/test/fake_picture_pile.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -15,26 +15,6 @@
namespace cc {
namespace {
-class TestPicturePile : public PicturePile {
- public:
- ~TestPicturePile() override {}
-
- using PicturePile::buffer_pixels;
- using PicturePile::CanRasterSlowTileCheck;
- using PicturePile::Clear;
-
- PictureMap& picture_map() { return picture_map_; }
- const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
-
- bool CanRasterLayerRect(const gfx::Rect& layer_rect) {
- return CanRaster(1.f, layer_rect);
- }
-
- typedef PicturePile::PictureInfo PictureInfo;
- typedef PicturePile::PictureMapKey PictureMapKey;
- typedef PicturePile::PictureMap PictureMap;
-};
-
class PicturePileTestBase {
public:
PicturePileTestBase()
@@ -56,36 +36,29 @@
UpdateAndExpandInvalidation(&invalidation, tiling_size, viewport_rect);
}
- gfx::Size tiling_size() const { return pile_.tiling_size(); }
- gfx::Rect tiling_rect() const { return gfx::Rect(pile_.tiling_size()); }
+ gfx::Size tiling_size() const { return pile_.GetSize(); }
+ gfx::Rect tiling_rect() const { return gfx::Rect(pile_.GetSize()); }
bool UpdateAndExpandInvalidation(Region* invalidation,
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,
- &stats_instrumentation_);
+ return pile_.UpdateAndExpandInvalidation(
+ &client_, invalidation, background_color_, contents_opaque_, false,
+ layer_size, visible_layer_rect, frame_number_,
+ Picture::RECORD_NORMALLY);
}
bool UpdateWholePile() {
Region invalidation = tiling_rect();
- bool result = UpdateAndExpandInvalidation(
- &invalidation, tiling_size(), tiling_rect());
+ bool result = UpdateAndExpandInvalidation(&invalidation, tiling_size(),
+ tiling_rect());
EXPECT_EQ(tiling_rect().ToString(), invalidation.ToString());
return result;
}
FakeContentLayerClient client_;
- FakeRenderingStatsInstrumentation stats_instrumentation_;
- TestPicturePile pile_;
+ FakePicturePile pile_;
SkColor background_color_;
float min_scale_;
int frame_number_;
@@ -99,7 +72,7 @@
TEST_F(PicturePileTest, InvalidationOnTileBorderOutsideInterestRect) {
// Don't expand the interest rect past what we invalidate.
- pile_.SetPixelRecordDistanceForTesting(0);
+ pile_.SetPixelRecordDistance(0);
gfx::Size tile_size(100, 100);
pile_.tiling().SetMaxTextureSize(tile_size);
@@ -182,8 +155,8 @@
EXPECT_EQ(1, pile_.tiling().num_tiles_x());
EXPECT_EQ(1, pile_.tiling().num_tiles_y());
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+ FakePicturePile::PictureInfo& picture_info =
+ pile_.picture_map().find(FakePicturePile::PictureMapKey(0, 0))->second;
// We should have a picture.
EXPECT_TRUE(!!picture_info.GetPicture());
gfx::Rect picture_rect = gfx::ScaleToEnclosedRect(
@@ -204,14 +177,14 @@
EXPECT_EQ(1, pile_.tiling().num_tiles_x());
EXPECT_EQ(1, pile_.tiling().num_tiles_y());
- TestPicturePile::PictureInfo& picture_info =
- pile_.picture_map().find(TestPicturePile::PictureMapKey(0, 0))->second;
+ FakePicturePile::PictureInfo& picture_info =
+ pile_.picture_map().find(FakePicturePile::PictureMapKey(0, 0))->second;
EXPECT_TRUE(!!picture_info.GetPicture());
int expected_inflation = pile_.buffer_pixels();
const Picture* base_picture = picture_info.GetPicture();
- gfx::Rect base_picture_rect(pile_.tiling_size());
+ gfx::Rect base_picture_rect(tiling_size());
base_picture_rect.Inset(-expected_inflation, -expected_inflation);
EXPECT_EQ(base_picture_rect.ToString(),
base_picture->LayerRect().ToString());
@@ -219,7 +192,7 @@
TEST_F(PicturePileTest, InvalidateOnTileBoundaryInflated) {
gfx::Size new_tiling_size =
- gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 2.f));
+ gfx::ToCeiledSize(gfx::ScaleSize(tiling_size(), 2.f));
// This creates initial pictures.
SetTilingSize(new_tiling_size);
@@ -247,20 +220,20 @@
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
+ FakePicturePile::PictureInfo& picture_info =
pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
+ .find(FakePicturePile::PictureMapKey(i, j))
->second;
// Expect (1, 1) and (1, 0) to be invalidated once more
// than the rest of the tiles.
if (i == 1 && (j == 0 || j == 1)) {
EXPECT_FLOAT_EQ(
- 2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+ 2.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
picture_info.GetInvalidationFrequencyForTesting());
} else {
EXPECT_FLOAT_EQ(
- 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+ 1.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
picture_info.GetInvalidationFrequencyForTesting());
}
}
@@ -273,7 +246,7 @@
// Everything was invalidated once so far.
for (auto& it : pile_.picture_map()) {
EXPECT_FLOAT_EQ(
- 1.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+ 1.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
it.second.GetInvalidationFrequencyForTesting());
}
@@ -284,14 +257,14 @@
// Everything was invalidated again.
for (auto& it : pile_.picture_map()) {
EXPECT_FLOAT_EQ(
- 2.0f / TestPicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
+ 2.0f / FakePicturePile::PictureInfo::INVALIDATION_FRAMES_TRACKED,
it.second.GetInvalidationFrequencyForTesting());
}
}
TEST_F(PicturePileTest, StopRecordingOffscreenInvalidations) {
gfx::Size new_tiling_size =
- gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f));
+ gfx::ToCeiledSize(gfx::ScaleSize(tiling_size(), 4.f));
SetTilingSize(new_tiling_size);
gfx::Rect viewport(tiling_size().width(), 1);
@@ -304,9 +277,9 @@
// Make sure we have a high invalidation frequency.
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
+ FakePicturePile::PictureInfo& picture_info =
pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
+ .find(FakePicturePile::PictureMapKey(i, j))
->second;
EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting())
<< "i " << i << " j " << j;
@@ -320,9 +293,9 @@
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
+ FakePicturePile::PictureInfo& picture_info =
pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
+ .find(FakePicturePile::PictureMapKey(i, j))
->second;
EXPECT_FLOAT_EQ(1.0f, picture_info.GetInvalidationFrequencyForTesting());
@@ -349,15 +322,15 @@
// Now update with no invalidation and full viewport
Region empty_invalidation;
- UpdateAndExpandInvalidation(
- &empty_invalidation, tiling_size(), tiling_rect());
+ UpdateAndExpandInvalidation(&empty_invalidation, tiling_size(),
+ tiling_rect());
EXPECT_EQ(Region().ToString(), empty_invalidation.ToString());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureInfo& picture_info =
+ FakePicturePile::PictureInfo& picture_info =
pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(i, j))
+ .find(FakePicturePile::PictureMapKey(i, j))
->second;
// Expect the invalidation frequency to be less than 1, since we just
// updated with no invalidations.
@@ -388,7 +361,7 @@
// tiles touching it, but is true for adjacent tiles, even if it
// overlaps on borders (edge case).
gfx::Size new_tiling_size =
- gfx::ToCeiledSize(gfx::ScaleSize(pile_.tiling_size(), 4.f));
+ gfx::ToCeiledSize(gfx::ScaleSize(tiling_size(), 4.f));
SetTilingSize(new_tiling_size);
gfx::Rect tile01_borders = pile_.tiling().TileBoundsWithBorder(0, 1);
@@ -422,10 +395,10 @@
// Sanity check some pictures exist and others don't.
EXPECT_TRUE(pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(0, 1))
+ .find(FakePicturePile::PictureMapKey(0, 1))
->second.GetPicture());
EXPECT_FALSE(pile_.picture_map()
- .find(TestPicturePile::PictureMapKey(0, 2))
+ .find(FakePicturePile::PictureMapKey(0, 2))
->second.GetPicture());
EXPECT_TRUE(pile_.CanRasterLayerRect(tile01_noborders));
@@ -454,8 +427,8 @@
// No invalidation, changing viewport.
invalidation = Region();
- UpdateAndExpandInvalidation(
- &invalidation, tiling_size(), gfx::Rect(5, 5, 5, 5));
+ UpdateAndExpandInvalidation(&invalidation, tiling_size(),
+ gfx::Rect(5, 5, 5, 5));
EXPECT_TRUE(!pile_.recorded_viewport().IsEmpty());
EXPECT_EQ(Region().ToString(), invalidation.ToString());
}
@@ -604,9 +577,9 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -616,14 +589,15 @@
grow_down_tiling_size,
CornerSinglePixelRect(corner, grow_down_tiling_size));
- // We should have lost the recordings in the bottom row.
+ // We should have lost all of the recordings in the bottom row as none of them
+ // are in the current interest rect (which is either the above or below it).
EXPECT_EQ(6, pile_.tiling().num_tiles_x());
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_EQ(j < 5, it != map.end() && it->second.GetPicture());
}
}
@@ -645,20 +619,58 @@
base_tiling_size,
CornerSinglePixelRect(corner, base_tiling_size));
- // We should have lost the recordings that are now outside the tiling only.
+ // When shrinking, we should have lost all the recordings in the bottom row
+ // not touching the interest rect.
EXPECT_EQ(6, pile_.tiling().num_tiles_x());
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_EQ(j < 6, it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ bool expect_tile;
+ switch (corner) {
+ case TOP_LEFT:
+ case TOP_RIGHT:
+ expect_tile = j < 5;
+ break;
+ case BOTTOM_LEFT:
+ // The interest rect in the bottom left tile means we'll record it.
+ expect_tile = j < 5 || (j == 5 && i == 0);
+ break;
+ case BOTTOM_RIGHT:
+ // The interest rect in the bottom right tile means we'll record it.
+ expect_tile = j < 5 || (j == 5 && i == 5);
+ break;
+ }
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- expected_invalidation.Clear();
+ // When shrinking, the previously exposed region is invalidated.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+ gfx::Rect(base_tiling_size));
+ // The whole bottom row of tiles (except any with the interest rect) are
+ // dropped.
+ gfx::Rect bottom_row_minus_existing_corner = gfx::UnionRects(
+ pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5));
+ switch (corner) {
+ case TOP_LEFT:
+ case TOP_RIGHT:
+ // No tiles are kept in the changed region because it doesn't
+ // intersect with the interest rect.
+ break;
+ case BOTTOM_LEFT:
+ bottom_row_minus_existing_corner.Subtract(
+ pile_.tiling().TileBounds(0, 5));
+ break;
+ case BOTTOM_RIGHT:
+ bottom_row_minus_existing_corner.Subtract(
+ pile_.tiling().TileBounds(5, 5));
+ break;
+ }
+
+ expected_invalidation.Union(bottom_row_minus_existing_corner);
EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
@@ -668,14 +680,16 @@
grow_right_tiling_size,
CornerSinglePixelRect(corner, grow_right_tiling_size));
- // We should have lost the recordings in the right column.
+ // We should have lost all of the recordings in the right column as none of
+ // them are in the current interest rect (which is either entirely left or
+ // right of it).
EXPECT_EQ(8, pile_.tiling().num_tiles_x());
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_EQ(i < 5, it != map.end() && it->second.GetPicture());
}
}
@@ -697,20 +711,57 @@
base_tiling_size,
CornerSinglePixelRect(corner, base_tiling_size));
- // We should have lost the recordings that are now outside the tiling only.
+ // When shrinking, we should have lost all the recordings in the right column
+ // not touching the interest rect.
EXPECT_EQ(6, pile_.tiling().num_tiles_x());
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_EQ(i < 6, it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ bool expect_tile;
+ switch (corner) {
+ case TOP_LEFT:
+ case BOTTOM_LEFT:
+ // No tiles are kept in the changed region because it doesn't
+ // intersect with the interest rect.
+ expect_tile = i < 5;
+ break;
+ case TOP_RIGHT:
+ // The interest rect in the top right tile means we'll record it.
+ expect_tile = i < 5 || (j == 0 && i == 5);
+ break;
+ case BOTTOM_RIGHT:
+ // The interest rect in the bottom right tile means we'll record it.
+ expect_tile = i < 5 || (j == 5 && i == 5);
+ break;
+ }
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- expected_invalidation.Clear();
+ // When shrinking, the previously exposed region is invalidated.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+ gfx::Rect(base_tiling_size));
+ // The whole right column of tiles (except for ones with the interest rect)
+ // are dropped.
+ gfx::Rect right_column_minus_existing_corner = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
+ switch (corner) {
+ case TOP_LEFT:
+ case BOTTOM_LEFT:
+ break;
+ case TOP_RIGHT:
+ right_column_minus_existing_corner.Subtract(
+ pile_.tiling().TileBounds(5, 0));
+ break;
+ case BOTTOM_RIGHT:
+ right_column_minus_existing_corner.Subtract(
+ pile_.tiling().TileBounds(5, 5));
+ break;
+ }
+ expected_invalidation.Union(right_column_minus_existing_corner);
EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
@@ -725,9 +776,9 @@
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 6; ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_EQ(i < 5 && j < 5, it != map.end() && it->second.GetPicture());
}
}
@@ -735,7 +786,7 @@
// We invalidated all new pixels in the recording.
expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
gfx::Rect(base_tiling_size));
- // But the new pixels don't cover the whole right_column.
+ // But the new pixels don't cover the whole right column or bottom row.
Region right_column_and_bottom_row =
UnionRegions(gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
pile_.tiling().TileBounds(5, 5)),
@@ -748,22 +799,66 @@
invalidation.Clear();
UpdateWholePile();
- UpdateAndExpandInvalidation(&invalidation, base_tiling_size, gfx::Rect());
+ UpdateAndExpandInvalidation(&invalidation, base_tiling_size,
+ CornerSinglePixelRect(corner, base_tiling_size));
- // We should have lost the recordings that are now outside the tiling only.
+ // We should have lost the recordings in the right column and bottom row,
+ // except where it intersects the interest rect.
EXPECT_EQ(6, pile_.tiling().num_tiles_x());
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_EQ(i < 6 && j < 6, it != map.end() && it->second.GetPicture());
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ bool expect_tile;
+ switch (corner) {
+ case TOP_LEFT:
+ expect_tile = i < 5 && j < 5;
+ break;
+ case TOP_RIGHT:
+ // The interest rect in the top right tile means we'll record it.
+ expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5);
+ break;
+ case BOTTOM_LEFT:
+ // The interest rect in the bottom left tile means we'll record it.
+ expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0);
+ break;
+ case BOTTOM_RIGHT:
+ // The interest rect in the bottom right tile means we'll record it.
+ expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
+ break;
+ }
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
+ << i << "," << j;
}
}
- // No invalidation when shrinking.
- expected_invalidation.Clear();
+ // We invalidated all previous pixels in the recording.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+ gfx::Rect(base_tiling_size));
+ // The whole right column and bottom row of tiles (except for ones with the
+ // interest rect) are dropped.
+ Region right_column_and_bottom_row_minus_existing_corner =
+ right_column_and_bottom_row;
+ switch (corner) {
+ case TOP_LEFT:
+ break;
+ case BOTTOM_LEFT:
+ right_column_and_bottom_row_minus_existing_corner.Subtract(
+ pile_.tiling().TileBounds(0, 5));
+ break;
+ case TOP_RIGHT:
+ right_column_and_bottom_row_minus_existing_corner.Subtract(
+ pile_.tiling().TileBounds(5, 0));
+ break;
+ case BOTTOM_RIGHT:
+ right_column_and_bottom_row_minus_existing_corner.Subtract(
+ pile_.tiling().TileBounds(5, 5));
+ break;
+ }
+ expected_invalidation.Union(
+ right_column_and_bottom_row_minus_existing_corner);
EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
}
@@ -796,268 +891,235 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
- UpdateAndExpandInvalidation(
- &invalidation,
- grow_down_tiling_size,
- CornerSinglePixelRect(corner, grow_down_tiling_size));
+ // In this test (unlike the large resize test), as all growing and shrinking
+ // happens within tiles, the resulting invalidation is symmetrical, so use
+ // this enum to repeat the test both ways.
+ enum ChangeDirection { GROW, SHRINK, LAST_DIRECTION = SHRINK };
- // We should have lost the recordings in the bottom row that do not intersect
- // the interest rect.
- EXPECT_EQ(6, pile_.tiling().num_tiles_x());
- EXPECT_EQ(6, pile_.tiling().num_tiles_y());
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- bool expect_tile;
+ // Grow downward.
+ for (int dir = 0; dir <= LAST_DIRECTION; ++dir) {
+ gfx::Size new_tiling_size =
+ dir == GROW ? grow_down_tiling_size : base_tiling_size;
+ UpdateWholePile();
+ UpdateAndExpandInvalidation(&invalidation, new_tiling_size,
+ CornerSinglePixelRect(corner, new_tiling_size));
+
+ // We should have lost the recordings in the bottom row that do not
+ // intersect the interest rect.
+ EXPECT_EQ(6, pile_.tiling().num_tiles_x());
+ EXPECT_EQ(6, pile_.tiling().num_tiles_y());
+ for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
+ for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ bool expect_tile;
+ switch (corner) {
+ case TOP_LEFT:
+ case TOP_RIGHT:
+ expect_tile = j < 5;
+ break;
+ case BOTTOM_LEFT:
+ // The interest rect in the bottom left tile means we'll record it.
+ expect_tile = j < 5 || (j == 5 && i == 0);
+ break;
+ case BOTTOM_RIGHT:
+ // The interest rect in the bottom right tile means we'll record it.
+ expect_tile = j < 5 || (j == 5 && i == 5);
+ break;
+ }
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+ }
+ }
+
+ // We invalidated the bottom row outside the new interest rect. The tile
+ // that insects the interest rect in invalidated only on its newly
+ // exposed or previously exposed pixels.
+ if (dir == GROW) {
+ // Only calculate the expected invalidation while growing, as the tile
+ // bounds post-growing is the newly exposed / previously exposed sizes.
+ // Post-shrinking, the tile bounds are smaller, so can't be used.
switch (corner) {
case TOP_LEFT:
case TOP_RIGHT:
- expect_tile = j < 5;
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5));
break;
case BOTTOM_LEFT:
- // The interest rect in the bottom left tile means we'll record it.
- expect_tile = j < 5 || (j == 5 && i == 0);
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5));
+ expected_invalidation.Union(SubtractRects(
+ pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size)));
break;
case BOTTOM_RIGHT:
- // The interest rect in the bottom right tile means we'll record it.
- expect_tile = j < 5 || (j == 5 && i == 5);
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5));
+ expected_invalidation.Union(SubtractRects(
+ pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
}
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
+ invalidation.Clear();
}
- // We invalidated the bottom row outside the new interest rect. The tile that
- // insects the interest rect in invalidated only on its new pixels.
- switch (corner) {
- case TOP_LEFT:
- case TOP_RIGHT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
- pile_.tiling().TileBounds(5, 5));
- break;
- case BOTTOM_LEFT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(1, 5),
- pile_.tiling().TileBounds(5, 5));
- expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(0, 5),
- gfx::Rect(base_tiling_size)));
- break;
- case BOTTOM_RIGHT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
- pile_.tiling().TileBounds(4, 5));
- expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 5),
- gfx::Rect(base_tiling_size)));
- break;
- }
- EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
- invalidation.Clear();
+ // Grow right.
+ for (int dir = 0; dir <= LAST_DIRECTION; ++dir) {
+ gfx::Size new_tiling_size =
+ dir == GROW ? grow_right_tiling_size : base_tiling_size;
+ UpdateWholePile();
+ UpdateAndExpandInvalidation(&invalidation, new_tiling_size,
+ CornerSinglePixelRect(corner, new_tiling_size));
- UpdateWholePile();
- UpdateAndExpandInvalidation(&invalidation,
- base_tiling_size,
- CornerSinglePixelRect(corner, base_tiling_size));
-
- // We should have lost nothing.
- EXPECT_EQ(6, pile_.tiling().num_tiles_x());
- EXPECT_EQ(6, pile_.tiling().num_tiles_y());
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ // We should have lost the recordings in the right column.
+ EXPECT_EQ(6, pile_.tiling().num_tiles_x());
+ EXPECT_EQ(6, pile_.tiling().num_tiles_y());
+ for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
+ for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ bool expect_tile;
+ switch (corner) {
+ case TOP_LEFT:
+ case BOTTOM_LEFT:
+ expect_tile = i < 5;
+ break;
+ case TOP_RIGHT:
+ // The interest rect in the top right tile means we'll record it.
+ expect_tile = i < 5 || (j == 0 && i == 5);
+ break;
+ case BOTTOM_RIGHT:
+ // The interest rect in the bottom right tile means we'll record it.
+ expect_tile = i < 5 || (j == 5 && i == 5);
+ break;
+ }
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
+ }
}
- }
- // We invalidated nothing.
- expected_invalidation.Clear();
- EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
- invalidation.Clear();
-
- UpdateWholePile();
- UpdateAndExpandInvalidation(
- &invalidation,
- grow_right_tiling_size,
- CornerSinglePixelRect(corner, grow_right_tiling_size));
-
- // We should have lost the recordings in the right column.
- EXPECT_EQ(6, pile_.tiling().num_tiles_x());
- EXPECT_EQ(6, pile_.tiling().num_tiles_y());
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- bool expect_tile;
+ // We invalidated the right column outside the new interest rect. The tile
+ // that insects the interest rect in invalidated only on its new or
+ // previously exposed pixels.
+ if (dir == GROW) {
+ // Calculate the expected invalidation the first time through the loop.
switch (corner) {
case TOP_LEFT:
case BOTTOM_LEFT:
- expect_tile = i < 5;
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
break;
case TOP_RIGHT:
- // The interest rect in the top right tile means we'll record it.
- expect_tile = i < 5 || (j == 0 && i == 5);
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5));
+ expected_invalidation.Union(SubtractRects(
+ pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size)));
break;
case BOTTOM_RIGHT:
- // The interest rect in the bottom right tile means we'll record it.
- expect_tile = i < 5 || (j == 5 && i == 5);
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4));
+ expected_invalidation.Union(SubtractRects(
+ pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture());
}
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
+ invalidation.Clear();
}
- // We invalidated the right column outside the new interest rect. The tile
- // that insects the interest rect in invalidated only on its new pixels.
- switch (corner) {
- case TOP_LEFT:
- case BOTTOM_LEFT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
- pile_.tiling().TileBounds(5, 5));
- break;
- case TOP_RIGHT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 1),
- pile_.tiling().TileBounds(5, 5));
- expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 0),
- gfx::Rect(base_tiling_size)));
- break;
- case BOTTOM_RIGHT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
- pile_.tiling().TileBounds(5, 4));
- expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 5),
- gfx::Rect(base_tiling_size)));
- break;
- }
- EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
- invalidation.Clear();
+ // Grow both.
+ for (int dir = 0; dir <= LAST_DIRECTION; ++dir) {
+ gfx::Size new_tiling_size =
+ dir == GROW ? grow_both_tiling_size : base_tiling_size;
+ UpdateWholePile();
+ UpdateAndExpandInvalidation(&invalidation, new_tiling_size,
+ CornerSinglePixelRect(corner, new_tiling_size));
- UpdateWholePile();
- UpdateAndExpandInvalidation(&invalidation,
- base_tiling_size,
- CornerSinglePixelRect(corner, base_tiling_size));
-
- // We should have lost nothing.
- EXPECT_EQ(6, pile_.tiling().num_tiles_x());
- EXPECT_EQ(6, pile_.tiling().num_tiles_y());
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
+ // We should have lost the recordings in the right column and bottom row.
+ // The tile that insects the interest rect in invalidated only on its new
+ // or previously exposed pixels.
+ EXPECT_EQ(6, pile_.tiling().num_tiles_x());
+ EXPECT_EQ(6, pile_.tiling().num_tiles_y());
+ for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
+ for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
+ bool expect_tile;
+ switch (corner) {
+ case TOP_LEFT:
+ expect_tile = i < 5 && j < 5;
+ break;
+ case TOP_RIGHT:
+ // The interest rect in the top right tile means we'll record it.
+ expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5);
+ break;
+ case BOTTOM_LEFT:
+ // The interest rect in the bottom left tile means we'll record it.
+ expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0);
+ break;
+ case BOTTOM_RIGHT:
+ // The interest rect in the bottom right tile means we'll record it.
+ expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
+ break;
+ }
+ EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
+ << i << "," << j;
+ }
}
- }
- // We invalidated nothing.
- expected_invalidation.Clear();
- EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
- invalidation.Clear();
-
- UpdateWholePile();
- UpdateAndExpandInvalidation(
- &invalidation,
- grow_both_tiling_size,
- CornerSinglePixelRect(corner, grow_both_tiling_size));
-
- // We should have lost the recordings in the right column and bottom row. The
- // tile that insects the interest rect in invalidated only on its new pixels.
- EXPECT_EQ(6, pile_.tiling().num_tiles_x());
- EXPECT_EQ(6, pile_.tiling().num_tiles_y());
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- bool expect_tile;
+ // We invalidated the right column and the bottom row outside the new
+ // interest rect. The tile that insects the interest rect in invalidated
+ // only on its new or previous exposed pixels.
+ if (dir == GROW) {
+ // Calculate the expected invalidation the first time through the loop.
switch (corner) {
case TOP_LEFT:
- expect_tile = i < 5 && j < 5;
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
+ expected_invalidation.Union(
+ gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
+ pile_.tiling().TileBounds(5, 5)));
break;
case TOP_RIGHT:
- // The interest rect in the top right tile means we'll record it.
- expect_tile = (i < 5 && j < 5) || (j == 0 && i == 5);
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 1), pile_.tiling().TileBounds(5, 5));
+ expected_invalidation.Union(
+ gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
+ pile_.tiling().TileBounds(5, 5)));
+ expected_invalidation.Union(SubtractRects(
+ pile_.tiling().TileBounds(5, 0), gfx::Rect(base_tiling_size)));
break;
case BOTTOM_LEFT:
- // The interest rect in the bottom left tile means we'll record it.
- expect_tile = (i < 5 && j < 5) || (j == 5 && i == 0);
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 5));
+ expected_invalidation.Union(
+ gfx::UnionRects(pile_.tiling().TileBounds(1, 5),
+ pile_.tiling().TileBounds(5, 5)));
+ expected_invalidation.Union(SubtractRects(
+ pile_.tiling().TileBounds(0, 5), gfx::Rect(base_tiling_size)));
break;
case BOTTOM_RIGHT:
- // The interest rect in the bottom right tile means we'll record it.
- expect_tile = (i < 5 && j < 5) || (j == 5 && i == 5);
+ expected_invalidation = gfx::UnionRects(
+ pile_.tiling().TileBounds(5, 0), pile_.tiling().TileBounds(5, 4));
+ expected_invalidation.Union(
+ gfx::UnionRects(pile_.tiling().TileBounds(0, 5),
+ pile_.tiling().TileBounds(4, 5)));
+ expected_invalidation.Union(SubtractRegions(
+ pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
break;
}
- EXPECT_EQ(expect_tile, it != map.end() && it->second.GetPicture())
- << i << "," << j;
}
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
+ invalidation.Clear();
}
-
- // We invalidated the right column and the bottom row outside the new interest
- // rect. The tile that insects the interest rect in invalidated only on its
- // new pixels.
- switch (corner) {
- case TOP_LEFT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
- pile_.tiling().TileBounds(5, 5));
- expected_invalidation.Union(gfx::UnionRects(
- pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)));
- break;
- case TOP_RIGHT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 1),
- pile_.tiling().TileBounds(5, 5));
- expected_invalidation.Union(gfx::UnionRects(
- pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(5, 5)));
- expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(5, 0),
- gfx::Rect(base_tiling_size)));
- break;
- case BOTTOM_LEFT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
- pile_.tiling().TileBounds(5, 5));
- expected_invalidation.Union(gfx::UnionRects(
- pile_.tiling().TileBounds(1, 5), pile_.tiling().TileBounds(5, 5)));
- expected_invalidation.Union(SubtractRects(pile_.tiling().TileBounds(0, 5),
- gfx::Rect(base_tiling_size)));
- break;
- case BOTTOM_RIGHT:
- expected_invalidation = gfx::UnionRects(pile_.tiling().TileBounds(5, 0),
- pile_.tiling().TileBounds(5, 4));
- expected_invalidation.Union(gfx::UnionRects(
- pile_.tiling().TileBounds(0, 5), pile_.tiling().TileBounds(4, 5)));
- expected_invalidation.Union(SubtractRegions(
- pile_.tiling().TileBounds(5, 5), gfx::Rect(base_tiling_size)));
- break;
- }
- EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
- invalidation.Clear();
-
- UpdateWholePile();
- UpdateAndExpandInvalidation(&invalidation,
- base_tiling_size,
- CornerSinglePixelRect(corner, base_tiling_size));
-
- // We should have lost nothing.
- EXPECT_EQ(6, pile_.tiling().num_tiles_x());
- EXPECT_EQ(6, pile_.tiling().num_tiles_y());
- for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
- for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
- EXPECT_TRUE(it != map.end() && it->second.GetPicture());
- }
- }
-
- // We invalidated nothing.
- expected_invalidation.Clear();
- EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
- invalidation.Clear();
}
INSTANTIATE_TEST_CASE_P(
@@ -1086,9 +1148,9 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1101,9 +1163,9 @@
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1127,15 +1189,18 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- EXPECT_EQ(Region().ToString(), invalidation.ToString());
+ // We invalidated the previously exposed pixels on the bottom row of tiles.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+ gfx::Rect(base_tiling_size));
+ EXPECT_TRUE(expected_invalidation.Contains(bottom_row_new_pixels));
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
UpdateWholePile();
@@ -1147,9 +1212,9 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1173,15 +1238,18 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- EXPECT_EQ(Region().ToString(), invalidation.ToString());
+ // We invalidated the previously exposed pixels on the right column of tiles.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+ gfx::Rect(base_tiling_size));
+ EXPECT_TRUE(expected_invalidation.Contains(right_column_new_pixels));
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
UpdateWholePile();
@@ -1193,9 +1261,9 @@
EXPECT_EQ(8, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1223,15 +1291,20 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- EXPECT_EQ(Region().ToString(), invalidation.ToString());
+ // We invalidated the previously exposed pixels on the bottom row and right
+ // column of tiles.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+ gfx::Rect(base_tiling_size));
+ EXPECT_TRUE(
+ expected_invalidation.Contains(bottom_row_and_right_column_new_pixels));
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
}
@@ -1256,9 +1329,9 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1271,9 +1344,9 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1292,15 +1365,17 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- EXPECT_EQ(Region().ToString(), invalidation.ToString());
+ // We invalidated the previously exposed pixels.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_down_tiling_size),
+ gfx::Rect(base_tiling_size));
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
UpdateWholePile();
@@ -1312,9 +1387,9 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1333,15 +1408,17 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- EXPECT_EQ(Region().ToString(), invalidation.ToString());
+ // We invalidated the previously exposed pixels.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_right_tiling_size),
+ gfx::Rect(base_tiling_size));
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
UpdateWholePile();
@@ -1353,9 +1430,9 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
@@ -1374,15 +1451,17 @@
EXPECT_EQ(6, pile_.tiling().num_tiles_y());
for (int i = 0; i < pile_.tiling().num_tiles_x(); ++i) {
for (int j = 0; j < pile_.tiling().num_tiles_y(); ++j) {
- TestPicturePile::PictureMapKey key(i, j);
- TestPicturePile::PictureMap& map = pile_.picture_map();
- TestPicturePile::PictureMap::iterator it = map.find(key);
+ FakePicturePile::PictureMapKey key(i, j);
+ FakePicturePile::PictureMap& map = pile_.picture_map();
+ FakePicturePile::PictureMap::iterator it = map.find(key);
EXPECT_TRUE(it != map.end() && it->second.GetPicture());
}
}
- // No invalidation when shrinking.
- EXPECT_EQ(Region().ToString(), invalidation.ToString());
+ // We invalidated the previously exposed pixels.
+ expected_invalidation = SubtractRegions(gfx::Rect(grow_both_tiling_size),
+ gfx::Rect(base_tiling_size));
+ EXPECT_EQ(expected_invalidation.ToString(), invalidation.ToString());
invalidation.Clear();
}
@@ -1458,12 +1537,12 @@
TEST_F(PicturePileTest, SetEmptyBounds) {
EXPECT_TRUE(pile_.is_solid_color());
- EXPECT_FALSE(pile_.tiling_size().IsEmpty());
+ EXPECT_FALSE(pile_.GetSize().IsEmpty());
EXPECT_FALSE(pile_.picture_map().empty());
EXPECT_TRUE(pile_.HasRecordings());
pile_.SetEmptyBounds();
EXPECT_FALSE(pile_.is_solid_color());
- EXPECT_TRUE(pile_.tiling_size().IsEmpty());
+ EXPECT_TRUE(pile_.GetSize().IsEmpty());
EXPECT_TRUE(pile_.picture_map().empty());
EXPECT_FALSE(pile_.HasRecordings());
}
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index 3e25408..f7ea271 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -9,9 +9,12 @@
#include "base/memory/ref_counted.h"
#include "cc/base/cc_export.h"
+#include "cc/debug/traced_value.h"
+#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
class SkCanvas;
+class SkPicture;
namespace cc {
@@ -30,10 +33,19 @@
// assumed that contents_scale has already been applied to this canvas.
// Writes the total number of pixels rasterized and the time spent
// rasterizing to the stats if the respective pointer is not nullptr.
+ // It is assumed that the canvas passed here will only be rasterized by
+ // this raster source via this call.
virtual void PlaybackToCanvas(SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const = 0;
+ // Similar to above, except that the canvas passed here can (or was already)
+ // rasterized into by another raster source. That is, it is not safe to clear
+ // the canvas or discard its underlying memory.
+ virtual void PlaybackToSharedCanvas(SkCanvas* canvas,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const = 0;
+
// Analyze to determine if the given rect at given scale is of solid color in
// this raster source.
virtual void PerformSolidColorAnalysis(
@@ -41,6 +53,16 @@
float contents_scale,
SolidColorAnalysis* analysis) const = 0;
+ // Returns true iff the whole raster source is of solid color.
+ virtual bool IsSolidColor() const = 0;
+
+ // Returns the color of the raster source if it is solid color. The results
+ // are unspecified if IsSolidColor returns false.
+ virtual SkColor GetSolidColor() const = 0;
+
+ // Returns the size of this raster source.
+ virtual gfx::Size GetSize() const = 0;
+
// Populate the given list with all SkPixelRefs that may overlap the given
// rect at given scale.
virtual void GatherPixelRefs(const gfx::Rect& content_rect,
@@ -52,9 +74,24 @@
virtual bool CoversRect(const gfx::Rect& content_rect,
float contents_scale) const = 0;
+ // Returns true if this raster source has anything to rasterize.
+ virtual bool HasRecordings() const = 0;
+
+ // Informs the raster source that it should attempt to use distance field text
+ // during rasterization.
+ virtual void SetShouldAttemptToUseDistanceFieldText() = 0;
+
// Return true iff this raster source would benefit from using distance
// field text.
- virtual bool SuitableForDistanceFieldText() const = 0;
+ virtual bool ShouldAttemptToUseDistanceFieldText() const = 0;
+
+ // Tracing functionality.
+ virtual void DidBeginTracing() = 0;
+ 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 0f7a845..fdec054 100644
--- a/cc/resources/raster_worker_pool_perftest.cc
+++ b/cc/resources/raster_worker_pool_perftest.cc
@@ -167,7 +167,7 @@
public:
typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector;
- enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 };
+ enum NamedTaskSet { ALL, REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW };
RasterWorkerPoolPerfTestBase()
: context_provider_(make_scoped_refptr(new PerfContextProvider)),
diff --git a/cc/resources/raster_worker_pool_unittest.cc b/cc/resources/raster_worker_pool_unittest.cc
index 9aee8e7..775acda 100644
--- a/cc/resources/raster_worker_pool_unittest.cc
+++ b/cc/resources/raster_worker_pool_unittest.cc
@@ -121,7 +121,7 @@
typedef std::vector<scoped_refptr<RasterTask>> RasterTaskVector;
- enum NamedTaskSet { REQUIRED_FOR_ACTIVATION = 0, ALL = 1 };
+ enum NamedTaskSet { ALL, REQUIRED_FOR_ACTIVATION, REQUIRED_FOR_DRAW };
RasterWorkerPoolTest()
: context_provider_(TestContextProvider::Create()),
diff --git a/cc/resources/rasterizer.h b/cc/resources/rasterizer.h
index 526058c..db84c22 100644
--- a/cc/resources/rasterizer.h
+++ b/cc/resources/rasterizer.h
@@ -87,7 +87,11 @@
ImageDecodeTask::Vector dependencies_;
};
-static const size_t kNumberOfTaskSets = 2;
+// kNumberOfTaskSets must be greater or equal to the number of values in
+// TileManager::NamedTaskSet.
+// TODO(reveman): Use template specialization to make it easy for client code to
+// check at compile time that the number of supported task sets is correct.
+static const size_t kNumberOfTaskSets = 3;
typedef size_t TaskSet;
typedef std::bitset<kNumberOfTaskSets> TaskSetCollection;
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
new file mode 100644
index 0000000..cbbeb70
--- /dev/null
+++ b/cc/resources/recording_source.h
@@ -0,0 +1,55 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_RECORDING_SOURCE_H_
+#define CC_RESOURCES_RECORDING_SOURCE_H_
+
+#include "cc/base/cc_export.h"
+#include "cc/resources/picture.h"
+#include "third_party/skia/include/core/SkBBHFactory.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+
+namespace cc {
+class ContentLayerClient;
+class Region;
+class RasterSource;
+
+class CC_EXPORT RecordingSource {
+ public:
+ virtual ~RecordingSource() {}
+ // Re-record parts of the picture that are invalid.
+ // Invalidations are in layer space, and will be expanded to cover everything
+ // that was either recorded/changed or that has no recording, leaving out only
+ // pieces that we had a recording for and it was not changed.
+ // Return true iff the pile was modified.
+ 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 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): Figure out how to remove this.
+ virtual void SetUnsuitableForGpuRasterizationForTesting() = 0;
+ virtual SkTileGridFactory::TileGridInfo GetTileGridInfoForTesting() const = 0;
+};
+}
+
+#endif // CC_RESOURCES_RECORDING_SOURCE_H_
diff --git a/cc/resources/skpicture_content_layer_updater.cc b/cc/resources/skpicture_content_layer_updater.cc
index bd524f2..3e6828f 100644
--- a/cc/resources/skpicture_content_layer_updater.cc
+++ b/cc/resources/skpicture_content_layer_updater.cc
@@ -16,9 +16,9 @@
SkPictureContentLayerUpdater::SkPictureContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id)
- : ContentLayerUpdater(painter.Pass(), stats_instrumentation, layer_id) {}
+ : ContentLayerUpdater(painter.Pass(), layer_id) {
+}
SkPictureContentLayerUpdater::~SkPictureContentLayerUpdater() {}
@@ -33,17 +33,11 @@
recorder.beginRecording(paint_rect.width(), paint_rect.height(), NULL, 0);
DCHECK_EQ(paint_rect.width(), canvas->getBaseLayerSize().width());
DCHECK_EQ(paint_rect.height(), canvas->getBaseLayerSize().height());
- base::TimeTicks start_time =
- rendering_stats_instrumentation_->StartRecording();
PaintContents(canvas,
content_size,
paint_rect,
contents_width_scale,
contents_height_scale);
- base::TimeDelta duration =
- rendering_stats_instrumentation_->EndRecording(start_time);
- rendering_stats_instrumentation_->AddRecord(
- duration, paint_rect.width() * paint_rect.height());
picture_ = skia::AdoptRef(recorder.endRecording());
}
diff --git a/cc/resources/skpicture_content_layer_updater.h b/cc/resources/skpicture_content_layer_updater.h
index ec49aae..33480a8 100644
--- a/cc/resources/skpicture_content_layer_updater.h
+++ b/cc/resources/skpicture_content_layer_updater.h
@@ -21,7 +21,6 @@
protected:
SkPictureContentLayerUpdater(
scoped_ptr<LayerPainter> painter,
- RenderingStatsInstrumentation* stats_instrumentation,
int layer_id);
~SkPictureContentLayerUpdater() override;
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index d6bd3c4..4cbc758 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -36,6 +36,7 @@
tiling_i_index_(-1),
tiling_j_index_(-1),
required_for_activation_(false),
+ required_for_draw_(false),
id_(s_next_id_++) {
set_raster_source(raster_source);
for (int i = 0; i < NUM_TREES; i++)
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index c641367..042d5ae 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -85,6 +85,10 @@
void set_required_for_activation(bool is_required) {
required_for_activation_ = is_required;
}
+ bool required_for_draw() const { return required_for_draw_; }
+ void set_required_for_draw(bool is_required) {
+ required_for_draw_ = is_required;
+ }
bool use_picture_analysis() const {
return !!(flags_ & USE_PICTURE_ANALYSIS);
@@ -174,6 +178,7 @@
int tiling_i_index_;
int tiling_j_index_;
bool required_for_activation_;
+ bool required_for_draw_;
Id id_;
static Id s_next_id_;
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 8b6a72a..1c7d4ca 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -175,6 +175,20 @@
DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
};
+const char* TaskSetName(TaskSet task_set) {
+ switch (task_set) {
+ case TileManager::ALL:
+ return "ALL";
+ case TileManager::REQUIRED_FOR_ACTIVATION:
+ return "REQUIRED_FOR_ACTIVATION";
+ case TileManager::REQUIRED_FOR_DRAW:
+ return "REQUIRED_FOR_DRAW";
+ }
+
+ NOTREACHED();
+ return "Invalid TaskSet";
+}
+
} // namespace
RasterTaskCompletionStats::RasterTaskCompletionStats()
@@ -225,7 +239,10 @@
ready_to_activate_check_notifier_(
task_runner_.get(),
base::Bind(&TileManager::CheckIfReadyToActivate,
- base::Unretained(this))) {
+ base::Unretained(this))),
+ ready_to_draw_check_notifier_(task_runner_.get(),
+ base::Bind(&TileManager::CheckIfReadyToDraw,
+ base::Unretained(this))) {
rasterizer_->SetClient(this);
}
@@ -295,85 +312,91 @@
}
void TileManager::DidFinishRunningTasks(TaskSet task_set) {
- if (task_set == ALL) {
- TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set", "ALL");
+ TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set",
+ TaskSetName(task_set));
- bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() >
- global_state_.soft_memory_limit_in_bytes;
+ switch (task_set) {
+ case ALL: {
+ bool memory_usage_above_limit =
+ resource_pool_->total_memory_usage_bytes() >
+ global_state_.soft_memory_limit_in_bytes;
- // When OOM, keep re-assigning memory until we reach a steady state
- // where top-priority tiles are initialized.
- if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
- !memory_usage_above_limit)
- return;
+ // When OOM, keep re-assigning memory until we reach a steady state
+ // where top-priority tiles are initialized.
+ if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
+ !memory_usage_above_limit)
+ return;
- rasterizer_->CheckForCompletedTasks();
- did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+ rasterizer_->CheckForCompletedTasks();
+ did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
- TileVector tiles_that_need_to_be_rasterized;
- AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
+ TileVector tiles_that_need_to_be_rasterized;
+ AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
- // |tiles_that_need_to_be_rasterized| will be empty when we reach a
- // steady memory state. Keep scheduling tasks until we reach this state.
- if (!tiles_that_need_to_be_rasterized.empty()) {
- ScheduleTasks(tiles_that_need_to_be_rasterized);
- return;
- }
-
- FreeResourcesForReleasedTiles();
-
- resource_pool_->ReduceResourceUsage();
-
- // We don't reserve memory for required-for-activation tiles during
- // accelerated gestures, so we just postpone activation when we don't
- // have these tiles, and activate after the accelerated gesture.
- // Likewise if we don't allow any tiles (as is the case when we're
- // invisible), if we have tiles that aren't ready, then we shouldn't
- // activate as activation can cause checkerboards.
- bool allow_rasterize_on_demand =
- global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
- global_state_.memory_limit_policy != ALLOW_NOTHING;
-
- // Use on-demand raster for any required-for-activation tiles that have not
- // been been assigned memory after reaching a steady memory state. This
- // ensures that we activate even when OOM. Note that we have to rebuilt the
- // queue in case the last AssignGpuMemoryToTiles evicted some tiles that
- // would otherwise not be picked up by the old raster queue.
- client_->BuildRasterQueue(&raster_priority_queue_,
- global_state_.tree_priority);
- bool ready_to_activate = true;
- while (!raster_priority_queue_.IsEmpty()) {
- Tile* tile = raster_priority_queue_.Top();
- ManagedTileState& mts = tile->managed_state();
-
- if (tile->required_for_activation() && !mts.draw_info.IsReadyToDraw()) {
- // If we can't raster on demand, give up early (and don't activate).
- if (!allow_rasterize_on_demand) {
- ready_to_activate = false;
- break;
- }
-
- mts.draw_info.set_rasterize_on_demand();
- client_->NotifyTileStateChanged(tile);
+ // |tiles_that_need_to_be_rasterized| will be empty when we reach a
+ // steady memory state. Keep scheduling tasks until we reach this state.
+ if (!tiles_that_need_to_be_rasterized.empty()) {
+ ScheduleTasks(tiles_that_need_to_be_rasterized);
+ return;
}
- raster_priority_queue_.Pop();
- }
- if (ready_to_activate) {
- DCHECK(IsReadyToActivate());
+ FreeResourcesForReleasedTiles();
+
+ resource_pool_->ReduceResourceUsage();
+
+ // We don't reserve memory for required-for-activation tiles during
+ // accelerated gestures, so we just postpone activation when we don't
+ // have these tiles, and activate after the accelerated gesture.
+ // Likewise if we don't allow any tiles (as is the case when we're
+ // invisible), if we have tiles that aren't ready, then we shouldn't
+ // activate as activation can cause checkerboards.
+ bool allow_rasterize_on_demand =
+ global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
+ global_state_.memory_limit_policy != ALLOW_NOTHING;
+
+ // Use on-demand raster for any required-for-activation tiles that have
+ // not
+ // been been assigned memory after reaching a steady memory state. This
+ // ensures that we activate even when OOM. Note that we have to rebuilt
+ // the
+ // queue in case the last AssignGpuMemoryToTiles evicted some tiles that
+ // would otherwise not be picked up by the old raster queue.
+ client_->BuildRasterQueue(&raster_priority_queue_,
+ global_state_.tree_priority);
+ bool ready_to_activate = true;
+ while (!raster_priority_queue_.IsEmpty()) {
+ Tile* tile = raster_priority_queue_.Top();
+ ManagedTileState& mts = tile->managed_state();
+
+ if (tile->required_for_activation() && !mts.draw_info.IsReadyToDraw()) {
+ // If we can't raster on demand, give up early (and don't activate).
+ if (!allow_rasterize_on_demand) {
+ ready_to_activate = false;
+ break;
+ }
+
+ mts.draw_info.set_rasterize_on_demand();
+ client_->NotifyTileStateChanged(tile);
+ }
+ raster_priority_queue_.Pop();
+ }
+
+ if (ready_to_activate) {
+ DCHECK(IsReadyToActivate());
+ ready_to_activate_check_notifier_.Schedule();
+ }
+ raster_priority_queue_.Reset();
+ return;
+ }
+ case REQUIRED_FOR_ACTIVATION:
ready_to_activate_check_notifier_.Schedule();
- }
- raster_priority_queue_.Reset();
- return;
+ return;
+ case REQUIRED_FOR_DRAW:
+ ready_to_draw_check_notifier_.Schedule();
+ return;
}
- if (task_set == REQUIRED_FOR_ACTIVATION) {
- TRACE_EVENT1("cc",
- "TileManager::DidFinishRunningTasks",
- "task_set",
- "REQUIRED_FOR_ACTIVATION");
- ready_to_activate_check_notifier_.Schedule();
- }
+ NOTREACHED();
}
void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
@@ -671,6 +694,8 @@
TaskSetCollection task_sets;
if (tile->required_for_activation())
task_sets.set(REQUIRED_FOR_ACTIVATION);
+ if (tile->required_for_draw())
+ task_sets.set(REQUIRED_FOR_DRAW);
task_sets.set(ALL);
raster_queue_.items.push_back(
RasterTaskQueue::Item(mts.raster_task.get(), task_sets));
@@ -840,10 +865,19 @@
TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
- for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin();
- it != layers.end();
- ++it) {
- if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw())
+ for (const auto& layer : layers) {
+ if (!layer->AllTilesRequiredForActivationAreReadyToDraw())
+ return false;
+ }
+
+ return true;
+}
+
+bool TileManager::IsReadyToDraw() const {
+ const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
+
+ for (const auto& layer : layers) {
+ if (!layer->AllTilesRequiredForDrawAreReadyToDraw())
return false;
}
@@ -860,6 +894,16 @@
client_->NotifyReadyToActivate();
}
+void TileManager::CheckIfReadyToDraw() {
+ TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
+
+ rasterizer_->CheckForCompletedTasks();
+ did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
+
+ if (IsReadyToDraw())
+ client_->NotifyReadyToDraw();
+}
+
TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
}
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index f5bea38..92821e0 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -47,6 +47,9 @@
// Called when all tiles marked as required for activation are ready to draw.
virtual void NotifyReadyToActivate() = 0;
+ // Called when all tiles marked as required for draw are ready to draw.
+ virtual void NotifyReadyToDraw() = 0;
+
// Called when the visible representation of a tile might have changed. Some
// examples are:
// - Tile version initialized.
@@ -87,8 +90,9 @@
public RefCountedManager<Tile> {
public:
enum NamedTaskSet {
- REQUIRED_FOR_ACTIVATION = 0,
- ALL = 1,
+ ALL,
+ REQUIRED_FOR_ACTIVATION,
+ REQUIRED_FOR_DRAW
// Adding additional values requires increasing kNumberOfTaskSets in
// rasterizer.h
};
@@ -231,7 +235,9 @@
MemoryUsage* usage);
bool TilePriorityViolatesMemoryPolicy(const TilePriority& priority);
bool IsReadyToActivate() const;
+ bool IsReadyToDraw() const;
void CheckIfReadyToActivate();
+ void CheckIfReadyToDraw();
TileManagerClient* client_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
@@ -272,6 +278,7 @@
std::vector<scoped_refptr<RasterTask>> orphan_raster_tasks_;
UniqueNotifier ready_to_activate_check_notifier_;
+ UniqueNotifier ready_to_draw_check_notifier_;
RasterTilePriorityQueue raster_priority_queue_;
EvictionTilePriorityQueue eviction_priority_queue_;
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 43c1031..7262926 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -159,7 +159,7 @@
pending_tree->DetachLayerTree();
scoped_ptr<FakePictureLayerImpl> pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile);
pending_layer->SetDrawsContent(true);
pending_tree->SetRootLayer(pending_layer.Pass());
@@ -361,8 +361,8 @@
FakePicturePileImpl::CreateFilledPile(kDefaultTileSize, layer_bounds);
while (static_cast<int>(layers.size()) < layer_count) {
scoped_ptr<FakePictureLayerImpl> layer =
- FakePictureLayerImpl::CreateWithPile(host_impl_.pending_tree(),
- next_id, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(
+ host_impl_.pending_tree(), next_id, pile);
layer->SetBounds(layer_bounds);
layers.push_back(layer.get());
pending_root_layer_->AddChild(layer.Pass());
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 2f0735c..a253672 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -109,14 +109,14 @@
if (old_pending_root) {
pending_layer.reset(
static_cast<FakePictureLayerImpl*>(old_pending_root.release()));
- pending_layer->SetPile(pile);
+ pending_layer->SetRasterSource(pile);
} else {
pending_layer =
- FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(pending_tree, id_, pile);
pending_layer->SetDrawsContent(true);
}
// The bounds() just mirror the pile size.
- pending_layer->SetBounds(pending_layer->pile()->tiling_size());
+ pending_layer->SetBounds(pending_layer->raster_source()->GetSize());
pending_tree->SetRootLayer(pending_layer.Pass());
pending_layer_ = static_cast<FakePictureLayerImpl*>(
@@ -193,9 +193,9 @@
// Invalidate the pending tree.
pending_layer_->set_invalidation(invalidation);
- pending_layer_->HighResTiling()->UpdateTilesToCurrentPile(
+ pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
invalidation, gfx::Size(1000, 1000));
- pending_layer_->LowResTiling()->UpdateTilesToCurrentPile(
+ pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
invalidation, gfx::Size(1000, 1000));
active_layer_->ResetAllTilesPriorities();
@@ -344,8 +344,8 @@
scoped_refptr<FakePicturePileImpl> pending_pile =
FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
scoped_ptr<FakePictureLayerImpl> pending_child =
- FakePictureLayerImpl::CreateWithPile(
- host_impl_.pending_tree(), id_ + 1, pending_pile);
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(),
+ id_ + 1, pending_pile);
pending_layer_->AddChild(pending_child.Pass());
FakePictureLayerImpl* pending_child_raw = static_cast<FakePictureLayerImpl*>(
host_impl_.pending_tree()->LayerById(id_ + 1));
@@ -441,9 +441,9 @@
// Invalidate the pending tree.
pending_layer_->set_invalidation(invalidation);
- pending_layer_->HighResTiling()->UpdateTilesToCurrentPile(
+ pending_layer_->HighResTiling()->UpdateTilesToCurrentRasterSource(
invalidation, gfx::Size(1000, 1000));
- pending_layer_->LowResTiling()->UpdateTilesToCurrentPile(
+ pending_layer_->LowResTiling()->UpdateTilesToCurrentRasterSource(
invalidation, gfx::Size(1000, 1000));
active_layer_->ResetAllTilesPriorities();
@@ -566,8 +566,8 @@
pending_layer_->CreateDefaultTilingsAndTiles();
scoped_ptr<FakePictureLayerImpl> pending_child =
- FakePictureLayerImpl::CreateWithPile(
- host_impl_.pending_tree(), 2, pending_pile);
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2,
+ pending_pile);
pending_layer_->AddChild(pending_child.Pass());
FakePictureLayerImpl* pending_child_layer =
@@ -669,6 +669,104 @@
EXPECT_EQ(expected_occluded_count, occluded_count);
}
+TEST_F(TileManagerTilePriorityQueueTest,
+ EvictionTilePriorityQueueWithTransparentLayer) {
+ gfx::Size tile_size(102, 102);
+ gfx::Size layer_bounds(1000, 1000);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ SetupPendingTree(pending_pile);
+ pending_layer_->CreateDefaultTilingsAndTiles();
+
+ scoped_ptr<FakePictureLayerImpl> pending_child =
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_.pending_tree(), 2,
+ pending_pile);
+ pending_layer_->AddChild(pending_child.Pass());
+
+ // Create a fully transparent child layer so that its tile priorities are not
+ // considered to be valid.
+ FakePictureLayerImpl* pending_child_layer =
+ static_cast<FakePictureLayerImpl*>(pending_layer_->children()[0]);
+ pending_child_layer->SetDrawsContent(true);
+ pending_child_layer->CreateDefaultTilingsAndTiles();
+ pending_child_layer->SetOpacity(0.0);
+ pending_child_layer->layer_tree_impl()->UpdateDrawProperties();
+ pending_child_layer->DoPostCommitInitializationIfNeeded();
+
+ // 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_child_layer->HighResTiling()->ComputeTilePriorityRects(
+ PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+ pending_child_layer->LowResTiling()->ComputeTilePriorityRects(
+ PENDING_TREE, viewport, 1.0f, 1.0, Occlusion());
+
+ // Populate all tiles directly from the tilings.
+ std::set<Tile*> all_pending_tiles;
+ std::vector<Tile*> pending_high_res_tiles =
+ pending_layer_->HighResTiling()->AllTilesForTesting();
+ all_pending_tiles.insert(pending_high_res_tiles.begin(),
+ pending_high_res_tiles.end());
+ EXPECT_EQ(16u, pending_high_res_tiles.size());
+
+ std::vector<Tile*> pending_low_res_tiles =
+ pending_layer_->LowResTiling()->AllTilesForTesting();
+ all_pending_tiles.insert(pending_low_res_tiles.begin(),
+ pending_low_res_tiles.end());
+ EXPECT_EQ(1u, pending_low_res_tiles.size());
+
+ std::set<Tile*> all_pending_child_tiles;
+ std::vector<Tile*> pending_child_high_res_tiles =
+ pending_child_layer->HighResTiling()->AllTilesForTesting();
+ all_pending_child_tiles.insert(pending_child_high_res_tiles.begin(),
+ pending_child_high_res_tiles.end());
+ EXPECT_EQ(16u, pending_child_high_res_tiles.size());
+
+ std::vector<Tile*> pending_child_low_res_tiles =
+ pending_child_layer->LowResTiling()->AllTilesForTesting();
+ all_pending_child_tiles.insert(pending_child_low_res_tiles.begin(),
+ pending_child_low_res_tiles.end());
+ EXPECT_EQ(1u, pending_child_low_res_tiles.size());
+
+ std::set<Tile*> all_tiles = all_pending_tiles;
+ all_tiles.insert(all_pending_child_tiles.begin(),
+ all_pending_child_tiles.end());
+
+ tile_manager()->InitializeTilesWithResourcesForTesting(
+ std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
+
+ EXPECT_TRUE(pending_layer_->HasValidTilePriorities());
+ EXPECT_FALSE(pending_child_layer->HasValidTilePriorities());
+
+ // Verify that eviction queue returns tiles also from layers without valid
+ // tile priorities and that the tile priority bin of those tiles is (at most)
+ // EVENTUALLY.
+ TreePriority tree_priority = NEW_CONTENT_TAKES_PRIORITY;
+ std::set<Tile*> new_content_tiles;
+ size_t tile_count = 0;
+ EvictionTilePriorityQueue queue;
+ host_impl_.BuildEvictionQueue(&queue, tree_priority);
+ while (!queue.IsEmpty()) {
+ Tile* tile = queue.Top();
+ const TilePriority& pending_priority = tile->priority(PENDING_TREE);
+ EXPECT_NE(std::numeric_limits<float>::infinity(),
+ pending_priority.distance_to_visible);
+ if (all_pending_child_tiles.find(tile) != all_pending_child_tiles.end())
+ EXPECT_EQ(TilePriority::EVENTUALLY, pending_priority.priority_bin);
+ else
+ EXPECT_EQ(TilePriority::NOW, pending_priority.priority_bin);
+ new_content_tiles.insert(tile);
+ ++tile_count;
+ queue.Pop();
+ }
+ EXPECT_EQ(tile_count, new_content_tiles.size());
+ EXPECT_EQ(all_tiles, new_content_tiles);
+}
+
TEST_F(TileManagerTilePriorityQueueTest, RasterTilePriorityQueueEmptyLayers) {
SetupDefaultTrees(gfx::Size(1000, 1000));
diff --git a/cc/scheduler/begin_frame_source.cc b/cc/scheduler/begin_frame_source.cc
index 4a9f184..dd6cdbe 100644
--- a/cc/scheduler/begin_frame_source.cc
+++ b/cc/scheduler/begin_frame_source.cc
@@ -79,9 +79,9 @@
"new state",
needs_begin_frames);
if (needs_begin_frames_ != needs_begin_frames) {
+ needs_begin_frames_ = needs_begin_frames;
OnNeedsBeginFramesChange(needs_begin_frames);
}
- needs_begin_frames_ = needs_begin_frames;
}
void BeginFrameSourceMixIn::AddObserver(BeginFrameObserver* obs) {
diff --git a/cc/scheduler/begin_frame_source.h b/cc/scheduler/begin_frame_source.h
index 3d849a4..28359d3 100644
--- a/cc/scheduler/begin_frame_source.h
+++ b/cc/scheduler/begin_frame_source.h
@@ -117,6 +117,9 @@
virtual void AddObserver(BeginFrameObserver* obs) = 0;
virtual void RemoveObserver(BeginFrameObserver* obs) = 0;
+ // Tells the Source that client is ready to handle BeginFrames messages.
+ virtual void SetClientReady() = 0;
+
// Tracing support - Recommend (but not required) to call this implementation
// in any override.
virtual void AsValueInto(base::debug::TracedValue* dict) const = 0;
@@ -137,8 +140,9 @@
bool NeedsBeginFrames() const override;
void SetNeedsBeginFrames(bool needs_begin_frames) override;
void DidFinishFrame(size_t remaining_frames) override {}
- void AddObserver(BeginFrameObserver* obs) override;
- void RemoveObserver(BeginFrameObserver* obs) override;
+ void AddObserver(BeginFrameObserver* obs) final;
+ void RemoveObserver(BeginFrameObserver* obs) final;
+ void SetClientReady() override {}
// Tracing support - Recommend (but not required) to call this implementation
// in any override.
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 88c27c1..5c515b2 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -5,6 +5,7 @@
#include "cc/scheduler/scheduler.h"
#include <algorithm>
+
#include "base/auto_reset.h"
#include "base/debug/trace_event.h"
#include "base/debug/trace_event_argument.h"
@@ -28,12 +29,14 @@
scheduler->primary_frame_source_internal_ =
BackToBackBeginFrameSource::Create(scheduler->task_runner_.get());
return scheduler->primary_frame_source_internal_.get();
- } else if (scheduler->settings_.begin_frame_scheduling_enabled) {
+ } else if (scheduler->settings_.use_external_begin_frame_source) {
TRACE_EVENT1("cc",
"Scheduler::Scheduler()",
"PrimaryFrameSource",
- "SchedulerClient");
- return scheduler->client_->ExternalBeginFrameSource();
+ "ExternalBeginFrameSource");
+ DCHECK(scheduler->primary_frame_source_internal_)
+ << "Need external BeginFrameSource";
+ return scheduler->primary_frame_source_internal_.get();
} else {
TRACE_EVENT1("cc",
"Scheduler::Scheduler()",
@@ -62,9 +65,9 @@
"SyntheticBeginFrameSource");
DCHECK(!(scheduler->background_frame_source_internal_));
scheduler->background_frame_source_internal_ =
- SyntheticBeginFrameSource::Create(scheduler->task_runner_.get(),
- scheduler->Now(),
- base::TimeDelta::FromSeconds(1));
+ SyntheticBeginFrameSource::Create(
+ scheduler->task_runner_.get(), scheduler->Now(),
+ scheduler->settings_.background_frame_interval);
return scheduler->background_frame_source_internal_.get();
}
@@ -74,11 +77,12 @@
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source,
SchedulerFrameSourcesConstructor* frame_sources_constructor)
: frame_source_(),
primary_frame_source_(NULL),
background_frame_source_(NULL),
- primary_frame_source_internal_(),
+ primary_frame_source_internal_(external_begin_frame_source.Pass()),
background_frame_source_internal_(),
vsync_observer_(NULL),
settings_(scheduler_settings),
@@ -114,6 +118,7 @@
primary_frame_source_ =
frame_sources_constructor->ConstructPrimaryFrameSource(this);
frame_source_->AddSource(primary_frame_source_);
+ primary_frame_source_->SetClientReady();
// Background ticking frame source
background_frame_source_ =
@@ -125,6 +130,8 @@
Scheduler::~Scheduler() {
TeardownPowerMonitoring();
+ if (frame_source_->NeedsBeginFrames())
+ frame_source_->SetNeedsBeginFrames(false);
}
base::TimeTicks Scheduler::Now() const {
@@ -197,6 +204,11 @@
ProcessScheduledActions();
}
+void Scheduler::NotifyReadyToDraw() {
+ // Empty for now, until we take action based on the notification as part of
+ // crbugs 352894, 383157, 421923.
+}
+
void Scheduler::SetNeedsCommit() {
state_machine_.SetNeedsCommit();
ProcessScheduledActions();
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index f470d17..523c246 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -34,7 +34,6 @@
class SchedulerClient {
public:
- virtual BeginFrameSource* ExternalBeginFrameSource() = 0;
virtual void WillBeginImplFrame(const BeginFrameArgs& args) = 0;
virtual void ScheduledActionSendBeginMainFrame() = 0;
virtual DrawResult ScheduledActionDrawAndSwapIfPossible() = 0;
@@ -81,13 +80,15 @@
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor) {
+ base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
SchedulerFrameSourcesConstructor frame_sources_constructor;
return make_scoped_ptr(new Scheduler(client,
scheduler_settings,
layer_tree_host_id,
task_runner,
power_monitor,
+ external_begin_frame_source.Pass(),
&frame_sources_constructor));
}
@@ -107,6 +108,7 @@
void SetVisible(bool visible);
void SetCanDraw(bool can_draw);
void NotifyReadyToActivate();
+ void NotifyReadyToDraw();
void SetNeedsCommit();
@@ -173,6 +175,7 @@
int layer_tree_host_id,
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source,
SchedulerFrameSourcesConstructor* frame_sources_constructor);
// virtual for testing - Don't call these in the constructor or
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index ab9add0..84f0fcd 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -10,18 +10,22 @@
namespace cc {
SchedulerSettings::SchedulerSettings()
- : begin_frame_scheduling_enabled(true),
+ : use_external_begin_frame_source(false),
+ forward_begin_frames_to_children(false),
main_frame_before_activation_enabled(false),
impl_side_painting(false),
timeout_and_draw_when_animation_checkerboards(true),
maximum_number_of_failed_draws_before_draw_is_forced_(3),
using_synchronous_renderer_compositor(false),
throttle_frame_production(true),
- disable_hi_res_timer_tasks_on_battery(false) {
+ disable_hi_res_timer_tasks_on_battery(false),
+ background_frame_interval(base::TimeDelta::FromSeconds(1)) {
}
SchedulerSettings::SchedulerSettings(const LayerTreeSettings& settings)
- : begin_frame_scheduling_enabled(settings.begin_frame_scheduling_enabled),
+ : use_external_begin_frame_source(settings.use_external_begin_frame_source),
+ forward_begin_frames_to_children(
+ settings.forward_begin_frames_to_children),
main_frame_before_activation_enabled(
settings.main_frame_before_activation_enabled),
impl_side_painting(settings.impl_side_painting),
@@ -33,7 +37,9 @@
settings.using_synchronous_renderer_compositor),
throttle_frame_production(settings.throttle_frame_production),
disable_hi_res_timer_tasks_on_battery(
- settings.disable_hi_res_timer_tasks_on_battery) {
+ settings.disable_hi_res_timer_tasks_on_battery),
+ background_frame_interval(base::TimeDelta::FromSecondsD(
+ 1.0 / settings.background_animation_rate)) {
}
SchedulerSettings::~SchedulerSettings() {}
@@ -42,8 +48,10 @@
SchedulerSettings::AsValue() const {
scoped_refptr<base::debug::TracedValue> state =
new base::debug::TracedValue();
- state->SetBoolean("begin_frame_scheduling_enabled",
- begin_frame_scheduling_enabled);
+ state->SetBoolean("use_external_begin_frame_source",
+ use_external_begin_frame_source);
+ state->SetBoolean("forward_begin_frames_to_children",
+ forward_begin_frames_to_children);
state->SetBoolean("main_frame_before_activation_enabled",
main_frame_before_activation_enabled);
state->SetBoolean("impl_side_painting", impl_side_painting);
@@ -56,6 +64,8 @@
state->SetBoolean("throttle_frame_production", throttle_frame_production);
state->SetBoolean("disable_hi_res_timer_tasks_on_battery",
disable_hi_res_timer_tasks_on_battery);
+ state->SetInteger("background_frame_interval",
+ background_frame_interval.InMicroseconds());
return state;
}
diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h
index 8607991..e3fd425 100644
--- a/cc/scheduler/scheduler_settings.h
+++ b/cc/scheduler/scheduler_settings.h
@@ -6,6 +6,7 @@
#define CC_SCHEDULER_SCHEDULER_SETTINGS_H_
#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
#include "base/values.h"
#include "cc/base/cc_export.h"
@@ -24,7 +25,8 @@
explicit SchedulerSettings(const LayerTreeSettings& settings);
~SchedulerSettings();
- bool begin_frame_scheduling_enabled;
+ bool use_external_begin_frame_source;
+ bool forward_begin_frames_to_children;
bool main_frame_before_activation_enabled;
bool impl_side_painting;
bool timeout_and_draw_when_animation_checkerboards;
@@ -33,6 +35,8 @@
bool throttle_frame_production;
bool disable_hi_res_timer_tasks_on_battery;
+ base::TimeDelta background_frame_interval;
+
scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
};
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 2b8210d..94016f3 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -423,9 +423,6 @@
}
bool SchedulerStateMachine::ShouldAnimate() const {
- if (!can_draw_)
- return false;
-
// If a commit occurred after our last call, we need to do animation again.
if (HasAnimatedThisFrame() && !did_commit_after_animating_)
return false;
@@ -765,29 +762,18 @@
if (!HasInitializedOutputSurface())
return false;
- // If we can't draw, don't tick until we are notified that we can draw again.
- if (!can_draw_)
- return false;
-
// The forced draw respects our normal draw scheduling, so we need to
// request a BeginImplFrame for it.
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_DRAW)
return true;
- // There's no need to produce frames if we are not visible.
- if (!visible_)
- return false;
-
// 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;
- if (needs_animate_)
- return true;
-
- return needs_redraw_;
+ return needs_animate_ || needs_redraw_;
}
// These are cases where we are very likely to draw soon, but might not
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index e3530c8..85160ed 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -703,6 +703,7 @@
state.SetVisible(true);
state.SetCanDraw(false);
state.OnBeginImplFrame(CreateBeginFrameArgsForTesting());
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -711,6 +712,7 @@
state.NotifyReadyToCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_COMMIT);
state.OnBeginImplFrameDeadline();
+ EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
}
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 7da6267..91900a2 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -1,6 +1,7 @@
// Copyright 2011 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/scheduler/scheduler.h"
#include <string>
@@ -47,13 +48,11 @@
class FakeSchedulerClient : public SchedulerClient {
public:
- struct FakeBeginFrameSourceForFakeSchedulerClient
- : public FakeBeginFrameSource {
- FakeSchedulerClient* client_;
-
- explicit FakeBeginFrameSourceForFakeSchedulerClient(
- FakeSchedulerClient* client)
+ class FakeExternalBeginFrameSource : public BeginFrameSourceMixIn {
+ public:
+ explicit FakeExternalBeginFrameSource(FakeSchedulerClient* client)
: client_(client) {}
+ virtual ~FakeExternalBeginFrameSource() {}
void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
if (needs_begin_frames) {
@@ -63,6 +62,13 @@
}
client_->states_.push_back(client_->scheduler_->AsValue());
}
+
+ void TestOnBeginFrame(const BeginFrameArgs& args) {
+ return CallOnBeginFrame(args);
+ }
+
+ private:
+ FakeSchedulerClient* client_;
};
class FakePowerMonitorSource : public base::PowerMonitorSource {
@@ -86,7 +92,7 @@
redraw_will_happen_if_update_visible_tiles_happens_(false),
now_src_(TestNowSource::Create()),
task_runner_(new OrderedSimpleTaskRunner(now_src_, true)),
- fake_frame_source_(this),
+ fake_external_begin_frame_source_(nullptr),
fake_power_monitor_source_(new FakePowerMonitorSource),
power_monitor_(make_scoped_ptr<base::PowerMonitorSource>(
fake_power_monitor_source_)),
@@ -108,8 +114,21 @@
}
TestScheduler* CreateScheduler(const SchedulerSettings& settings) {
- scheduler_ = TestScheduler::Create(
- now_src_, this, settings, 0, task_runner_, &power_monitor_);
+ scoped_ptr<FakeExternalBeginFrameSource> fake_external_begin_frame_source;
+ if (settings.use_external_begin_frame_source &&
+ settings.throttle_frame_production) {
+ fake_external_begin_frame_source.reset(
+ new FakeExternalBeginFrameSource(this));
+ fake_external_begin_frame_source_ =
+ fake_external_begin_frame_source.get();
+ }
+ scheduler_ = TestScheduler::Create(now_src_,
+ this,
+ settings,
+ 0,
+ task_runner_,
+ &power_monitor_,
+ fake_external_begin_frame_source.Pass());
DCHECK(scheduler_);
return scheduler_.get();
}
@@ -119,7 +138,10 @@
void set_log_anticipated_draw_time_change(bool log) {
log_anticipated_draw_time_change_ = log;
}
- bool needs_begin_frames() { return fake_frame_source_.NeedsBeginFrames(); }
+ bool needs_begin_frames() {
+ DCHECK(ExternalBeginFrame());
+ return fake_external_begin_frame_source_->NeedsBeginFrames();
+ }
int num_draws() const { return num_draws_; }
int num_actions_() const { return static_cast<int>(actions_.size()); }
const char* Action(int i) const { return actions_[i]; }
@@ -129,11 +151,12 @@
}
bool ExternalBeginFrame() {
- return scheduler_->settings().begin_frame_scheduling_enabled &&
+ return scheduler_->settings().use_external_begin_frame_source &&
scheduler_->settings().throttle_frame_production;
}
- FakeBeginFrameSource* ExternalBeginFrameSource() override {
- return &fake_frame_source_;
+
+ FakeExternalBeginFrameSource* fake_external_begin_frame_source() const {
+ return fake_external_begin_frame_source_;
}
base::PowerMonitor* PowerMonitor() { return &power_monitor_; }
@@ -145,12 +168,11 @@
void AdvanceFrame() {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler.frames"),
"FakeSchedulerClient::AdvanceFrame");
- // EXPECT_TRUE(needs_begin_frames());
if (ExternalBeginFrame()) {
// Creep the time forward so that any BeginFrameArgs is not equal to the
// last one otherwise we violate the BeginFrameSource contract.
now_src_->AdvanceNowMicroseconds(1);
- fake_frame_source_.TestOnBeginFrame(
+ fake_external_begin_frame_source_->TestOnBeginFrame(
CreateBeginFrameArgsForTesting(now_src_));
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
}
@@ -288,7 +310,7 @@
std::vector<scoped_refptr<base::debug::ConvertableToTraceFormat>> states_;
scoped_refptr<TestNowSource> now_src_;
scoped_refptr<OrderedSimpleTaskRunner> task_runner_;
- FakeBeginFrameSourceForFakeSchedulerClient fake_frame_source_;
+ FakeExternalBeginFrameSource* fake_external_begin_frame_source_;
FakePowerMonitorSource* fake_power_monitor_source_;
base::PowerMonitor power_monitor_;
scoped_ptr<TestScheduler> scheduler_;
@@ -327,14 +349,13 @@
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client->task_runner().RunTasksWhile(client->ImplFrameDeadlinePending(true));
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
-
- // EXPECT_FALSE(client->needs_begin_frames());
}
TEST(SchedulerTest, InitializeOutputSurfaceDoesNotBeginImplFrame) {
FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -348,6 +369,7 @@
TEST(SchedulerTest, RequestCommit) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -413,6 +435,7 @@
TEST(SchedulerTest, RequestCommitAfterBeginMainFrameSent) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -511,8 +534,9 @@
// 2. the scheduler drawing twice inside a single tick
TEST(SchedulerTest, RequestRedrawInsideDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -548,8 +572,9 @@
// Test that requesting redraw inside a failed draw doesn't lose the request.
TEST(SchedulerTest, RequestRedrawInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -626,8 +651,9 @@
// happen inside a ScheduledActionDrawAndSwap
TEST(SchedulerTest, RequestCommitInsideDraw) {
SchedulerClientThatSetNeedsCommitInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -671,8 +697,9 @@
// Tests that when a draw fails then the pending commit should not be dropped.
TEST(SchedulerTest, RequestCommitInsideFailedDraw) {
SchedulerClientThatsetNeedsDrawInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -718,8 +745,9 @@
TEST(SchedulerTest, NoSwapWhenDrawFails) {
SchedulerClientThatSetNeedsCommitInsideDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -760,8 +788,9 @@
// Test manage tiles is independant of draws.
TEST(SchedulerTest, ManageTiles) {
SchedulerClientNeedsManageTilesInDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -866,8 +895,9 @@
// initiates it, then the state machine should not ManageTiles on that frame.
TEST(SchedulerTest, ManageTilesOncePerFrame) {
FakeSchedulerClient client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -986,6 +1016,7 @@
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);
@@ -1045,8 +1076,9 @@
TEST(SchedulerTest, TriggerBeginFrameDeadlineEarly) {
SchedulerClientNeedsManageTilesInDraw client;
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -1096,8 +1128,9 @@
base::TimeDelta::FromMilliseconds(
begin_main_frame_to_commit_estimate_in_ms),
base::TimeDelta::FromMilliseconds(commit_to_activate_estimate_in_ms));
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
scheduler->SetCanDraw(true);
@@ -1163,8 +1196,9 @@
base::TimeDelta::FromMilliseconds(32),
base::TimeDelta::FromMilliseconds(32));
client.set_log_anticipated_draw_time_change(true);
- SchedulerSettings default_scheduler_settings;
- TestScheduler* scheduler = client.CreateScheduler(default_scheduler_settings);
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
+ TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanDraw(true);
scheduler->SetCanStart();
@@ -1179,7 +1213,7 @@
BeginFrameArgs frame_args = CreateBeginFrameArgsForTesting(client.now_src());
frame_args.interval = base::TimeDelta::FromMilliseconds(1000);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.task_runner().RunPendingTasks(); // Run posted deadline.
@@ -1192,7 +1226,7 @@
// the NotifyReadyToCommit for now.
EXPECT_FALSE(scheduler->CommitPending());
scheduler->SetNeedsCommit();
- client.ExternalBeginFrameSource()->TestOnBeginFrame(frame_args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(frame_args);
EXPECT_TRUE(scheduler->CommitPending());
// Draw and swap the frame, but don't ack the swap to simulate the Browser
@@ -1235,6 +1269,7 @@
TEST(SchedulerTest, BeginRetroFrame) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1251,7 +1286,7 @@
// This is the first BeginFrame, which will be handled immediately.
BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1260,9 +1295,9 @@
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
client.task_runner().RunPendingTasks(); // Run posted deadline.
@@ -1308,6 +1343,7 @@
TEST(SchedulerTest, BeginRetroFrame_SwapThrottled) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1328,7 +1364,7 @@
// This is the first BeginFrame, which will be handled immediately.
BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1338,7 +1374,7 @@
// Queue BeginFrame while we are still handling the previous BeginFrame.
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_NO_ACTION(client);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
client.Reset();
@@ -1369,7 +1405,7 @@
// Queue BeginFrame while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_NO_ACTION(client);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
EXPECT_TRUE(client.needs_begin_frames());
@@ -1395,12 +1431,12 @@
client.Reset();
}
-void BeginFramesNotFromClient(bool begin_frame_scheduling_enabled,
+void BeginFramesNotFromClient(bool use_external_begin_frame_source,
bool throttle_frame_production) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled =
- begin_frame_scheduling_enabled;
+ scheduler_settings.use_external_begin_frame_source =
+ use_external_begin_frame_source;
scheduler_settings.throttle_frame_production = throttle_frame_production;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
@@ -1408,11 +1444,12 @@
scheduler->SetCanDraw(true);
InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ DCHECK(!client.fake_external_begin_frame_source());
+
// SetNeedsCommit should begin the frame on the next BeginImplFrame
// without calling SetNeedsBeginFrame.
client.Reset();
scheduler->SetNeedsCommit();
- EXPECT_FALSE(client.needs_begin_frames());
EXPECT_NO_ACTION(client);
client.Reset();
@@ -1422,21 +1459,18 @@
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// If we don't swap on the deadline, we wait for the next BeginFrame.
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_NO_ACTION(client);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// NotifyReadyToCommit should trigger the commit.
scheduler->NotifyBeginMainFrameStarted();
scheduler->NotifyReadyToCommit();
EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// BeginImplFrame should prepare the draw.
@@ -1444,14 +1478,12 @@
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionAnimate", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// BeginImplFrame deadline should draw.
client.task_runner().RunTasksWhile(client.ImplFrameDeadlinePending(true));
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 0, 1);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
@@ -1465,37 +1497,37 @@
// when the BeginFrame is no longer needed.
client.task_runner().RunPendingTasks(); // Run posted deadline.
EXPECT_NO_ACTION(client);
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
}
TEST(SchedulerTest, SyntheticBeginFrames) {
- bool begin_frame_scheduling_enabled = false;
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = true;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
TEST(SchedulerTest, VSyncThrottlingDisabled) {
- bool begin_frame_scheduling_enabled = true;
+ bool use_external_begin_frame_source = true;
bool throttle_frame_production = false;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
TEST(SchedulerTest, SyntheticBeginFrames_And_VSyncThrottlingDisabled) {
- bool begin_frame_scheduling_enabled = false;
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = false;
- BeginFramesNotFromClient(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient(use_external_begin_frame_source,
throttle_frame_production);
}
-void BeginFramesNotFromClient_SwapThrottled(bool begin_frame_scheduling_enabled,
- bool throttle_frame_production) {
+void BeginFramesNotFromClient_SwapThrottled(
+ bool use_external_begin_frame_source,
+ bool throttle_frame_production) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled =
- begin_frame_scheduling_enabled;
+ scheduler_settings.use_external_begin_frame_source =
+ use_external_begin_frame_source;
scheduler_settings.throttle_frame_production = throttle_frame_production;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
@@ -1503,6 +1535,8 @@
scheduler->SetCanDraw(true);
InitializeOutputSurfaceAndFirstCommit(scheduler, &client);
+ DCHECK(!client.fake_external_begin_frame_source());
+
// To test swap ack throttling, this test disables automatic swap acks.
scheduler->SetMaxSwapsPending(1);
client.SetAutomaticSwapAck(false);
@@ -1510,7 +1544,6 @@
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
client.Reset();
scheduler->SetNeedsCommit();
- EXPECT_FALSE(client.needs_begin_frames());
EXPECT_NO_ACTION(client);
client.Reset();
@@ -1519,14 +1552,12 @@
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// NotifyReadyToCommit should trigger the pending commit and draw.
scheduler->NotifyBeginMainFrameStarted();
scheduler->NotifyReadyToCommit();
EXPECT_SINGLE_ACTION("ScheduledActionCommit", client);
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// Swapping will put us into a swap throttled state.
@@ -1534,7 +1565,6 @@
EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// While swap throttled, BeginFrames should trigger BeginImplFrames,
@@ -1543,14 +1573,12 @@
client.task_runner().RunPendingTasks(); // Run posted BeginFrame.
EXPECT_ACTION("WillBeginImplFrame", client, 0, 1);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// Take us out of a swap throttled state.
scheduler->DidSwapBuffersComplete();
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 0, 1);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
// BeginImplFrame deadline should draw.
@@ -1559,35 +1587,35 @@
EXPECT_ACTION("ScheduledActionAnimate", client, 0, 2);
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client, 1, 2);
EXPECT_FALSE(scheduler->BeginImplFrameDeadlinePending());
- EXPECT_FALSE(client.needs_begin_frames());
client.Reset();
}
TEST(SchedulerTest, SyntheticBeginFrames_SwapThrottled) {
- bool begin_frame_scheduling_enabled = false;
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = true;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
TEST(SchedulerTest, VSyncThrottlingDisabled_SwapThrottled) {
- bool begin_frame_scheduling_enabled = true;
+ bool use_external_begin_frame_source = true;
bool throttle_frame_production = false;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
TEST(SchedulerTest,
SyntheticBeginFrames_And_VSyncThrottlingDisabled_SwapThrottled) {
- bool begin_frame_scheduling_enabled = false;
+ bool use_external_begin_frame_source = false;
bool throttle_frame_production = false;
- BeginFramesNotFromClient_SwapThrottled(begin_frame_scheduling_enabled,
+ BeginFramesNotFromClient_SwapThrottled(use_external_begin_frame_source,
throttle_frame_production);
}
TEST(SchedulerTest, DidLoseOutputSurfaceAfterOutputSurfaceIsInitialized) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1605,6 +1633,7 @@
TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginFrameStarted) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1643,6 +1672,7 @@
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
scheduler_settings.impl_side_painting = impl_side_painting;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1710,6 +1740,7 @@
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
scheduler_settings.impl_side_painting = impl_side_painting;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1760,6 +1791,7 @@
TEST(SchedulerTest, DidLoseOutputSurfaceAfterSetNeedsManageTiles) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1790,6 +1822,7 @@
TEST(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1806,7 +1839,7 @@
client.Reset();
BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1814,9 +1847,9 @@
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
client.Reset();
@@ -1848,6 +1881,7 @@
TEST(SchedulerTest, DidLoseOutputSurfaceDuringBeginRetroFrameRunning) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1864,7 +1898,7 @@
client.Reset();
BeginFrameArgs args = CreateBeginFrameArgsForTesting(client.now_src());
args.deadline += base::TimeDelta::FromHours(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
EXPECT_ACTION("WillBeginImplFrame", client, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client, 1, 2);
EXPECT_TRUE(scheduler->BeginImplFrameDeadlinePending());
@@ -1872,9 +1906,9 @@
// Queue BeginFrames while we are still handling the previous BeginFrame.
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
args.frame_time += base::TimeDelta::FromSeconds(1);
- client.ExternalBeginFrameSource()->TestOnBeginFrame(args);
+ client.fake_external_begin_frame_source()->TestOnBeginFrame(args);
// If we don't swap on the deadline, we wait for the next BeginImplFrame.
client.Reset();
@@ -1921,7 +1955,6 @@
StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
FakeSchedulerClient client;
SchedulerSettings scheduler_settings;
- scheduler_settings.begin_frame_scheduling_enabled = false;
TestScheduler* scheduler = client.CreateScheduler(scheduler_settings);
scheduler->SetCanStart();
scheduler->SetVisible(true);
@@ -1963,6 +1996,7 @@
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);
@@ -2063,6 +2097,7 @@
SimulateWindowsLowResolutionTimerOnBattery_PrioritizeImplLatencyOff) {
FakeSchedulerClient client;
SchedulerSettings settings;
+ settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(settings);
scheduler->SetCanStart();
@@ -2108,6 +2143,7 @@
FakeSchedulerClient client;
SchedulerSettings settings;
settings.disable_hi_res_timer_tasks_on_battery = true;
+ settings.use_external_begin_frame_source = true;
TestScheduler* scheduler = client.CreateScheduler(settings);
scheduler->SetCanStart();
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 5f80d64..5935534 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -63,7 +63,6 @@
void CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
- void BeginFrame(const BeginFrameArgs& args) override {}
void DidSwapBuffers() override;
void DidSwapBuffersComplete() override;
void ReclaimResources(const CompositorFrameAck* ack) override {}
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc
index 5ab8942..fba3166 100644
--- a/cc/test/animation_test_common.cc
+++ b/cc/test/animation_test_common.cc
@@ -124,14 +124,16 @@
}
FakeFloatAnimationCurve::FakeFloatAnimationCurve()
- : duration_(1.0) {}
+ : duration_(base::TimeDelta::FromSecondsD(1.0)) {
+}
FakeFloatAnimationCurve::FakeFloatAnimationCurve(double duration)
- : duration_(duration) {}
+ : duration_(base::TimeDelta::FromSecondsD(duration)) {
+}
FakeFloatAnimationCurve::~FakeFloatAnimationCurve() {}
-double FakeFloatAnimationCurve::Duration() const {
+base::TimeDelta FakeFloatAnimationCurve::Duration() const {
return duration_;
}
@@ -144,11 +146,12 @@
}
FakeTransformTransition::FakeTransformTransition(double duration)
- : duration_(duration) {}
+ : duration_(base::TimeDelta::FromSecondsD(duration)) {
+}
FakeTransformTransition::~FakeTransformTransition() {}
-double FakeTransformTransition::Duration() const {
+base::TimeDelta FakeTransformTransition::Duration() const {
return duration_;
}
@@ -175,18 +178,18 @@
return make_scoped_ptr(new FakeTransformTransition(*this));
}
-
FakeFloatTransition::FakeFloatTransition(double duration, float from, float to)
- : duration_(duration), from_(from), to_(to) {}
+ : duration_(base::TimeDelta::FromSecondsD(duration)), from_(from), to_(to) {
+}
FakeFloatTransition::~FakeFloatTransition() {}
-double FakeFloatTransition::Duration() const {
+base::TimeDelta FakeFloatTransition::Duration() const {
return duration_;
}
float FakeFloatTransition::GetValue(double time) const {
- time /= duration_;
+ time /= duration_.InSecondsF();
if (time >= 1.0)
time = 1.0;
return (1.0 - time) * from_ + time * to_;
diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h
index 328ae84..a69f0c9 100644
--- a/cc/test/animation_test_common.h
+++ b/cc/test/animation_test_common.h
@@ -26,12 +26,12 @@
explicit FakeFloatAnimationCurve(double duration);
~FakeFloatAnimationCurve() override;
- double Duration() const override;
+ base::TimeDelta Duration() const override;
float GetValue(double now) const override;
scoped_ptr<AnimationCurve> Clone() const override;
private:
- double duration_;
+ base::TimeDelta duration_;
};
class FakeTransformTransition : public TransformAnimationCurve {
@@ -39,7 +39,7 @@
explicit FakeTransformTransition(double duration);
~FakeTransformTransition() override;
- double Duration() const override;
+ base::TimeDelta Duration() const override;
gfx::Transform GetValue(double time) const override;
bool AnimatedBoundsForBox(const gfx::BoxF& box,
gfx::BoxF* bounds) const override;
@@ -51,7 +51,7 @@
scoped_ptr<AnimationCurve> Clone() const override;
private:
- double duration_;
+ base::TimeDelta duration_;
};
class FakeFloatTransition : public FloatAnimationCurve {
@@ -59,13 +59,13 @@
FakeFloatTransition(double duration, float from, float to);
~FakeFloatTransition() override;
- double Duration() const override;
+ base::TimeDelta Duration() const override;
float GetValue(double time) const override;
scoped_ptr<AnimationCurve> Clone() const override;
private:
- double duration_;
+ base::TimeDelta duration_;
float from_;
float to_;
};
diff --git a/cc/test/data/background_filter_blur_off_axis.png b/cc/test/data/background_filter_blur_off_axis.png
index 050ec54..5077171 100644
--- a/cc/test/data/background_filter_blur_off_axis.png
+++ b/cc/test/data/background_filter_blur_off_axis.png
Binary files differ
diff --git a/cc/test/data/background_filter_blur_outsets.png b/cc/test/data/background_filter_blur_outsets.png
index 9234496..3293ab8 100644
--- a/cc/test/data/background_filter_blur_outsets.png
+++ b/cc/test/data/background_filter_blur_outsets.png
Binary files differ
diff --git a/cc/test/data/blending_and_filter.png b/cc/test/data/blending_and_filter.png
index 07e7fea..f231475 100644
--- a/cc/test/data/blending_and_filter.png
+++ b/cc/test/data/blending_and_filter.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass.png b/cc/test/data/blending_render_pass.png
index 76fe369..9186864 100644
--- a/cc/test/data/blending_render_pass.png
+++ b/cc/test/data/blending_render_pass.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_mask.png b/cc/test/data/blending_render_pass_mask.png
index 8b63f35..21d792a 100644
--- a/cc/test/data/blending_render_pass_mask.png
+++ b/cc/test/data/blending_render_pass_mask.png
Binary files differ
diff --git a/cc/test/data/blending_transparent.png b/cc/test/data/blending_transparent.png
index dc20808..f98607e 100644
--- a/cc/test/data/blending_transparent.png
+++ b/cc/test/data/blending_transparent.png
Binary files differ
diff --git a/cc/test/data/blending_with_root.png b/cc/test/data/blending_with_root.png
index 519c642..276df1d 100644
--- a/cc/test/data/blending_with_root.png
+++ b/cc/test/data/blending_with_root.png
Binary files differ
diff --git a/cc/test/data/filter_on_scaled_layer.png b/cc/test/data/filter_on_scaled_layer.png
new file mode 100644
index 0000000..83cb2c5
--- /dev/null
+++ b/cc/test/data/filter_on_scaled_layer.png
Binary files differ
diff --git a/cc/test/fake_layer_tree_host_impl_client.h b/cc/test/fake_layer_tree_host_impl_client.h
index d7b4704..3c44994 100644
--- a/cc/test/fake_layer_tree_host_impl_client.h
+++ b/cc/test/fake_layer_tree_host_impl_client.h
@@ -23,6 +23,7 @@
void DidSwapBuffersCompleteOnImplThread() override {}
void OnCanDrawStateChanged(bool can_draw) override {}
void NotifyReadyToActivate() override {}
+ void NotifyReadyToDraw() override {}
void SetNeedsRedrawOnImplThread() override {}
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {}
void SetNeedsAnimateOnImplThread() override {}
diff --git a/cc/test/fake_output_surface.cc b/cc/test/fake_output_surface.cc
index df9c0f7..46efba0 100644
--- a/cc/test/fake_output_surface.cc
+++ b/cc/test/fake_output_surface.cc
@@ -20,9 +20,7 @@
: OutputSurface(context_provider),
client_(NULL),
num_sent_frames_(0),
- needs_begin_frame_(false),
- has_external_stencil_test_(false),
- fake_weak_ptr_factory_(this) {
+ has_external_stencil_test_(false) {
if (delegated_rendering) {
capabilities_.delegated_rendering = true;
capabilities_.max_frames_pending = 1;
@@ -35,8 +33,7 @@
: OutputSurface(software_device.Pass()),
client_(NULL),
num_sent_frames_(0),
- has_external_stencil_test_(false),
- fake_weak_ptr_factory_(this) {
+ has_external_stencil_test_(false) {
if (delegated_rendering) {
capabilities_.delegated_rendering = true;
capabilities_.max_frames_pending = 1;
@@ -50,8 +47,7 @@
: OutputSurface(context_provider, software_device.Pass()),
client_(NULL),
num_sent_frames_(0),
- has_external_stencil_test_(false),
- fake_weak_ptr_factory_(this) {
+ has_external_stencil_test_(false) {
if (delegated_rendering) {
capabilities_.delegated_rendering = true;
capabilities_.max_frames_pending = 1;
@@ -82,24 +78,6 @@
client_->DidSwapBuffers();
}
-void FakeOutputSurface::SetNeedsBeginFrame(bool enable) {
- needs_begin_frame_ = enable;
- OutputSurface::SetNeedsBeginFrame(enable);
-
- if (enable) {
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&FakeOutputSurface::OnBeginFrame,
- fake_weak_ptr_factory_.GetWeakPtr()),
- base::TimeDelta::FromMilliseconds(16));
- }
-}
-
-void FakeOutputSurface::OnBeginFrame() {
- client_->BeginFrame(CreateBeginFrameArgsForTesting());
-}
-
-
bool FakeOutputSurface::BindToClient(OutputSurfaceClient* client) {
if (OutputSurface::BindToClient(client)) {
client_ = client;
diff --git a/cc/test/fake_output_surface.h b/cc/test/fake_output_surface.h
index 59c9a8c..f28fccc 100644
--- a/cc/test/fake_output_surface.h
+++ b/cc/test/fake_output_surface.h
@@ -94,9 +94,6 @@
void SwapBuffers(CompositorFrame* frame) override;
- void SetNeedsBeginFrame(bool enable) override;
- bool needs_begin_frame() const { return needs_begin_frame_; }
-
bool BindToClient(OutputSurfaceClient* client) override;
using OutputSurface::ReleaseGL;
@@ -137,18 +134,13 @@
scoped_ptr<SoftwareOutputDevice> software_device,
bool delegated_rendering);
- void OnBeginFrame();
-
OutputSurfaceClient* client_;
CompositorFrame last_sent_frame_;
size_t num_sent_frames_;
- bool needs_begin_frame_;
bool has_external_stencil_test_;
TransferableResourceArray resources_held_by_parent_;
scoped_ptr<ManagedMemoryPolicy> memory_policy_to_set_at_bind_;
gfx::Rect last_swap_rect_;
-
- base::WeakPtrFactory<FakeOutputSurface> fake_weak_ptr_factory_;
};
} // namespace cc
diff --git a/cc/test/fake_output_surface_client.cc b/cc/test/fake_output_surface_client.cc
index 77c7f8a..073a29f 100644
--- a/cc/test/fake_output_surface_client.cc
+++ b/cc/test/fake_output_surface_client.cc
@@ -16,10 +16,6 @@
output_surface_->ReleaseContextProvider();
}
-void FakeOutputSurfaceClient::BeginFrame(const BeginFrameArgs& args) {
- begin_frame_count_++;
-}
-
void FakeOutputSurfaceClient::DidSwapBuffers() {
swap_count_++;
}
diff --git a/cc/test/fake_output_surface_client.h b/cc/test/fake_output_surface_client.h
index a7620b6..310842d 100644
--- a/cc/test/fake_output_surface_client.h
+++ b/cc/test/fake_output_surface_client.h
@@ -16,7 +16,6 @@
public:
FakeOutputSurfaceClient()
: output_surface_(NULL),
- begin_frame_count_(0),
swap_count_(0),
deferred_initialize_called_(false),
did_lose_output_surface_called_(false),
@@ -24,7 +23,6 @@
explicit FakeOutputSurfaceClient(OutputSurface* output_surface)
: output_surface_(output_surface),
- begin_frame_count_(0),
swap_count_(0),
deferred_initialize_called_(false),
did_lose_output_surface_called_(false),
@@ -35,7 +33,6 @@
void CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override {}
void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
- void BeginFrame(const BeginFrameArgs& args) override;
void DidSwapBuffers() override;
void DidSwapBuffersComplete() override {}
void ReclaimResources(const CompositorFrameAck* ack) override {}
@@ -50,7 +47,6 @@
void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override;
void SetTreeActivationCallback(const base::Closure&) override {}
- int begin_frame_count() { return begin_frame_count_; }
int swap_count() { return swap_count_; }
bool deferred_initialize_called() {
@@ -65,7 +61,6 @@
private:
OutputSurface* output_surface_;
- int begin_frame_count_;
int swap_count_;
bool deferred_initialize_called_;
bool did_lose_output_surface_called_;
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index 73c1ae3..bf55ebf 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -10,31 +10,33 @@
namespace cc {
-FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl,
- int id,
- scoped_refptr<PicturePileImpl> pile)
+FakePictureLayerImpl::FakePictureLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<RasterSource> raster_source)
: PictureLayerImpl(tree_impl, id),
append_quads_count_(0),
did_become_active_call_count_(0),
has_valid_tile_priorities_(false),
use_set_valid_tile_priorities_flag_(false),
release_resources_count_(0) {
- pile_ = pile;
- SetBounds(pile_->tiling_size());
- SetContentBounds(pile_->tiling_size());
+ raster_source_ = raster_source;
+ SetBounds(raster_source_->GetSize());
+ SetContentBounds(raster_source_->GetSize());
}
-FakePictureLayerImpl::FakePictureLayerImpl(LayerTreeImpl* tree_impl,
- int id,
- scoped_refptr<PicturePileImpl> pile,
- const gfx::Size& layer_bounds)
+FakePictureLayerImpl::FakePictureLayerImpl(
+ LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<RasterSource> raster_source,
+ const gfx::Size& layer_bounds)
: PictureLayerImpl(tree_impl, id),
append_quads_count_(0),
did_become_active_call_count_(0),
has_valid_tile_priorities_(false),
use_set_valid_tile_priorities_flag_(false),
release_resources_count_(0) {
- pile_ = pile;
+ raster_source_ = raster_source;
SetBounds(layer_bounds);
SetContentBounds(layer_bounds);
}
@@ -97,12 +99,13 @@
return result;
}
-void FakePictureLayerImpl::SetPile(scoped_refptr<PicturePileImpl> pile) {
- pile_.swap(pile);
+void FakePictureLayerImpl::SetRasterSource(
+ scoped_refptr<RasterSource> raster_source) {
+ raster_source_.swap(raster_source);
if (tilings()) {
for (size_t i = 0; i < num_tilings(); ++i) {
- tilings()->tiling_at(i)->UpdateTilesToCurrentPile(Region(),
- pile_->tiling_size());
+ tilings()->tiling_at(i)->UpdateTilesToCurrentRasterSource(
+ Region(), raster_source_->GetSize());
}
}
}
@@ -190,6 +193,65 @@
: PictureLayerImpl::HasValidTilePriorities();
}
+size_t FakePictureLayerImpl::CountTilesRequired(
+ TileRequirementCheck is_tile_required_callback) const {
+ if (!HasValidTilePriorities())
+ return 0;
+
+ if (!tilings_)
+ return 0;
+
+ if (visible_rect_for_tile_priority_.IsEmpty())
+ return 0;
+
+ gfx::Rect rect = GetViewportForTilePriorityInContentSpace();
+ rect.Intersect(visible_rect_for_tile_priority_);
+
+ size_t count = 0;
+
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = tilings_->tiling_at(i);
+ if (tiling->resolution() != HIGH_RESOLUTION &&
+ tiling->resolution() != LOW_RESOLUTION)
+ continue;
+
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
+ ++iter) {
+ const Tile* tile = *iter;
+ // A null tile (i.e. missing recording) can just be skipped.
+ // TODO(vmpstr): Verify this is true if we create tiles in raster
+ // iterators.
+ if (!tile)
+ continue;
+
+ // We can't check tile->required_for_activation, because that value might
+ // be out of date. It is updated in the raster/eviction iterators.
+ // TODO(vmpstr): Remove the comment once you can't access this information
+ // from the tile.
+ if ((tiling->*is_tile_required_callback)(tile))
+ ++count;
+ }
+ }
+
+ return count;
+}
+
+size_t FakePictureLayerImpl::CountTilesRequiredForActivation() const {
+ if (!layer_tree_impl()->IsPendingTree())
+ return 0;
+
+ return CountTilesRequired(
+ &PictureLayerTiling::IsTileRequiredForActivationIfVisible);
+}
+
+size_t FakePictureLayerImpl::CountTilesRequiredForDraw() const {
+ if (!layer_tree_impl()->IsActiveTree())
+ return 0;
+
+ return CountTilesRequired(
+ &PictureLayerTiling::IsTileRequiredForDrawIfVisible);
+}
+
void FakePictureLayerImpl::ReleaseResources() {
PictureLayerImpl::ReleaseResources();
++release_resources_count_;
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index 4223811..b10b357 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -17,20 +17,23 @@
return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id));
}
- // Create layer from a pile that covers the entire layer.
- static scoped_ptr<FakePictureLayerImpl> CreateWithPile(
- LayerTreeImpl* tree_impl, int id, scoped_refptr<PicturePileImpl> pile) {
- return make_scoped_ptr(new FakePictureLayerImpl(tree_impl, id, pile));
- }
-
- // Create layer from a pile that only covers part of the layer.
- static scoped_ptr<FakePictureLayerImpl> CreateWithPartialPile(
+ // Create layer from a raster source that covers the entire layer.
+ static scoped_ptr<FakePictureLayerImpl> CreateWithRasterSource(
LayerTreeImpl* tree_impl,
int id,
- scoped_refptr<PicturePileImpl> pile,
+ scoped_refptr<RasterSource> raster_source) {
+ return make_scoped_ptr(
+ new FakePictureLayerImpl(tree_impl, id, raster_source));
+ }
+
+ // Create layer from a raster source that only covers part of the layer.
+ static scoped_ptr<FakePictureLayerImpl> CreateWithPartialRasterSource(
+ LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<RasterSource> raster_source,
const gfx::Size& layer_bounds) {
return make_scoped_ptr(
- new FakePictureLayerImpl(tree_impl, id, pile, layer_bounds));
+ new FakePictureLayerImpl(tree_impl, id, raster_source, layer_bounds));
}
scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override;
@@ -50,6 +53,11 @@
use_set_valid_tile_priorities_flag_ = true;
}
+ size_t CountTilesRequired(
+ TileRequirementCheck is_tile_required_callback) const;
+ size_t CountTilesRequiredForActivation() const;
+ size_t CountTilesRequiredForDraw() const;
+
using PictureLayerImpl::AddTiling;
using PictureLayerImpl::CleanUpTilingsOnActiveLayer;
using PictureLayerImpl::CanHaveTilings;
@@ -58,7 +66,7 @@
using PictureLayerImpl::GetViewportForTilePriorityInContentSpace;
using PictureLayerImpl::SanityCheckTilingState;
using PictureLayerImpl::GetRecycledTwinLayer;
- using PictureLayerImpl::UpdatePile;
+ using PictureLayerImpl::UpdateRasterSource;
using PictureLayerImpl::UpdateIdealScales;
using PictureLayerImpl::MaximumTilingContentsScale;
@@ -82,8 +90,8 @@
size_t num_tilings() const { return tilings_->num_tilings(); }
PictureLayerTilingSet* tilings() { return tilings_.get(); }
- PicturePileImpl* pile() { return pile_.get(); }
- void SetPile(scoped_refptr<PicturePileImpl> pile);
+ RasterSource* raster_source() { return raster_source_.get(); }
+ void SetRasterSource(scoped_refptr<RasterSource> raster_source);
size_t append_quads_count() { return append_quads_count_; }
const Region& invalidation() const { return invalidation_; }
@@ -113,13 +121,12 @@
}
protected:
- FakePictureLayerImpl(
- LayerTreeImpl* tree_impl,
- int id,
- scoped_refptr<PicturePileImpl> pile);
FakePictureLayerImpl(LayerTreeImpl* tree_impl,
int id,
- scoped_refptr<PicturePileImpl> pile,
+ scoped_refptr<RasterSource> raster_source);
+ FakePictureLayerImpl(LayerTreeImpl* tree_impl,
+ int id,
+ scoped_refptr<RasterSource> raster_source,
const gfx::Size& layer_bounds);
FakePictureLayerImpl(LayerTreeImpl* tree_impl, int id);
diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc
index 2149ff4..a218a21 100644
--- a/cc/test/fake_picture_layer_tiling_client.cc
+++ b/cc/test/fake_picture_layer_tiling_client.cc
@@ -17,6 +17,7 @@
twin_tiling_(NULL),
recycled_twin_tiling_(NULL),
allow_create_tile_(true),
+ max_tile_priority_bin_(TilePriority::NOW),
max_tiles_for_interest_area_(10000),
skewport_target_time_in_seconds_(1.0f),
skewport_extrapolation_limit_in_content_pixels_(2000) {
@@ -32,6 +33,7 @@
twin_tiling_(NULL),
recycled_twin_tiling_(NULL),
allow_create_tile_(true),
+ max_tile_priority_bin_(TilePriority::NOW),
max_tiles_for_interest_area_(10000),
skewport_target_time_in_seconds_(1.0f) {
}
@@ -60,6 +62,11 @@
return tile_size_;
}
+TilePriority::PriorityBin FakePictureLayerTilingClient::GetMaxTilePriorityBin()
+ const {
+ return max_tile_priority_bin_;
+}
+
size_t FakePictureLayerTilingClient::GetMaxTilesForInterestArea() const {
return max_tiles_for_interest_area_;
}
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h
index 3df4ca4..c8cc4e2 100644
--- a/cc/test/fake_picture_layer_tiling_client.h
+++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -25,6 +25,7 @@
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;
float GetSkewportTargetTimeInSeconds() const override;
int GetSkewportExtrapolationLimitInContentPixels() const override;
@@ -47,6 +48,9 @@
void set_text_rect(const gfx::Rect& rect) { text_rect_ = rect; }
void set_allow_create_tile(bool allow) { allow_create_tile_ = allow; }
void set_invalidation(const Region& region) { invalidation_ = region; }
+ void set_max_tile_priority_bin(TilePriority::PriorityBin bin) {
+ max_tile_priority_bin_ = bin;
+ }
void set_max_tiles_for_interest_area(size_t area) {
max_tiles_for_interest_area_ = area;
}
@@ -73,6 +77,7 @@
gfx::Rect text_rect_;
bool allow_create_tile_;
Region invalidation_;
+ TilePriority::PriorityBin max_tile_priority_bin_;
size_t max_tiles_for_interest_area_;
float skewport_target_time_in_seconds_;
int skewport_extrapolation_limit_in_content_pixels_;
diff --git a/cc/test/fake_picture_pile.h b/cc/test/fake_picture_pile.h
new file mode 100644
index 0000000..e486e3b
--- /dev/null
+++ b/cc/test/fake_picture_pile.h
@@ -0,0 +1,53 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_FAKE_PICTURE_PILE_H_
+#define CC_TEST_FAKE_PICTURE_PILE_H_
+
+#include "cc/resources/picture_pile.h"
+
+namespace cc {
+
+class FakePicturePile : public PicturePile {
+ public:
+ ~FakePicturePile() override {}
+
+ using PicturePile::buffer_pixels;
+ using PicturePile::CanRasterSlowTileCheck;
+ using PicturePile::Clear;
+
+ PictureMap& picture_map() { return picture_map_; }
+ const gfx::Rect& recorded_viewport() const { return recorded_viewport_; }
+
+ bool CanRasterLayerRect(gfx::Rect layer_rect) {
+ layer_rect.Intersect(gfx::Rect(tiling_.tiling_size()));
+ if (recorded_viewport_.Contains(layer_rect))
+ return true;
+ return CanRasterSlowTileCheck(layer_rect);
+ }
+
+ bool HasRecordings() const { return has_any_recordings_; }
+
+ void SetRecordedViewport(const gfx::Rect& viewport) {
+ recorded_viewport_ = viewport;
+ }
+
+ void SetHasAnyRecordings(bool has_recordings) {
+ has_any_recordings_ = has_recordings;
+ }
+
+ TilingData& tiling() { return tiling_; }
+
+ bool is_solid_color() const { return is_solid_color_; }
+ SkColor solid_color() const { return solid_color_; }
+
+ void SetPixelRecordDistance(int d) { pixel_record_distance_ = d; }
+
+ typedef PicturePile::PictureInfo PictureInfo;
+ typedef PicturePile::PictureMapKey PictureMapKey;
+ typedef PicturePile::PictureMap PictureMap;
+};
+} // 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 32a6589..3d31c12 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -4,9 +4,12 @@
#include "cc/test/fake_picture_pile_impl.h"
+#include <algorithm>
#include <limits>
#include <utility>
+#include "cc/resources/picture_pile.h"
+#include "cc/test/fake_picture_pile.h"
#include "cc/test/impl_side_painting_settings.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -14,62 +17,71 @@
FakePicturePileImpl::FakePicturePileImpl() {}
+FakePicturePileImpl::FakePicturePileImpl(const PicturePile* other)
+ : PicturePileImpl(other),
+ tile_grid_info_(other->GetTileGridInfoForTesting()) {
+}
+
FakePicturePileImpl::~FakePicturePileImpl() {}
scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateFilledPile(
const gfx::Size& tile_size,
const gfx::Size& layer_bounds) {
- scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
- pile->tiling().SetTilingSize(layer_bounds);
- pile->tiling().SetMaxTextureSize(tile_size);
- pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
- pile->recorded_viewport_ = gfx::Rect(layer_bounds);
- pile->has_any_recordings_ = true;
- for (int x = 0; x < pile->tiling().num_tiles_x(); ++x) {
- for (int y = 0; y < pile->tiling().num_tiles_y(); ++y)
- pile->AddRecordingAt(x, y);
+ FakePicturePile pile;
+ pile.tiling().SetTilingSize(layer_bounds);
+ pile.tiling().SetMaxTextureSize(tile_size);
+ pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
+ pile.SetRecordedViewport(gfx::Rect(layer_bounds));
+ pile.SetHasAnyRecordings(true);
+
+ auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+ 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);
}
- return pile;
+ return pile_impl;
}
scoped_refptr<FakePicturePileImpl> FakePicturePileImpl::CreateEmptyPile(
const gfx::Size& tile_size,
const gfx::Size& layer_bounds) {
- scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
- pile->tiling().SetTilingSize(layer_bounds);
- pile->tiling().SetMaxTextureSize(tile_size);
- pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
- pile->recorded_viewport_ = gfx::Rect();
- pile->has_any_recordings_ = false;
- return pile;
+ FakePicturePile pile;
+ pile.tiling().SetTilingSize(layer_bounds);
+ pile.tiling().SetMaxTextureSize(tile_size);
+ pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
+ pile.SetRecordedViewport(gfx::Rect());
+ pile.SetHasAnyRecordings(false);
+ return make_scoped_refptr(new FakePicturePileImpl(&pile));
}
scoped_refptr<FakePicturePileImpl>
FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
const gfx::Size& tile_size,
const gfx::Size& layer_bounds) {
- scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
- pile->tiling().SetTilingSize(layer_bounds);
- pile->tiling().SetMaxTextureSize(tile_size);
- pile->SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
+ FakePicturePile pile;
+ pile.tiling().SetTilingSize(layer_bounds);
+ pile.tiling().SetMaxTextureSize(tile_size);
+ pile.SetTileGridSize(ImplSidePaintingSettings().default_tile_grid_size);
// This simulates a false positive for this flag.
- pile->recorded_viewport_ = gfx::Rect();
- pile->has_any_recordings_ = true;
- return pile;
+ pile.SetRecordedViewport(gfx::Rect());
+ pile.SetHasAnyRecordings(true);
+ return make_scoped_refptr(new FakePicturePileImpl(&pile));
}
scoped_refptr<FakePicturePileImpl>
FakePicturePileImpl::CreateInfiniteFilledPile() {
- scoped_refptr<FakePicturePileImpl> pile(new FakePicturePileImpl());
+ FakePicturePile pile;
gfx::Size size(std::numeric_limits<int>::max(),
std::numeric_limits<int>::max());
- pile->tiling().SetTilingSize(size);
- pile->tiling().SetMaxTextureSize(size);
- pile->SetTileGridSize(size);
- pile->recorded_viewport_ = gfx::Rect(size);
- pile->has_any_recordings_ = true;
- pile->AddRecordingAt(0, 0);
- return pile;
+ pile.tiling().SetTilingSize(size);
+ pile.tiling().SetMaxTextureSize(size);
+ pile.SetTileGridSize(size);
+ pile.SetRecordedViewport(gfx::Rect(size));
+ pile.SetHasAnyRecordings(true);
+
+ auto pile_impl = make_scoped_refptr(new FakePicturePileImpl(&pile));
+ pile_impl->AddRecordingAt(0, 0);
+ return pile_impl;
}
void FakePicturePileImpl::AddRecordingAt(int x, int y) {
@@ -103,6 +115,13 @@
EXPECT_FALSE(HasRecordingAt(x, y));
}
+bool FakePicturePileImpl::HasRecordingAt(int x, int y) const {
+ PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
+ if (found == picture_map_.end())
+ return false;
+ return !!found->second.GetPicture();
+}
+
void FakePicturePileImpl::RerecordPile() {
for (int y = 0; y < num_tiles_y(); ++y) {
for (int x = 0; x < num_tiles_x(); ++x) {
@@ -112,4 +131,37 @@
}
}
+void FakePicturePileImpl::SetMinContentsScale(float min_contents_scale) {
+ if (min_contents_scale_ == min_contents_scale)
+ return;
+
+ // Picture contents are played back scaled. When the final contents scale is
+ // less than 1 (i.e. low res), then multiple recorded pixels will be used
+ // to raster one final pixel. To avoid splitting a final pixel across
+ // pictures (which would result in incorrect rasterization due to blending), a
+ // buffer margin is added so that any picture can be snapped to integral
+ // final pixels.
+ //
+ // For example, if a 1/4 contents scale is used, then that would be 3 buffer
+ // pixels, since that's the minimum number of pixels to add so that resulting
+ // content can be snapped to a four pixel aligned grid.
+ int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
+ buffer_pixels = std::max(0, buffer_pixels);
+ SetBufferPixels(buffer_pixels);
+ min_contents_scale_ = min_contents_scale;
+}
+
+void FakePicturePileImpl::SetBufferPixels(int new_buffer_pixels) {
+ if (new_buffer_pixels == buffer_pixels())
+ return;
+
+ Clear();
+ tiling_.SetBorderTexels(new_buffer_pixels);
+}
+
+void FakePicturePileImpl::Clear() {
+ picture_map_.clear();
+ recorded_viewport_ = gfx::Rect();
+}
+
} // namespace cc
diff --git a/cc/test/fake_picture_pile_impl.h b/cc/test/fake_picture_pile_impl.h
index 10c769a..f1a9d31 100644
--- a/cc/test/fake_picture_pile_impl.h
+++ b/cc/test/fake_picture_pile_impl.h
@@ -72,12 +72,24 @@
is_solid_color_ = is_solid_color;
}
+ 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(); }
+
+ void SetMinContentsScale(float scale);
+ void SetBufferPixels(int new_buffer_pixels);
+ void Clear();
+
protected:
FakePicturePileImpl();
+ explicit FakePicturePileImpl(const PicturePile* other);
~FakePicturePileImpl() override;
FakeContentLayerClient client_;
SkPaint default_paint_;
+ SkTileGridFactory::TileGridInfo tile_grid_info_;
};
} // namespace cc
diff --git a/cc/test/fake_tile_manager_client.h b/cc/test/fake_tile_manager_client.h
index 4b42468..94cfca6 100644
--- a/cc/test/fake_tile_manager_client.h
+++ b/cc/test/fake_tile_manager_client.h
@@ -19,6 +19,7 @@
// TileManagerClient implementation.
const std::vector<PictureLayerImpl*>& GetPictureLayers() const override;
void NotifyReadyToActivate() override {}
+ void NotifyReadyToDraw() override {}
void NotifyTileStateChanged(const Tile* tile) override {}
void BuildRasterQueue(RasterTilePriorityQueue* queue,
TreePriority tree_priority) override {}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index d1d1962..373959d 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -15,6 +15,7 @@
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/test/animation_test_common.h"
+#include "cc/test/begin_frame_args_test.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/test_context_provider.h"
@@ -53,9 +54,51 @@
raster_worker_pool, resource_pool, staging_resource_pool);
}
-base::TimeDelta TestHooks::LowFrequencyAnimationInterval() const {
- return base::TimeDelta::FromMilliseconds(16);
-}
+class ExternalBeginFrameSourceForTest
+ : public BeginFrameSourceMixIn,
+ public NON_EXPORTED_BASE(base::NonThreadSafe) {
+ public:
+ explicit ExternalBeginFrameSourceForTest(double refresh_rate)
+ : milliseconds_per_frame_(1000.0 / refresh_rate),
+ is_ready_(false),
+ weak_ptr_factory_(this) {
+ DetachFromThread();
+ }
+
+ virtual ~ExternalBeginFrameSourceForTest() {
+ DCHECK(CalledOnValidThread());
+ }
+
+ virtual void OnNeedsBeginFramesChange(bool needs_begin_frames) override {
+ DCHECK(CalledOnValidThread());
+ if (needs_begin_frames) {
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ExternalBeginFrameSourceForTest::TestOnBeginFrame,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(milliseconds_per_frame_));
+ }
+ }
+
+ virtual void SetClientReady() override {
+ DCHECK(CalledOnValidThread());
+ is_ready_ = true;
+ }
+
+ bool is_ready() const {
+ return is_ready_;
+ }
+
+ void TestOnBeginFrame() {
+ DCHECK(CalledOnValidThread());
+ CallOnBeginFrame(CreateBeginFrameArgsForTesting());
+ }
+
+ private:
+ double milliseconds_per_frame_;
+ bool is_ready_;
+ base::WeakPtrFactory<ExternalBeginFrameSourceForTest> weak_ptr_factory_;
+};
// Adapts ThreadProxy for test. Injects test hooks for testing.
class ThreadProxyForTest : public ThreadProxy {
@@ -64,9 +107,14 @@
TestHooks* test_hooks,
LayerTreeHost* host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
return make_scoped_ptr(new ThreadProxyForTest(
- test_hooks, host, main_task_runner, impl_task_runner));
+ test_hooks,
+ host,
+ main_task_runner,
+ impl_task_runner,
+ external_begin_frame_source.Pass()));
}
~ThreadProxyForTest() override {}
@@ -109,8 +157,11 @@
TestHooks* test_hooks,
LayerTreeHost* host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
- : ThreadProxy(host, main_task_runner, impl_task_runner),
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
+ : ThreadProxy(host, main_task_runner,
+ impl_task_runner,
+ external_begin_frame_source.Pass()),
test_hooks_(test_hooks) {}
};
@@ -214,10 +265,17 @@
}
void NotifyReadyToActivate() override {
- if (block_notify_ready_to_activate_for_testing_)
+ if (block_notify_ready_to_activate_for_testing_) {
notify_ready_to_activate_was_blocked_ = true;
- else
+ } else {
client_->NotifyReadyToActivate();
+ test_hooks_->NotifyReadyToActivateOnThread(this);
+ }
+ }
+
+ void NotifyReadyToDraw() override {
+ client_->NotifyReadyToDraw();
+ test_hooks_->NotifyReadyToDrawOnThread(this);
}
void BlockNotifyReadyToActivateForTesting(bool block) override {
@@ -269,10 +327,6 @@
test_hooks_->UpdateAnimationState(this, has_unfinished_animation);
}
- base::TimeDelta LowFrequencyAnimationInterval() const override {
- return test_hooks_->LowFrequencyAnimationInterval();
- }
-
private:
TestHooks* test_hooks_;
bool block_notify_ready_to_activate_for_testing_;
@@ -361,7 +415,8 @@
LayerTreeHostClientForTesting* client,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
scoped_ptr<LayerTreeHostForTesting> layer_tree_host(
new LayerTreeHostForTesting(test_hooks, client, settings));
if (impl_task_runner.get()) {
@@ -369,10 +424,14 @@
ThreadProxyForTest::Create(test_hooks,
layer_tree_host.get(),
main_task_runner,
- impl_task_runner));
+ impl_task_runner,
+ external_begin_frame_source.Pass()));
} else {
layer_tree_host->InitializeForTesting(SingleThreadProxy::Create(
- layer_tree_host.get(), client, main_task_runner));
+ layer_tree_host.get(),
+ client,
+ main_task_runner,
+ external_begin_frame_source.Pass()));
}
return layer_tree_host.Pass();
}
@@ -417,6 +476,7 @@
LayerTreeTest::LayerTreeTest()
: output_surface_(nullptr),
+ external_begin_frame_source_(nullptr),
beginning_(false),
end_when_begin_returns_(false),
timed_out_(false),
@@ -546,13 +606,22 @@
void LayerTreeTest::DoBeginTest() {
client_ = LayerTreeHostClientForTesting::Create(this);
+ scoped_ptr<ExternalBeginFrameSourceForTest> external_begin_frame_source;
+ if (settings_.use_external_begin_frame_source &&
+ settings_.throttle_frame_production) {
+ external_begin_frame_source.reset(
+ new ExternalBeginFrameSourceForTest(settings_.refresh_rate));
+ external_begin_frame_source_ = external_begin_frame_source.get();
+ }
+
DCHECK(!impl_thread_ || impl_thread_->message_loop_proxy().get());
layer_tree_host_ = LayerTreeHostForTesting::Create(
this,
client_.get(),
settings_,
base::MessageLoopProxy::current(),
- impl_thread_ ? impl_thread_->message_loop_proxy() : NULL);
+ impl_thread_ ? impl_thread_->message_loop_proxy() : NULL,
+ external_begin_frame_source.Pass());
ASSERT_TRUE(layer_tree_host_);
started_ = true;
@@ -675,6 +744,7 @@
// Spend less time waiting for BeginFrame because the output is
// mocked out.
settings_.refresh_rate = 200.0;
+ settings_.background_animation_rate = 200.0;
settings_.impl_side_painting = impl_side_painting;
InitializeSettings(&settings_);
@@ -720,6 +790,12 @@
output_surface->capabilities().delegated_rendering);
}
output_surface_ = output_surface.get();
+
+ if (settings_.use_external_begin_frame_source &&
+ settings_.throttle_frame_production) {
+ DCHECK(external_begin_frame_source_);
+ DCHECK(external_begin_frame_source_->is_ready());
+ }
return output_surface.Pass();
}
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index 36d669c..531e28d 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -17,6 +17,7 @@
}
namespace cc {
+class ExternalBeginFrameSourceForTest;
class FakeLayerTreeHostClient;
class FakeOutputSurface;
class LayerImpl;
@@ -57,6 +58,8 @@
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 AnimateLayers(LayerTreeHostImpl* host_impl,
base::TimeTicks monotonic_time) {}
virtual void UpdateAnimationState(LayerTreeHostImpl* host_impl,
@@ -84,7 +87,6 @@
virtual void DidDeferCommit() {}
virtual void DidSetVisibleOnImplTree(LayerTreeHostImpl* host_impl,
bool visible) {}
- virtual base::TimeDelta LowFrequencyAnimationInterval() const;
virtual void ScheduleComposite() {}
// Hooks for SchedulerClient.
@@ -209,6 +211,7 @@
scoped_ptr<LayerTreeHostClientForTesting> client_;
scoped_ptr<LayerTreeHost> layer_tree_host_;
FakeOutputSurface* output_surface_;
+ ExternalBeginFrameSourceForTest* external_begin_frame_source_;
bool beginning_;
bool end_when_begin_returns_;
@@ -236,12 +239,15 @@
} \
class SingleThreadDirectNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
-#define SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
- SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+#define SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME) \
TEST_F(TEST_FIXTURE_NAME, RunSingleThread_DirectRenderer_ImplSidePaint) { \
RunTest(false, false, true); \
} \
- class SingleThreadDirectNeedsSemicolon##TEST_FIXTURE_NAME {}
+ class SingleThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+#define SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
+ SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+ SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
#define SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
TEST_F(TEST_FIXTURE_NAME, \
@@ -250,34 +256,44 @@
} \
class SingleThreadDelegatingNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+#define SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+ TEST_F(TEST_FIXTURE_NAME, \
+ RunSingleThread_DelegatingRenderer_ImplSidePaint) { \
+ RunTest(false, true, true); \
+ } \
+ class SingleThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
#define SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
- TEST_F(TEST_FIXTURE_NAME, \
- RunSingleThread_DelegatingRenderer_ImplSidePaint) { \
- RunTest(false, true, true); \
- } \
- class SingleThreadDelegatingNeedsSemicolon##TEST_FIXTURE_NAME {}
-
-#define SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME) \
- SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
- SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
+ SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
#define SINGLE_THREAD_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
+#define SINGLE_THREAD_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+ SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+ SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
+#define SINGLE_THREAD_TEST_F(TEST_FIXTURE_NAME) \
+ SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
+ SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
+
#define MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DirectRenderer_MainThreadPaint) { \
RunTest(true, false, false); \
} \
class MultiThreadDirectNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
-#define MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
- MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+#define MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME) \
TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DirectRenderer_ImplSidePaint) { \
RunTest(true, false, true); \
} \
- class MultiThreadDirectNeedsSemicolon##TEST_FIXTURE_NAME {}
+ class MultiThreadDirectImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+#define MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
+ MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+ MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
#define MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
TEST_F(TEST_FIXTURE_NAME, \
@@ -286,17 +302,24 @@
} \
class MultiThreadDelegatingNoImplNeedsSemicolon##TEST_FIXTURE_NAME {}
-#define MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
- MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+#define MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME) \
TEST_F(TEST_FIXTURE_NAME, RunMultiThread_DelegatingRenderer_ImplSidePaint) { \
RunTest(true, true, true); \
} \
- class MultiThreadDelegatingNeedsSemicolon##TEST_FIXTURE_NAME {}
+ class MultiThreadDelegatingImplNeedsSemicolon##TEST_FIXTURE_NAME {}
+
+#define MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
+ MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
+ MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
#define MULTI_THREAD_NOIMPL_TEST_F(TEST_FIXTURE_NAME) \
MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
+#define MULTI_THREAD_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+ MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+ MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
#define MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \
MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
@@ -306,6 +329,10 @@
SINGLE_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
+#define SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+ SINGLE_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+ MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
#define SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
SINGLE_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME)
@@ -315,6 +342,11 @@
SINGLE_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
+#define SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F( \
+ TEST_FIXTURE_NAME) \
+ SINGLE_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+ MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
#define SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME) \
SINGLE_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
@@ -323,6 +355,10 @@
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME); \
SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_NOIMPL_TEST_F(TEST_FIXTURE_NAME)
+#define SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(TEST_FIXTURE_NAME) \
+ SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME); \
+ SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_IMPL_TEST_F(TEST_FIXTURE_NAME)
+
#define SINGLE_AND_MULTI_THREAD_TEST_F(TEST_FIXTURE_NAME) \
SINGLE_AND_MULTI_THREAD_DIRECT_RENDERER_TEST_F(TEST_FIXTURE_NAME); \
SINGLE_AND_MULTI_THREAD_DELEGATING_RENDERER_TEST_F(TEST_FIXTURE_NAME)
diff --git a/cc/test/scheduler_test_common.cc b/cc/test/scheduler_test_common.cc
index ef4cefd..61ef0cf 100644
--- a/cc/test/scheduler_test_common.cc
+++ b/cc/test/scheduler_test_common.cc
@@ -84,7 +84,7 @@
scheduler->primary_frame_source_internal_ =
TestBackToBackBeginFrameSource::Create(now_src_, test_task_runner_);
return scheduler->primary_frame_source_internal_.get();
- } else if (scheduler->settings_.begin_frame_scheduling_enabled) {
+ } else if (scheduler->settings_.use_external_begin_frame_source) {
return SchedulerFrameSourcesConstructor::ConstructPrimaryFrameSource(
scheduler);
} else {
@@ -128,12 +128,14 @@
int layer_tree_host_id,
const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner,
base::PowerMonitor* power_monitor,
- TestSchedulerFrameSourcesConstructor* frame_sources_constructor)
+ TestSchedulerFrameSourcesConstructor* frame_sources_constructor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
: Scheduler(client,
scheduler_settings,
layer_tree_host_id,
test_task_runner,
power_monitor,
+ external_begin_frame_source.Pass(),
frame_sources_constructor),
now_src_(now_src) {
}
diff --git a/cc/test/scheduler_test_common.h b/cc/test/scheduler_test_common.h
index d9cb3cf..ea6b2ef 100644
--- a/cc/test/scheduler_test_common.h
+++ b/cc/test/scheduler_test_common.h
@@ -162,16 +162,19 @@
const SchedulerSettings& scheduler_settings,
int layer_tree_host_id,
const scoped_refptr<OrderedSimpleTaskRunner>& task_runner,
- base::PowerMonitor* power_monitor) {
+ base::PowerMonitor* power_monitor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
TestSchedulerFrameSourcesConstructor frame_sources_constructor(
task_runner.get(), now_src.get());
- return make_scoped_ptr(new TestScheduler(now_src,
- client,
- scheduler_settings,
- layer_tree_host_id,
- task_runner,
- power_monitor,
- &frame_sources_constructor));
+ return make_scoped_ptr(new TestScheduler(
+ now_src,
+ client,
+ scheduler_settings,
+ layer_tree_host_id,
+ task_runner,
+ power_monitor,
+ &frame_sources_constructor,
+ external_begin_frame_source.Pass()));
}
// Extra test helper functionality
@@ -195,7 +198,8 @@
int layer_tree_host_id,
const scoped_refptr<OrderedSimpleTaskRunner>& test_task_runner,
base::PowerMonitor* power_monitor,
- TestSchedulerFrameSourcesConstructor* frame_sources_constructor);
+ TestSchedulerFrameSourcesConstructor* frame_sources_constructor,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
scoped_refptr<TestNowSource> now_src_;
};
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index af7eb5b..f85d4e7 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -32,6 +32,7 @@
#include "cc/layers/render_surface.h"
#include "cc/resources/prioritized_resource_manager.h"
#include "cc/resources/ui_resource_request.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/layer_tree_host_impl.h"
@@ -71,12 +72,15 @@
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
DCHECK(main_task_runner.get());
DCHECK(impl_task_runner.get());
scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(
client, shared_bitmap_manager, gpu_memory_buffer_manager, settings));
- layer_tree_host->InitializeThreaded(main_task_runner, impl_task_runner);
+ layer_tree_host->InitializeThreaded(main_task_runner,
+ impl_task_runner,
+ external_begin_frame_source.Pass());
return layer_tree_host.Pass();
}
@@ -86,11 +90,13 @@
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
scoped_ptr<LayerTreeHost> layer_tree_host(new LayerTreeHost(
client, shared_bitmap_manager, gpu_memory_buffer_manager, settings));
layer_tree_host->InitializeSingleThreaded(single_thread_client,
- main_task_runner);
+ main_task_runner,
+ external_begin_frame_source.Pass());
return layer_tree_host.Pass();
}
@@ -139,16 +145,23 @@
void LayerTreeHost::InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- InitializeProxy(
- ThreadProxy::Create(this, main_task_runner, impl_task_runner));
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+ InitializeProxy(ThreadProxy::Create(this,
+ main_task_runner,
+ impl_task_runner,
+ external_begin_frame_source.Pass()));
}
void LayerTreeHost::InitializeSingleThreaded(
LayerTreeHostSingleThreadClient* single_thread_client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
InitializeProxy(
- SingleThreadProxy::Create(this, single_thread_client, main_task_runner));
+ SingleThreadProxy::Create(this,
+ single_thread_client,
+ main_task_runner,
+ external_begin_frame_source.Pass()));
}
void LayerTreeHost::InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing) {
@@ -960,7 +973,6 @@
size_t LayerTreeHost::CalculateMemoryForRenderSurfaces(
const RenderSurfaceLayerList& update_list) {
size_t readback_bytes = 0;
- size_t max_background_texture_bytes = 0;
size_t contents_texture_bytes = 0;
// Start iteration at 1 to skip the root surface as it does not have a texture
@@ -974,17 +986,16 @@
RGBA_8888);
contents_texture_bytes += bytes;
- if (render_surface_layer->background_filters().IsEmpty())
+ if (render_surface_layer->background_filters().IsEmpty() &&
+ render_surface_layer->uses_default_blend_mode())
continue;
- if (bytes > max_background_texture_bytes)
- max_background_texture_bytes = bytes;
if (!readback_bytes) {
readback_bytes = Resource::MemorySizeBytes(device_viewport_size_,
RGBA_8888);
}
}
- return readback_bytes + max_background_texture_bytes + contents_texture_bytes;
+ return readback_bytes + contents_texture_bytes;
}
void LayerTreeHost::PaintMasksForRenderSurface(Layer* render_surface_layer,
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index a56a6cd..7820cc2 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -48,6 +48,7 @@
namespace cc {
class AnimationRegistrar;
+class BeginFrameSource;
class HeadsUpDisplayLayer;
class Layer;
class LayerTreeHostImpl;
@@ -92,7 +93,8 @@
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
static scoped_ptr<LayerTreeHost> CreateSingleThreaded(
LayerTreeHostClient* client,
@@ -100,7 +102,8 @@
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
const LayerTreeSettings& settings,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
virtual ~LayerTreeHost();
void SetLayerTreeHostClientReady();
@@ -318,10 +321,12 @@
const LayerTreeSettings& settings);
void InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
void InitializeSingleThreaded(
LayerTreeHostSingleThreadClient* single_thread_client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
void InitializeForTesting(scoped_ptr<Proxy> proxy_for_testing);
void SetOutputSurfaceLostForTesting(bool is_lost) {
output_surface_lost_ = is_lost;
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index fd15b52..0ff6608 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -1883,6 +1883,7 @@
render_surface->SetDrawOpacityIsAnimating(animating_opacity_to_target);
animating_opacity_to_target = false;
layer_draw_properties.opacity = 1.f;
+ layer_draw_properties.blend_mode = SkXfermode::kSrcOver_Mode;
layer_draw_properties.opacity_is_animating = animating_opacity_to_target;
layer_draw_properties.screen_space_opacity_is_animating =
animating_opacity_to_screen;
@@ -2007,6 +2008,7 @@
layer_draw_properties.screen_space_transform_is_animating =
animating_transform_to_screen;
layer_draw_properties.opacity = accumulated_draw_opacity;
+ layer_draw_properties.blend_mode = layer->blend_mode();
layer_draw_properties.opacity_is_animating = animating_opacity_to_target;
layer_draw_properties.screen_space_opacity_is_animating =
animating_opacity_to_screen;
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index e0436ba..b40f66d 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -1392,6 +1392,36 @@
EXPECT_EQ(gfx::Rect(), parent->drawable_content_rect());
}
+TEST_F(LayerTreeHostCommonTest, RenderSurfaceForBlendMode) {
+ scoped_refptr<Layer> parent = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> child =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(parent);
+
+ const gfx::Transform identity_matrix;
+ const SkXfermode::Mode blend_mode = SkXfermode::kMultiply_Mode;
+ SetLayerPropertiesForTesting(child.get(), identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(10, 10), true, false);
+
+ parent->AddChild(child);
+ child->SetBlendMode(blend_mode);
+
+ RenderSurfaceLayerList render_surface_layer_list;
+ LayerTreeHostCommon::CalcDrawPropsMainInputsForTesting inputs(
+ parent.get(), parent->bounds(), &render_surface_layer_list);
+ LayerTreeHostCommon::CalculateDrawProperties(&inputs);
+
+ // Since the child layer has a blend mode other than normal, it should get
+ // its own render surface. Also, layer's draw_properties should contain the
+ // default blend mode, since the render surface becomes responsible for
+ // applying the blend mode.
+ ASSERT_TRUE(child->render_surface());
+ EXPECT_EQ(1U, child->render_surface()->layer_list().size());
+ EXPECT_EQ(SkXfermode::kSrcOver_Mode, child->draw_properties().blend_mode);
+}
+
TEST_F(LayerTreeHostCommonTest, ForceRenderSurface) {
scoped_refptr<Layer> parent = Layer::Create();
scoped_refptr<Layer> render_surface1 = Layer::Create();
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index d2041ac..696da7a 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -29,6 +29,7 @@
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/debug/traced_value.h"
#include "cc/input/page_scale_animation.h"
+#include "cc/input/scroll_elasticity_helper.h"
#include "cc/input/top_controls_manager.h"
#include "cc/layers/append_quads_data.h"
#include "cc/layers/heads_up_display_layer_impl.h"
@@ -173,77 +174,6 @@
} // namespace
-class LayerTreeHostImplTimeSourceAdapter : public TimeSourceClient {
- public:
- static scoped_ptr<LayerTreeHostImplTimeSourceAdapter> Create(
- LayerTreeHostImpl* layer_tree_host_impl,
- scoped_refptr<DelayBasedTimeSource> time_source) {
- return make_scoped_ptr(
- new LayerTreeHostImplTimeSourceAdapter(layer_tree_host_impl,
- time_source));
- }
- ~LayerTreeHostImplTimeSourceAdapter() override {
- time_source_->SetClient(NULL);
- time_source_->SetActive(false);
- }
-
- void OnTimerTick() override {
- // In single threaded mode we attempt to simulate changing the current
- // thread by maintaining a fake thread id. When we switch from one
- // thread to another, we construct DebugScopedSetXXXThread objects that
- // update the thread id. This lets DCHECKS that ensure we're on the
- // right thread to work correctly in single threaded mode. The problem
- // here is that the timer tasks are run via the message loop, and when
- // they run, we've had no chance to construct a DebugScopedSetXXXThread
- // object. The result is that we report that we're running on the main
- // thread. In multi-threaded mode, this timer is run on the compositor
- // thread, so to keep this consistent in single-threaded mode, we'll
- // construct a DebugScopedSetImplThread object. There is no need to do
- // this in multi-threaded mode since the real thread id's will be
- // correct. In fact, setting fake thread id's interferes with the real
- // thread id's and causes breakage.
- scoped_ptr<DebugScopedSetImplThread> set_impl_thread;
- if (!layer_tree_host_impl_->proxy()->HasImplThread()) {
- set_impl_thread.reset(
- new DebugScopedSetImplThread(layer_tree_host_impl_->proxy()));
- }
-
- layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
- layer_tree_host_impl_->UpdateBackgroundAnimateTicking(true);
- bool start_ready_animations = true;
- layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
-
- if (layer_tree_host_impl_->pending_tree()) {
- layer_tree_host_impl_->pending_tree()->UpdateDrawProperties();
- layer_tree_host_impl_->ManageTiles();
- }
-
- layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
- }
-
- void SetActive(bool active) {
- if (active != time_source_->Active())
- time_source_->SetActive(active);
- }
-
- bool Active() const { return time_source_->Active(); }
-
- private:
- LayerTreeHostImplTimeSourceAdapter(
- LayerTreeHostImpl* layer_tree_host_impl,
- scoped_refptr<DelayBasedTimeSource> time_source)
- : layer_tree_host_impl_(layer_tree_host_impl),
- time_source_(time_source) {
- time_source_->SetClient(this);
- }
-
- LayerTreeHostImpl* layer_tree_host_impl_;
- scoped_refptr<DelayBasedTimeSource> time_source_;
-
- DISALLOW_COPY_AND_ASSIGN(LayerTreeHostImplTimeSourceAdapter);
-};
-
LayerTreeHostImpl::FrameData::FrameData()
: contains_incomplete_tile(false), has_no_damage(false) {}
@@ -274,8 +204,7 @@
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
int id)
- : BeginFrameSourceMixIn(),
- client_(client),
+ : client_(client),
proxy_(proxy),
use_gpu_rasterization_(false),
input_handler_client_(NULL),
@@ -352,6 +281,8 @@
input_handler_client_->WillShutdown();
input_handler_client_ = NULL;
}
+ if (scroll_elasticity_helper_)
+ scroll_elasticity_helper_.reset();
// The layer trees must be destroyed before the layer tree host. We've
// made a contract with our animation controllers that the registrar
@@ -521,6 +452,12 @@
new LatencyInfoSwapPromiseMonitor(latency, NULL, this));
}
+ScrollElasticityHelper* LayerTreeHostImpl::CreateScrollElasticityHelper() {
+ DCHECK(!scroll_elasticity_helper_);
+ scroll_elasticity_helper_.reset(new ScrollElasticityHelper(this));
+ return scroll_elasticity_helper_.get();
+}
+
void LayerTreeHostImpl::QueueSwapPromiseForMainThreadScrollUpdate(
scoped_ptr<SwapPromise> swap_promise) {
swap_promises_for_main_thread_scroll_update_.push_back(swap_promise.Pass());
@@ -974,28 +911,6 @@
input_handler_client_->MainThreadHasStoppedFlinging();
}
-void LayerTreeHostImpl::UpdateBackgroundAnimateTicking(
- bool should_background_tick) {
- DCHECK(proxy_->IsImplThread());
- if (should_background_tick)
- DCHECK(active_tree_->root_layer());
-
- bool enabled = should_background_tick && needs_animate_layers();
-
- // Lazily create the time_source adapter so that we can vary the interval for
- // testing.
- if (!time_source_client_adapter_) {
- time_source_client_adapter_ = LayerTreeHostImplTimeSourceAdapter::Create(
- this,
- DelayBasedTimeSource::Create(
- LowFrequencyAnimationInterval(),
- proxy_->HasImplThread() ? proxy_->ImplThreadTaskRunner()
- : proxy_->MainThreadTaskRunner()));
- }
-
- time_source_client_adapter_->SetActive(enabled);
-}
-
void LayerTreeHostImpl::DidAnimateScrollOffset() {
client_->SetNeedsCommitOnImplThread();
client_->RenewTreePriority();
@@ -1271,7 +1186,8 @@
}
void LayerTreeHostImpl::GetPictureLayerImplPairs(
- std::vector<PictureLayerImpl::Pair>* layer_pairs) const {
+ std::vector<PictureLayerImpl::Pair>* layer_pairs,
+ bool need_valid_tile_priorities) const {
DCHECK(layer_pairs->empty());
for (std::vector<PictureLayerImpl*>::const_iterator it =
picture_layers_.begin();
@@ -1279,24 +1195,25 @@
++it) {
PictureLayerImpl* layer = *it;
- // TODO(vmpstr): Iterators and should handle this instead. crbug.com/381704
- if (!layer->HasValidTilePriorities())
+ if (!layer->IsOnActiveOrPendingTree() ||
+ (need_valid_tile_priorities && !layer->HasValidTilePriorities()))
continue;
PictureLayerImpl* twin_layer = layer->GetPendingOrActiveTwinLayer();
// Ignore the twin layer when tile priorities are invalid.
- // TODO(vmpstr): Iterators should handle this instead. crbug.com/381704
- if (twin_layer && !twin_layer->HasValidTilePriorities())
+ if (need_valid_tile_priorities && twin_layer &&
+ !twin_layer->HasValidTilePriorities())
twin_layer = NULL;
// If the current tree is ACTIVE_TREE, then always generate a layer_pair.
// If current tree is PENDING_TREE, then only generate a layer_pair if
// there is no twin layer.
if (layer->GetTree() == ACTIVE_TREE) {
- DCHECK(!twin_layer || twin_layer->GetTree() == PENDING_TREE);
+ DCHECK_IMPLIES(twin_layer, twin_layer->GetTree() == PENDING_TREE);
layer_pairs->push_back(PictureLayerImpl::Pair(layer, twin_layer));
} else if (!twin_layer) {
+ DCHECK(layer->GetTree() == PENDING_TREE);
layer_pairs->push_back(PictureLayerImpl::Pair(NULL, layer));
}
}
@@ -1306,7 +1223,7 @@
TreePriority tree_priority) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::BuildRasterQueue");
picture_layer_pairs_.clear();
- GetPictureLayerImplPairs(&picture_layer_pairs_);
+ GetPictureLayerImplPairs(&picture_layer_pairs_, true);
queue->Build(picture_layer_pairs_, tree_priority);
}
@@ -1314,7 +1231,7 @@
TreePriority tree_priority) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::BuildEvictionQueue");
picture_layer_pairs_.clear();
- GetPictureLayerImplPairs(&picture_layer_pairs_);
+ GetPictureLayerImplPairs(&picture_layer_pairs_, false);
queue->Build(picture_layer_pairs_, tree_priority);
}
@@ -1327,6 +1244,10 @@
client_->NotifyReadyToActivate();
}
+void LayerTreeHostImpl::NotifyReadyToDraw() {
+ client_->NotifyReadyToDraw();
+}
+
void LayerTreeHostImpl::NotifyTileStateChanged(const Tile* tile) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::NotifyTileStateChanged");
@@ -1437,10 +1358,6 @@
client_->SetNeedsRedrawRectOnImplThread(damage_rect);
}
-void LayerTreeHostImpl::BeginFrame(const BeginFrameArgs& args) {
- CallOnBeginFrame(args);
-}
-
void LayerTreeHostImpl::DidSwapBuffers() {
client_->DidSwapBuffersOnImplThread();
}
@@ -1543,7 +1460,8 @@
if (!settings_.impl_side_painting && debug_state_.continuous_painting) {
const RenderingStats& stats =
rendering_stats_instrumentation_->GetRenderingStats();
- paint_time_counter_->SavePaintTime(stats.main_stats.paint_time);
+ paint_time_counter_->SavePaintTime(
+ stats.begin_main_frame_to_commit_duration.GetLastTimeDelta());
}
bool is_new_trace;
@@ -1678,13 +1596,6 @@
return true;
}
-void LayerTreeHostImpl::OnNeedsBeginFramesChange(bool enable) {
- if (output_surface_)
- output_surface_->SetNeedsBeginFrame(enable);
- else
- DCHECK(!enable);
-}
-
void LayerTreeHostImpl::WillBeginImplFrame(const BeginFrameArgs& args) {
// Sample the frame time now. This time will be used for updating animations
// when we draw.
@@ -1883,13 +1794,10 @@
// TODO(hendrikw): This requires a different metric when we commit directly
// to the active tree. See crbug.com/429311.
paint_time_counter_->SavePaintTime(
- stats.impl_stats.commit_to_activate_duration.GetLastTimeDelta() +
- stats.impl_stats.draw_duration.GetLastTimeDelta());
+ stats.commit_to_activate_duration.GetLastTimeDelta() +
+ stats.draw_duration.GetLastTimeDelta());
}
- if (time_source_client_adapter_ && time_source_client_adapter_->Active())
- DCHECK(active_tree_->root_layer());
-
scoped_ptr<PageScaleAnimation> page_scale_animation =
active_tree_->TakePageScaleAnimation();
if (page_scale_animation) {
@@ -2195,7 +2103,7 @@
// TODO(brianderson): Don't use a hard-coded parent draw time.
base::TimeDelta parent_draw_time =
- (!settings_.begin_frame_scheduling_enabled &&
+ (!settings_.use_external_begin_frame_source &&
output_surface_->capabilities().adjust_deadline_for_parent)
? BeginFrameArgs::DefaultEstimatedParentDrawTime()
: base::TimeDelta();
@@ -2472,9 +2380,10 @@
new_target.SetToMax(gfx::ScrollOffset());
new_target.SetToMin(layer_impl->MaxScrollOffset());
- curve->UpdateTarget(animation->TrimTimeToCurrentIteration(
- CurrentBeginFrameArgs().frame_time),
- new_target);
+ curve->UpdateTarget(
+ animation->TrimTimeToCurrentIteration(
+ CurrentBeginFrameArgs().frame_time).InSecondsF(),
+ new_target);
return ScrollStarted;
}
@@ -2628,21 +2537,19 @@
CurrentlyScrollingLayer() != OuterViewportScrollLayer())
return false;
- if (InnerViewportScrollLayer()->MaxScrollOffset().y() > 0)
- return true;
-
- if (OuterViewportScrollLayer() &&
- OuterViewportScrollLayer()->MaxScrollOffset().y() > 0)
+ if (active_tree()->TotalScrollOffset().y() <
+ active_tree()->TotalMaxScrollOffset().y())
return true;
return false;
}
-bool LayerTreeHostImpl::ScrollBy(const gfx::Point& viewport_point,
- const gfx::Vector2dF& scroll_delta) {
+InputHandlerScrollResult LayerTreeHostImpl::ScrollBy(
+ const gfx::Point& viewport_point,
+ const gfx::Vector2dF& scroll_delta) {
TRACE_EVENT0("cc", "LayerTreeHostImpl::ScrollBy");
if (!CurrentlyScrollingLayer())
- return false;
+ return InputHandlerScrollResult();
gfx::Vector2dF pending_delta = scroll_delta;
gfx::Vector2dF unused_root_delta;
@@ -2763,15 +2670,14 @@
accumulated_root_overscroll_.set_x(0);
if (did_scroll_y)
accumulated_root_overscroll_.set_y(0);
-
accumulated_root_overscroll_ += unused_root_delta;
- bool did_overscroll = !unused_root_delta.IsZero();
- if (did_overscroll && input_handler_client_) {
- input_handler_client_->DidOverscroll(
- viewport_point, accumulated_root_overscroll_, unused_root_delta);
- }
- return did_scroll_content || did_scroll_top_controls;
+ InputHandlerScrollResult scroll_result;
+ scroll_result.did_scroll = did_scroll_content || did_scroll_top_controls;
+ scroll_result.did_overscroll_root = !unused_root_delta.IsZero();
+ scroll_result.accumulated_root_overscroll = accumulated_root_overscroll_;
+ scroll_result.unused_scroll_delta = unused_root_delta;
+ return scroll_result;
}
// This implements scrolling by page as described here:
@@ -3197,10 +3103,8 @@
iter != copy.end();
++iter)
(*iter).second->ActivateAnimations();
-}
-base::TimeDelta LayerTreeHostImpl::LowFrequencyAnimationInterval() const {
- return base::TimeDelta::FromSeconds(1);
+ SetNeedsAnimate();
}
std::string LayerTreeHostImpl::LayerTreeAsJson() const {
@@ -3287,10 +3191,6 @@
BeginFrameArgs::DefaultInterval());
}
-void LayerTreeHostImpl::AsValueInto(base::debug::TracedValue* value) const {
- return AsValueWithFrameInto(NULL, value);
-}
-
scoped_refptr<base::debug::ConvertableToTraceFormat>
LayerTreeHostImpl::AsValue() const {
return AsValueWithFrame(NULL);
@@ -3304,6 +3204,10 @@
return state;
}
+void LayerTreeHostImpl::AsValueInto(base::debug::TracedValue* value) const {
+ return AsValueWithFrameInto(NULL, value);
+}
+
void LayerTreeHostImpl::AsValueWithFrameInto(
FrameData* frame,
base::debug::TracedValue* state) const {
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 157fe00..24cb730 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -31,7 +31,6 @@
#include "cc/quads/render_pass.h"
#include "cc/resources/resource_provider.h"
#include "cc/resources/tile_manager.h"
-#include "cc/scheduler/begin_frame_source.h"
#include "cc/scheduler/draw_result.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
@@ -45,7 +44,6 @@
class EvictionTilePriorityQueue;
class FrameRateCounter;
class LayerImpl;
-class LayerTreeHostImplTimeSourceAdapter;
class LayerTreeImpl;
class MemoryHistory;
class PageScaleAnimation;
@@ -56,6 +54,7 @@
class RenderPassDrawQuad;
class RenderingStatsInstrumentation;
class ResourcePool;
+class ScrollElasticityHelper;
class ScrollbarLayerImplBase;
class TextureMailboxDeleter;
class TopControlsManager;
@@ -76,6 +75,7 @@
virtual void DidSwapBuffersCompleteOnImplThread() = 0;
virtual void OnCanDrawStateChanged(bool can_draw) = 0;
virtual void NotifyReadyToActivate() = 0;
+ virtual void NotifyReadyToDraw() = 0;
// Please call these 3 functions through
// LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
// SetNeedsAnimate().
@@ -112,7 +112,6 @@
public OutputSurfaceClient,
public TopControlsManagerClient,
public ScrollbarAnimationControllerClient,
- public BeginFrameSourceMixIn,
public base::SupportsWeakPtr<LayerTreeHostImpl> {
public:
static scoped_ptr<LayerTreeHostImpl> Create(
@@ -125,9 +124,6 @@
int id);
~LayerTreeHostImpl() override;
- // BeginFrameSourceMixIn implementation
- void OnNeedsBeginFramesChange(bool needs_begin_frames) override;
-
// InputHandler implementation
void BindToClient(InputHandlerClient* client) override;
InputHandler::ScrollStatus ScrollBegin(
@@ -136,8 +132,9 @@
InputHandler::ScrollStatus ScrollAnimated(
const gfx::Point& viewport_point,
const gfx::Vector2dF& scroll_delta) override;
- bool ScrollBy(const gfx::Point& viewport_point,
- const gfx::Vector2dF& scroll_delta) override;
+ InputHandlerScrollResult ScrollBy(
+ const gfx::Point& viewport_point,
+ const gfx::Vector2dF& scroll_delta) override;
bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
ScrollDirection direction) override;
void SetRootLayerScrollOffsetDelegate(
@@ -156,6 +153,7 @@
bool HaveTouchEventHandlersAt(const gfx::Point& viewport_port) override;
scoped_ptr<SwapPromiseMonitor> CreateLatencyInfoSwapPromiseMonitor(
ui::LatencyInfo* latency) override;
+ ScrollElasticityHelper* CreateScrollElasticityHelper() override;
// TopControlsManagerClient implementation.
void SetControlsTopOffset(float offset) override;
@@ -188,7 +186,6 @@
virtual void UpdateAnimationState(bool start_ready_animations);
void ActivateAnimations();
void MainThreadHasStoppedFlinging();
- void UpdateBackgroundAnimateTicking(bool should_background_tick);
void DidAnimateScrollOffset();
void SetViewportDamage(const gfx::Rect& damage_rect);
@@ -234,6 +231,7 @@
// TileManagerClient implementation.
const std::vector<PictureLayerImpl*>& GetPictureLayers() const override;
void NotifyReadyToActivate() override;
+ void NotifyReadyToDraw() override;
void NotifyTileStateChanged(const Tile* tile) override;
void BuildRasterQueue(RasterTilePriorityQueue* queue,
TreePriority tree_priority) override;
@@ -251,8 +249,6 @@
void CommitVSyncParameters(base::TimeTicks timebase,
base::TimeDelta interval) override;
void SetNeedsRedrawRect(const gfx::Rect& rect) override;
- void BeginFrame(const BeginFrameArgs& args) override;
-
void SetExternalDrawConstraints(
const gfx::Transform& transform,
const gfx::Rect& viewport,
@@ -329,6 +325,8 @@
virtual void SetVisible(bool visible);
bool visible() const { return visible_; }
+ bool AnimationsAreVisible() { return visible() && CanDraw(); }
+
void SetNeedsCommit() { client_->SetNeedsCommitOnImplThread(); }
void SetNeedsRedraw();
@@ -424,7 +422,7 @@
return begin_impl_frame_interval_;
}
- void AsValueInto(base::debug::TracedValue* value) const override;
+ void AsValueInto(base::debug::TracedValue* value) const;
void AsValueWithFrameInto(FrameData* frame,
base::debug::TracedValue* value) const;
scoped_refptr<base::debug::ConvertableToTraceFormat> AsValue() const;
@@ -473,8 +471,8 @@
void RegisterPictureLayerImpl(PictureLayerImpl* layer);
void UnregisterPictureLayerImpl(PictureLayerImpl* layer);
- void GetPictureLayerImplPairs(
- std::vector<PictureLayerImpl::Pair>* layers) const;
+ void GetPictureLayerImplPairs(std::vector<PictureLayerImpl::Pair>* layers,
+ bool need_valid_tile_priorities) const;
void SetTopControlsLayoutHeight(float height);
@@ -506,8 +504,6 @@
// Virtual for testing.
virtual void AnimateLayers(base::TimeTicks monotonic_time);
- virtual base::TimeDelta LowFrequencyAnimationInterval() const;
-
const AnimationRegistrar::AnimationControllerMap&
active_animation_controllers() const {
return animation_registrar_->active_animation_controllers();
@@ -627,6 +623,10 @@
int scroll_layer_id_when_mouse_over_scrollbar_;
ScopedPtrVector<SwapPromise> swap_promises_for_main_thread_scroll_update_;
+ // An object to implement the ScrollElasticityHelper interface and
+ // hold all state related to elasticity. May be NULL if never requested.
+ scoped_ptr<ScrollElasticityHelper> scroll_elasticity_helper_;
+
bool tile_priorities_dirty_;
// The optional delegate for the root layer scroll offset.
@@ -646,9 +646,6 @@
scoped_ptr<PageScaleAnimation> page_scale_animation_;
- // This is used for ticking animations slowly when hidden.
- scoped_ptr<LayerTreeHostImplTimeSourceAdapter> time_source_client_adapter_;
-
scoped_ptr<FrameRateCounter> fps_counter_;
scoped_ptr<PaintTimeCounter> paint_time_counter_;
scoped_ptr<MemoryHistory> memory_history_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 5d2d939..17179cd 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -124,6 +124,7 @@
did_notify_ready_to_activate_ = true;
host_impl_->ActivateSyncTree();
}
+ void NotifyReadyToDraw() override {}
void SetNeedsRedrawOnImplThread() override { did_request_redraw_ = true; }
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& damage_rect) override {
did_request_redraw_ = true;
@@ -772,27 +773,40 @@
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
// Trying to scroll to the left/top will not succeed.
- EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
- EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
- EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
+ EXPECT_FALSE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll);
+ EXPECT_FALSE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)).did_scroll);
+ EXPECT_FALSE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)).did_scroll);
// Scrolling to the right/bottom will succeed.
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0)).did_scroll);
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 10)).did_scroll);
// Scrolling to left/top will now succeed.
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll);
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10)).did_scroll);
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, -10)).did_scroll);
// Scrolling diagonally against an edge will succeed.
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10)));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -10)).did_scroll);
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 0)).did_scroll);
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-10, 10)).did_scroll);
// Trying to scroll more than the available space will also succeed.
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(5000, 5000)).did_scroll);
}
TEST_F(LayerTreeHostImplTest, ScrollVerticallyByPageReturnsCorrectValue) {
@@ -2574,6 +2588,14 @@
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
+
+ // scrolling down at the max extents no longer hides the top controls
+ EXPECT_EQ(0.f,
+ settings_.top_controls_height -
+ host_impl_->active_tree()->total_top_controls_content_offset());
+
+ // forcefully hide the top controls by 25px
+ host_impl_->top_controls_manager()->ScrollBy(scroll_delta);
host_impl_->ScrollEnd();
EXPECT_EQ(scroll_delta.y(),
@@ -3705,6 +3727,7 @@
}
TEST_F(LayerTreeHostImplTest, OverscrollRoot) {
+ InputHandlerScrollResult scroll_result;
SetupScrollAndContentsLayers(gfx::Size(100, 100));
host_impl_->SetViewportSize(gfx::Size(50, 50));
host_impl_->active_tree()->SetPageScaleFactorAndLimits(1.f, 0.5f, 4.f);
@@ -3714,38 +3737,105 @@
// In-bounds scrolling does not affect overscroll.
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_FALSE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
// Overscroll events are reflected immediately.
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50));
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 50));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, 10), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
// In-bounds scrolling resets accumulated overscroll for the scrolled axes.
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50));
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -50));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_FALSE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10));
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -10));
+ EXPECT_FALSE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0));
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, 0));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_FALSE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-15, 0));
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(-15, 0));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(-5, 0), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(-5, -10), host_impl_->accumulated_root_overscroll());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 60));
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 60));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, 10), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(-5, 10), host_impl_->accumulated_root_overscroll());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -60));
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(10, -60));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
// Overscroll accumulates within the scope of ScrollBegin/ScrollEnd as long
// as no scroll occurs.
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_FALSE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, -20), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, -30), host_impl_->accumulated_root_overscroll());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_FALSE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, -20), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, -50), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
// Overscroll resets on valid scroll.
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_FALSE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, 0), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, 0), host_impl_->accumulated_root_overscroll());
- host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
+ scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -20));
+ EXPECT_TRUE(scroll_result.did_scroll);
+ EXPECT_TRUE(scroll_result.did_overscroll_root);
+ EXPECT_EQ(gfx::Vector2dF(0, -10), scroll_result.unused_scroll_delta);
EXPECT_EQ(gfx::Vector2dF(0, -10), host_impl_->accumulated_root_overscroll());
+ EXPECT_EQ(scroll_result.accumulated_root_overscroll,
+ host_impl_->accumulated_root_overscroll());
+
host_impl_->ScrollEnd();
}
@@ -5981,7 +6071,8 @@
pile_tile_size, content_layer_bounds));
scoped_ptr<FakePictureLayerImpl> scoped_content_layer =
- FakePictureLayerImpl::CreateWithPile(host_impl_->pending_tree(), 3, pile);
+ FakePictureLayerImpl::CreateWithRasterSource(host_impl_->pending_tree(),
+ 3, pile);
LayerImpl* content_layer = scoped_content_layer.get();
scrolling_layer->AddChild(scoped_content_layer.Pass());
content_layer->SetBounds(content_layer_bounds);
@@ -6527,7 +6618,7 @@
gfx::Vector2d scroll_delta(0, -2);
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
// The grand child should have scrolled up to its limit.
scroll_info = host_impl_->ProcessScrollDeltas();
@@ -6537,7 +6628,7 @@
// The child should have received the bubbled delta, but the locked
// scrolling layer should remain set as the grand child.
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
scroll_info = host_impl_->ProcessScrollDeltas();
ASSERT_EQ(2u, scroll_info->scrolls.size());
ExpectContains(*scroll_info, grand_child->id(), scroll_delta);
@@ -6547,7 +6638,7 @@
// The first |ScrollBy| after the fling should re-lock the scrolling
// layer to the first layer that scrolled, which is the child.
EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
// The child should have scrolled up to its limit.
@@ -6557,7 +6648,7 @@
ExpectContains(*scroll_info, child->id(), scroll_delta + scroll_delta);
// As the locked layer is at it's limit, no further scrolling can occur.
- EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta));
+ EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
host_impl_->ScrollEnd();
}
@@ -6955,7 +7046,8 @@
// Scrolling normally should not trigger any forwarding.
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
host_impl_->ScrollEnd();
EXPECT_EQ(0, set_needs_commit_count);
@@ -6967,7 +7059,8 @@
scroll_layer->SetHaveScrollEventHandlers(true);
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
host_impl_->ScrollEnd();
EXPECT_EQ(0, set_needs_commit_count);
@@ -7022,7 +7115,8 @@
// Scroll just the top controls and verify that the scroll succeeds.
const float residue = 10;
float offset = top_controls_height_ - residue;
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
scroll_layer->TotalScrollOffset().ToString());
@@ -7030,7 +7124,8 @@
// Scroll across the boundary
const float content_scroll = 20;
offset = residue + content_scroll;
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(-top_controls_height_,
host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF(0, content_scroll).ToString(),
@@ -7038,7 +7133,8 @@
// Now scroll back to the top of the content
offset = -content_scroll;
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(-top_controls_height_,
host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
@@ -7046,13 +7142,15 @@
// And scroll the top controls completely into view
offset = -top_controls_height_;
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
scroll_layer->TotalScrollOffset().ToString());
// And attempt to scroll past the end
- EXPECT_FALSE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_FALSE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
scroll_layer->TotalScrollOffset().ToString());
@@ -7076,7 +7174,8 @@
// Scroll the top controls partially.
const float residue = 35;
float offset = top_controls_height_ - residue;
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
scroll_layer->TotalScrollOffset().ToString());
@@ -7144,7 +7243,8 @@
// Scroll the top controls partially.
const float residue = 15;
float offset = top_controls_height_ - residue;
- EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)));
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
scroll_layer->TotalScrollOffset().ToString());
@@ -7184,6 +7284,68 @@
EXPECT_FALSE(host_impl_->top_controls_manager()->animation());
}
+TEST_F(LayerTreeHostImplWithTopControlsTest,
+ TopControlsScrollDeltaInOverScroll) {
+ // test varifies that the overscroll delta should not have accumulated in
+ // the top controls if we do a hide and show without releasing finger.
+
+ LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 200));
+ host_impl_->SetViewportSize(gfx::Size(100, 100));
+ host_impl_->top_controls_manager()->UpdateTopControlsState(BOTH, SHOWN,
+ false);
+ DrawFrame();
+
+ EXPECT_EQ(InputHandler::ScrollStarted,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ float offset = 50;
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+ EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+ EXPECT_EQ(gfx::Vector2dF().ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, offset).ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, offset)).did_scroll);
+
+ // Should have fully scrolled
+ EXPECT_EQ(gfx::Vector2dF(0, scroll_layer->MaxScrollOffset().y()).ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ float overscrollamount = 10;
+
+ // Overscroll the content
+ EXPECT_FALSE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, overscrollamount))
+ .did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, 2 * offset).ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+ EXPECT_EQ(gfx::Vector2dF(0, overscrollamount).ToString(),
+ host_impl_->accumulated_root_overscroll().ToString());
+
+ EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -2 * offset))
+ .did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, 0).ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+ EXPECT_EQ(-offset, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ EXPECT_TRUE(
+ host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, -offset)).did_scroll);
+ EXPECT_EQ(gfx::Vector2dF(0, 0).ToString(),
+ scroll_layer->TotalScrollOffset().ToString());
+
+ // Top controls should be fully visible
+ EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
+
+ host_impl_->ScrollEnd();
+}
+
class LayerTreeHostImplVirtualViewportTest : public LayerTreeHostImplTest {
public:
void SetupVirtualViewportLayers(const gfx::Size& content_size,
@@ -7398,7 +7560,7 @@
LayerImpl* pending_layer = pending_tree->root_layer();
std::vector<PictureLayerImpl::Pair> layer_pairs;
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+ host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
EXPECT_EQ(1u, layer_pairs.size());
EXPECT_EQ(pending_layer, layer_pairs[0].pending);
EXPECT_EQ(nullptr, layer_pairs[0].active);
@@ -7415,7 +7577,7 @@
host_impl_->CreatePendingTree();
layer_pairs.clear();
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+ host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
EXPECT_EQ(1u, layer_pairs.size());
EXPECT_EQ(active_layer, layer_pairs[0].active);
EXPECT_EQ(pending_layer, layer_pairs[0].pending);
@@ -7424,7 +7586,7 @@
host_impl_->ActivateSyncTree();
layer_pairs.clear();
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+ host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
EXPECT_EQ(1u, layer_pairs.size());
EXPECT_EQ(active_layer, layer_pairs[0].active);
EXPECT_EQ(nullptr, layer_pairs[0].pending);
@@ -7438,7 +7600,7 @@
LayerImpl* new_pending_layer = pending_tree->root_layer()->children()[0];
layer_pairs.clear();
- host_impl_->GetPictureLayerImplPairs(&layer_pairs);
+ host_impl_->GetPictureLayerImplPairs(&layer_pairs, true);
EXPECT_EQ(2u, layer_pairs.size());
// The pair ordering is flaky, so make it consistent.
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index 7a9ef21..148769e 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -52,25 +52,29 @@
const uint32 kUseMasks = 1 << 0;
const uint32 kUseAntialiasing = 1 << 1;
const uint32 kUseColorMatrix = 1 << 2;
+const uint32 kForceShaders = 1 << 3;
class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
public:
- LayerTreeHostBlendingPixelTest() {
+ LayerTreeHostBlendingPixelTest()
+ : force_antialiasing_(false), force_blending_with_shaders_(false) {
pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
}
virtual void InitializeSettings(LayerTreeSettings* settings) override {
settings->force_antialiasing = force_antialiasing_;
+ settings->force_blending_with_shaders = force_blending_with_shaders_;
}
protected:
void RunBlendingWithRootPixelTestType(PixelTestType type) {
- const int kLaneWidth = 15;
- const int kLaneHeight = kBlendModesCount * kLaneWidth;
- const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+ const int kLaneWidth = 2;
+ const int kLaneHeight = kLaneWidth;
+ const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+ const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+ CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange);
// Orange child layers will blend with the green background
for (int i = 0; i < kBlendModesCount; ++i) {
@@ -88,15 +92,16 @@
}
void RunBlendingWithTransparentPixelTestType(PixelTestType type) {
- const int kLaneWidth = 15;
- const int kLaneHeight = kBlendModesCount * kLaneWidth;
- const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+ const int kLaneWidth = 2;
+ const int kLaneHeight = 3 * kLaneWidth;
+ const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+ const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
scoped_refptr<SolidColorLayer> root =
- CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSBrown);
+ CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSBrown);
scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
- gfx::Rect(0, kLaneWidth * 2, kRootSize, kLaneWidth), kCSSOrange);
+ gfx::Rect(0, kLaneWidth * 2, kRootWidth, kLaneWidth), kCSSOrange);
root->AddChild(background);
background->SetIsRootForIsolatedGroup(true);
@@ -138,7 +143,7 @@
}
void SetupMaskLayer(scoped_refptr<Layer> layer) {
- const int kMaskOffset = 5;
+ const int kMaskOffset = 2;
gfx::Size bounds = layer->bounds();
scoped_refptr<ImageLayer> mask = ImageLayer::Create();
mask->SetIsDrawable(true);
@@ -162,23 +167,22 @@
void SetupColorMatrix(scoped_refptr<Layer> layer) {
FilterOperations filter_operations;
- filter_operations.Append(FilterOperation::CreateSepiaFilter(1.f));
+ filter_operations.Append(FilterOperation::CreateSepiaFilter(.001f));
layer->SetFilters(filter_operations);
}
- void CreateBlendingColorLayers(int width,
- int height,
+ void CreateBlendingColorLayers(int lane_width,
+ int lane_height,
scoped_refptr<Layer> background,
RenderPassOptions flags) {
const int kLanesCount = kBlendModesCount + 4;
- int lane_width = width / kLanesCount;
const SkColor kMiscOpaqueColor = 0xffc86464;
const SkColor kMiscTransparentColor = 0x80c86464;
const SkXfermode::Mode kCoeffBlendMode = SkXfermode::kScreen_Mode;
const SkXfermode::Mode kShaderBlendMode = SkXfermode::kColorBurn_Mode;
// add vertical lanes with each of the blend modes
for (int i = 0; i < kLanesCount; ++i) {
- gfx::Rect child_rect(i * lane_width, 0, lane_width, height);
+ gfx::Rect child_rect(i * lane_width, 0, lane_width, lane_height);
SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
float opacity = 1.f;
SkColor color = kMiscOpaqueColor;
@@ -216,7 +220,9 @@
void RunBlendingWithRenderPass(PixelTestType type,
const base::FilePath::CharType* expected_path,
RenderPassOptions flags) {
- const int kRootSize = 400;
+ const int kLaneWidth = 8;
+ const int kLaneHeight = kLaneWidth * kCSSTestColorsCount;
+ const int kRootSize = kLaneHeight;
scoped_refptr<SolidColorLayer> root =
CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), SK_ColorWHITE);
@@ -226,47 +232,25 @@
background->SetIsRootForIsolatedGroup(true);
root->AddChild(background);
- CreateBlendingColorLayers(kRootSize, kRootSize, background.get(), flags);
+ CreateBlendingColorLayers(kLaneWidth, kLaneHeight, background.get(), flags);
this->impl_side_painting_ = false;
this->force_antialiasing_ = (flags & kUseAntialiasing);
+ this->force_blending_with_shaders_ = (flags & kForceShaders);
if ((flags & kUseAntialiasing) && (type == PIXEL_TEST_GL)) {
- // Anti aliasing causes differences up to 7 pixels at the edges.
- // Several pixels have 9 units difference on the alpha channel.
- int large_error_allowed = (flags & kUseMasks) ? 7 : 9;
+ // Anti aliasing causes differences up to 8 pixels at the edges.
+ int large_error_allowed = 8;
// Blending results might differ with one pixel.
int small_error_allowed = 1;
// Most of the errors are one pixel errors.
- float percentage_pixels_small_error = (flags & kUseMasks) ? 7.7f : 12.1f;
- // Because of anti-aliasing, around 3% of pixels (at the edges) have
+ float percentage_pixels_small_error = 13.1f;
+ // Because of anti-aliasing, around 10% of pixels (at the edges) have
// bigger errors (from small_error_allowed + 1 to large_error_allowed).
- float percentage_pixels_error = (flags & kUseMasks) ? 12.4f : 15.f;
+ float percentage_pixels_error = 22.5f;
// The average error is still close to 1.
- float average_error_allowed_in_bad_pixels =
- (flags & kUseMasks) ? 1.3f : 1.f;
+ float average_error_allowed_in_bad_pixels = 1.4f;
- // The sepia filter generates more small errors, but the number of large
- // errors remains around 3%.
- if (flags & kUseColorMatrix) {
- percentage_pixels_small_error = (flags & kUseMasks) ? 14.0f : 26.f;
- percentage_pixels_error = (flags & kUseMasks) ? 18.5f : 29.f;
- average_error_allowed_in_bad_pixels = (flags & kUseMasks) ? 0.9f : 0.7f;
- }
-
- pixel_comparator_.reset(
- new FuzzyPixelComparator(false, // discard_alpha
- percentage_pixels_error,
- percentage_pixels_small_error,
- average_error_allowed_in_bad_pixels,
- large_error_allowed,
- small_error_allowed));
- } else if ((flags & kUseColorMatrix) && (type == PIXEL_TEST_GL)) {
- float percentage_pixels_error = 100.f;
- float percentage_pixels_small_error = 0.f;
- float average_error_allowed_in_bad_pixels = 1.f;
- int large_error_allowed = 2;
- int small_error_allowed = 0;
pixel_comparator_.reset(
new FuzzyPixelComparator(false, // discard_alpha
percentage_pixels_error,
@@ -279,7 +263,8 @@
RunPixelTest(type, root, base::FilePath(expected_path));
}
- bool force_antialiasing_ = false;
+ bool force_antialiasing_;
+ bool force_blending_with_shaders_;
};
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) {
@@ -291,12 +276,13 @@
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithBackgroundFilter) {
- const int kLaneWidth = 15;
- const int kLaneHeight = kBlendModesCount * kLaneWidth;
- const int kRootSize = (kBlendModesCount + 2) * kLaneWidth;
+ const int kLaneWidth = 2;
+ const int kLaneHeight = kLaneWidth;
+ const int kRootWidth = (kBlendModesCount + 2) * kLaneWidth;
+ const int kRootHeight = 2 * kLaneWidth + kLaneHeight;
scoped_refptr<SolidColorLayer> background =
- CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange);
+ CreateSolidColorLayer(gfx::Rect(kRootWidth, kRootHeight), kCSSOrange);
// Orange child layers have a background filter set and they will blend with
// the green background
@@ -377,60 +363,111 @@
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) {
RunBlendingWithRenderPass(PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ FILE_PATH_LITERAL("blending_render_pass.png"),
kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassColorMatrix_Software) {
RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ FILE_PATH_LITERAL("blending_render_pass.png"),
kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) {
RunBlendingWithRenderPass(PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ FILE_PATH_LITERAL("blending_render_pass.png"),
kUseAntialiasing | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassColorMatrixAA_Software) {
RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ FILE_PATH_LITERAL("blending_render_pass.png"),
kUseAntialiasing | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrix_GL) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseColorMatrix);
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrix_Software) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseColorMatrix);
+ RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrixAA_GL) {
- RunBlendingWithRenderPass(
- PIXEL_TEST_GL,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseAntialiasing | kUseColorMatrix);
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
}
TEST_F(LayerTreeHostBlendingPixelTest,
BlendingWithRenderPassWithMaskColorMatrixAA_Software) {
+ RunBlendingWithRenderPass(PIXEL_TEST_SOFTWARE,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
+}
+
+// Tests for render passes forcing shaders for all the blend modes.
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShaders_GL) {
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassShadersAA_GL) {
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMask_GL) {
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskAA_GL) {
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersColorMatrix_GL) {
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersColorMatrixAA_GL) {
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskColorMatrix_GL) {
+ RunBlendingWithRenderPass(PIXEL_TEST_GL,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseColorMatrix | kForceShaders);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassShadersWithMaskColorMatrixAA_GL) {
RunBlendingWithRenderPass(
- PIXEL_TEST_SOFTWARE,
- FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
- kUseMasks | kUseAntialiasing | kUseColorMatrix);
+ PIXEL_TEST_GL, FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix | kForceShaders);
}
} // namespace
diff --git a/cc/trees/layer_tree_host_pixeltest_filters.cc b/cc/trees/layer_tree_host_pixeltest_filters.cc
index 40fa2c3..dc8cc4a 100644
--- a/cc/trees/layer_tree_host_pixeltest_filters.cc
+++ b/cc/trees/layer_tree_host_pixeltest_filters.cc
@@ -136,8 +136,8 @@
blur->SetBackgroundFilters(filters);
#if defined(OS_WIN)
- // Windows has 153 pixels off by at most 2: crbug.com/225027
- float percentage_pixels_large_error = 0.3825f; // 153px / (200*200)
+ // Windows has 116 pixels off by at most 2: crbug.com/225027
+ float percentage_pixels_large_error = 0.3f; // 116px / (200*200), rounded up
float percentage_pixels_small_error = 0.0f;
float average_error_allowed_in_bad_pixels = 1.f;
int large_error_allowed = 2;
@@ -277,6 +277,63 @@
RunPixelTestType(PIXEL_TEST_SOFTWARE);
}
+TEST_F(LayerTreeHostFiltersPixelTest, ImageFilterScaled_GL) {
+ scoped_refptr<SolidColorLayer> background =
+ CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
+
+ gfx::Rect rect(50, 50, 100, 100);
+
+ static const int kInset = 3;
+ for (int i = 0; !rect.IsEmpty(); ++i) {
+ scoped_refptr<SolidColorLayer> layer =
+ CreateSolidColorLayer(rect, (i & 1) ? SK_ColorWHITE : SK_ColorRED);
+
+ gfx::Transform transform;
+ transform.Translate(rect.width() / 2.0, rect.height() / 2.0);
+ transform.RotateAboutZAxis(30.0);
+ transform.Translate(-rect.width() / 2.0, -rect.height() / 2.0);
+ layer->SetTransform(transform);
+
+ background->AddChild(layer);
+
+ rect.Inset(kInset, kInset);
+ }
+
+ scoped_refptr<SolidColorLayer> filter =
+ CreateSolidColorLayer(gfx::Rect(100, 0, 100, 200), SK_ColorTRANSPARENT);
+
+ background->AddChild(filter);
+
+ // Apply a scale to |background| so that we can see any scaling artifacts that
+ // may appear.
+ gfx::Transform background_transform;
+ static float scale = 1.1f;
+ background_transform.Scale(scale, scale);
+ background->SetTransform(background_transform);
+
+ FilterOperations filters;
+ filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f));
+ filter->SetBackgroundFilters(filters);
+
+#if defined(OS_WIN)
+ // Windows has 153 pixels off by at most 2: crbug.com/225027
+ float percentage_pixels_large_error = 0.3825f; // 153px / (200*200)
+ float percentage_pixels_small_error = 0.0f;
+ float average_error_allowed_in_bad_pixels = 1.f;
+ int large_error_allowed = 2;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(new FuzzyPixelComparator(
+ true, // discard_alpha
+ percentage_pixels_large_error, percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels, large_error_allowed,
+ small_error_allowed));
+#endif
+
+ // TODO(hendrikw): Enable test in software as well: crbug.com/432157
+ RunPixelTest(PIXEL_TEST_GL, background,
+ base::FilePath(FILE_PATH_LITERAL("filter_on_scaled_layer.png")));
+}
+
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 0859d86..5c66790 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -67,6 +67,151 @@
class LayerTreeHostTest : public LayerTreeTest {};
+// Test if the LTHI receives ReadyToActivate notifications from the TileManager
+// when no raster tasks get scheduled.
+class LayerTreeHostTestReadyToActivateEmpty : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestReadyToActivateEmpty()
+ : did_notify_ready_to_activate_(false),
+ all_tiles_required_for_activation_are_ready_to_draw_(false),
+ required_for_activation_count_(0) {}
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
+ const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+ required_for_activation_count_ = 0;
+ for (const auto& layer : layers) {
+ FakePictureLayerImpl* fake_layer =
+ static_cast<FakePictureLayerImpl*>(layer);
+ required_for_activation_count_ +=
+ fake_layer->CountTilesRequiredForActivation();
+ }
+ }
+
+ void NotifyReadyToActivateOnThread(LayerTreeHostImpl* impl) override {
+ did_notify_ready_to_activate_ = true;
+ const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+ all_tiles_required_for_activation_are_ready_to_draw_ = true;
+ for (const auto& layer : layers) {
+ if (!layer->AllTilesRequiredForActivationAreReadyToDraw())
+ all_tiles_required_for_activation_are_ready_to_draw_ = false;
+ }
+ EndTest();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_activate_);
+ EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_);
+ EXPECT_EQ(size_t(0), required_for_activation_count_);
+ }
+
+ protected:
+ bool did_notify_ready_to_activate_;
+ bool all_tiles_required_for_activation_are_ready_to_draw_;
+ size_t required_for_activation_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateEmpty);
+
+// Test if the LTHI receives ReadyToActivate notifications from the TileManager
+// when some raster tasks flagged as REQUIRED_FOR_ACTIVATION got scheduled.
+class LayerTreeHostTestReadyToActivateNonEmpty
+ : public LayerTreeHostTestReadyToActivateEmpty {
+ public:
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(1024, 1024));
+ root_layer->SetIsDrawable(true);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_activate_);
+ EXPECT_TRUE(all_tiles_required_for_activation_are_ready_to_draw_);
+ EXPECT_LE(size_t(1), required_for_activation_count_);
+ }
+
+ private:
+ FakeContentLayerClient client_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToActivateNonEmpty);
+
+// Test if the LTHI receives ReadyToDraw notifications from the TileManager when
+// no raster tasks get scheduled.
+class LayerTreeHostTestReadyToDrawEmpty : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestReadyToDrawEmpty()
+ : did_notify_ready_to_draw_(false),
+ all_tiles_required_for_draw_are_ready_to_draw_(false),
+ required_for_draw_count_(0) {}
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ void NotifyReadyToDrawOnThread(LayerTreeHostImpl* impl) override {
+ did_notify_ready_to_draw_ = true;
+ const std::vector<PictureLayerImpl*>& layers = impl->GetPictureLayers();
+ all_tiles_required_for_draw_are_ready_to_draw_ = true;
+ for (const auto& layer : layers) {
+ if (!layer->AllTilesRequiredForDrawAreReadyToDraw())
+ all_tiles_required_for_draw_are_ready_to_draw_ = false;
+ FakePictureLayerImpl* fake_layer =
+ static_cast<FakePictureLayerImpl*>(layer);
+ required_for_draw_count_ += fake_layer->CountTilesRequiredForDraw();
+ }
+
+ EndTest();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_draw_);
+ EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_);
+ EXPECT_EQ(size_t(0), required_for_draw_count_);
+ }
+
+ protected:
+ bool did_notify_ready_to_draw_;
+ bool all_tiles_required_for_draw_are_ready_to_draw_;
+ size_t required_for_draw_count_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToDrawEmpty);
+
+// Test if the LTHI receives ReadyToDraw notifications from the TileManager when
+// some raster tasks flagged as REQUIRED_FOR_DRAW got scheduled.
+class LayerTreeHostTestReadyToDrawNonEmpty
+ : public LayerTreeHostTestReadyToDrawEmpty {
+ public:
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+ scoped_refptr<FakePictureLayer> root_layer =
+ FakePictureLayer::Create(&client_);
+ root_layer->SetBounds(gfx::Size(1024, 1024));
+ root_layer->SetIsDrawable(true);
+
+ layer_tree_host()->SetRootLayer(root_layer);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void AfterTest() override {
+ EXPECT_TRUE(did_notify_ready_to_draw_);
+ EXPECT_TRUE(all_tiles_required_for_draw_are_ready_to_draw_);
+ EXPECT_LE(size_t(1), required_for_draw_count_);
+ }
+
+ private:
+ FakeContentLayerClient client_;
+};
+
+// Note: With this test setup, we only get tiles flagged as REQUIRED_FOR_DRAW in
+// single threaded mode.
+SINGLE_THREAD_IMPL_TEST_F(LayerTreeHostTestReadyToDrawNonEmpty);
+
// Two setNeedsCommits in a row should lead to at least 1 commit and at least 1
// draw with frame 0.
class LayerTreeHostTestSetNeedsCommit1 : public LayerTreeHostTest {
@@ -1969,7 +2114,8 @@
shared_bitmap_manager.get(),
NULL,
settings,
- base::MessageLoopProxy::current());
+ base::MessageLoopProxy::current(),
+ nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -1991,7 +2137,8 @@
shared_bitmap_manager.get(),
NULL,
settings,
- base::MessageLoopProxy::current());
+ base::MessageLoopProxy::current(),
+ nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2013,7 +2160,8 @@
shared_bitmap_manager.get(),
NULL,
settings,
- base::MessageLoopProxy::current());
+ base::MessageLoopProxy::current(),
+ nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2036,7 +2184,8 @@
shared_bitmap_manager.get(),
NULL,
settings,
- base::MessageLoopProxy::current());
+ base::MessageLoopProxy::current(),
+ nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2225,7 +2374,7 @@
class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->begin_frame_scheduling_enabled = true;
+ settings->use_external_begin_frame_source = true;
}
void BeginTest() override {
@@ -2253,7 +2402,7 @@
: public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->begin_frame_scheduling_enabled = true;
+ settings->use_external_begin_frame_source = true;
settings->using_synchronous_renderer_compositor = true;
}
@@ -2280,7 +2429,7 @@
: commit_count_(0), commit_abort_count_(0), commit_complete_count_(0) {}
void InitializeSettings(LayerTreeSettings* settings) override {
- settings->begin_frame_scheduling_enabled = true;
+ settings->use_external_begin_frame_source = true;
}
void BeginTest() override { PostSetNeedsCommitToMainThread(); }
@@ -4739,12 +4888,12 @@
void BeginTest() override {
Layer* root = layer_tree_host()->root_layer();
PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Verify default values.
EXPECT_TRUE(root->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
@@ -4795,12 +4944,12 @@
void BeginTest() override {
Layer* root = layer_tree_host()->root_layer();
PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Verify default values.
EXPECT_TRUE(root->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
EXPECT_FALSE(layer_tree_host()->UseGpuRasterization());
@@ -4810,8 +4959,8 @@
EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
// Content-based veto is relevant as well.
- pile->SetUnsuitableForGpuRasterizationForTesting();
- EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ recording_source->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
// Veto will take effect when layers are updated.
// The results will be verified after commit is completed below.
@@ -4860,12 +5009,12 @@
void BeginTest() override {
Layer* root = layer_tree_host()->root_layer();
PictureLayer* layer = static_cast<PictureLayer*>(root->child_at(0));
- PicturePile* pile = layer->GetPicturePileForTesting();
+ RecordingSource* recording_source = layer->GetRecordingSourceForTesting();
// Verify default values.
EXPECT_TRUE(root->IsSuitableForGpuRasterization());
EXPECT_TRUE(layer->IsSuitableForGpuRasterization());
- EXPECT_TRUE(pile->is_suitable_for_gpu_rasterization());
+ EXPECT_TRUE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer_tree_host()->has_gpu_rasterization_trigger());
// With gpu rasterization forced, gpu rasterization trigger is irrelevant.
@@ -4875,8 +5024,8 @@
EXPECT_TRUE(layer_tree_host()->UseGpuRasterization());
// Content-based veto is irrelevant as well.
- pile->SetUnsuitableForGpuRasterizationForTesting();
- EXPECT_FALSE(pile->is_suitable_for_gpu_rasterization());
+ recording_source->SetUnsuitableForGpuRasterizationForTesting();
+ EXPECT_FALSE(recording_source->IsSuitableForGpuRasterization());
EXPECT_FALSE(layer->IsSuitableForGpuRasterization());
// Veto will take effect when layers are updated.
// The results will be verified after commit is completed below.
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index cfd8a14..9c346e2 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -348,8 +348,9 @@
LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree()
: active_tree_was_animated_(false) {}
- base::TimeDelta LowFrequencyAnimationInterval() const override {
- return base::TimeDelta::FromMilliseconds(4);
+ base::TimeDelta BackgroundAnimationInterval(LayerTreeHostImpl* host_impl) {
+ return base::TimeDelta::FromSecondsD(
+ 1.0 / host_impl->settings().background_animation_rate);
}
void BeginTest() override {
@@ -409,10 +410,9 @@
FROM_HERE,
base::Bind(
&LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree::
- UnblockActivations,
- base::Unretained(this),
- host_impl),
- 4 * LowFrequencyAnimationInterval());
+ UnblockActivations,
+ base::Unretained(this), host_impl),
+ 4 * BackgroundAnimationInterval(host_impl));
}
}
@@ -447,10 +447,9 @@
FROM_HERE,
base::Bind(
&LayerTreeHostAnimationTestNoBackgroundTickingWithoutActiveTree::
- InitiateNextCommit,
- base::Unretained(this),
- host_impl),
- 4 * LowFrequencyAnimationInterval());
+ InitiateNextCommit,
+ base::Unretained(this), host_impl),
+ 4 * BackgroundAnimationInterval(host_impl));
}
}
@@ -505,10 +504,10 @@
const FloatAnimationCurve* curve =
animation->curve()->ToFloatAnimationCurve();
float start_opacity = curve->GetValue(0.0);
- float end_opacity = curve->GetValue(curve->Duration());
+ float end_opacity = curve->GetValue(curve->Duration().InSecondsF());
float linearly_interpolated_opacity =
0.25f * end_opacity + 0.75f * start_opacity;
- double time = curve->Duration() * 0.25;
+ double time = curve->Duration().InSecondsF() * 0.25;
// If the linear timing function associated with this animation was not
// picked up, then the linearly interpolated opacity would be different
// because of the default ease timing function.
diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
index aa5a508..a0b2bdf 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -13,6 +13,7 @@
#include "cc/output/output_surface.h"
#include "cc/output/output_surface_client.h"
#include "cc/resources/resource_provider.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/test/fake_delegated_renderer_layer.h"
#include "cc/test/test_context_provider.h"
#include "cc/trees/layer_tree_host.h"
@@ -99,7 +100,7 @@
LayerTreeSettings settings;
settings.single_thread_proxy_scheduler = false;
layer_tree_host_ = LayerTreeHost::CreateSingleThreaded(
- this, this, NULL, NULL, settings, NULL);
+ this, this, nullptr, nullptr, settings, nullptr, nullptr);
layer_tree_host_->SetViewportSize(size_);
layer_tree_host_->SetRootLayer(root_layer_);
}
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index e922f21..6526ff8 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -8,6 +8,7 @@
#include "cc/layers/layer.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/test/fake_content_layer_client.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_picture_layer.h"
@@ -1091,13 +1092,6 @@
*received_stop_flinging_ = true;
}
- void DidOverscroll(const gfx::PointF& causal_event_viewport_point,
- const gfx::Vector2dF& accumulated_overscroll,
- const gfx::Vector2dF& latest_overscroll_delta) override {
- if (!task_runner_->BelongsToCurrentThread())
- ADD_FAILURE() << "DidOverscroll called on wrong thread";
- }
-
private:
base::SingleThreadTaskRunner* task_runner_;
bool* received_stop_flinging_;
@@ -1129,7 +1123,8 @@
NULL,
settings,
base::MessageLoopProxy::current(),
- impl_thread.message_loop_proxy());
+ impl_thread.message_loop_proxy(),
+ nullptr);
impl_thread.message_loop_proxy()
->PostTask(FROM_HERE,
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 1d5cf1b..48c4133 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -16,9 +16,11 @@
: impl_side_painting(false),
allow_antialiasing(true),
force_antialiasing(false),
+ force_blending_with_shaders(false),
throttle_frame_production(true),
single_thread_proxy_scheduler(true),
- begin_frame_scheduling_enabled(false),
+ use_external_begin_frame_source(false),
+ forward_begin_frames_to_children(false),
main_frame_before_activation_enabled(false),
using_synchronous_renderer_compositor(false),
disable_hi_res_timer_tasks_on_battery(false),
@@ -47,6 +49,7 @@
top_controls_show_threshold(0.5f),
top_controls_hide_threshold(0.5f),
refresh_rate(60.0),
+ background_animation_rate(1.0),
max_partial_texture_updates(std::numeric_limits<size_t>::max()),
default_tile_size(gfx::Size(256, 256)),
max_untiled_layer_size(gfx::Size(512, 512)),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 74a3b0c..3097e59 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -21,9 +21,11 @@
bool impl_side_painting;
bool allow_antialiasing;
bool force_antialiasing;
+ bool force_blending_with_shaders;
bool throttle_frame_production;
bool single_thread_proxy_scheduler;
- bool begin_frame_scheduling_enabled;
+ bool use_external_begin_frame_source;
+ bool forward_begin_frames_to_children;
bool main_frame_before_activation_enabled;
bool using_synchronous_renderer_compositor;
bool disable_hi_res_timer_tasks_on_battery;
@@ -58,6 +60,7 @@
float top_controls_show_threshold;
float top_controls_hide_threshold;
double refresh_rate;
+ double background_animation_rate;
size_t max_partial_texture_updates;
gfx::Size default_tile_size;
gfx::Size max_untiled_layer_size;
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 1af657a..f15c7ec 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -23,15 +23,20 @@
scoped_ptr<Proxy> SingleThreadProxy::Create(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner) {
- return make_scoped_ptr(
- new SingleThreadProxy(layer_tree_host, client, main_task_runner));
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+ return make_scoped_ptr(new SingleThreadProxy(
+ layer_tree_host,
+ client,
+ main_task_runner,
+ external_begin_frame_source.Pass()));
}
SingleThreadProxy::SingleThreadProxy(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
: Proxy(main_task_runner, NULL),
layer_tree_host_(layer_tree_host),
client_(client),
@@ -43,6 +48,7 @@
commit_requested_(false),
inside_synchronous_composite_(false),
output_surface_creation_requested_(false),
+ external_begin_frame_source_(external_begin_frame_source.Pass()),
weak_factory_(this) {
TRACE_EVENT0("cc", "SingleThreadProxy::SingleThreadProxy");
DCHECK(Proxy::IsMainThread());
@@ -84,11 +90,13 @@
if (layer_tree_host_->settings().single_thread_proxy_scheduler &&
!scheduler_on_impl_thread_) {
SchedulerSettings scheduler_settings(layer_tree_host_->settings());
- scheduler_on_impl_thread_ = Scheduler::Create(this,
- scheduler_settings,
- layer_tree_host_->id(),
- MainThreadTaskRunner(),
- base::PowerMonitor::Get());
+ scheduler_on_impl_thread_ =
+ Scheduler::Create(this,
+ scheduler_settings,
+ layer_tree_host_->id(),
+ MainThreadTaskRunner(),
+ base::PowerMonitor::Get(),
+ external_begin_frame_source_.Pass());
scheduler_on_impl_thread_->SetCanStart();
scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
}
@@ -101,7 +109,6 @@
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->SetVisible(layer_tree_host_impl_->visible());
// Changing visibility could change ShouldComposite().
- UpdateBackgroundAnimateTicking();
}
void SingleThreadProxy::RequestNewOutputSurface() {
@@ -161,6 +168,24 @@
SetNeedsCommit();
}
+void SingleThreadProxy::DoAnimate() {
+ // Don't animate if there is no root layer.
+ // TODO(mithro): Both Animate and UpdateAnimationState already have a
+ // "!active_tree_->root_layer()" check?
+ if (!layer_tree_host_impl_->active_tree()->root_layer()) {
+ return;
+ }
+
+ layer_tree_host_impl_->Animate(
+ layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
+
+ // If animations are not visible, update the animation state now as it
+ // won't happen in DoComposite.
+ if (!layer_tree_host_impl_->AnimationsAreVisible()) {
+ layer_tree_host_impl_->UpdateAnimationState(true);
+ }
+}
+
void SingleThreadProxy::DoCommit() {
TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
DCHECK(Proxy::IsMainThread());
@@ -202,8 +227,6 @@
layer_tree_host_impl_->CommitComplete();
- UpdateBackgroundAnimateTicking();
-
#if DCHECK_IS_ON
// In the single-threaded case, the scale and scroll deltas should never be
// touched on the impl layer tree.
@@ -212,12 +235,6 @@
DCHECK(!scroll_info->scrolls.size());
DCHECK_EQ(1.f, scroll_info->page_scale_delta);
#endif
-
- RenderingStatsInstrumentation* stats_instrumentation =
- layer_tree_host_->rendering_stats_instrumentation();
- benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
- stats_instrumentation->main_thread_rendering_stats());
- stats_instrumentation->AccumulateAndClearMainThreadStats();
}
if (layer_tree_host_->settings().impl_side_painting) {
@@ -328,7 +345,6 @@
TRACE_EVENT1(
"cc", "SingleThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
DCHECK(Proxy::IsImplThread());
- UpdateBackgroundAnimateTicking();
if (scheduler_on_impl_thread_)
scheduler_on_impl_thread_->SetCanDraw(can_draw);
}
@@ -340,6 +356,9 @@
scheduler_on_impl_thread_->NotifyReadyToActivate();
}
+void SingleThreadProxy::NotifyReadyToDraw() {
+}
+
void SingleThreadProxy::SetNeedsRedrawOnImplThread() {
client_->ScheduleComposite();
if (scheduler_on_impl_thread_)
@@ -347,7 +366,9 @@
}
void SingleThreadProxy::SetNeedsAnimateOnImplThread() {
- SetNeedsRedrawOnImplThread();
+ client_->ScheduleComposite();
+ if (scheduler_on_impl_thread_)
+ scheduler_on_impl_thread_->SetNeedsAnimate();
}
void SingleThreadProxy::SetNeedsManageTilesOnImplThread() {
@@ -420,7 +441,6 @@
weak_factory_.GetWeakPtr()));
}
- UpdateBackgroundAnimateTicking();
timing_history_.DidActivateSyncTree();
}
@@ -498,6 +518,8 @@
layer_tree_host_impl_->SynchronouslyInitializeAllTiles();
}
+ DoAnimate();
+
LayerTreeHostImpl::FrameData frame;
DoComposite(frame_begin_time, &frame);
@@ -539,12 +561,6 @@
layer_tree_host_impl_->CanDraw();
}
-void SingleThreadProxy::UpdateBackgroundAnimateTicking() {
- DCHECK(Proxy::IsImplThread());
- layer_tree_host_impl_->UpdateBackgroundAnimateTicking(
- !ShouldComposite() && layer_tree_host_impl_->active_tree()->root_layer());
-}
-
void SingleThreadProxy::ScheduleRequestNewOutputSurface() {
if (output_surface_creation_callback_.IsCancelled() &&
!output_surface_creation_requested_) {
@@ -572,16 +588,11 @@
// DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
// CanDraw() as well.
if (!ShouldComposite()) {
- UpdateBackgroundAnimateTicking();
return DRAW_ABORTED_CANT_DRAW;
}
timing_history_.DidStartDrawing();
- layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
- UpdateBackgroundAnimateTicking();
-
draw_result = layer_tree_host_impl_->PrepareToDraw(frame);
draw_frame = draw_result == DRAW_SUCCESS;
if (draw_frame)
@@ -629,10 +640,6 @@
return false;
}
-BeginFrameSource* SingleThreadProxy::ExternalBeginFrameSource() {
- return layer_tree_host_impl_.get();
-}
-
void SingleThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
layer_tree_host_impl_->WillBeginImplFrame(args);
}
@@ -742,8 +749,8 @@
void SingleThreadProxy::ScheduledActionAnimate() {
TRACE_EVENT0("cc", "ScheduledActionAnimate");
- layer_tree_host_impl_->Animate(
- layer_tree_host_impl_->CurrentBeginFrameArgs().frame_time);
+ DebugScopedSetImplThread impl(this);
+ DoAnimate();
}
void SingleThreadProxy::ScheduledActionUpdateVisibleTiles() {
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 5b3766b..fa300de 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -19,6 +19,7 @@
namespace cc {
+class BeginFrameSource;
class ContextProvider;
class LayerTreeHost;
class LayerTreeHostSingleThreadClient;
@@ -30,7 +31,8 @@
static scoped_ptr<Proxy> Create(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
~SingleThreadProxy() override;
// Proxy implementation
@@ -59,7 +61,6 @@
bool MainFrameWillHappenForTesting() override;
// SchedulerClient implementation
- BeginFrameSource* ExternalBeginFrameSource() override;
void WillBeginImplFrame(const BeginFrameArgs& args) override;
void ScheduledActionSendBeginMainFrame() override;
DrawResult ScheduledActionDrawAndSwapIfPossible() override;
@@ -87,6 +88,7 @@
void DidSwapBuffersCompleteOnImplThread() override;
void OnCanDrawStateChanged(bool can_draw) override;
void NotifyReadyToActivate() override;
+ void NotifyReadyToDraw() override;
void SetNeedsRedrawOnImplThread() override;
void SetNeedsRedrawRectOnImplThread(const gfx::Rect& dirty_rect) override;
void SetNeedsAnimateOnImplThread() override;
@@ -114,10 +116,12 @@
SingleThreadProxy(
LayerTreeHost* layer_tree_host,
LayerTreeHostSingleThreadClient* client,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
void BeginMainFrame();
void BeginMainFrameAbortedOnImplThread();
+ void DoAnimate();
void DoBeginMainFrame(const BeginFrameArgs& begin_frame_args);
void DoCommit();
DrawResult DoComposite(base::TimeTicks frame_begin_time,
@@ -127,7 +131,6 @@
void CommitComplete();
bool ShouldComposite() const;
- void UpdateBackgroundAnimateTicking();
void ScheduleRequestNewOutputSurface();
// Accessed on main thread only.
@@ -160,6 +163,8 @@
// This is the callback for the scheduled RequestNewOutputSurface.
base::CancelableClosure output_surface_creation_callback_;
+ scoped_ptr<BeginFrameSource> external_begin_frame_source_;
+
base::WeakPtrFactory<SingleThreadProxy> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SingleThreadProxy);
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 14e2181..0f7a2a3 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -48,22 +48,27 @@
scoped_ptr<Proxy> ThreadProxy::Create(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner) {
- return make_scoped_ptr(
- new ThreadProxy(layer_tree_host, main_task_runner, impl_task_runner));
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source) {
+ return make_scoped_ptr(new ThreadProxy(layer_tree_host,
+ main_task_runner,
+ impl_task_runner,
+ external_begin_frame_source.Pass()));
}
ThreadProxy::ThreadProxy(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner)
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
: Proxy(main_task_runner, impl_task_runner),
main_thread_only_vars_unsafe_(this, layer_tree_host->id()),
main_thread_or_blocked_vars_unsafe_(layer_tree_host),
compositor_thread_vars_unsafe_(
this,
layer_tree_host->id(),
- layer_tree_host->rendering_stats_instrumentation()) {
+ layer_tree_host->rendering_stats_instrumentation(),
+ external_begin_frame_source.Pass()) {
TRACE_EVENT0("cc", "ThreadProxy::ThreadProxy");
DCHECK(IsMainThread());
DCHECK(this->layer_tree_host());
@@ -99,7 +104,8 @@
ThreadProxy::CompositorThreadOnly::CompositorThreadOnly(
ThreadProxy* proxy,
int layer_tree_host_id,
- RenderingStatsInstrumentation* rendering_stats_instrumentation)
+ RenderingStatsInstrumentation* rendering_stats_instrumentation,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source)
: layer_tree_host_id(layer_tree_host_id),
contents_texture_manager(NULL),
commit_completion_event(NULL),
@@ -113,6 +119,7 @@
base::TimeDelta::FromMilliseconds(
kSmoothnessTakesPriorityExpirationDelay * 1000)),
timing_history(rendering_stats_instrumentation),
+ external_begin_frame_source(external_begin_frame_source.Pass()),
weak_factory(proxy) {
}
@@ -176,18 +183,9 @@
TRACE_EVENT0("cc", "ThreadProxy::SetVisibleOnImplThread");
impl().layer_tree_host_impl->SetVisible(visible);
impl().scheduler->SetVisible(visible);
- UpdateBackgroundAnimateTicking();
completion->Signal();
}
-void ThreadProxy::UpdateBackgroundAnimateTicking() {
- bool should_background_tick =
- !impl().scheduler->WillDrawIfNeeded() &&
- impl().layer_tree_host_impl->active_tree()->root_layer();
- impl().layer_tree_host_impl->UpdateBackgroundAnimateTicking(
- should_background_tick);
-}
-
void ThreadProxy::DidLoseOutputSurface() {
TRACE_EVENT0("cc", "ThreadProxy::DidLoseOutputSurface");
DCHECK(IsMainThread());
@@ -345,10 +343,6 @@
base::Bind(&ThreadProxy::DidCompleteSwapBuffers, main_thread_weak_ptr_));
}
-BeginFrameSource* ThreadProxy::ExternalBeginFrameSource() {
- return impl().layer_tree_host_impl.get();
-}
-
void ThreadProxy::WillBeginImplFrame(const BeginFrameArgs& args) {
impl().layer_tree_host_impl->WillBeginImplFrame(args);
}
@@ -358,7 +352,6 @@
"cc", "ThreadProxy::OnCanDrawStateChanged", "can_draw", can_draw);
DCHECK(IsImplThread());
impl().scheduler->SetCanDraw(can_draw);
- UpdateBackgroundAnimateTicking();
}
void ThreadProxy::NotifyReadyToActivate() {
@@ -366,6 +359,11 @@
impl().scheduler->NotifyReadyToActivate();
}
+void ThreadProxy::NotifyReadyToDraw() {
+ TRACE_EVENT0("cc", "ThreadProxy::NotifyReadyToDraw");
+ impl().scheduler->NotifyReadyToDraw();
+}
+
void ThreadProxy::SetNeedsCommitOnImplThread() {
TRACE_EVENT0("cc", "ThreadProxy::SetNeedsCommitOnImplThread");
DCHECK(IsImplThread());
@@ -851,12 +849,6 @@
&completion,
queue.release()));
completion.Wait();
-
- RenderingStatsInstrumentation* stats_instrumentation =
- layer_tree_host()->rendering_stats_instrumentation();
- benchmark_instrumentation::IssueMainThreadRenderingStatsEvent(
- stats_instrumentation->main_thread_rendering_stats());
- stats_instrumentation->AccumulateAndClearMainThreadStats();
}
layer_tree_host()->CommitComplete();
@@ -933,9 +925,22 @@
TRACE_EVENT0("cc", "ThreadProxy::ScheduledActionAnimate");
DCHECK(IsImplThread());
+ // Don't animate if there is no root layer.
+ // TODO(mithro): Both Animate and UpdateAnimationState already have a
+ // "!active_tree_->root_layer()" check?
+ if (!impl().layer_tree_host_impl->active_tree()->root_layer()) {
+ return;
+ }
+
impl().animation_time =
impl().layer_tree_host_impl->CurrentBeginFrameArgs().frame_time;
impl().layer_tree_host_impl->Animate(impl().animation_time);
+
+ // If animations are not visible, update the state now as
+ // ScheduledActionDrawAndSwapIfPossible will never be called.
+ if (!impl().layer_tree_host_impl->AnimationsAreVisible()) {
+ impl().layer_tree_host_impl->UpdateAnimationState(true);
+ }
}
void ThreadProxy::ScheduledActionCommit() {
@@ -979,8 +984,6 @@
SetInputThrottledUntilCommitOnImplThread(false);
- UpdateBackgroundAnimateTicking();
-
impl().next_frame_is_newly_committed_frame = true;
impl().timing_history.DidCommit();
@@ -1149,13 +1152,14 @@
impl().layer_tree_host_impl =
layer_tree_host()->CreateLayerTreeHostImpl(this);
SchedulerSettings scheduler_settings(layer_tree_host()->settings());
- impl().scheduler = Scheduler::Create(this,
- scheduler_settings,
- impl().layer_tree_host_id,
- ImplThreadTaskRunner(),
- base::PowerMonitor::Get());
+ impl().scheduler = Scheduler::Create(
+ this,
+ scheduler_settings,
+ impl().layer_tree_host_id,
+ ImplThreadTaskRunner(),
+ base::PowerMonitor::Get(),
+ impl().external_begin_frame_source.Pass());
impl().scheduler->SetVisible(impl().layer_tree_host_impl->visible());
-
impl_thread_weak_ptr_ = impl().weak_factory.GetWeakPtr();
completion->Signal();
}
@@ -1213,7 +1217,6 @@
layer_tree_host()->DeleteContentsTexturesOnImplThread(
impl().layer_tree_host_impl->resource_provider());
impl().current_resource_update_controller = nullptr;
- impl().layer_tree_host_impl->SetNeedsBeginFrames(false);
impl().scheduler = nullptr;
impl().layer_tree_host_impl = nullptr;
impl().weak_factory.InvalidateWeakPtrs();
@@ -1358,8 +1361,6 @@
impl().completion_event_for_commit_held_on_tree_activation = NULL;
}
- UpdateBackgroundAnimateTicking();
-
impl().timing_history.DidActivateSyncTree();
}
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index 2f3e7c5..adccf72 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -25,6 +25,7 @@
namespace cc {
+class BeginFrameSource;
class ContextProvider;
class InputHandlerClient;
class LayerTreeHost;
@@ -40,7 +41,8 @@
static scoped_ptr<Proxy> Create(
LayerTreeHost* layer_tree_host,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
~ThreadProxy() override;
@@ -96,7 +98,8 @@
CompositorThreadOnly(
ThreadProxy* proxy,
int layer_tree_host_id,
- RenderingStatsInstrumentation* rendering_stats_instrumentation);
+ RenderingStatsInstrumentation* rendering_stats_instrumentation,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
~CompositorThreadOnly();
const int layer_tree_host_id;
@@ -137,6 +140,8 @@
ProxyTimingHistory timing_history;
+ scoped_ptr<BeginFrameSource> external_begin_frame_source;
+
scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl;
base::WeakPtrFactory<ThreadProxy> weak_factory;
};
@@ -182,6 +187,7 @@
void DidSwapBuffersCompleteOnImplThread() override;
void OnCanDrawStateChanged(bool can_draw) override;
void NotifyReadyToActivate() override;
+ void NotifyReadyToDraw() override;
// Please call these 3 functions through
// LayerTreeHostImpl's SetNeedsRedraw(), SetNeedsRedrawRect() and
// SetNeedsAnimate().
@@ -203,7 +209,6 @@
void DidManageTiles() override;
// SchedulerClient implementation
- BeginFrameSource* ExternalBeginFrameSource() override;
void WillBeginImplFrame(const BeginFrameArgs& args) override;
void ScheduledActionSendBeginMainFrame() override;
DrawResult ScheduledActionDrawAndSwapIfPossible() override;
@@ -224,9 +229,11 @@
void ReadyToFinalizeTextureUpdates() override;
protected:
- ThreadProxy(LayerTreeHost* layer_tree_host,
- scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
- scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner);
+ ThreadProxy(
+ LayerTreeHost* layer_tree_host,
+ scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
+ scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
+ scoped_ptr<BeginFrameSource> external_begin_frame_source);
private:
// Called on main thread.
@@ -253,7 +260,6 @@
void InitializeImplOnImplThread(CompletionEvent* completion);
void SetLayerTreeHostClientReadyOnImplThread();
void SetVisibleOnImplThread(CompletionEvent* completion, bool visible);
- void UpdateBackgroundAnimateTicking();
void HasInitializedOutputSurfaceOnImplThread(
CompletionEvent* completion,
bool* has_initialized_output_surface);
diff --git a/crypto/BUILD.gn b/crypto/BUILD.gn
index 5991d02..f342af9 100644
--- a/crypto/BUILD.gn
+++ b/crypto/BUILD.gn
@@ -124,11 +124,6 @@
deps += [ "//third_party/android_tools:cpu_features" ]
}
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
- }
-
if (use_openssl) {
# Remove NSS files when using OpenSSL
sources -= [
@@ -173,7 +168,9 @@
defines = [ "CRYPTO_IMPLEMENTATION" ]
}
-if (is_win) {
+# TODO(GYP): TODO(dpranke), fix the compile errors for this stuff
+# and make it work.
+if (false && is_win) {
# A minimal crypto subset for hmac-related stuff that small standalone
# targets can use to reduce code size on Windows. This does not depend on
# OpenSSL/NSS but will use Windows APIs for that functionality.
@@ -203,52 +200,55 @@
}
}
-test("crypto_unittests") {
- sources = [
- # Tests.
- "curve25519_unittest.cc",
- "ec_private_key_unittest.cc",
- "ec_signature_creator_unittest.cc",
- "encryptor_unittest.cc",
- "ghash_unittest.cc",
- "hkdf_unittest.cc",
- "hmac_unittest.cc",
- "nss_util_unittest.cc",
- "openssl_bio_string_unittest.cc",
- "p224_unittest.cc",
- "p224_spake_unittest.cc",
- "random_unittest.cc",
- "rsa_private_key_unittest.cc",
- "rsa_private_key_nss_unittest.cc",
- "secure_hash_unittest.cc",
- "sha2_unittest.cc",
- "signature_creator_unittest.cc",
- "signature_verifier_unittest.cc",
- "symmetric_key_unittest.cc",
- ]
-
- if (use_openssl || !is_linux) {
- sources -= [
+# TODO(GYP): Make this link on win as well.
+if (!is_win) {
+ test("crypto_unittests") {
+ sources = [
+ # Tests.
+ "curve25519_unittest.cc",
+ "ec_private_key_unittest.cc",
+ "ec_signature_creator_unittest.cc",
+ "encryptor_unittest.cc",
+ "ghash_unittest.cc",
+ "hkdf_unittest.cc",
+ "hmac_unittest.cc",
+ "nss_util_unittest.cc",
+ "openssl_bio_string_unittest.cc",
+ "p224_unittest.cc",
+ "p224_spake_unittest.cc",
+ "random_unittest.cc",
+ "rsa_private_key_unittest.cc",
"rsa_private_key_nss_unittest.cc",
+ "secure_hash_unittest.cc",
+ "sha2_unittest.cc",
+ "signature_creator_unittest.cc",
+ "signature_verifier_unittest.cc",
+ "symmetric_key_unittest.cc",
+ ]
+
+ if (use_openssl || !is_linux) {
+ sources -= [
+ "rsa_private_key_nss_unittest.cc",
+ ]
+ }
+
+ if (use_openssl) {
+ sources -= [ "nss_util_unittest.cc" ]
+ } else {
+ sources -= [ "openssl_bio_string_unittest.cc" ]
+ }
+
+ deps = [
+ ":crypto",
+ ":platform",
+ ":test_support",
+ "//base",
+ "//base/test:run_all_unittests",
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
]
}
-
- if (use_openssl) {
- sources -= [ "nss_util_unittest.cc" ]
- } else {
- sources -= [ "openssl_bio_string_unittest.cc" ]
- }
-
- deps = [
- ":crypto",
- ":platform",
- ":test_support",
- "//base",
- "//base/test:run_all_unittests",
- "//base/test:test_support",
- "//testing/gmock",
- "//testing/gtest",
- ]
}
source_set("test_support") {
diff --git a/crypto/ec_signature_creator_openssl.cc b/crypto/ec_signature_creator_openssl.cc
index 91e8a6a..c422cef 100644
--- a/crypto/ec_signature_creator_openssl.cc
+++ b/crypto/ec_signature_creator_openssl.cc
@@ -60,24 +60,13 @@
// The result is made of two 32-byte vectors.
const size_t kMaxBytesPerBN = 32;
- std::vector<uint8> result;
- result.resize(2 * kMaxBytesPerBN);
- memset(&result[0], 0, result.size());
+ std::vector<uint8> result(2 * kMaxBytesPerBN);
- BIGNUM* r = ecdsa_sig.get()->r;
- BIGNUM* s = ecdsa_sig.get()->s;
- int r_bytes = BN_num_bytes(r);
- int s_bytes = BN_num_bytes(s);
- // NOTE: Can't really check for equality here since sometimes the value
- // returned by BN_num_bytes() will be slightly smaller than kMaxBytesPerBN.
- if (r_bytes > static_cast<int>(kMaxBytesPerBN) ||
- s_bytes > static_cast<int>(kMaxBytesPerBN)) {
- DLOG(ERROR) << "Invalid key sizes r(" << r_bytes << ") s(" << s_bytes
- << ")";
+ if (!BN_bn2bin_padded(&result[0], kMaxBytesPerBN, ecdsa_sig->r) ||
+ !BN_bn2bin_padded(&result[kMaxBytesPerBN], kMaxBytesPerBN,
+ ecdsa_sig->s)) {
return false;
}
- BN_bn2bin(ecdsa_sig.get()->r, &result[kMaxBytesPerBN - r_bytes]);
- BN_bn2bin(ecdsa_sig.get()->s, &result[2 * kMaxBytesPerBN - s_bytes]);
out_raw_sig->swap(result);
return true;
}
diff --git a/crypto/nss_util.cc b/crypto/nss_util.cc
index 8f9865a..02c9327 100644
--- a/crypto/nss_util.cc
+++ b/crypto/nss_util.cc
@@ -835,7 +835,8 @@
base::CPU cpu;
if (cpu.has_avx_hardware() && !cpu.has_avx()) {
- base::Environment::Create()->SetVar("NSS_DISABLE_HW_AES", "1");
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ env->SetVar("NSS_DISABLE_HW_AES", "1");
}
}
}
diff --git a/crypto/rsa_private_key_nss.cc b/crypto/rsa_private_key_nss.cc
index 078544d..0065875 100644
--- a/crypto/rsa_private_key_nss.cc
+++ b/crypto/rsa_private_key_nss.cc
@@ -285,6 +285,9 @@
// and signature generation.
const unsigned int key_usage = KU_KEY_ENCIPHERMENT | KU_DATA_ENCIPHERMENT |
KU_DIGITAL_SIGNATURE;
+ // TODO(davidben): PK11_ImportDERPrivateKeyInfoAndReturnKey calls NSS's
+ // SEC_ASN1DecodeItem which does not enforce that there is no trailing
+ // data.
SECStatus rv = PK11_ImportDERPrivateKeyInfoAndReturnKey(
slot, &der_private_key_info, NULL, NULL, permanent, sensitive,
key_usage, &result->key_, NULL);
diff --git a/crypto/rsa_private_key_openssl.cc b/crypto/rsa_private_key_openssl.cc
index 053c4a2..0df1730 100644
--- a/crypto/rsa_private_key_openssl.cc
+++ b/crypto/rsa_private_key_openssl.cc
@@ -19,6 +19,9 @@
namespace {
+typedef ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type
+ ScopedPKCS8_PRIV_KEY_INFO;
+
// Function pointer definition, for injecting the required key export function
// into ExportKey, below. The supplied function should export EVP_PKEY into
// the supplied BIO, returning 1 on success or 0 on failure.
@@ -76,17 +79,16 @@
return NULL;
OpenSSLErrStackTracer err_tracer(FROM_HERE);
- // BIO_new_mem_buf is not const aware, but it does not modify the buffer.
- char* data = reinterpret_cast<char*>(const_cast<uint8*>(&input[0]));
- ScopedBIO bio(BIO_new_mem_buf(data, input.size()));
- if (!bio.get())
- return NULL;
// Importing is a little more involved than exporting, as we must first
// PKCS#8 decode the input, and then import the EVP_PKEY from Private Key
// Info structure returned.
- ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>::Type p8inf(
- d2i_PKCS8_PRIV_KEY_INFO_bio(bio.get(), NULL));
+ //
+ // TODO(davidben): This should check that |ptr| advanced to the end of |input|
+ // to ensure there is no trailing data.
+ const uint8_t* ptr = &input[0];
+ ScopedPKCS8_PRIV_KEY_INFO p8inf(
+ d2i_PKCS8_PRIV_KEY_INFO(nullptr, &ptr, input.size()));
if (!p8inf.get())
return NULL;
diff --git a/crypto/signature_verifier_openssl.cc b/crypto/signature_verifier_openssl.cc
index a855120..93ce9ba 100644
--- a/crypto/signature_verifier_openssl.cc
+++ b/crypto/signature_verifier_openssl.cc
@@ -122,8 +122,7 @@
int rv = EVP_DigestVerifyFinal(verify_context_->ctx.get(),
vector_as_array(&signature_),
signature_.size());
- // rv is -1 if a DER-encoded ECDSA signature cannot be decoded correctly.
- DCHECK_GE(rv, -1);
+ DCHECK_EQ(static_cast<int>(!!rv), rv);
Reset();
return rv == 1;
}
@@ -141,19 +140,14 @@
signature_.assign(signature, signature + signature_len);
- // BIO_new_mem_buf is not const aware, but it does not modify the buffer.
- char* data = reinterpret_cast<char*>(const_cast<uint8*>(public_key_info));
- ScopedBIO bio(BIO_new_mem_buf(data, public_key_info_len));
- if (!bio.get())
- return false;
-
- ScopedEVP_PKEY public_key(d2i_PUBKEY_bio(bio.get(), NULL));
- if (!public_key.get())
+ const uint8_t* ptr = public_key_info;
+ ScopedEVP_PKEY public_key(d2i_PUBKEY(nullptr, &ptr, public_key_info_len));
+ if (!public_key.get() || ptr != public_key_info + public_key_info_len)
return false;
verify_context_->ctx.reset(EVP_MD_CTX_create());
int rv = EVP_DigestVerifyInit(verify_context_->ctx.get(), pkey_ctx,
- digest, NULL, public_key.get());
+ digest, nullptr, public_key.get());
return rv == 1;
}
diff --git a/crypto/signature_verifier_unittest.cc b/crypto/signature_verifier_unittest.cc
index f6c42e0..b521bd7 100644
--- a/crypto/signature_verifier_unittest.cc
+++ b/crypto/signature_verifier_unittest.cc
@@ -258,6 +258,26 @@
ok = verifier.VerifyFinal();
EXPECT_FALSE(ok);
}
+
+ // Test 5: import an invalid key.
+ uint8_t bad_public_key_info[sizeof(public_key_info)];
+ memcpy(bad_public_key_info, public_key_info, sizeof(public_key_info));
+ bad_public_key_info[0] += 1; // Corrupt part of the SPKI syntax.
+ ok = verifier.VerifyInit(signature_algorithm,
+ sizeof(signature_algorithm),
+ signature, sizeof(signature),
+ bad_public_key_info, sizeof(bad_public_key_info));
+ EXPECT_FALSE(ok);
+
+ // Test 6: import a key with extra data.
+ uint8_t long_public_key_info[sizeof(public_key_info) + 5];
+ memset(long_public_key_info, 0, sizeof(long_public_key_info));
+ memcpy(long_public_key_info, public_key_info, sizeof(public_key_info));
+ ok = verifier.VerifyInit(signature_algorithm,
+ sizeof(signature_algorithm),
+ signature, sizeof(signature),
+ long_public_key_info, sizeof(long_public_key_info));
+ EXPECT_FALSE(ok);
}
//////////////////////////////////////////////////////////////////////
diff --git a/gin/isolate_holder.cc b/gin/isolate_holder.cc
index 334c0e0..2cdacc0 100644
--- a/gin/isolate_holder.cc
+++ b/gin/isolate_holder.cc
@@ -7,6 +7,7 @@
#include <stdlib.h>
#include <string.h>
+#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/message_loop/message_loop.h"
#include "base/rand_util.h"
@@ -19,7 +20,6 @@
#include "gin/run_microtasks_observer.h"
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-#include "base/files/memory_mapped_file.h"
#include "base/path_service.h"
#endif // V8_USE_EXTERNAL_STARTUP_DATA
@@ -34,10 +34,10 @@
return true;
}
-#ifdef V8_USE_EXTERNAL_STARTUP_DATA
base::MemoryMappedFile* g_mapped_natives = NULL;
base::MemoryMappedFile* g_mapped_snapshot = NULL;
+#ifdef V8_USE_EXTERNAL_STARTUP_DATA
bool MapV8Files(base::FilePath* natives_path, base::FilePath* snapshot_path,
int natives_fd = -1, int snapshot_fd = -1) {
int flags = base::File::FLAG_OPEN | base::File::FLAG_READ;
@@ -80,7 +80,13 @@
return true;
base::FilePath data_path;
- PathService::Get(base::DIR_ANDROID_APP_DATA, &data_path);
+ PathService::Get(
+#if defined(OS_ANDROID)
+ base::DIR_ANDROID_APP_DATA,
+#elif defined(OS_POSIX)
+ base::DIR_EXE,
+#endif
+ &data_path);
DCHECK(!data_path.empty());
base::FilePath natives_path = data_path.AppendASCII("natives_blob.bin");
@@ -98,6 +104,22 @@
}
#endif // V8_USE_EXTERNAL_STARTUP_DATA
+//static
+void IsolateHolder::GetV8ExternalSnapshotData(const char** natives_data_out,
+ int* natives_size_out,
+ const char** snapshot_data_out,
+ int* snapshot_size_out) {
+ if (!g_mapped_natives || !g_mapped_snapshot) {
+ *natives_data_out = *snapshot_data_out = NULL;
+ *natives_size_out = *snapshot_size_out = 0;
+ return;
+ }
+ *natives_data_out = reinterpret_cast<const char*>(g_mapped_natives->data());
+ *snapshot_data_out = reinterpret_cast<const char*>(g_mapped_snapshot->data());
+ *natives_size_out = static_cast<int>(g_mapped_natives->length());
+ *snapshot_size_out = static_cast<int>(g_mapped_snapshot->length());
+}
+
IsolateHolder::IsolateHolder() {
CHECK(g_array_buffer_allocator)
<< "You need to invoke gin::IsolateHolder::Initialize first";
@@ -158,14 +180,14 @@
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
v8::StartupData natives;
natives.data = reinterpret_cast<const char*>(g_mapped_natives->data());
- natives.raw_size = g_mapped_natives->length();
- natives.compressed_size = g_mapped_natives->length();
+ natives.raw_size = static_cast<int>(g_mapped_natives->length());
+ natives.compressed_size = static_cast<int>(g_mapped_natives->length());
v8::V8::SetNativesDataBlob(&natives);
v8::StartupData snapshot;
snapshot.data = reinterpret_cast<const char*>(g_mapped_snapshot->data());
- snapshot.raw_size = g_mapped_snapshot->length();
- snapshot.compressed_size = g_mapped_snapshot->length();
+ snapshot.raw_size = static_cast<int>(g_mapped_snapshot->length());
+ snapshot.compressed_size = static_cast<int>(g_mapped_snapshot->length());
v8::V8::SetSnapshotDataBlob(&snapshot);
#endif // V8_USE_EXTERNAL_STARTUP_DATA
v8::V8::Initialize();
diff --git a/gin/public/isolate_holder.h b/gin/public/isolate_holder.h
index 4e14ade..b12734c 100644
--- a/gin/public/isolate_holder.h
+++ b/gin/public/isolate_holder.h
@@ -52,11 +52,13 @@
void RemoveRunMicrotasksObserver();
#ifdef V8_USE_EXTERNAL_STARTUP_DATA
-#ifdef OS_ANDROID
static bool LoadV8SnapshotFD(int natives_fd, int snapshot_fd);
-#endif
static bool LoadV8Snapshot();
#endif // V8_USE_EXTERNAL_STARTUP_DATA
+ static void GetV8ExternalSnapshotData(const char** natives_data_out,
+ int* natives_size_out,
+ const char** snapshot_data_out,
+ int* snapshot_size_out);
private:
v8::Isolate* isolate_;
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index e8bf519..990cd02 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -184,6 +184,7 @@
"command_buffer/service/gles2_cmd_decoder_unittest_programs.cc",
"command_buffer/service/gles2_cmd_decoder_unittest_textures.cc",
"command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc",
+ "command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc",
"command_buffer/service/gl_surface_mock.cc",
"command_buffer/service/gl_surface_mock.h",
"command_buffer/service/gpu_scheduler_unittest.cc",
@@ -195,11 +196,13 @@
"command_buffer/service/mocks.cc",
"command_buffer/service/mocks.h",
"command_buffer/service/program_manager_unittest.cc",
+ "command_buffer/service/valuebuffer_manager_unittest.cc",
"command_buffer/service/query_manager_unittest.cc",
"command_buffer/service/renderbuffer_manager_unittest.cc",
"command_buffer/service/program_cache_unittest.cc",
"command_buffer/service/shader_manager_unittest.cc",
"command_buffer/service/shader_translator_unittest.cc",
+ "command_buffer/service/shader_translator_cache_unittest.cc",
"command_buffer/service/test_helper.cc",
"command_buffer/service/test_helper.h",
"command_buffer/service/texture_manager_unittest.cc",
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
index 0a35700..d4685d5 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_get_multiple.txt
@@ -16,8 +16,8 @@
Overview
- This extension adds the ability to query multiple state and program
- information in a single call.
+ This extension adds the ability to query multiple program information in a
+ single call.
Issues
@@ -28,27 +28,6 @@
New Procedures and Functions
- void GetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count,
- GLint* results, GLsizeiptr size)
-
- <pnames> points to an array of state enums that would normally be queried by
- GetIntegerv. <count> is the number of pnames. <results> points memory large
- enough to contain all the state being queried. <size> is the size of the
- buffer pointed to be <results>
-
- Example: <pnames> points to an array with VIEWPORT and MAX_TEXTURE_SIZE.
- VIEWPORT returns 4 values, MAX_TEXTURE_SIZE returns 1 value. Therefore
- results must point to a buffer of size 5 * sizeof(GLint) and size must be at
- least 5 * sizeof(GLint)
-
- INVALID_ENUM is generated if any of the pnames are not valid for GetIntegerv
-
- INVALID_VALUE is generated if <size> does not equal the size needed for the
- query
-
- INVALID_VALUE is generated if the memory pointed to be <results> has not
- been zeroed out.
-
void GetProgrmaInfoCHROMIUM (GLuint program, GLsizei bufsize,
GLsizei* size, void* info)
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt
new file mode 100644
index 0000000..2427d32
--- /dev/null
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_subscribe_uniform.txt
@@ -0,0 +1,113 @@
+Name
+
+ CHROMIUM_subscribe_uniform
+
+Name Strings
+
+ CHROMIUM_subscribe_uniform
+
+Version
+
+ Last Modifed Date: October 30, 2014
+
+Dependencies
+
+ OpenGL ES 2.0 is required.
+
+Overview
+
+ Allows clients to subscribe to a set of input uniforms which can
+ be populated within buffers and used to modify uniform variables within
+ their programs.
+
+ Decreases percieved latency for operations performed against these
+ uniforms.
+
+New Tokens
+
+ Accepted by the <target> parameter of glBindValueBufferCHROMIUM,
+ glSubscribeValueCHROMIUM, glPopulateSubscribedValuesCHROMIUM and
+ glUniformValueBufferCHROMIUM
+
+ GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM 0x924B
+
+ Accepted by the <subscription> parameter of glSubscribeValueCHROMIUM and
+ glUniformValueBufferCHROMIUM:
+
+ GL_MOUSE_POSITION_CHROMIUM 0x924C
+
+New Procedures and Functions
+
+ The command
+
+ void glGenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers)
+
+ Generates value buffer object names.
+ <n> Specifies the number of value buffer object names to be generated.
+ <buffers> Specifies an array in which the generated value buffer object
+ names are stored.
+
+ The command
+
+ void glDeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers)
+
+ Deletes named value buffer objects.
+ <n> Specifies the number of value buffer objects to be deleted.
+ <buffers> Specifies an array of value buffer objects to be deleted.
+
+ The command
+
+ boolean glIsValuebufferCHROMIUM(GLuint buffer);
+
+ Returns whether an object is a value buffer object.
+ <buffer> Specifies the name of a buffer object.
+
+ The command
+
+ void glBindValuebufferCHROMIUM(GLenum target, GLuint buffer);
+
+ Lets you use a named value buffer object.
+ <target> Specifies the target to which the buffer object is bound.
+ <buffer> Specifies the name of a buffer object.
+
+ The command
+
+ void glSubscribeValueCHROMIUM(GLenum target, GLenum subscription)
+
+ Subscribes the currently bound buffer object to a subscription target.
+ <target> Specifies the target to which the buffer object is bound.
+ <subscription> Specifies the subscription to which the currently bound
+ buffer object should be subscribed.
+
+ The command
+
+ void glPopulateSubscribedValuesCHROMIUM(GLenum target)
+
+ Populates the currently bound buffer object with all subscription states
+ to which it is subscribed.
+ <target> Specifies the target to which the buffer object is bound.
+
+ The command
+
+ void glUniformValueBufferCHROMIUM(GLint location, GLenum target,
+ GLenum subscription)
+
+ Populates the uniform specified by location within the currently bound
+ program with the value in the currently bound buffer for the subscription
+ target.
+ <location> Specifies the location of the uniform variable to by modified.
+ <target> Specifies the target to which the buffer object is bound.
+ <subscription> Specifies the subscription in the currently bound buffer
+ whose value should be used to populate the uniform.
+
+Errors
+
+ None.
+
+New State
+
+ None.
+
+Revision History
+
+ 10/30/2014 Documented the extension
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index c6a3919..5489d06 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -195,7 +195,6 @@
#define glRequestExtensionCHROMIUM GLES2_GET_FUN(RequestExtensionCHROMIUM)
#define glRateLimitOffscreenContextCHROMIUM \
GLES2_GET_FUN(RateLimitOffscreenContextCHROMIUM)
-#define glGetMultipleIntegervCHROMIUM GLES2_GET_FUN(GetMultipleIntegervCHROMIUM)
#define glGetProgramInfoCHROMIUM GLES2_GET_FUN(GetProgramInfoCHROMIUM)
#define glCreateStreamTextureCHROMIUM GLES2_GET_FUN(CreateStreamTextureCHROMIUM)
#define glCreateImageCHROMIUM GLES2_GET_FUN(CreateImageCHROMIUM)
@@ -218,6 +217,14 @@
#define glCreateAndConsumeTextureCHROMIUM \
GLES2_GET_FUN(CreateAndConsumeTextureCHROMIUM)
#define glBindUniformLocationCHROMIUM GLES2_GET_FUN(BindUniformLocationCHROMIUM)
+#define glGenValuebuffersCHROMIUM GLES2_GET_FUN(GenValuebuffersCHROMIUM)
+#define glDeleteValuebuffersCHROMIUM GLES2_GET_FUN(DeleteValuebuffersCHROMIUM)
+#define glIsValuebufferCHROMIUM GLES2_GET_FUN(IsValuebufferCHROMIUM)
+#define glBindValuebufferCHROMIUM GLES2_GET_FUN(BindValuebufferCHROMIUM)
+#define glSubscribeValueCHROMIUM GLES2_GET_FUN(SubscribeValueCHROMIUM)
+#define glPopulateSubscribedValuesCHROMIUM \
+ GLES2_GET_FUN(PopulateSubscribedValuesCHROMIUM)
+#define glUniformValuebufferCHROMIUM GLES2_GET_FUN(UniformValuebufferCHROMIUM)
#define glBindTexImage2DCHROMIUM GLES2_GET_FUN(BindTexImage2DCHROMIUM)
#define glReleaseTexImage2DCHROMIUM GLES2_GET_FUN(ReleaseTexImage2DCHROMIUM)
#define glTraceBeginCHROMIUM GLES2_GET_FUN(TraceBeginCHROMIUM)
diff --git a/gpu/GLES2/gl2extchromium.h b/gpu/GLES2/gl2extchromium.h
index b524112..a4017ec 100644
--- a/gpu/GLES2/gl2extchromium.h
+++ b/gpu/GLES2/gl2extchromium.h
@@ -623,13 +623,9 @@
#ifndef GL_CHROMIUM_get_multiple
#define GL_CHROMIUM_get_multiple 1
#ifdef GL_GLEXT_PROTOTYPES
-GL_APICALL void GL_APIENTRY glGetMultipleIntegervCHROMIUM(
- const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
GL_APICALL void GL_APIENTRY glGetProgramInfoCHROMIUM(
GLuint program, GLsizei bufsize, GLsizei* size, void* info);
#endif
-typedef void (GL_APIENTRYP PFNGLGETMULTIPLEINTEGERVCHROMIUMPROC) (
- const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
typedef void (GL_APIENTRYP PFNGLGETPROGRAMINFOCHROMIUMPROC) (
GLuint program, GLsizei bufsize, GLsizei* size, void* info);
#endif /* GL_CHROMIUM_get_multiple */
@@ -687,6 +683,35 @@
#define GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM 0x924A
#endif
+/* GL_CHROMIUM_subscribe_uniform */
+#ifndef GL_CHROMIUM_subscribe_uniform
+#define GL_CHROMIUM_subscribe_uniform 1
+
+#ifndef GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM
+#define GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM 0x924B
+#endif
+
+#ifndef GL_MOUSE_POSITION_CHROMIUM
+#define GL_MOUSE_POSITION_CHROMIUM 0x924C
+#endif
+
+#ifdef GL_GLEXT_PROTOTYPES
+GL_APICALL void GL_APIENTRY
+glGenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY
+glDeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers);
+GL_APICALL GLboolean GL_APIENTRY glIsValuebufferCHROMIUM(GLuint valuebuffer);
+GL_APICALL void GL_APIENTRY
+glBindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer);
+GL_APICALL void GL_APIENTRY
+glSubscribeValueCHROMIUM(GLenum target, GLenum subscription);
+GL_APICALL void GL_APIENTRY glPopulateSubscribedValuesCHROMIUM(GLenum target);
+GL_APICALL void GL_APIENTRY glUniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription);
+#endif
+#endif /* GL_CHROMIUM_subscribe_uniform */
+
#ifdef GL_GLEXT_PROTOTYPES
GL_APICALL void GL_APIENTRY
glScheduleOverlayPlaneCHROMIUM(GLint plane_z_order,
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 94c3b34..226cb73 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1195,6 +1195,18 @@
'GL_SCANOUT_CHROMIUM'
],
},
+ 'ValueBufferTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM',
+ ],
+ },
+ 'SubscriptionTarget': {
+ 'type': 'GLenum',
+ 'valid': [
+ 'GL_MOUSE_POSITION_CHROMIUM',
+ ],
+ },
'VertexAttribType': {
'type': 'GLenum',
'valid': [
@@ -1448,6 +1460,57 @@
'extension': "CHROMIUM_texture_mailbox",
'chromium': True,
},
+ 'GenValuebuffersCHROMIUM': {
+ 'type': 'GENn',
+ 'gl_test_func': 'glGenValuebuffersCHROMIUM',
+ 'resource_type': 'Valuebuffer',
+ 'resource_types': 'Valuebuffers',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'DeleteValuebuffersCHROMIUM': {
+ 'type': 'DELn',
+ 'gl_test_func': 'glDeleteValuebuffersCHROMIUM',
+ 'resource_type': 'Valuebuffer',
+ 'resource_types': 'Valuebuffers',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'IsValuebufferCHROMIUM': {
+ 'type': 'Is',
+ 'decoder_func': 'DoIsValuebufferCHROMIUM',
+ 'expectation': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'BindValuebufferCHROMIUM': {
+ 'type': 'Bind',
+ 'decoder_func': 'DoBindValueBufferCHROMIUM',
+ 'gen_func': 'GenValueBuffersCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'SubscribeValueCHROMIUM': {
+ 'decoder_func': 'DoSubscribeValueCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'PopulateSubscribedValuesCHROMIUM': {
+ 'decoder_func': 'DoPopulateSubscribedValuesCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
+ 'UniformValuebufferCHROMIUM': {
+ 'decoder_func': 'DoUniformValueBufferCHROMIUM',
+ 'unit_test': False,
+ 'extension': True,
+ 'chromium': True,
+ },
'ClearStencil': {
'type': 'StateSet',
'state': 'ClearStencil',
@@ -1807,14 +1870,6 @@
'chromium': True,
'impl_func': False,
},
- 'GetMultipleIntegervCHROMIUM': {
- 'type': 'Custom',
- 'data_transfer_methods': ['shm'],
- 'expectation': False,
- 'extension': True,
- 'chromium': True,
- 'client_test': False,
- },
'GetProgramiv': {
'type': 'GETn',
'decoder_func': 'DoGetProgramiv',
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 56f1880..b1181ae 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -751,13 +751,6 @@
void GLES2RateLimitOffscreenContextCHROMIUM() {
gles2::GetGLContext()->RateLimitOffscreenContextCHROMIUM();
}
-void GLES2GetMultipleIntegervCHROMIUM(const GLenum* pnames,
- GLuint count,
- GLint* results,
- GLsizeiptr size) {
- gles2::GetGLContext()->GetMultipleIntegervCHROMIUM(pnames, count, results,
- size);
-}
void GLES2GetProgramInfoCHROMIUM(GLuint program,
GLsizei bufsize,
GLsizei* size,
@@ -853,6 +846,30 @@
const char* name) {
gles2::GetGLContext()->BindUniformLocationCHROMIUM(program, location, name);
}
+void GLES2GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) {
+ gles2::GetGLContext()->GenValuebuffersCHROMIUM(n, buffers);
+}
+void GLES2DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) {
+ gles2::GetGLContext()->DeleteValuebuffersCHROMIUM(n, valuebuffers);
+}
+GLboolean GLES2IsValuebufferCHROMIUM(GLuint valuebuffer) {
+ return gles2::GetGLContext()->IsValuebufferCHROMIUM(valuebuffer);
+}
+void GLES2BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) {
+ gles2::GetGLContext()->BindValuebufferCHROMIUM(target, valuebuffer);
+}
+void GLES2SubscribeValueCHROMIUM(GLenum target, GLenum subscription) {
+ gles2::GetGLContext()->SubscribeValueCHROMIUM(target, subscription);
+}
+void GLES2PopulateSubscribedValuesCHROMIUM(GLenum target) {
+ gles2::GetGLContext()->PopulateSubscribedValuesCHROMIUM(target);
+}
+void GLES2UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) {
+ gles2::GetGLContext()->UniformValuebufferCHROMIUM(location, target,
+ subscription);
+}
void GLES2BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
gles2::GetGLContext()->BindTexImage2DCHROMIUM(target, imageId);
}
@@ -1654,10 +1671,6 @@
glRateLimitOffscreenContextCHROMIUM),
},
{
- "glGetMultipleIntegervCHROMIUM",
- reinterpret_cast<GLES2FunctionPointer>(glGetMultipleIntegervCHROMIUM),
- },
- {
"glGetProgramInfoCHROMIUM",
reinterpret_cast<GLES2FunctionPointer>(glGetProgramInfoCHROMIUM),
},
@@ -1731,6 +1744,34 @@
reinterpret_cast<GLES2FunctionPointer>(glBindUniformLocationCHROMIUM),
},
{
+ "glGenValuebuffersCHROMIUM",
+ reinterpret_cast<GLES2FunctionPointer>(glGenValuebuffersCHROMIUM),
+ },
+ {
+ "glDeleteValuebuffersCHROMIUM",
+ reinterpret_cast<GLES2FunctionPointer>(glDeleteValuebuffersCHROMIUM),
+ },
+ {
+ "glIsValuebufferCHROMIUM",
+ reinterpret_cast<GLES2FunctionPointer>(glIsValuebufferCHROMIUM),
+ },
+ {
+ "glBindValuebufferCHROMIUM",
+ reinterpret_cast<GLES2FunctionPointer>(glBindValuebufferCHROMIUM),
+ },
+ {
+ "glSubscribeValueCHROMIUM",
+ reinterpret_cast<GLES2FunctionPointer>(glSubscribeValueCHROMIUM),
+ },
+ {
+ "glPopulateSubscribedValuesCHROMIUM",
+ reinterpret_cast<GLES2FunctionPointer>(glPopulateSubscribedValuesCHROMIUM),
+ },
+ {
+ "glUniformValuebufferCHROMIUM",
+ reinterpret_cast<GLES2FunctionPointer>(glUniformValuebufferCHROMIUM),
+ },
+ {
"glBindTexImage2DCHROMIUM",
reinterpret_cast<GLES2FunctionPointer>(glBindTexImage2DCHROMIUM),
},
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index 9aeb449..75796a2 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -1538,20 +1538,6 @@
}
}
-void GetMultipleIntegervCHROMIUM(uint32_t pnames_shm_id,
- uint32_t pnames_shm_offset,
- GLuint count,
- uint32_t results_shm_id,
- uint32_t results_shm_offset,
- GLsizeiptr size) {
- gles2::cmds::GetMultipleIntegervCHROMIUM* c =
- GetCmdSpace<gles2::cmds::GetMultipleIntegervCHROMIUM>();
- if (c) {
- c->Init(pnames_shm_id, pnames_shm_offset, count, results_shm_id,
- results_shm_offset, size);
- }
-}
-
void GetProgramInfoCHROMIUM(GLuint program, uint32_t bucket_id) {
gles2::cmds::GetProgramInfoCHROMIUM* c =
GetCmdSpace<gles2::cmds::GetProgramInfoCHROMIUM>();
@@ -1677,6 +1663,73 @@
}
}
+void GenValuebuffersCHROMIUMImmediate(GLsizei n, GLuint* buffers) {
+ const uint32_t size =
+ gles2::cmds::GenValuebuffersCHROMIUMImmediate::ComputeSize(n);
+ gles2::cmds::GenValuebuffersCHROMIUMImmediate* c =
+ GetImmediateCmdSpaceTotalSize<
+ gles2::cmds::GenValuebuffersCHROMIUMImmediate>(size);
+ if (c) {
+ c->Init(n, buffers);
+ }
+}
+
+void DeleteValuebuffersCHROMIUMImmediate(GLsizei n,
+ const GLuint* valuebuffers) {
+ const uint32_t size =
+ gles2::cmds::DeleteValuebuffersCHROMIUMImmediate::ComputeSize(n);
+ gles2::cmds::DeleteValuebuffersCHROMIUMImmediate* c =
+ GetImmediateCmdSpaceTotalSize<
+ gles2::cmds::DeleteValuebuffersCHROMIUMImmediate>(size);
+ if (c) {
+ c->Init(n, valuebuffers);
+ }
+}
+
+void IsValuebufferCHROMIUM(GLuint valuebuffer,
+ uint32_t result_shm_id,
+ uint32_t result_shm_offset) {
+ gles2::cmds::IsValuebufferCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::IsValuebufferCHROMIUM>();
+ if (c) {
+ c->Init(valuebuffer, result_shm_id, result_shm_offset);
+ }
+}
+
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) {
+ gles2::cmds::BindValuebufferCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::BindValuebufferCHROMIUM>();
+ if (c) {
+ c->Init(target, valuebuffer);
+ }
+}
+
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) {
+ gles2::cmds::SubscribeValueCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::SubscribeValueCHROMIUM>();
+ if (c) {
+ c->Init(target, subscription);
+ }
+}
+
+void PopulateSubscribedValuesCHROMIUM(GLenum target) {
+ gles2::cmds::PopulateSubscribedValuesCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::PopulateSubscribedValuesCHROMIUM>();
+ if (c) {
+ c->Init(target);
+ }
+}
+
+void UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) {
+ gles2::cmds::UniformValuebufferCHROMIUM* c =
+ GetCmdSpace<gles2::cmds::UniformValuebufferCHROMIUM>();
+ if (c) {
+ c->Init(location, target, subscription);
+ }
+}
+
void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
gles2::cmds::BindTexImage2DCHROMIUM* c =
GetCmdSpace<gles2::cmds::BindTexImage2DCHROMIUM>();
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 66d8c2b..e7118e8 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -49,21 +49,6 @@
GLES2Implementation::GLStaticState::~GLStaticState() {
}
-GLES2Implementation::GLStaticState::IntState::IntState()
- : max_combined_texture_image_units(0),
- max_cube_map_texture_size(0),
- max_fragment_uniform_vectors(0),
- max_renderbuffer_size(0),
- max_texture_image_units(0),
- max_texture_size(0),
- max_varying_vectors(0),
- max_vertex_attribs(0),
- max_vertex_texture_image_units(0),
- max_vertex_uniform_vectors(0),
- num_compressed_texture_formats(0),
- num_shader_binary_formats(0),
- bind_generates_resource_chromium(0) {}
-
GLES2Implementation::SingleThreadChecker::SingleThreadChecker(
GLES2Implementation* gles2_implementation)
: gles2_implementation_(gles2_implementation) {
@@ -99,6 +84,7 @@
bound_framebuffer_(0),
bound_read_framebuffer_(0),
bound_renderbuffer_(0),
+ bound_valuebuffer_(0),
current_program_(0),
bound_array_buffer_id_(0),
bound_pixel_pack_transfer_buffer_id_(0),
@@ -173,17 +159,22 @@
}
mapped_memory_->set_chunk_size_multiple(chunk_size);
- if (!QueryAndCacheStaticState())
- return false;
+ GLStaticState::ShaderPrecisionMap* shader_precisions =
+ &static_state_.shader_precisions;
+ capabilities_.VisitPrecisions([shader_precisions](
+ GLenum shader, GLenum type, Capabilities::ShaderPrecision* result) {
+ const GLStaticState::ShaderPrecisionKey key(shader, type);
+ cmds::GetShaderPrecisionFormat::Result cached_result = {
+ true, result->min_range, result->max_range, result->precision};
+ shader_precisions->insert(std::make_pair(key, cached_result));
+ });
util_.set_num_compressed_texture_formats(
- static_state_.int_state.num_compressed_texture_formats);
- util_.set_num_shader_binary_formats(
- static_state_.int_state.num_shader_binary_formats);
+ capabilities_.num_compressed_texture_formats);
+ util_.set_num_shader_binary_formats(capabilities_.num_shader_binary_formats);
texture_units_.reset(
- new TextureUnit[
- static_state_.int_state.max_combined_texture_image_units]);
+ new TextureUnit[capabilities_.max_combined_texture_image_units]);
query_tracker_.reset(new QueryTracker(mapped_memory_.get()));
buffer_tracker_.reset(new BufferTracker(mapped_memory_.get()));
@@ -195,14 +186,12 @@
}
vertex_array_object_manager_.reset(new VertexArrayObjectManager(
- static_state_.int_state.max_vertex_attribs,
- reserved_ids_[0],
- reserved_ids_[1],
+ capabilities_.max_vertex_attribs, reserved_ids_[0], reserved_ids_[1],
support_client_side_arrays_));
// GL_BIND_GENERATES_RESOURCE_CHROMIUM state must be the same
// on Client & Service.
- if (static_state_.int_state.bind_generates_resource_chromium !=
+ if (capabilities_.bind_generates_resource_chromium !=
(share_group_->bind_generates_resource() ? 1 : 0)) {
SetGLError(GL_INVALID_OPERATION,
"Initialize",
@@ -213,80 +202,6 @@
return true;
}
-bool GLES2Implementation::QueryAndCacheStaticState() {
- TRACE_EVENT0("gpu", "GLES2Implementation::QueryAndCacheStaticState");
- // Setup query for multiple GetIntegerv's
- static const GLenum pnames[] = {
- GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
- GL_MAX_CUBE_MAP_TEXTURE_SIZE,
- GL_MAX_FRAGMENT_UNIFORM_VECTORS,
- GL_MAX_RENDERBUFFER_SIZE,
- GL_MAX_TEXTURE_IMAGE_UNITS,
- GL_MAX_TEXTURE_SIZE,
- GL_MAX_VARYING_VECTORS,
- GL_MAX_VERTEX_ATTRIBS,
- GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
- GL_MAX_VERTEX_UNIFORM_VECTORS,
- GL_NUM_COMPRESSED_TEXTURE_FORMATS,
- GL_NUM_SHADER_BINARY_FORMATS,
- GL_BIND_GENERATES_RESOURCE_CHROMIUM,
- };
-
- GetMultipleIntegervState integerv_state(
- pnames, arraysize(pnames),
- &static_state_.int_state.max_combined_texture_image_units,
- sizeof(static_state_.int_state));
- if (!GetMultipleIntegervSetup(&integerv_state)) {
- return false;
- }
-
- // Setup query for multiple GetShaderPrecisionFormat's
- static const GLenum precision_params[][2] = {
- { GL_VERTEX_SHADER, GL_LOW_INT },
- { GL_VERTEX_SHADER, GL_MEDIUM_INT },
- { GL_VERTEX_SHADER, GL_HIGH_INT },
- { GL_VERTEX_SHADER, GL_LOW_FLOAT },
- { GL_VERTEX_SHADER, GL_MEDIUM_FLOAT },
- { GL_VERTEX_SHADER, GL_HIGH_FLOAT },
- { GL_FRAGMENT_SHADER, GL_LOW_INT },
- { GL_FRAGMENT_SHADER, GL_MEDIUM_INT },
- { GL_FRAGMENT_SHADER, GL_HIGH_INT },
- { GL_FRAGMENT_SHADER, GL_LOW_FLOAT },
- { GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT },
- { GL_FRAGMENT_SHADER, GL_HIGH_FLOAT },
- };
-
- GetAllShaderPrecisionFormatsState precision_state(
- precision_params, arraysize(precision_params));
- GetAllShaderPrecisionFormatsSetup(&precision_state);
-
- // Allocate and partition transfer buffer for all requests
- void* buffer = transfer_buffer_->Alloc(
- integerv_state.transfer_buffer_size_needed +
- precision_state.transfer_buffer_size_needed);
- if (!buffer) {
- SetGLError(GL_OUT_OF_MEMORY, "QueryAndCacheStaticState",
- "Transfer buffer allocation failed.");
- return false;
- }
- integerv_state.buffer = buffer;
- precision_state.results_buffer =
- static_cast<char*>(buffer) + integerv_state.transfer_buffer_size_needed;
-
- // Make all the requests and wait once for all the results.
- GetMultipleIntegervRequest(&integerv_state);
- GetAllShaderPrecisionFormatsRequest(&precision_state);
- WaitForCmd();
- GetMultipleIntegervOnCompleted(&integerv_state);
- GetAllShaderPrecisionFormatsOnCompleted(&precision_state);
-
- // TODO(gman): We should be able to free without a token.
- transfer_buffer_->FreePendingToken(buffer, helper_->InsertToken());
- CheckGLError();
-
- return true;
-}
-
GLES2Implementation::~GLES2Implementation() {
// Make sure the queries are finished otherwise we'll delete the
// shared memory (mapped_memory_) which will free the memory used
@@ -683,40 +598,40 @@
bool GLES2Implementation::GetHelper(GLenum pname, GLint* params) {
switch (pname) {
case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
- *params = static_state_.int_state.max_combined_texture_image_units;
+ *params = capabilities_.max_combined_texture_image_units;
return true;
case GL_MAX_CUBE_MAP_TEXTURE_SIZE:
- *params = static_state_.int_state.max_cube_map_texture_size;
+ *params = capabilities_.max_cube_map_texture_size;
return true;
case GL_MAX_FRAGMENT_UNIFORM_VECTORS:
- *params = static_state_.int_state.max_fragment_uniform_vectors;
+ *params = capabilities_.max_fragment_uniform_vectors;
return true;
case GL_MAX_RENDERBUFFER_SIZE:
- *params = static_state_.int_state.max_renderbuffer_size;
+ *params = capabilities_.max_renderbuffer_size;
return true;
case GL_MAX_TEXTURE_IMAGE_UNITS:
- *params = static_state_.int_state.max_texture_image_units;
+ *params = capabilities_.max_texture_image_units;
return true;
case GL_MAX_TEXTURE_SIZE:
- *params = static_state_.int_state.max_texture_size;
+ *params = capabilities_.max_texture_size;
return true;
case GL_MAX_VARYING_VECTORS:
- *params = static_state_.int_state.max_varying_vectors;
+ *params = capabilities_.max_varying_vectors;
return true;
case GL_MAX_VERTEX_ATTRIBS:
- *params = static_state_.int_state.max_vertex_attribs;
+ *params = capabilities_.max_vertex_attribs;
return true;
case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
- *params = static_state_.int_state.max_vertex_texture_image_units;
+ *params = capabilities_.max_vertex_texture_image_units;
return true;
case GL_MAX_VERTEX_UNIFORM_VECTORS:
- *params = static_state_.int_state.max_vertex_uniform_vectors;
+ *params = capabilities_.max_vertex_uniform_vectors;
return true;
case GL_NUM_COMPRESSED_TEXTURE_FORMATS:
- *params = static_state_.int_state.num_compressed_texture_formats;
+ *params = capabilities_.num_compressed_texture_formats;
return true;
case GL_NUM_SHADER_BINARY_FORMATS:
- *params = static_state_.int_state.num_shader_binary_formats;
+ *params = capabilities_.num_shader_binary_formats;
return true;
case GL_ARRAY_BUFFER_BINDING:
if (share_group_->bind_generates_resource()) {
@@ -2327,8 +2242,8 @@
GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glActiveTexture("
<< GLES2Util::GetStringEnum(texture) << ")");
GLuint texture_index = texture - GL_TEXTURE0;
- if (texture_index >= static_cast<GLuint>(
- static_state_.int_state.max_combined_texture_image_units)) {
+ if (texture_index >=
+ static_cast<GLuint>(capabilities_.max_combined_texture_image_units)) {
SetGLErrorInvalidEnum(
"glActiveTexture", texture, "texture");
return;
@@ -2364,6 +2279,11 @@
GLsizei /* n */, const GLuint* /* queries */) {
}
+void GLES2Implementation::GenValuebuffersCHROMIUMHelper(
+ GLsizei /* n */,
+ const GLuint* /* valuebuffers */) {
+}
+
// NOTE #1: On old versions of OpenGL, calling glBindXXX with an unused id
// generates a new resource. On newer versions of OpenGL they don't. The code
// related to binding below will need to change if we switch to the new OpenGL
@@ -2513,6 +2433,26 @@
return changed;
}
+bool GLES2Implementation::BindValuebufferCHROMIUMHelper(GLenum target,
+ GLuint valuebuffer) {
+ bool changed = false;
+ switch (target) {
+ case GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM:
+ if (bound_valuebuffer_ != valuebuffer) {
+ bound_valuebuffer_ = valuebuffer;
+ changed = true;
+ }
+ break;
+ default:
+ changed = true;
+ break;
+ }
+ // TODO(gman): There's a bug here. If the target is invalid the ID will not be
+ // used even though it's marked it as used here.
+ GetIdHandler(id_namespaces::kValuebuffers)->MarkAsUsedForBind(valuebuffer);
+ return changed;
+}
+
bool GLES2Implementation::UseProgramHelper(GLuint program) {
bool changed = false;
if (current_program_ != program) {
@@ -2612,8 +2552,7 @@
return;
}
for (GLsizei ii = 0; ii < n; ++ii) {
- for (GLint tt = 0;
- tt < static_state_.int_state.max_combined_texture_image_units;
+ for (GLint tt = 0; tt < capabilities_.max_combined_texture_image_units;
++tt) {
TextureUnit& unit = texture_units_[tt];
if (textures[ii] == unit.bound_texture_2d) {
@@ -2629,6 +2568,11 @@
}
}
+void GLES2Implementation::DeleteTexturesStub(GLsizei n,
+ const GLuint* textures) {
+ helper_->DeleteTexturesImmediate(n, textures);
+}
+
void GLES2Implementation::DeleteVertexArraysOESHelper(
GLsizei n, const GLuint* arrays) {
vertex_array_object_manager_->DeleteVertexArrays(n, arrays);
@@ -2646,9 +2590,27 @@
helper_->DeleteVertexArraysOESImmediate(n, arrays);
}
-void GLES2Implementation::DeleteTexturesStub(
- GLsizei n, const GLuint* textures) {
- helper_->DeleteTexturesImmediate(n, textures);
+void GLES2Implementation::DeleteValuebuffersCHROMIUMHelper(
+ GLsizei n,
+ const GLuint* valuebuffers) {
+ if (!GetIdHandler(id_namespaces::kValuebuffers)
+ ->FreeIds(this, n, valuebuffers,
+ &GLES2Implementation::DeleteValuebuffersCHROMIUMStub)) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM",
+ "id not created by this context.");
+ return;
+ }
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (valuebuffers[ii] == bound_valuebuffer_) {
+ bound_valuebuffer_ = 0;
+ }
+ }
+}
+
+void GLES2Implementation::DeleteValuebuffersCHROMIUMStub(
+ GLsizei n,
+ const GLuint* valuebuffers) {
+ helper_->DeleteValuebuffersCHROMIUMImmediate(n, valuebuffers);
}
void GLES2Implementation::DisableVertexAttribArray(GLuint index) {
@@ -3034,134 +2996,6 @@
rate_limit_tokens_.push(helper_->InsertToken());
}
-void GLES2Implementation::GetMultipleIntegervCHROMIUM(
- const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size) {
- GPU_CLIENT_SINGLE_THREAD_CHECK();
- GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGetMultipleIntegervCHROMIUM("
- << static_cast<const void*>(pnames) << ", "
- << count << ", " << results << ", "
- << size << ")");
- GPU_CLIENT_LOG_CODE_BLOCK({
- for (GLuint i = 0; i < count; ++i) {
- GPU_CLIENT_LOG(
- " " << i << ": " << GLES2Util::GetStringGLState(pnames[i]));
- }
- });
- DCHECK(size >= 0 && FitInt32NonNegative<GLsizeiptr>(size));
-
- GetMultipleIntegervState state(pnames, count, results, size);
- if (!GetMultipleIntegervSetup(&state)) {
- return;
- }
- state.buffer = transfer_buffer_->Alloc(state.transfer_buffer_size_needed);
- if (!state.buffer) {
- SetGLError(GL_OUT_OF_MEMORY, "glGetMultipleIntegervCHROMIUM",
- "Transfer buffer allocation failed.");
- return;
- }
- GetMultipleIntegervRequest(&state);
- WaitForCmd();
- GetMultipleIntegervOnCompleted(&state);
-
- GPU_CLIENT_LOG(" returned");
- GPU_CLIENT_LOG_CODE_BLOCK({
- for (int i = 0; i < state.num_results; ++i) {
- GPU_CLIENT_LOG(" " << i << ": " << (results[i]));
- }
- });
-
- // TODO(gman): We should be able to free without a token.
- transfer_buffer_->FreePendingToken(state.buffer, helper_->InsertToken());
- CheckGLError();
-}
-
-bool GLES2Implementation::GetMultipleIntegervSetup(
- GetMultipleIntegervState* state) {
- state->num_results = 0;
- for (GLuint ii = 0; ii < state->pnames_count; ++ii) {
- int num = util_.GLGetNumValuesReturned(state->pnames[ii]);
- if (!num) {
- SetGLErrorInvalidEnum(
- "glGetMultipleIntegervCHROMIUM", state->pnames[ii], "pname");
- return false;
- }
- state->num_results += num;
- }
- if (static_cast<size_t>(state->results_size) !=
- state->num_results * sizeof(GLint)) {
- SetGLError(GL_INVALID_VALUE, "glGetMultipleIntegervCHROMIUM", "bad size");
- return false;
- }
- for (int ii = 0; ii < state->num_results; ++ii) {
- if (state->results[ii] != 0) {
- SetGLError(GL_INVALID_VALUE,
- "glGetMultipleIntegervCHROMIUM", "results not set to zero.");
- return false;
- }
- }
- state->transfer_buffer_size_needed =
- state->pnames_count * sizeof(state->pnames[0]) +
- state->num_results * sizeof(state->results[0]);
- return true;
-}
-
-void GLES2Implementation::GetMultipleIntegervRequest(
- GetMultipleIntegervState* state) {
- GLenum* pnames_buffer = static_cast<GLenum*>(state->buffer);
- state->results_buffer = pnames_buffer + state->pnames_count;
- memcpy(pnames_buffer, state->pnames, state->pnames_count * sizeof(GLenum));
- memset(state->results_buffer, 0, state->num_results * sizeof(GLint));
- helper_->GetMultipleIntegervCHROMIUM(
- transfer_buffer_->GetShmId(),
- transfer_buffer_->GetOffset(pnames_buffer),
- state->pnames_count,
- transfer_buffer_->GetShmId(),
- transfer_buffer_->GetOffset(state->results_buffer),
- state->results_size);
-}
-
-void GLES2Implementation::GetMultipleIntegervOnCompleted(
- GetMultipleIntegervState* state) {
- memcpy(state->results, state->results_buffer, state->results_size);;
-}
-
-void GLES2Implementation::GetAllShaderPrecisionFormatsSetup(
- GetAllShaderPrecisionFormatsState* state) {
- state->transfer_buffer_size_needed =
- state->precision_params_count *
- sizeof(cmds::GetShaderPrecisionFormat::Result);
-}
-
-void GLES2Implementation::GetAllShaderPrecisionFormatsRequest(
- GetAllShaderPrecisionFormatsState* state) {
- typedef cmds::GetShaderPrecisionFormat::Result Result;
- Result* result = static_cast<Result*>(state->results_buffer);
-
- for (int i = 0; i < state->precision_params_count; i++) {
- result->success = false;
- helper_->GetShaderPrecisionFormat(state->precision_params[i][0],
- state->precision_params[i][1],
- transfer_buffer_->GetShmId(),
- transfer_buffer_->GetOffset(result));
- result++;
- }
-}
-
-void GLES2Implementation::GetAllShaderPrecisionFormatsOnCompleted(
- GetAllShaderPrecisionFormatsState* state) {
- typedef cmds::GetShaderPrecisionFormat::Result Result;
- Result* result = static_cast<Result*>(state->results_buffer);
-
- for (int i = 0; i < state->precision_params_count; i++) {
- if (result->success) {
- const GLStaticState::ShaderPrecisionKey key(
- state->precision_params[i][0], state->precision_params[i][1]);
- static_state_.shader_precisions[key] = *result;
- }
- result++;
- }
-}
-
void GLES2Implementation::GetProgramInfoCHROMIUMHelper(
GLuint program, std::vector<int8>* result) {
DCHECK(result);
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index a612ac2..cfe8ed9 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -137,24 +137,6 @@
GLStaticState();
~GLStaticState();
- struct GLES2_IMPL_EXPORT IntState {
- IntState();
- GLint max_combined_texture_image_units;
- GLint max_cube_map_texture_size;
- GLint max_fragment_uniform_vectors;
- GLint max_renderbuffer_size;
- GLint max_texture_image_units;
- GLint max_texture_size;
- GLint max_varying_vectors;
- GLint max_vertex_attribs;
- GLint max_vertex_texture_image_units;
- GLint max_vertex_uniform_vectors;
- GLint num_compressed_texture_formats;
- GLint num_shader_binary_formats;
- GLint bind_generates_resource_chromium;
- };
- IntState int_state;
-
typedef std::pair<GLenum, GLenum> ShaderPrecisionKey;
typedef std::map<ShaderPrecisionKey,
cmds::GetShaderPrecisionFormat::Result>
@@ -398,58 +380,6 @@
int32 GetResultShmId();
uint32 GetResultShmOffset();
- bool QueryAndCacheStaticState();
-
- // Helpers used to batch synchronous GetIntergerv calls with other
- // synchronous calls.
- struct GetMultipleIntegervState {
- GetMultipleIntegervState(const GLenum* pnames, GLuint pnames_count,
- GLint* results, GLsizeiptr results_size)
- : pnames(pnames),
- pnames_count(pnames_count),
- results(results),
- results_size(results_size)
- { }
- // inputs
- const GLenum* pnames;
- GLuint pnames_count;
- // outputs
- GLint* results;
- GLsizeiptr results_size;
- // transfer buffer
- int num_results;
- int transfer_buffer_size_needed;
- void* buffer;
- void* results_buffer;
- };
- bool GetMultipleIntegervSetup(
- GetMultipleIntegervState* state);
- void GetMultipleIntegervRequest(
- GetMultipleIntegervState* state);
- void GetMultipleIntegervOnCompleted(
- GetMultipleIntegervState* state);
-
- // Helpers used to batch synchronous GetShaderPrecision calls with other
- // synchronous calls.
- struct GetAllShaderPrecisionFormatsState {
- GetAllShaderPrecisionFormatsState(
- const GLenum (*precision_params)[2],
- int precision_params_count)
- : precision_params(precision_params),
- precision_params_count(precision_params_count)
- { }
- const GLenum (*precision_params)[2];
- int precision_params_count;
- int transfer_buffer_size_needed;
- void* results_buffer;
- };
- void GetAllShaderPrecisionFormatsSetup(
- GetAllShaderPrecisionFormatsState* state);
- void GetAllShaderPrecisionFormatsRequest(
- GetAllShaderPrecisionFormatsState* state);
- void GetAllShaderPrecisionFormatsOnCompleted(
- GetAllShaderPrecisionFormatsState* state);
-
// Lazily determines if GL_ANGLE_pack_reverse_row_order is available
bool IsAnglePackReverseRowOrderAvailable();
bool IsChromiumFramebufferMultisampleAvailable();
@@ -495,17 +425,19 @@
// Returns true if id is reserved.
bool IsBufferReservedId(GLuint id);
- bool IsFramebufferReservedId(GLuint id) { return false; }
+ bool IsFramebufferReservedId(GLuint id) { return false; }
bool IsRenderbufferReservedId(GLuint id) { return false; }
bool IsTextureReservedId(GLuint id) { return false; }
bool IsVertexArrayReservedId(GLuint id) { return false; }
bool IsProgramReservedId(GLuint id) { return false; }
+ bool IsValuebufferReservedId(GLuint id) { return false; }
bool BindBufferHelper(GLenum target, GLuint texture);
bool BindFramebufferHelper(GLenum target, GLuint texture);
bool BindRenderbufferHelper(GLenum target, GLuint texture);
bool BindTextureHelper(GLenum target, GLuint texture);
bool BindVertexArrayOESHelper(GLuint array);
+ bool BindValuebufferCHROMIUMHelper(GLenum target, GLuint valuebuffer);
bool UseProgramHelper(GLuint program);
void GenBuffersHelper(GLsizei n, const GLuint* buffers);
@@ -514,6 +446,7 @@
void GenTexturesHelper(GLsizei n, const GLuint* textures);
void GenVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
void GenQueriesEXTHelper(GLsizei n, const GLuint* queries);
+ void GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
void DeleteBuffersHelper(GLsizei n, const GLuint* buffers);
void DeleteFramebuffersHelper(GLsizei n, const GLuint* framebuffers);
@@ -523,6 +456,7 @@
bool DeleteShaderHelper(GLuint shader);
void DeleteQueriesEXTHelper(GLsizei n, const GLuint* queries);
void DeleteVertexArraysOESHelper(GLsizei n, const GLuint* arrays);
+ void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* valuebuffers);
void DeleteBuffersStub(GLsizei n, const GLuint* buffers);
void DeleteFramebuffersStub(GLsizei n, const GLuint* framebuffers);
@@ -531,6 +465,7 @@
void DeleteProgramStub(GLsizei n, const GLuint* programs);
void DeleteShaderStub(GLsizei n, const GLuint* shaders);
void DeleteVertexArraysOESStub(GLsizei n, const GLuint* arrays);
+ void DeleteValuebuffersCHROMIUMStub(GLsizei n, const GLuint* valuebuffers);
void BufferDataHelper(
GLenum target, GLsizeiptr size, const void* data, GLenum usage);
@@ -699,6 +634,7 @@
GLuint bound_framebuffer_;
GLuint bound_read_framebuffer_;
GLuint bound_renderbuffer_;
+ GLuint bound_valuebuffer_;
// The program in use by glUseProgram
GLuint current_program_;
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 4e547d9..f58c0a8 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -552,11 +552,6 @@
void RateLimitOffscreenContextCHROMIUM() override;
-void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
- GLuint count,
- GLint* results,
- GLsizeiptr size) override;
-
void GetProgramInfoCHROMIUM(GLuint program,
GLsizei bufsize,
GLsizei* size,
@@ -629,6 +624,22 @@
GLint location,
const char* name) override;
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+
+void UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) override;
+
void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index e7cc074..8541e77 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -2019,6 +2019,120 @@
CheckGLError();
}
+void GLES2Implementation::GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) {
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glGenValuebuffersCHROMIUM(" << n
+ << ", " << static_cast<const void*>(buffers) << ")");
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glGenValuebuffersCHROMIUM", "n < 0");
+ return;
+ }
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GetIdHandler(id_namespaces::kValuebuffers)->MakeIds(this, 0, n, buffers);
+ GenValuebuffersCHROMIUMHelper(n, buffers);
+ helper_->GenValuebuffersCHROMIUMImmediate(n, buffers);
+ if (share_group_->bind_generates_resource())
+ helper_->CommandBufferHelper::Flush();
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << buffers[i]);
+ }
+ });
+ CheckGLError();
+}
+
+void GLES2Implementation::DeleteValuebuffersCHROMIUM(
+ GLsizei n,
+ const GLuint* valuebuffers) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glDeleteValuebuffersCHROMIUM(" << n
+ << ", " << static_cast<const void*>(valuebuffers) << ")");
+ GPU_CLIENT_LOG_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ GPU_CLIENT_LOG(" " << i << ": " << valuebuffers[i]);
+ }
+ });
+ GPU_CLIENT_DCHECK_CODE_BLOCK({
+ for (GLsizei i = 0; i < n; ++i) {
+ DCHECK(valuebuffers[i] != 0);
+ }
+ });
+ if (n < 0) {
+ SetGLError(GL_INVALID_VALUE, "glDeleteValuebuffersCHROMIUM", "n < 0");
+ return;
+ }
+ DeleteValuebuffersCHROMIUMHelper(n, valuebuffers);
+ CheckGLError();
+}
+
+GLboolean GLES2Implementation::IsValuebufferCHROMIUM(GLuint valuebuffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ TRACE_EVENT0("gpu", "GLES2Implementation::IsValuebufferCHROMIUM");
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glIsValuebufferCHROMIUM("
+ << valuebuffer << ")");
+ typedef cmds::IsValuebufferCHROMIUM::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ return GL_FALSE;
+ }
+ *result = 0;
+ helper_->IsValuebufferCHROMIUM(valuebuffer, GetResultShmId(),
+ GetResultShmOffset());
+ WaitForCmd();
+ GLboolean result_value = *result != 0;
+ GPU_CLIENT_LOG("returned " << result_value);
+ CheckGLError();
+ return result_value;
+}
+
+void GLES2Implementation::BindValuebufferCHROMIUM(GLenum target,
+ GLuint valuebuffer) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindValuebufferCHROMIUM("
+ << GLES2Util::GetStringValueBufferTarget(target) << ", "
+ << valuebuffer << ")");
+ if (IsValuebufferReservedId(valuebuffer)) {
+ SetGLError(GL_INVALID_OPERATION, "BindValuebufferCHROMIUM",
+ "valuebuffer reserved id");
+ return;
+ }
+ if (BindValuebufferCHROMIUMHelper(target, valuebuffer)) {
+ helper_->BindValuebufferCHROMIUM(target, valuebuffer);
+ }
+ CheckGLError();
+}
+
+void GLES2Implementation::SubscribeValueCHROMIUM(GLenum target,
+ GLenum subscription) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glSubscribeValueCHROMIUM("
+ << GLES2Util::GetStringValueBufferTarget(target) << ", "
+ << GLES2Util::GetStringSubscriptionTarget(subscription)
+ << ")");
+ helper_->SubscribeValueCHROMIUM(target, subscription);
+ CheckGLError();
+}
+
+void GLES2Implementation::PopulateSubscribedValuesCHROMIUM(GLenum target) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix()
+ << "] glPopulateSubscribedValuesCHROMIUM("
+ << GLES2Util::GetStringValueBufferTarget(target) << ")");
+ helper_->PopulateSubscribedValuesCHROMIUM(target);
+ CheckGLError();
+}
+
+void GLES2Implementation::UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG(
+ "[" << GetLogPrefix() << "] glUniformValuebufferCHROMIUM(" << location
+ << ", " << GLES2Util::GetStringValueBufferTarget(target) << ", "
+ << GLES2Util::GetStringSubscriptionTarget(subscription) << ")");
+ helper_->UniformValuebufferCHROMIUM(location, target, subscription);
+ CheckGLError();
+}
+
void GLES2Implementation::BindTexImage2DCHROMIUM(GLenum target, GLint imageId) {
GPU_CLIENT_SINGLE_THREAD_CHECK();
GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glBindTexImage2DCHROMIUM("
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index be1f1a3..5c944a8 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -383,6 +383,7 @@
static const GLuint kTexturesStartId = 1;
static const GLuint kQueriesStartId = 1;
static const GLuint kVertexArraysStartId = 1;
+ static const GLuint kValuebuffersStartId = 1;
typedef MockTransferBuffer::ExpectedMemoryInfo ExpectedMemoryInfo;
@@ -408,43 +409,36 @@
helper_->Initialize(kCommandBufferSizeBytes);
gpu_control_.reset(new StrictMock<MockClientGpuControl>());
- EXPECT_CALL(*gpu_control_, GetCapabilities())
- .WillOnce(testing::Return(Capabilities()));
-
- GLES2Implementation::GLStaticState state;
- GLES2Implementation::GLStaticState::IntState& int_state = state.int_state;
- int_state.max_combined_texture_image_units =
+ Capabilities capabilities;
+ capabilities.VisitPrecisions(
+ [](GLenum shader, GLenum type,
+ Capabilities::ShaderPrecision* precision) {
+ precision->min_range = 3;
+ precision->max_range = 5;
+ precision->precision = 7;
+ });
+ capabilities.max_combined_texture_image_units =
kMaxCombinedTextureImageUnits;
- int_state.max_cube_map_texture_size = kMaxCubeMapTextureSize;
- int_state.max_fragment_uniform_vectors = kMaxFragmentUniformVectors;
- int_state.max_renderbuffer_size = kMaxRenderbufferSize;
- int_state.max_texture_image_units = kMaxTextureImageUnits;
- int_state.max_texture_size = kMaxTextureSize;
- int_state.max_varying_vectors = kMaxVaryingVectors;
- int_state.max_vertex_attribs = kMaxVertexAttribs;
- int_state.max_vertex_texture_image_units = kMaxVertexTextureImageUnits;
- int_state.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
- int_state.num_compressed_texture_formats = kNumCompressedTextureFormats;
- int_state.num_shader_binary_formats = kNumShaderBinaryFormats;
- int_state.bind_generates_resource_chromium =
+ capabilities.max_cube_map_texture_size = kMaxCubeMapTextureSize;
+ capabilities.max_fragment_uniform_vectors = kMaxFragmentUniformVectors;
+ capabilities.max_renderbuffer_size = kMaxRenderbufferSize;
+ capabilities.max_texture_image_units = kMaxTextureImageUnits;
+ capabilities.max_texture_size = kMaxTextureSize;
+ capabilities.max_varying_vectors = kMaxVaryingVectors;
+ capabilities.max_vertex_attribs = kMaxVertexAttribs;
+ capabilities.max_vertex_texture_image_units = kMaxVertexTextureImageUnits;
+ capabilities.max_vertex_uniform_vectors = kMaxVertexUniformVectors;
+ capabilities.num_compressed_texture_formats =
+ kNumCompressedTextureFormats;
+ capabilities.num_shader_binary_formats = kNumShaderBinaryFormats;
+ capabilities.bind_generates_resource_chromium =
bind_generates_resource_service ? 1 : 0;
-
- // This just happens to work for now because IntState has 1 GLint per
- // state.
- // If IntState gets more complicated this code will need to get more
- // complicated.
- ExpectedMemoryInfo mem1 = transfer_buffer_->GetExpectedMemory(
- sizeof(GLES2Implementation::GLStaticState::IntState) * 2 +
- sizeof(cmds::GetShaderPrecisionFormat::Result) * 12);
+ EXPECT_CALL(*gpu_control_, GetCapabilities())
+ .WillOnce(testing::Return(capabilities));
{
InSequence sequence;
- EXPECT_CALL(*command_buffer_, OnFlush())
- .WillOnce(SetMemory(mem1.ptr + sizeof(int_state), int_state))
- .RetiresOnSaturation();
- GetNextToken(); // eat the token that starting up will use.
-
const bool support_client_side_arrays = true;
gl_.reset(new GLES2Implementation(helper_.get(),
share_group,
@@ -461,7 +455,6 @@
return false;
}
- EXPECT_CALL(*command_buffer_, OnFlush()).Times(1).RetiresOnSaturation();
helper_->CommandBufferHelper::Finish();
::testing::Mock::VerifyAndClearExpectations(gl_.get());
@@ -755,6 +748,7 @@
const GLuint GLES2ImplementationTest::kTexturesStartId;
const GLuint GLES2ImplementationTest::kQueriesStartId;
const GLuint GLES2ImplementationTest::kVertexArraysStartId;
+const GLuint GLES2ImplementationTest::kValuebuffersStartId;
#endif
TEST_F(GLES2ImplementationTest, Basic) {
@@ -817,20 +811,22 @@
cmds::GetShaderPrecisionFormat cmd;
};
typedef cmds::GetShaderPrecisionFormat::Result Result;
+ const unsigned kDummyType1 = 3;
+ const unsigned kDummyType2 = 4;
- // The first call for mediump should trigger a command buffer request.
+ // The first call for dummy type 1 should trigger a command buffer request.
GLint range1[2] = {0, 0};
GLint precision1 = 0;
Cmds expected1;
ExpectedMemoryInfo client_result1 = GetExpectedResultMemory(4);
- expected1.cmd.Init(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
- client_result1.id, client_result1.offset);
+ expected1.cmd.Init(GL_FRAGMENT_SHADER, kDummyType1, client_result1.id,
+ client_result1.offset);
Result server_result1 = {true, 14, 14, 10};
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(client_result1.ptr, server_result1))
.RetiresOnSaturation();
- gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
- range1, &precision1);
+ gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType1, range1,
+ &precision1);
const void* commands2 = GetPut();
EXPECT_NE(commands_, commands2);
EXPECT_EQ(0, memcmp(&expected1, commands_, sizeof(expected1)));
@@ -838,39 +834,53 @@
EXPECT_EQ(range1[1], 14);
EXPECT_EQ(precision1, 10);
- // The second call for mediump should use the cached value and avoid
+ // The second call for dummy type 1 should use the cached value and avoid
// triggering a command buffer request, so we do not expect a call to
// OnFlush() here. We do expect the results to be correct though.
GLint range2[2] = {0, 0};
GLint precision2 = 0;
- gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT,
- range2, &precision2);
+ gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType1, range2,
+ &precision2);
const void* commands3 = GetPut();
EXPECT_EQ(commands2, commands3);
EXPECT_EQ(range2[0], 14);
EXPECT_EQ(range2[1], 14);
EXPECT_EQ(precision2, 10);
- // If we then make a request for highp, we should get another command
+ // If we then make a request for dummy type 2, we should get another command
// buffer request since it hasn't been cached yet.
GLint range3[2] = {0, 0};
GLint precision3 = 0;
Cmds expected3;
ExpectedMemoryInfo result3 = GetExpectedResultMemory(4);
- expected3.cmd.Init(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT,
- result3.id, result3.offset);
+ expected3.cmd.Init(GL_FRAGMENT_SHADER, kDummyType2, result3.id,
+ result3.offset);
Result result3_source = {true, 62, 62, 16};
EXPECT_CALL(*command_buffer(), OnFlush())
.WillOnce(SetMemory(result3.ptr, result3_source))
.RetiresOnSaturation();
- gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT,
- range3, &precision3);
+ gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, kDummyType2, range3,
+ &precision3);
const void* commands4 = GetPut();
EXPECT_NE(commands3, commands4);
EXPECT_EQ(0, memcmp(&expected3, commands3, sizeof(expected3)));
EXPECT_EQ(range3[0], 62);
EXPECT_EQ(range3[1], 62);
EXPECT_EQ(precision3, 16);
+
+ // Any call for predefined types should use the cached value from the
+ // Capabilities and avoid triggering a command buffer request, so we do not
+ // expect a call to OnFlush() here. We do expect the results to be correct
+ // though.
+ GLint range4[2] = {0, 0};
+ GLint precision4 = 0;
+ gl_->GetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, range4,
+ &precision4);
+ const void* commands5 = GetPut();
+ EXPECT_EQ(commands4, commands5);
+ EXPECT_EQ(range4[0], 3);
+ EXPECT_EQ(range4[1], 5);
+ EXPECT_EQ(precision4, 7);
}
TEST_F(GLES2ImplementationTest, ShaderSource) {
@@ -1947,122 +1957,6 @@
EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
}
-TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMValidArgs) {
- const GLenum pnames[] = {
- GL_DEPTH_WRITEMASK,
- GL_COLOR_WRITEMASK,
- GL_STENCIL_WRITEMASK,
- };
- const GLint num_results = 6;
- GLint results[num_results + 1];
- struct Cmds {
- cmds::GetMultipleIntegervCHROMIUM get_multiple;
- cmd::SetToken set_token;
- };
- const GLsizei kNumPnames = arraysize(pnames);
- const GLsizeiptr kResultsSize = num_results * sizeof(results[0]);
- const size_t kPNamesSize = kNumPnames * sizeof(pnames[0]);
-
- ExpectedMemoryInfo mem1 = GetExpectedMemory(kPNamesSize + kResultsSize);
- ExpectedMemoryInfo result1 = GetExpectedResultMemory(
- sizeof(cmds::GetError::Result));
-
- const uint32 kPnamesOffset = mem1.offset;
- const uint32 kResultsOffset = mem1.offset + kPNamesSize;
- Cmds expected;
- expected.get_multiple.Init(
- mem1.id, kPnamesOffset, kNumPnames,
- mem1.id, kResultsOffset, kResultsSize);
- expected.set_token.Init(GetNextToken());
-
- const GLint kSentinel = 0x12345678;
- memset(results, 0, sizeof(results));
- results[num_results] = kSentinel;
- const GLint returned_results[] = {
- 1, 0, 1, 0, 1, -1,
- };
- // One call to flush to wait for results
- EXPECT_CALL(*command_buffer(), OnFlush())
- .WillOnce(SetMemoryFromArray(mem1.ptr + kPNamesSize,
- returned_results, sizeof(returned_results)))
- .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
- .RetiresOnSaturation();
-
- gl_->GetMultipleIntegervCHROMIUM(
- &pnames[0], kNumPnames, &results[0], kResultsSize);
- EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
- EXPECT_EQ(0, memcmp(&returned_results, results, sizeof(returned_results)));
- EXPECT_EQ(kSentinel, results[num_results]);
- EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), gl_->GetError());
-}
-
-TEST_F(GLES2ImplementationTest, GetMultipleIntegervCHROMIUMBadArgs) {
- GLenum pnames[] = {
- GL_DEPTH_WRITEMASK,
- GL_COLOR_WRITEMASK,
- GL_STENCIL_WRITEMASK,
- };
- const GLint num_results = 6;
- GLint results[num_results + 1];
- const GLsizei kNumPnames = arraysize(pnames);
- const GLsizeiptr kResultsSize = num_results * sizeof(results[0]);
-
- ExpectedMemoryInfo result1 =
- GetExpectedResultMemory(sizeof(cmds::GetError::Result));
- ExpectedMemoryInfo result2 =
- GetExpectedResultMemory(sizeof(cmds::GetError::Result));
- ExpectedMemoryInfo result3 =
- GetExpectedResultMemory(sizeof(cmds::GetError::Result));
- ExpectedMemoryInfo result4 =
- GetExpectedResultMemory(sizeof(cmds::GetError::Result));
-
- // Calls to flush to wait for GetError
- EXPECT_CALL(*command_buffer(), OnFlush())
- .WillOnce(SetMemory(result1.ptr, GLuint(GL_NO_ERROR)))
- .WillOnce(SetMemory(result2.ptr, GLuint(GL_NO_ERROR)))
- .WillOnce(SetMemory(result3.ptr, GLuint(GL_NO_ERROR)))
- .WillOnce(SetMemory(result4.ptr, GLuint(GL_NO_ERROR)))
- .RetiresOnSaturation();
-
- const GLint kSentinel = 0x12345678;
- memset(results, 0, sizeof(results));
- results[num_results] = kSentinel;
- // try bad size.
- gl_->GetMultipleIntegervCHROMIUM(
- &pnames[0], kNumPnames, &results[0], kResultsSize + 1);
- EXPECT_TRUE(NoCommandsWritten());
- EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
- EXPECT_EQ(0, results[0]);
- EXPECT_EQ(kSentinel, results[num_results]);
- // try bad size.
- ClearCommands();
- gl_->GetMultipleIntegervCHROMIUM(
- &pnames[0], kNumPnames, &results[0], kResultsSize - 1);
- EXPECT_TRUE(NoCommandsWritten());
- EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
- EXPECT_EQ(0, results[0]);
- EXPECT_EQ(kSentinel, results[num_results]);
- // try uncleared results.
- ClearCommands();
- results[2] = 1;
- gl_->GetMultipleIntegervCHROMIUM(
- &pnames[0], kNumPnames, &results[0], kResultsSize);
- EXPECT_TRUE(NoCommandsWritten());
- EXPECT_EQ(static_cast<GLenum>(GL_INVALID_VALUE), gl_->GetError());
- EXPECT_EQ(0, results[0]);
- EXPECT_EQ(kSentinel, results[num_results]);
- // try bad enum results.
- ClearCommands();
- results[2] = 0;
- pnames[1] = GL_TRUE;
- gl_->GetMultipleIntegervCHROMIUM(
- &pnames[0], kNumPnames, &results[0], kResultsSize);
- EXPECT_TRUE(NoCommandsWritten());
- EXPECT_EQ(static_cast<GLenum>(GL_INVALID_ENUM), gl_->GetError());
- EXPECT_EQ(0, results[0]);
- EXPECT_EQ(kSentinel, results[num_results]);
-}
-
TEST_F(GLES2ImplementationTest, GetProgramInfoCHROMIUMGoodArgs) {
const uint32 kBucketId = GLES2Implementation::kResultBucketId;
const GLuint kProgramId = 123;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 8069b12..74a438c 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -1800,6 +1800,108 @@
// TODO: Implement unit test for GenMailboxCHROMIUM
// TODO: Implement unit test for BindUniformLocationCHROMIUM
+TEST_F(GLES2ImplementationTest, GenValuebuffersCHROMIUM) {
+ GLuint ids[2] = {
+ 0,
+ };
+ struct Cmds {
+ cmds::GenValuebuffersCHROMIUMImmediate gen;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.gen.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kValuebuffersStartId;
+ expected.data[1] = kValuebuffersStartId + 1;
+ gl_->GenValuebuffersCHROMIUM(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(kValuebuffersStartId, ids[0]);
+ EXPECT_EQ(kValuebuffersStartId + 1, ids[1]);
+}
+
+TEST_F(GLES2ImplementationTest, DeleteValuebuffersCHROMIUM) {
+ GLuint ids[2] = {kValuebuffersStartId, kValuebuffersStartId + 1};
+ struct Cmds {
+ cmds::DeleteValuebuffersCHROMIUMImmediate del;
+ GLuint data[2];
+ };
+ Cmds expected;
+ expected.del.Init(arraysize(ids), &ids[0]);
+ expected.data[0] = kValuebuffersStartId;
+ expected.data[1] = kValuebuffersStartId + 1;
+ gl_->DeleteValuebuffersCHROMIUM(arraysize(ids), &ids[0]);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, IsValuebufferCHROMIUM) {
+ struct Cmds {
+ cmds::IsValuebufferCHROMIUM cmd;
+ };
+
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::IsValuebufferCHROMIUM::Result));
+ expected.cmd.Init(1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32_t(1)))
+ .RetiresOnSaturation();
+
+ GLboolean result = gl_->IsValuebufferCHROMIUM(1);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_TRUE(result);
+}
+
+TEST_F(GLES2ImplementationTest, BindValuebufferCHROMIUM) {
+ struct Cmds {
+ cmds::BindValuebufferCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+
+ gl_->BindValuebufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ ClearCommands();
+ gl_->BindValuebufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 2);
+ EXPECT_TRUE(NoCommandsWritten());
+}
+
+TEST_F(GLES2ImplementationTest, SubscribeValueCHROMIUM) {
+ struct Cmds {
+ cmds::SubscribeValueCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ GL_MOUSE_POSITION_CHROMIUM);
+
+ gl_->SubscribeValueCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, PopulateSubscribedValuesCHROMIUM) {
+ struct Cmds {
+ cmds::PopulateSubscribedValuesCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+
+ gl_->PopulateSubscribedValuesCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
+TEST_F(GLES2ImplementationTest, UniformValuebufferCHROMIUM) {
+ struct Cmds {
+ cmds::UniformValuebufferCHROMIUM cmd;
+ };
+ Cmds expected;
+ expected.cmd.Init(1, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ GL_MOUSE_POSITION_CHROMIUM);
+
+ gl_->UniformValuebufferCHROMIUM(1, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
TEST_F(GLES2ImplementationTest, BindTexImage2DCHROMIUM) {
struct Cmds {
cmds::BindTexImage2DCHROMIUM cmd;
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index d840804..ee4591c 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -392,10 +392,6 @@
virtual const GLchar* GetRequestableExtensionsCHROMIUM() = 0;
virtual void RequestExtensionCHROMIUM(const char* extension) = 0;
virtual void RateLimitOffscreenContextCHROMIUM() = 0;
-virtual void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
- GLuint count,
- GLint* results,
- GLsizeiptr size) = 0;
virtual void GetProgramInfoCHROMIUM(GLuint program,
GLsizei bufsize,
GLsizei* size,
@@ -450,6 +446,16 @@
virtual void BindUniformLocationCHROMIUM(GLuint program,
GLint location,
const char* name) = 0;
+virtual void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) = 0;
+virtual void DeleteValuebuffersCHROMIUM(GLsizei n,
+ const GLuint* valuebuffers) = 0;
+virtual GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) = 0;
+virtual void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) = 0;
+virtual void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) = 0;
+virtual void PopulateSubscribedValuesCHROMIUM(GLenum target) = 0;
+virtual void UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) = 0;
virtual void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
virtual void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) = 0;
virtual void TraceBeginCHROMIUM(const char* name) = 0;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 687ff48..637c000 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -383,10 +383,6 @@
const GLchar* GetRequestableExtensionsCHROMIUM() override;
void RequestExtensionCHROMIUM(const char* extension) override;
void RateLimitOffscreenContextCHROMIUM() override;
-void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
- GLuint count,
- GLint* results,
- GLsizeiptr size) override;
void GetProgramInfoCHROMIUM(GLuint program,
GLsizei bufsize,
GLsizei* size,
@@ -441,6 +437,15 @@
void BindUniformLocationCHROMIUM(GLuint program,
GLint location,
const char* name) override;
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+void UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) override;
void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
void TraceBeginCHROMIUM(const char* name) override;
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index e78b07c..5a986e9 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -694,11 +694,6 @@
}
void GLES2InterfaceStub::RateLimitOffscreenContextCHROMIUM() {
}
-void GLES2InterfaceStub::GetMultipleIntegervCHROMIUM(const GLenum* /* pnames */,
- GLuint /* count */,
- GLint* /* results */,
- GLsizeiptr /* size */) {
-}
void GLES2InterfaceStub::GetProgramInfoCHROMIUM(GLuint /* program */,
GLsizei /* bufsize */,
GLsizei* /* size */,
@@ -781,6 +776,28 @@
GLint /* location */,
const char* /* name */) {
}
+void GLES2InterfaceStub::GenValuebuffersCHROMIUM(GLsizei /* n */,
+ GLuint* /* buffers */) {
+}
+void GLES2InterfaceStub::DeleteValuebuffersCHROMIUM(
+ GLsizei /* n */,
+ const GLuint* /* valuebuffers */) {
+}
+GLboolean GLES2InterfaceStub::IsValuebufferCHROMIUM(GLuint /* valuebuffer */) {
+ return 0;
+}
+void GLES2InterfaceStub::BindValuebufferCHROMIUM(GLenum /* target */,
+ GLuint /* valuebuffer */) {
+}
+void GLES2InterfaceStub::SubscribeValueCHROMIUM(GLenum /* target */,
+ GLenum /* subscription */) {
+}
+void GLES2InterfaceStub::PopulateSubscribedValuesCHROMIUM(GLenum /* target */) {
+}
+void GLES2InterfaceStub::UniformValuebufferCHROMIUM(GLint /* location */,
+ GLenum /* target */,
+ GLenum /* subscription */) {
+}
void GLES2InterfaceStub::BindTexImage2DCHROMIUM(GLenum /* target */,
GLint /* imageId */) {
}
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index a599eb4..b4349ae 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -383,10 +383,6 @@
const GLchar* GetRequestableExtensionsCHROMIUM() override;
void RequestExtensionCHROMIUM(const char* extension) override;
void RateLimitOffscreenContextCHROMIUM() override;
-void GetMultipleIntegervCHROMIUM(const GLenum* pnames,
- GLuint count,
- GLint* results,
- GLsizeiptr size) override;
void GetProgramInfoCHROMIUM(GLuint program,
GLsizei bufsize,
GLsizei* size,
@@ -441,6 +437,15 @@
void BindUniformLocationCHROMIUM(GLuint program,
GLint location,
const char* name) override;
+void GenValuebuffersCHROMIUM(GLsizei n, GLuint* buffers) override;
+void DeleteValuebuffersCHROMIUM(GLsizei n, const GLuint* valuebuffers) override;
+GLboolean IsValuebufferCHROMIUM(GLuint valuebuffer) override;
+void BindValuebufferCHROMIUM(GLenum target, GLuint valuebuffer) override;
+void SubscribeValueCHROMIUM(GLenum target, GLenum subscription) override;
+void PopulateSubscribedValuesCHROMIUM(GLenum target) override;
+void UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) override;
void BindTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
void ReleaseTexImage2DCHROMIUM(GLenum target, GLint imageId) override;
void TraceBeginCHROMIUM(const char* name) override;
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index cf614a9..d7b53b4 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1207,15 +1207,6 @@
gl_->RateLimitOffscreenContextCHROMIUM();
}
-void GLES2TraceImplementation::GetMultipleIntegervCHROMIUM(const GLenum* pnames,
- GLuint count,
- GLint* results,
- GLsizeiptr size) {
- TRACE_EVENT_BINARY_EFFICIENT0("gpu",
- "GLES2Trace::GetMultipleIntegervCHROMIUM");
- gl_->GetMultipleIntegervCHROMIUM(pnames, count, results, size);
-}
-
void GLES2TraceImplementation::GetProgramInfoCHROMIUM(GLuint program,
GLsizei bufsize,
GLsizei* size,
@@ -1358,6 +1349,51 @@
gl_->BindUniformLocationCHROMIUM(program, location, name);
}
+void GLES2TraceImplementation::GenValuebuffersCHROMIUM(GLsizei n,
+ GLuint* buffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::GenValuebuffersCHROMIUM");
+ gl_->GenValuebuffersCHROMIUM(n, buffers);
+}
+
+void GLES2TraceImplementation::DeleteValuebuffersCHROMIUM(
+ GLsizei n,
+ const GLuint* valuebuffers) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "GLES2Trace::DeleteValuebuffersCHROMIUM");
+ gl_->DeleteValuebuffersCHROMIUM(n, valuebuffers);
+}
+
+GLboolean GLES2TraceImplementation::IsValuebufferCHROMIUM(GLuint valuebuffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::IsValuebufferCHROMIUM");
+ return gl_->IsValuebufferCHROMIUM(valuebuffer);
+}
+
+void GLES2TraceImplementation::BindValuebufferCHROMIUM(GLenum target,
+ GLuint valuebuffer) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindValuebufferCHROMIUM");
+ gl_->BindValuebufferCHROMIUM(target, valuebuffer);
+}
+
+void GLES2TraceImplementation::SubscribeValueCHROMIUM(GLenum target,
+ GLenum subscription) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::SubscribeValueCHROMIUM");
+ gl_->SubscribeValueCHROMIUM(target, subscription);
+}
+
+void GLES2TraceImplementation::PopulateSubscribedValuesCHROMIUM(GLenum target) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "GLES2Trace::PopulateSubscribedValuesCHROMIUM");
+ gl_->PopulateSubscribedValuesCHROMIUM(target);
+}
+
+void GLES2TraceImplementation::UniformValuebufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "GLES2Trace::UniformValuebufferCHROMIUM");
+ gl_->UniformValuebufferCHROMIUM(location, target, subscription);
+}
+
void GLES2TraceImplementation::BindTexImage2DCHROMIUM(GLenum target,
GLint imageId) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::BindTexImage2DCHROMIUM");
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 37c33be..0f17198 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -183,7 +183,6 @@
GL_APICALL const GLchar* GL_APIENTRY glGetRequestableExtensionsCHROMIUM (void);
GL_APICALL void GL_APIENTRY glRequestExtensionCHROMIUM (const char* extension);
GL_APICALL void GL_APIENTRY glRateLimitOffscreenContextCHROMIUM (void);
-GL_APICALL void GL_APIENTRY glGetMultipleIntegervCHROMIUM (const GLenum* pnames, GLuint count, GLint* results, GLsizeiptr size);
GL_APICALL void GL_APIENTRY glGetProgramInfoCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
GL_APICALL GLuint GL_APIENTRY glCreateStreamTextureCHROMIUM (GLuint texture);
GL_APICALL GLuint GL_APIENTRY glCreateImageCHROMIUM (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat);
@@ -202,6 +201,13 @@
GL_APICALL void GL_APIENTRY glConsumeTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
GL_APICALL GLuint GL_APIENTRY glCreateAndConsumeTextureCHROMIUM (GLenumTextureBindTarget target, const GLbyte* mailbox);
GL_APICALL void GL_APIENTRY glBindUniformLocationCHROMIUM (GLidProgram program, GLint location, const char* name);
+GL_APICALL void GL_APIENTRY glGenValuebuffersCHROMIUM (GLsizeiNotNegative n, GLuint* buffers);
+GL_APICALL void GL_APIENTRY glDeleteValuebuffersCHROMIUM (GLsizeiNotNegative n, const GLuint* valuebuffers);
+GL_APICALL GLboolean GL_APIENTRY glIsValuebufferCHROMIUM (GLidBindValuebuffer valuebuffer);
+GL_APICALL void GL_APIENTRY glBindValuebufferCHROMIUM (GLenumValueBufferTarget target, GLidBindValuebuffer valuebuffer);
+GL_APICALL void GL_APIENTRY glSubscribeValueCHROMIUM (GLenumValueBufferTarget target, GLenumSubscriptionTarget subscription);
+GL_APICALL void GL_APIENTRY glPopulateSubscribedValuesCHROMIUM (GLenumValueBufferTarget target);
+GL_APICALL void GL_APIENTRY glUniformValuebufferCHROMIUM (GLintUniformLocation location, GLenumValueBufferTarget target, GLenumSubscriptionTarget subscription);
GL_APICALL void GL_APIENTRY glBindTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
GL_APICALL void GL_APIENTRY glReleaseTexImage2DCHROMIUM (GLenumTextureBindTarget target, GLint imageId);
GL_APICALL void GL_APIENTRY glTraceBeginCHROMIUM (const char* name);
diff --git a/gpu/command_buffer/common/capabilities.cc b/gpu/command_buffer/common/capabilities.cc
index f905f4e..9d9e90d 100644
--- a/gpu/command_buffer/common/capabilities.cc
+++ b/gpu/command_buffer/common/capabilities.cc
@@ -6,8 +6,24 @@
namespace gpu {
+Capabilities::PerStagePrecisions::PerStagePrecisions() {
+}
+
Capabilities::Capabilities()
- : post_sub_buffer(false),
+ : max_combined_texture_image_units(0),
+ max_cube_map_texture_size(0),
+ max_fragment_uniform_vectors(0),
+ max_renderbuffer_size(0),
+ max_texture_image_units(0),
+ max_texture_size(0),
+ max_varying_vectors(0),
+ max_vertex_attribs(0),
+ max_vertex_texture_image_units(0),
+ max_vertex_uniform_vectors(0),
+ num_compressed_texture_formats(0),
+ num_shader_binary_formats(0),
+ bind_generates_resource_chromium(0),
+ post_sub_buffer(false),
egl_image_external(false),
texture_format_bgra8888(false),
texture_format_etc1(false),
diff --git a/gpu/command_buffer/common/capabilities.h b/gpu/command_buffer/common/capabilities.h
index fff1ef8..224829c 100644
--- a/gpu/command_buffer/common/capabilities.h
+++ b/gpu/command_buffer/common/capabilities.h
@@ -7,9 +7,75 @@
#include "gpu/gpu_export.h"
+// From gl2.h. We want to avoid including gl headers because client-side and
+// service-side headers conflict.
+#define GL_FRAGMENT_SHADER 0x8B30
+#define GL_VERTEX_SHADER 0x8B31
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_LOW_INT 0x8DF3
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_HIGH_INT 0x8DF5
+
namespace gpu {
struct GPU_EXPORT Capabilities {
+ struct ShaderPrecision {
+ ShaderPrecision() : min_range(0), max_range(0), precision(0) {}
+ int min_range;
+ int max_range;
+ int precision;
+ };
+
+ struct PerStagePrecisions {
+ PerStagePrecisions();
+
+ ShaderPrecision low_int;
+ ShaderPrecision medium_int;
+ ShaderPrecision high_int;
+ ShaderPrecision low_float;
+ ShaderPrecision medium_float;
+ ShaderPrecision high_float;
+ };
+
+ Capabilities();
+
+ template <typename T>
+ void VisitStagePrecisions(unsigned stage,
+ PerStagePrecisions* precisions,
+ const T& visitor) {
+ visitor(stage, GL_LOW_INT, &precisions->low_int);
+ visitor(stage, GL_MEDIUM_INT, &precisions->medium_int);
+ visitor(stage, GL_HIGH_INT, &precisions->high_int);
+ visitor(stage, GL_LOW_FLOAT, &precisions->low_float);
+ visitor(stage, GL_MEDIUM_FLOAT, &precisions->medium_float);
+ visitor(stage, GL_HIGH_FLOAT, &precisions->high_float);
+ }
+
+ template <typename T>
+ void VisitPrecisions(const T& visitor) {
+ VisitStagePrecisions(GL_VERTEX_SHADER, &vertex_shader_precisions, visitor);
+ VisitStagePrecisions(GL_FRAGMENT_SHADER, &fragment_shader_precisions,
+ visitor);
+ }
+
+ PerStagePrecisions vertex_shader_precisions;
+ PerStagePrecisions fragment_shader_precisions;
+ int max_combined_texture_image_units;
+ int max_cube_map_texture_size;
+ int max_fragment_uniform_vectors;
+ int max_renderbuffer_size;
+ int max_texture_image_units;
+ int max_texture_size;
+ int max_varying_vectors;
+ int max_vertex_attribs;
+ int max_vertex_texture_image_units;
+ int max_vertex_uniform_vectors;
+ int num_compressed_texture_formats;
+ int num_shader_binary_formats;
+ int bind_generates_resource_chromium;
+
bool post_sub_buffer;
bool egl_image_external;
bool texture_format_bgra8888;
@@ -25,8 +91,6 @@
bool future_sync_points;
bool blend_equation_advanced;
bool blend_equation_advanced_coherent;
-
- Capabilities();
};
} // namespace gpu
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 393303e..c0bc663 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -59,6 +59,7 @@
kTextures,
kQueries,
kVertexArrays,
+ kValuebuffers,
kNumIdNamespaces
};
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index ecef6bb..14f0728 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -7533,72 +7533,6 @@
COMPILE_ASSERT(offsetof(RequestExtensionCHROMIUM, bucket_id) == 4,
OffsetOf_RequestExtensionCHROMIUM_bucket_id_not_4);
-struct GetMultipleIntegervCHROMIUM {
- typedef GetMultipleIntegervCHROMIUM ValueType;
- static const CommandId kCmdId = kGetMultipleIntegervCHROMIUM;
- static const cmd::ArgFlags kArgFlags = cmd::kFixed;
- static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
-
- static uint32_t ComputeSize() {
- return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
- }
-
- void SetHeader() { header.SetCmd<ValueType>(); }
-
- void Init(uint32_t _pnames_shm_id,
- uint32_t _pnames_shm_offset,
- GLuint _count,
- uint32_t _results_shm_id,
- uint32_t _results_shm_offset,
- GLsizeiptr _size) {
- SetHeader();
- pnames_shm_id = _pnames_shm_id;
- pnames_shm_offset = _pnames_shm_offset;
- count = _count;
- results_shm_id = _results_shm_id;
- results_shm_offset = _results_shm_offset;
- size = _size;
- }
-
- void* Set(void* cmd,
- uint32_t _pnames_shm_id,
- uint32_t _pnames_shm_offset,
- GLuint _count,
- uint32_t _results_shm_id,
- uint32_t _results_shm_offset,
- GLsizeiptr _size) {
- static_cast<ValueType*>(cmd)->Init(_pnames_shm_id, _pnames_shm_offset,
- _count, _results_shm_id,
- _results_shm_offset, _size);
- return NextCmdAddress<ValueType>(cmd);
- }
-
- gpu::CommandHeader header;
- uint32_t pnames_shm_id;
- uint32_t pnames_shm_offset;
- uint32_t count;
- uint32_t results_shm_id;
- uint32_t results_shm_offset;
- int32_t size;
-};
-
-COMPILE_ASSERT(sizeof(GetMultipleIntegervCHROMIUM) == 28,
- Sizeof_GetMultipleIntegervCHROMIUM_is_not_28);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, header) == 0,
- OffsetOf_GetMultipleIntegervCHROMIUM_header_not_0);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, pnames_shm_id) == 4,
- OffsetOf_GetMultipleIntegervCHROMIUM_pnames_shm_id_not_4);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, pnames_shm_offset) == 8,
- OffsetOf_GetMultipleIntegervCHROMIUM_pnames_shm_offset_not_8);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, count) == 12,
- OffsetOf_GetMultipleIntegervCHROMIUM_count_not_12);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, results_shm_id) == 16,
- OffsetOf_GetMultipleIntegervCHROMIUM_results_shm_id_not_16);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, results_shm_offset) == 20,
- OffsetOf_GetMultipleIntegervCHROMIUM_results_shm_offset_not_20);
-COMPILE_ASSERT(offsetof(GetMultipleIntegervCHROMIUM, size) == 24,
- OffsetOf_GetMultipleIntegervCHROMIUM_size_not_24);
-
struct GetProgramInfoCHROMIUM {
typedef GetProgramInfoCHROMIUM ValueType;
static const CommandId kCmdId = kGetProgramInfoCHROMIUM;
@@ -8171,6 +8105,287 @@
offsetof(BindUniformLocationCHROMIUMBucket, name_bucket_id) == 12,
OffsetOf_BindUniformLocationCHROMIUMBucket_name_bucket_id_not_12);
+struct GenValuebuffersCHROMIUMImmediate {
+ typedef GenValuebuffersCHROMIUMImmediate ValueType;
+ static const CommandId kCmdId = kGenValuebuffersCHROMIUMImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ static uint32_t ComputeDataSize(GLsizei n) {
+ return static_cast<uint32_t>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32_t ComputeSize(GLsizei n) {
+ return static_cast<uint32_t>(sizeof(ValueType) +
+ ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, GLuint* _buffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this), _buffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, GLuint* _buffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _buffers);
+ const uint32_t size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(GenValuebuffersCHROMIUMImmediate) == 8,
+ Sizeof_GenValuebuffersCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(GenValuebuffersCHROMIUMImmediate, header) == 0,
+ OffsetOf_GenValuebuffersCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(GenValuebuffersCHROMIUMImmediate, n) == 4,
+ OffsetOf_GenValuebuffersCHROMIUMImmediate_n_not_4);
+
+struct DeleteValuebuffersCHROMIUMImmediate {
+ typedef DeleteValuebuffersCHROMIUMImmediate ValueType;
+ static const CommandId kCmdId = kDeleteValuebuffersCHROMIUMImmediate;
+ static const cmd::ArgFlags kArgFlags = cmd::kAtLeastN;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ static uint32_t ComputeDataSize(GLsizei n) {
+ return static_cast<uint32_t>(sizeof(GLuint) * n); // NOLINT
+ }
+
+ static uint32_t ComputeSize(GLsizei n) {
+ return static_cast<uint32_t>(sizeof(ValueType) +
+ ComputeDataSize(n)); // NOLINT
+ }
+
+ void SetHeader(GLsizei n) {
+ header.SetCmdByTotalSize<ValueType>(ComputeSize(n));
+ }
+
+ void Init(GLsizei _n, const GLuint* _valuebuffers) {
+ SetHeader(_n);
+ n = _n;
+ memcpy(ImmediateDataAddress(this), _valuebuffers, ComputeDataSize(_n));
+ }
+
+ void* Set(void* cmd, GLsizei _n, const GLuint* _valuebuffers) {
+ static_cast<ValueType*>(cmd)->Init(_n, _valuebuffers);
+ const uint32_t size = ComputeSize(_n);
+ return NextImmediateCmdAddressTotalSize<ValueType>(cmd, size);
+ }
+
+ gpu::CommandHeader header;
+ int32_t n;
+};
+
+COMPILE_ASSERT(sizeof(DeleteValuebuffersCHROMIUMImmediate) == 8,
+ Sizeof_DeleteValuebuffersCHROMIUMImmediate_is_not_8);
+COMPILE_ASSERT(offsetof(DeleteValuebuffersCHROMIUMImmediate, header) == 0,
+ OffsetOf_DeleteValuebuffersCHROMIUMImmediate_header_not_0);
+COMPILE_ASSERT(offsetof(DeleteValuebuffersCHROMIUMImmediate, n) == 4,
+ OffsetOf_DeleteValuebuffersCHROMIUMImmediate_n_not_4);
+
+struct IsValuebufferCHROMIUM {
+ typedef IsValuebufferCHROMIUM ValueType;
+ static const CommandId kCmdId = kIsValuebufferCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ typedef uint32_t Result;
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLuint _valuebuffer,
+ uint32_t _result_shm_id,
+ uint32_t _result_shm_offset) {
+ SetHeader();
+ valuebuffer = _valuebuffer;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(void* cmd,
+ GLuint _valuebuffer,
+ uint32_t _result_shm_id,
+ uint32_t _result_shm_offset) {
+ static_cast<ValueType*>(cmd)
+ ->Init(_valuebuffer, _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32_t valuebuffer;
+ uint32_t result_shm_id;
+ uint32_t result_shm_offset;
+};
+
+COMPILE_ASSERT(sizeof(IsValuebufferCHROMIUM) == 16,
+ Sizeof_IsValuebufferCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, header) == 0,
+ OffsetOf_IsValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, valuebuffer) == 4,
+ OffsetOf_IsValuebufferCHROMIUM_valuebuffer_not_4);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, result_shm_id) == 8,
+ OffsetOf_IsValuebufferCHROMIUM_result_shm_id_not_8);
+COMPILE_ASSERT(offsetof(IsValuebufferCHROMIUM, result_shm_offset) == 12,
+ OffsetOf_IsValuebufferCHROMIUM_result_shm_offset_not_12);
+
+struct BindValuebufferCHROMIUM {
+ typedef BindValuebufferCHROMIUM ValueType;
+ static const CommandId kCmdId = kBindValuebufferCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLenum _target, GLuint _valuebuffer) {
+ SetHeader();
+ target = _target;
+ valuebuffer = _valuebuffer;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLuint _valuebuffer) {
+ static_cast<ValueType*>(cmd)->Init(_target, _valuebuffer);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32_t target;
+ uint32_t valuebuffer;
+};
+
+COMPILE_ASSERT(sizeof(BindValuebufferCHROMIUM) == 12,
+ Sizeof_BindValuebufferCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, header) == 0,
+ OffsetOf_BindValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, target) == 4,
+ OffsetOf_BindValuebufferCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(BindValuebufferCHROMIUM, valuebuffer) == 8,
+ OffsetOf_BindValuebufferCHROMIUM_valuebuffer_not_8);
+
+struct SubscribeValueCHROMIUM {
+ typedef SubscribeValueCHROMIUM ValueType;
+ static const CommandId kCmdId = kSubscribeValueCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLenum _target, GLenum _subscription) {
+ SetHeader();
+ target = _target;
+ subscription = _subscription;
+ }
+
+ void* Set(void* cmd, GLenum _target, GLenum _subscription) {
+ static_cast<ValueType*>(cmd)->Init(_target, _subscription);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32_t target;
+ uint32_t subscription;
+};
+
+COMPILE_ASSERT(sizeof(SubscribeValueCHROMIUM) == 12,
+ Sizeof_SubscribeValueCHROMIUM_is_not_12);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, header) == 0,
+ OffsetOf_SubscribeValueCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, target) == 4,
+ OffsetOf_SubscribeValueCHROMIUM_target_not_4);
+COMPILE_ASSERT(offsetof(SubscribeValueCHROMIUM, subscription) == 8,
+ OffsetOf_SubscribeValueCHROMIUM_subscription_not_8);
+
+struct PopulateSubscribedValuesCHROMIUM {
+ typedef PopulateSubscribedValuesCHROMIUM ValueType;
+ static const CommandId kCmdId = kPopulateSubscribedValuesCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLenum _target) {
+ SetHeader();
+ target = _target;
+ }
+
+ void* Set(void* cmd, GLenum _target) {
+ static_cast<ValueType*>(cmd)->Init(_target);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32_t target;
+};
+
+COMPILE_ASSERT(sizeof(PopulateSubscribedValuesCHROMIUM) == 8,
+ Sizeof_PopulateSubscribedValuesCHROMIUM_is_not_8);
+COMPILE_ASSERT(offsetof(PopulateSubscribedValuesCHROMIUM, header) == 0,
+ OffsetOf_PopulateSubscribedValuesCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(PopulateSubscribedValuesCHROMIUM, target) == 4,
+ OffsetOf_PopulateSubscribedValuesCHROMIUM_target_not_4);
+
+struct UniformValuebufferCHROMIUM {
+ typedef UniformValuebufferCHROMIUM ValueType;
+ static const CommandId kCmdId = kUniformValuebufferCHROMIUM;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLint _location, GLenum _target, GLenum _subscription) {
+ SetHeader();
+ location = _location;
+ target = _target;
+ subscription = _subscription;
+ }
+
+ void* Set(void* cmd, GLint _location, GLenum _target, GLenum _subscription) {
+ static_cast<ValueType*>(cmd)->Init(_location, _target, _subscription);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ int32_t location;
+ uint32_t target;
+ uint32_t subscription;
+};
+
+COMPILE_ASSERT(sizeof(UniformValuebufferCHROMIUM) == 16,
+ Sizeof_UniformValuebufferCHROMIUM_is_not_16);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, header) == 0,
+ OffsetOf_UniformValuebufferCHROMIUM_header_not_0);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, location) == 4,
+ OffsetOf_UniformValuebufferCHROMIUM_location_not_4);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, target) == 8,
+ OffsetOf_UniformValuebufferCHROMIUM_target_not_8);
+COMPILE_ASSERT(offsetof(UniformValuebufferCHROMIUM, subscription) == 12,
+ OffsetOf_UniformValuebufferCHROMIUM_subscription_not_12);
+
struct BindTexImage2DCHROMIUM {
typedef BindTexImage2DCHROMIUM ValueType;
static const CommandId kCmdId = kBindTexImage2DCHROMIUM;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index 7d037a6..d1470d4 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -2533,25 +2533,6 @@
CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
}
-TEST_F(GLES2FormatTest, GetMultipleIntegervCHROMIUM) {
- cmds::GetMultipleIntegervCHROMIUM& cmd =
- *GetBufferAs<cmds::GetMultipleIntegervCHROMIUM>();
- void* next_cmd =
- cmd.Set(&cmd, static_cast<uint32_t>(11), static_cast<uint32_t>(12),
- static_cast<GLuint>(13), static_cast<uint32_t>(14),
- static_cast<uint32_t>(15), static_cast<GLsizeiptr>(16));
- EXPECT_EQ(static_cast<uint32_t>(cmds::GetMultipleIntegervCHROMIUM::kCmdId),
- cmd.header.command);
- EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
- EXPECT_EQ(static_cast<uint32_t>(11), cmd.pnames_shm_id);
- EXPECT_EQ(static_cast<uint32_t>(12), cmd.pnames_shm_offset);
- EXPECT_EQ(static_cast<GLuint>(13), cmd.count);
- EXPECT_EQ(static_cast<uint32_t>(14), cmd.results_shm_id);
- EXPECT_EQ(static_cast<uint32_t>(15), cmd.results_shm_offset);
- EXPECT_EQ(static_cast<GLsizeiptr>(16), cmd.size);
- CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
-}
-
TEST_F(GLES2FormatTest, GetProgramInfoCHROMIUM) {
cmds::GetProgramInfoCHROMIUM& cmd =
*GetBufferAs<cmds::GetProgramInfoCHROMIUM>();
@@ -2939,6 +2920,111 @@
CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
}
+TEST_F(GLES2FormatTest, GenValuebuffersCHROMIUMImmediate) {
+ static GLuint ids[] = {
+ 12, 23, 34,
+ };
+ cmds::GenValuebuffersCHROMIUMImmediate& cmd =
+ *GetBufferAs<cmds::GenValuebuffersCHROMIUMImmediate>();
+ void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(
+ static_cast<uint32_t>(cmds::GenValuebuffersCHROMIUMImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd,
+ sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, DeleteValuebuffersCHROMIUMImmediate) {
+ static GLuint ids[] = {
+ 12, 23, 34,
+ };
+ cmds::DeleteValuebuffersCHROMIUMImmediate& cmd =
+ *GetBufferAs<cmds::DeleteValuebuffersCHROMIUMImmediate>();
+ void* next_cmd = cmd.Set(&cmd, static_cast<GLsizei>(arraysize(ids)), ids);
+ EXPECT_EQ(
+ static_cast<uint32_t>(cmds::DeleteValuebuffersCHROMIUMImmediate::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd) + RoundSizeToMultipleOfEntries(cmd.n * 4u),
+ cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLsizei>(arraysize(ids)), cmd.n);
+ CheckBytesWrittenMatchesExpectedSize(
+ next_cmd,
+ sizeof(cmd) + RoundSizeToMultipleOfEntries(arraysize(ids) * 4u));
+ // TODO(gman): Check that ids were inserted;
+}
+
+TEST_F(GLES2FormatTest, IsValuebufferCHROMIUM) {
+ cmds::IsValuebufferCHROMIUM& cmd =
+ *GetBufferAs<cmds::IsValuebufferCHROMIUM>();
+ void* next_cmd =
+ cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<uint32_t>(12),
+ static_cast<uint32_t>(13));
+ EXPECT_EQ(static_cast<uint32_t>(cmds::IsValuebufferCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.valuebuffer);
+ EXPECT_EQ(static_cast<uint32_t>(12), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32_t>(13), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, BindValuebufferCHROMIUM) {
+ cmds::BindValuebufferCHROMIUM& cmd =
+ *GetBufferAs<cmds::BindValuebufferCHROMIUM>();
+ void* next_cmd =
+ cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLuint>(12));
+ EXPECT_EQ(static_cast<uint32_t>(cmds::BindValuebufferCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLuint>(12), cmd.valuebuffer);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, SubscribeValueCHROMIUM) {
+ cmds::SubscribeValueCHROMIUM& cmd =
+ *GetBufferAs<cmds::SubscribeValueCHROMIUM>();
+ void* next_cmd =
+ cmd.Set(&cmd, static_cast<GLenum>(11), static_cast<GLenum>(12));
+ EXPECT_EQ(static_cast<uint32_t>(cmds::SubscribeValueCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.subscription);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, PopulateSubscribedValuesCHROMIUM) {
+ cmds::PopulateSubscribedValuesCHROMIUM& cmd =
+ *GetBufferAs<cmds::PopulateSubscribedValuesCHROMIUM>();
+ void* next_cmd = cmd.Set(&cmd, static_cast<GLenum>(11));
+ EXPECT_EQ(
+ static_cast<uint32_t>(cmds::PopulateSubscribedValuesCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLenum>(11), cmd.target);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
+TEST_F(GLES2FormatTest, UniformValuebufferCHROMIUM) {
+ cmds::UniformValuebufferCHROMIUM& cmd =
+ *GetBufferAs<cmds::UniformValuebufferCHROMIUM>();
+ void* next_cmd = cmd.Set(&cmd, static_cast<GLint>(11),
+ static_cast<GLenum>(12), static_cast<GLenum>(13));
+ EXPECT_EQ(static_cast<uint32_t>(cmds::UniformValuebufferCHROMIUM::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLint>(11), cmd.location);
+ EXPECT_EQ(static_cast<GLenum>(12), cmd.target);
+ EXPECT_EQ(static_cast<GLenum>(13), cmd.subscription);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
TEST_F(GLES2FormatTest, BindTexImage2DCHROMIUM) {
cmds::BindTexImage2DCHROMIUM& cmd =
*GetBufferAs<cmds::BindTexImage2DCHROMIUM>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index 8bd5c0a..9c98f51 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -178,39 +178,45 @@
OP(ResizeCHROMIUM) /* 419 */ \
OP(GetRequestableExtensionsCHROMIUM) /* 420 */ \
OP(RequestExtensionCHROMIUM) /* 421 */ \
- OP(GetMultipleIntegervCHROMIUM) /* 422 */ \
- OP(GetProgramInfoCHROMIUM) /* 423 */ \
- OP(GetTranslatedShaderSourceANGLE) /* 424 */ \
- OP(PostSubBufferCHROMIUM) /* 425 */ \
- OP(TexImageIOSurface2DCHROMIUM) /* 426 */ \
- OP(CopyTextureCHROMIUM) /* 427 */ \
- OP(DrawArraysInstancedANGLE) /* 428 */ \
- OP(DrawElementsInstancedANGLE) /* 429 */ \
- OP(VertexAttribDivisorANGLE) /* 430 */ \
- OP(GenMailboxCHROMIUM) /* 431 */ \
- OP(ProduceTextureCHROMIUMImmediate) /* 432 */ \
- OP(ProduceTextureDirectCHROMIUMImmediate) /* 433 */ \
- OP(ConsumeTextureCHROMIUMImmediate) /* 434 */ \
- OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 435 */ \
- OP(BindUniformLocationCHROMIUMBucket) /* 436 */ \
- OP(BindTexImage2DCHROMIUM) /* 437 */ \
- OP(ReleaseTexImage2DCHROMIUM) /* 438 */ \
- OP(TraceBeginCHROMIUM) /* 439 */ \
- OP(TraceEndCHROMIUM) /* 440 */ \
- OP(AsyncTexSubImage2DCHROMIUM) /* 441 */ \
- OP(AsyncTexImage2DCHROMIUM) /* 442 */ \
- OP(WaitAsyncTexImage2DCHROMIUM) /* 443 */ \
- OP(WaitAllAsyncTexImage2DCHROMIUM) /* 444 */ \
- OP(DiscardFramebufferEXTImmediate) /* 445 */ \
- OP(LoseContextCHROMIUM) /* 446 */ \
- OP(InsertSyncPointCHROMIUM) /* 447 */ \
- OP(WaitSyncPointCHROMIUM) /* 448 */ \
- OP(DrawBuffersEXTImmediate) /* 449 */ \
- OP(DiscardBackbufferCHROMIUM) /* 450 */ \
- OP(ScheduleOverlayPlaneCHROMIUM) /* 451 */ \
- OP(MatrixLoadfCHROMIUMImmediate) /* 452 */ \
- OP(MatrixLoadIdentityCHROMIUM) /* 453 */ \
- OP(BlendBarrierKHR) /* 454 */
+ OP(GetProgramInfoCHROMIUM) /* 422 */ \
+ OP(GetTranslatedShaderSourceANGLE) /* 423 */ \
+ OP(PostSubBufferCHROMIUM) /* 424 */ \
+ OP(TexImageIOSurface2DCHROMIUM) /* 425 */ \
+ OP(CopyTextureCHROMIUM) /* 426 */ \
+ OP(DrawArraysInstancedANGLE) /* 427 */ \
+ OP(DrawElementsInstancedANGLE) /* 428 */ \
+ OP(VertexAttribDivisorANGLE) /* 429 */ \
+ OP(GenMailboxCHROMIUM) /* 430 */ \
+ OP(ProduceTextureCHROMIUMImmediate) /* 431 */ \
+ OP(ProduceTextureDirectCHROMIUMImmediate) /* 432 */ \
+ OP(ConsumeTextureCHROMIUMImmediate) /* 433 */ \
+ OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 434 */ \
+ OP(BindUniformLocationCHROMIUMBucket) /* 435 */ \
+ OP(GenValuebuffersCHROMIUMImmediate) /* 436 */ \
+ OP(DeleteValuebuffersCHROMIUMImmediate) /* 437 */ \
+ OP(IsValuebufferCHROMIUM) /* 438 */ \
+ OP(BindValuebufferCHROMIUM) /* 439 */ \
+ OP(SubscribeValueCHROMIUM) /* 440 */ \
+ OP(PopulateSubscribedValuesCHROMIUM) /* 441 */ \
+ OP(UniformValuebufferCHROMIUM) /* 442 */ \
+ OP(BindTexImage2DCHROMIUM) /* 443 */ \
+ OP(ReleaseTexImage2DCHROMIUM) /* 444 */ \
+ OP(TraceBeginCHROMIUM) /* 445 */ \
+ OP(TraceEndCHROMIUM) /* 446 */ \
+ OP(AsyncTexSubImage2DCHROMIUM) /* 447 */ \
+ OP(AsyncTexImage2DCHROMIUM) /* 448 */ \
+ OP(WaitAsyncTexImage2DCHROMIUM) /* 449 */ \
+ OP(WaitAllAsyncTexImage2DCHROMIUM) /* 450 */ \
+ OP(DiscardFramebufferEXTImmediate) /* 451 */ \
+ OP(LoseContextCHROMIUM) /* 452 */ \
+ OP(InsertSyncPointCHROMIUM) /* 453 */ \
+ OP(WaitSyncPointCHROMIUM) /* 454 */ \
+ OP(DrawBuffersEXTImmediate) /* 455 */ \
+ OP(DiscardBackbufferCHROMIUM) /* 456 */ \
+ OP(ScheduleOverlayPlaneCHROMIUM) /* 457 */ \
+ OP(MatrixLoadfCHROMIUMImmediate) /* 458 */ \
+ OP(MatrixLoadIdentityCHROMIUM) /* 459 */ \
+ OP(BlendBarrierKHR) /* 460 */
enum CommandId {
kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
index 1871201..e8631e6 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -55,6 +55,7 @@
static std::string GetStringSrcBlendFactor(uint32_t value);
static std::string GetStringStencilOp(uint32_t value);
static std::string GetStringStringType(uint32_t value);
+static std::string GetStringSubscriptionTarget(uint32_t value);
static std::string GetStringTextureBindTarget(uint32_t value);
static std::string GetStringTextureFormat(uint32_t value);
static std::string GetStringTextureInternalFormat(uint32_t value);
@@ -66,6 +67,7 @@
static std::string GetStringTextureTarget(uint32_t value);
static std::string GetStringTextureUsage(uint32_t value);
static std::string GetStringTextureWrapMode(uint32_t value);
+static std::string GetStringValueBufferTarget(uint32_t value);
static std::string GetStringVertexAttribType(uint32_t value);
static std::string GetStringVertexAttribute(uint32_t value);
static std::string GetStringVertexPointer(uint32_t value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index aba98aa..1a0945a 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -3065,6 +3065,14 @@
"GL_MAX_GEOMETRY_OUTPUT_VERTICES_EXT",
},
{
+ 0x924C,
+ "GL_MOUSE_POSITION_CHROMIUM",
+ },
+ {
+ 0x924B,
+ "GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM",
+ },
+ {
0x924A,
"GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM",
},
@@ -4355,6 +4363,14 @@
arraysize(string_table), value);
}
+std::string GLES2Util::GetStringSubscriptionTarget(uint32_t value) {
+ static const EnumToString string_table[] = {
+ {GL_MOUSE_POSITION_CHROMIUM, "GL_MOUSE_POSITION_CHROMIUM"},
+ };
+ return GLES2Util::GetQualifiedEnumString(string_table,
+ arraysize(string_table), value);
+}
+
std::string GLES2Util::GetStringTextureBindTarget(uint32_t value) {
static const EnumToString string_table[] = {
{GL_TEXTURE_2D, "GL_TEXTURE_2D"},
@@ -4479,6 +4495,15 @@
arraysize(string_table), value);
}
+std::string GLES2Util::GetStringValueBufferTarget(uint32_t value) {
+ static const EnumToString string_table[] = {
+ {GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ "GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM"},
+ };
+ return GLES2Util::GetQualifiedEnumString(string_table,
+ arraysize(string_table), value);
+}
+
std::string GLES2Util::GetStringVertexAttribType(uint32_t value) {
static const EnumToString string_table[] = {
{GL_BYTE, "GL_BYTE"},
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 8293fbc..4013c3a 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -107,6 +107,8 @@
"texture_manager.cc",
"transfer_buffer_manager.cc",
"transfer_buffer_manager.h",
+ "valuebuffer_manager.h",
+ "valuebuffer_manager.cc",
"vertex_array_manager.h",
"vertex_array_manager.cc",
"vertex_attrib_manager.h",
diff --git a/gpu/command_buffer/service/context_group.cc b/gpu/command_buffer/service/context_group.cc
index 00e7ec3..6ee57e4 100644
--- a/gpu/command_buffer/service/context_group.cc
+++ b/gpu/command_buffer/service/context_group.cc
@@ -21,6 +21,7 @@
#include "gpu/command_buffer/service/shader_manager.h"
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/command_buffer/service/transfer_buffer_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "ui/gl/gl_implementation.h"
namespace gpu {
@@ -121,6 +122,7 @@
renderbuffer_manager_.reset(new RenderbufferManager(
memory_tracker_.get(), max_renderbuffer_size, max_samples,
depth24_supported));
+ valuebuffer_manager_.reset(new ValuebufferManager());
shader_manager_.reset(new ShaderManager());
// Lookup GL things we need to know.
@@ -300,6 +302,11 @@
renderbuffer_manager_.reset();
}
+ if (valuebuffer_manager_ != NULL) {
+ valuebuffer_manager_->Destroy();
+ valuebuffer_manager_.reset();
+ }
+
if (texture_manager_ != NULL) {
texture_manager_->Destroy(have_context);
texture_manager_.reset();
diff --git a/gpu/command_buffer/service/context_group.h b/gpu/command_buffer/service/context_group.h
index ae4550c..eb53252 100644
--- a/gpu/command_buffer/service/context_group.h
+++ b/gpu/command_buffer/service/context_group.h
@@ -34,6 +34,7 @@
class ProgramManager;
class ShaderManager;
class TextureManager;
+class ValuebufferManager;
class MemoryTracker;
struct DisallowedFeatures;
@@ -126,6 +127,10 @@
return renderbuffer_manager_.get();
}
+ ValuebufferManager* valuebuffer_manager() const {
+ return valuebuffer_manager_.get();
+ }
+
TextureManager* texture_manager() const {
return texture_manager_.get();
}
@@ -199,6 +204,8 @@
scoped_ptr<RenderbufferManager> renderbuffer_manager_;
+ scoped_ptr<ValuebufferManager> valuebuffer_manager_;
+
scoped_ptr<TextureManager> texture_manager_;
scoped_ptr<ProgramManager> program_manager_;
diff --git a/gpu/command_buffer/service/context_state.h b/gpu/command_buffer/service/context_state.h
index 7488f57..b4e812c 100644
--- a/gpu/command_buffer/service/context_state.h
+++ b/gpu/command_buffer/service/context_state.h
@@ -13,6 +13,7 @@
#include "gpu/command_buffer/service/gl_utils.h"
#include "gpu/command_buffer/service/query_manager.h"
#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
#include "gpu/command_buffer/service/vertex_array_manager.h"
#include "gpu/gpu_export.h"
@@ -200,6 +201,9 @@
scoped_refptr<Renderbuffer> bound_renderbuffer;
bool bound_renderbuffer_valid;
+ // The currently bound valuebuffer
+ scoped_refptr<Valuebuffer> bound_valuebuffer;
+
// A map of of target -> Query for current queries
typedef std::map<GLuint, scoped_refptr<QueryManager::Query> > QueryMap;
QueryMap current_queries;
diff --git a/gpu/command_buffer/service/feature_info.cc b/gpu/command_buffer/service/feature_info.cc
index 9be747d..24e1f92 100644
--- a/gpu/command_buffer/service/feature_info.cc
+++ b/gpu/command_buffer/service/feature_info.cc
@@ -477,16 +477,22 @@
enable_texture_half_float_linear = true;
may_enable_chromium_color_buffer_float = true;
} else {
- if (is_es3 || extensions.Contains("GL_OES_texture_float")) {
+ // GLES3 adds support for Float type by default but it doesn't support all
+ // formats as GL_OES_texture_float(i.e.LUMINANCE_ALPHA,LUMINANCE and Alpha)
+ if (extensions.Contains("GL_OES_texture_float")) {
enable_texture_float = true;
if (extensions.Contains("GL_OES_texture_float_linear")) {
enable_texture_float_linear = true;
}
+ // This extension allows a variety of floating point formats to be
+ // rendered to via framebuffer objects. Enable it's usage only if
+ // support for Floating textures is enabled.
if ((is_es3 && extensions.Contains("GL_EXT_color_buffer_float")) ||
feature_flags_.is_angle) {
may_enable_chromium_color_buffer_float = true;
}
}
+
// TODO(dshwang): GLES3 supports half float by default but GL_HALF_FLOAT_OES
// isn't equal to GL_HALF_FLOAT.
if (extensions.Contains("GL_OES_texture_half_float")) {
diff --git a/gpu/command_buffer/service/feature_info_unittest.cc b/gpu/command_buffer/service/feature_info_unittest.cc
index 69bd4d3..88a0a37 100644
--- a/gpu/command_buffer/service/feature_info_unittest.cc
+++ b/gpu/command_buffer/service/feature_info_unittest.cc
@@ -669,6 +669,26 @@
GL_RGB32F));
}
+TEST_F(FeatureInfoTest, Initialize_texture_floatGLES3) {
+ SetupInitExpectationsWithGLVersion("", "", "OpenGL ES 3.0");
+ EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_float")));
+ EXPECT_THAT(info_->extensions(), Not(HasSubstr("GL_OES_texture_half_float")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_float_linear")));
+ EXPECT_THAT(info_->extensions(),
+ Not(HasSubstr("GL_OES_texture_half_float_linear")));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGB).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_RGBA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_LUMINANCE_ALPHA).IsValid(
+ GL_FLOAT));
+ EXPECT_FALSE(info_->GetTextureFormatValidator(GL_ALPHA).IsValid(
+ GL_FLOAT));
+}
+
TEST_F(FeatureInfoTest, InitializeOES_texture_floatGLES2) {
SetupInitExpectations("GL_OES_texture_float");
EXPECT_FALSE(info_->feature_flags().enable_texture_float_linear);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 9b028fd..4d54739 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -56,6 +56,7 @@
#include "gpu/command_buffer/service/shader_translator.h"
#include "gpu/command_buffer/service/shader_translator_cache.h"
#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "gpu/command_buffer/service/vertex_array_manager.h"
#include "gpu/command_buffer/service/vertex_attrib_manager.h"
#include "third_party/smhasher/src/City.h"
@@ -627,7 +628,7 @@
return vertex_array_manager_.get();
}
ImageManager* GetImageManager() override { return image_manager_.get(); }
- bool ProcessPendingQueries() override;
+ bool ProcessPendingQueries(bool did_finish) override;
bool HasMoreIdleWork() override;
void PerformIdleWork() override;
@@ -727,6 +728,8 @@
void DeleteFramebuffersHelper(GLsizei n, const GLuint* client_ids);
bool GenRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
void DeleteRenderbuffersHelper(GLsizei n, const GLuint* client_ids);
+ bool GenValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
+ void DeleteValuebuffersCHROMIUMHelper(GLsizei n, const GLuint* client_ids);
bool GenQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
void DeleteQueriesEXTHelper(GLsizei n, const GLuint* client_ids);
bool GenVertexArraysOESHelper(GLsizei n, const GLuint* client_ids);
@@ -756,6 +759,10 @@
return group_->framebuffer_manager();
}
+ ValuebufferManager* valuebuffer_manager() {
+ return group_->valuebuffer_manager();
+ }
+
ProgramManager* program_manager() {
return group_->program_manager();
}
@@ -944,6 +951,14 @@
void DoCreateAndConsumeTextureCHROMIUM(GLenum target, const GLbyte* key,
GLuint client_id);
+ bool DoIsValuebufferCHROMIUM(GLuint client_id);
+ void DoBindValueBufferCHROMIUM(GLenum target, GLuint valuebuffer);
+ void DoSubscribeValueCHROMIUM(GLenum target, GLenum subscription);
+ void DoPopulateSubscribedValuesCHROMIUM(GLenum target);
+ void DoUniformValueBufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription);
+
void DoBindTexImage2DCHROMIUM(
GLenum target,
GLint image_id);
@@ -1096,6 +1111,21 @@
renderbuffer_manager()->RemoveRenderbuffer(client_id);
}
+ // Creates a valuebuffer info for the given valuebuffer.
+ void CreateValuebuffer(GLuint client_id) {
+ return valuebuffer_manager()->CreateValuebuffer(client_id);
+ }
+
+ // Gets the valuebuffer info for a given valuebuffer.
+ Valuebuffer* GetValuebuffer(GLuint client_id) {
+ return valuebuffer_manager()->GetValuebuffer(client_id);
+ }
+
+ // Removes the valuebuffer info for the given valuebuffer.
+ void RemoveValuebuffer(GLuint client_id) {
+ valuebuffer_manager()->RemoveValuebuffer(client_id);
+ }
+
// Gets the vertex attrib manager for the given vertex array.
VertexAttribManager* GetVertexAttribManager(GLuint client_id) {
VertexAttribManager* info =
@@ -1177,6 +1207,22 @@
GLenum target,
const char* func_name);
+ // Check if the current valuebuffer exists and is valid. If not generates
+ // the appropriate GL error. Returns true if the current valuebuffer is in
+ // a usable state.
+ bool CheckCurrentValuebuffer(const char* function_name);
+
+ // Check if the current valuebuffer exists and is valiud and that the
+ // value buffer is actually subscribed to the given subscription
+ bool CheckCurrentValuebufferForSubscription(GLenum subscription,
+ const char* function_name);
+
+ // Check if the location can be used for the given subscription target. If not
+ // generates the appropriate GL error. Returns true if the location is usable
+ bool CheckSubscriptionTarget(GLint location,
+ GLenum subscription,
+ const char* function_name);
+
// Checks if the current program exists and is valid. If not generates the
// appropriate GL error. Returns true if the current program is in a usable
// state.
@@ -1193,6 +1239,13 @@
// of the draw operation are the same.
bool CheckDrawingFeedbackLoops();
+ // Checks if |api_type| is valid for the given uniform
+ // If the api type is not valid generates the appropriate GL
+ // error. Returns true if |api_type| is valid for the uniform
+ bool CheckUniformForApiType(const Program::UniformInfo* info,
+ const char* function_name,
+ Program::UniformApiType api_type);
+
// Gets the type of a uniform for a location in the current program. Sets GL
// errors if the current program is not valid. Returns true if the current
// program is valid and the location exists. Adjusts count so it
@@ -2670,6 +2723,7 @@
DoBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
DoBindFramebuffer(GL_FRAMEBUFFER, 0);
DoBindRenderbuffer(GL_RENDERBUFFER, 0);
+ DoBindValueBufferCHROMIUM(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, 0);
bool call_gl_clear = !surfaceless_;
#if defined(OS_ANDROID)
@@ -2719,6 +2773,34 @@
DCHECK(initialized());
Capabilities caps;
+ caps.VisitPrecisions([](GLenum shader, GLenum type,
+ Capabilities::ShaderPrecision* shader_precision) {
+ GLint range[2] = {0, 0};
+ GLint precision = 0;
+ GetShaderPrecisionFormatImpl(shader, type, range, &precision);
+ shader_precision->min_range = range[0];
+ shader_precision->max_range = range[1];
+ shader_precision->precision = precision;
+ });
+ DoGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS,
+ &caps.max_combined_texture_image_units);
+ DoGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &caps.max_cube_map_texture_size);
+ DoGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS,
+ &caps.max_fragment_uniform_vectors);
+ DoGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &caps.max_renderbuffer_size);
+ DoGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &caps.max_texture_image_units);
+ DoGetIntegerv(GL_MAX_TEXTURE_SIZE, &caps.max_texture_size);
+ DoGetIntegerv(GL_MAX_VARYING_VECTORS, &caps.max_varying_vectors);
+ DoGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &caps.max_vertex_attribs);
+ DoGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS,
+ &caps.max_vertex_texture_image_units);
+ DoGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS,
+ &caps.max_vertex_uniform_vectors);
+ DoGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS,
+ &caps.num_compressed_texture_formats);
+ DoGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &caps.num_shader_binary_formats);
+ DoGetIntegerv(GL_BIND_GENERATES_RESOURCE_CHROMIUM,
+ &caps.bind_generates_resource_chromium);
caps.egl_image_external =
feature_info_->feature_flags().oes_egl_image_external;
@@ -2907,6 +2989,19 @@
return true;
}
+bool GLES2DecoderImpl::GenValuebuffersCHROMIUMHelper(GLsizei n,
+ const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ if (GetValuebuffer(client_ids[ii])) {
+ return false;
+ }
+ }
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ CreateValuebuffer(client_ids[ii]);
+ }
+ return true;
+}
+
bool GLES2DecoderImpl::GenTexturesHelper(GLsizei n, const GLuint* client_ids) {
for (GLsizei ii = 0; ii < n; ++ii) {
if (GetTexture(client_ids[ii])) {
@@ -2996,6 +3091,20 @@
}
}
+void GLES2DecoderImpl::DeleteValuebuffersCHROMIUMHelper(
+ GLsizei n,
+ const GLuint* client_ids) {
+ for (GLsizei ii = 0; ii < n; ++ii) {
+ Valuebuffer* valuebuffer = GetValuebuffer(client_ids[ii]);
+ if (valuebuffer) {
+ if (state_.bound_valuebuffer.get() == valuebuffer) {
+ state_.bound_valuebuffer = NULL;
+ }
+ RemoveValuebuffer(client_ids[ii]);
+ }
+ }
+}
+
void GLES2DecoderImpl::DeleteTexturesHelper(
GLsizei n, const GLuint* client_ids) {
bool supports_separate_framebuffer_binds =
@@ -3425,6 +3534,7 @@
framebuffer_state_.bound_read_framebuffer = NULL;
framebuffer_state_.bound_draw_framebuffer = NULL;
state_.bound_renderbuffer = NULL;
+ state_.bound_valuebuffer = NULL;
if (offscreen_saved_color_texture_info_.get()) {
DCHECK(offscreen_target_color_texture_);
@@ -3916,12 +4026,12 @@
void GLES2DecoderImpl::DoFinish() {
glFinish();
ProcessPendingReadPixels();
- ProcessPendingQueries();
+ ProcessPendingQueries(true);
}
void GLES2DecoderImpl::DoFlush() {
glFlush();
- ProcessPendingQueries();
+ ProcessPendingQueries(false);
}
void GLES2DecoderImpl::DoActiveTexture(GLenum texture_unit) {
@@ -5722,6 +5832,55 @@
"glTexParameteriv", GetErrorState(), texture, pname, *params);
}
+bool GLES2DecoderImpl::CheckCurrentValuebuffer(const char* function_name) {
+ if (!state_.bound_valuebuffer.get()) {
+ // There is no valuebuffer bound
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+ "no valuebuffer in use");
+ return false;
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::CheckCurrentValuebufferForSubscription(
+ GLenum subscription,
+ const char* function_name) {
+ if (!CheckCurrentValuebuffer(function_name)) {
+ return false;
+ }
+ if (!state_.bound_valuebuffer.get()->IsSubscribed(subscription)) {
+ // The valuebuffer is not subscribed to the target
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+ "valuebuffer is not subscribed");
+ return false;
+ }
+ return true;
+}
+
+bool GLES2DecoderImpl::CheckSubscriptionTarget(GLint location,
+ GLenum subscription,
+ const char* function_name) {
+ if (!CheckCurrentProgramForUniform(location, function_name)) {
+ return false;
+ }
+ GLint real_location = -1;
+ GLint array_index = -1;
+ const Program::UniformInfo* info =
+ state_.current_program->GetUniformInfoByFakeLocation(
+ location, &real_location, &array_index);
+ if (!info) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name, "unknown location");
+ return false;
+ }
+ if ((ValuebufferManager::ApiTypeForSubscriptionTarget(subscription) &
+ info->accepts_api_type) == 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+ "wrong type for subscription");
+ return false;
+ }
+ return true;
+}
+
bool GLES2DecoderImpl::CheckCurrentProgram(const char* function_name) {
if (!state_.current_program.get()) {
// The program does not exist.
@@ -5777,6 +5936,19 @@
return false;
}
+bool GLES2DecoderImpl::CheckUniformForApiType(
+ const Program::UniformInfo* info,
+ const char* function_name,
+ Program::UniformApiType api_type) {
+ DCHECK(info);
+ if ((api_type & info->accepts_api_type) == 0) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, function_name,
+ "wrong uniform function for type");
+ return false;
+ }
+ return true;
+}
+
bool GLES2DecoderImpl::PrepForSetUniformByLocation(
GLint fake_location,
const char* function_name,
@@ -5800,11 +5972,7 @@
GL_INVALID_OPERATION, function_name, "unknown location");
return false;
}
-
- if ((api_type & info->accepts_api_type) == 0) {
- LOCAL_SET_GL_ERROR(
- GL_INVALID_OPERATION, function_name,
- "wrong uniform function for type");
+ if (!CheckUniformForApiType(info, function_name, api_type)) {
return false;
}
if (*count > 1 && !info->is_array) {
@@ -7608,7 +7776,7 @@
}
} else {
if (async && features().use_async_readpixels) {
- GLuint buffer;
+ 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);
@@ -7627,6 +7795,7 @@
} else {
// On error, unbind pack buffer and fall through to sync readpixels
glBindBuffer(GL_PIXEL_PACK_BUFFER_ARB, 0);
+ glDeleteBuffersARB(1, &buffer);
}
}
glReadPixels(x, y, width, height, format, type, pixels);
@@ -9572,88 +9741,6 @@
return error::kNoError;
}
-error::Error GLES2DecoderImpl::HandleGetMultipleIntegervCHROMIUM(
- uint32 immediate_data_size,
- const void* cmd_data) {
- const gles2::cmds::GetMultipleIntegervCHROMIUM& c =
- *static_cast<const gles2::cmds::GetMultipleIntegervCHROMIUM*>(cmd_data);
- GLuint count = c.count;
- uint32 pnames_size;
- if (!SafeMultiplyUint32(count, sizeof(GLenum), &pnames_size)) {
- return error::kOutOfBounds;
- }
- const GLenum* pnames = GetSharedMemoryAs<const GLenum*>(
- c.pnames_shm_id, c.pnames_shm_offset, pnames_size);
- if (pnames == NULL) {
- return error::kOutOfBounds;
- }
-
- // We have to copy them since we use them twice so the client
- // can't change them between the time we validate them and the time we use
- // them.
- scoped_ptr<GLenum[]> enums(new GLenum[count]);
- memcpy(enums.get(), pnames, pnames_size);
-
- // Count up the space needed for the result.
- uint32 num_results = 0;
- for (GLuint ii = 0; ii < count; ++ii) {
- uint32 num = util_.GLGetNumValuesReturned(enums[ii]);
- if (num == 0) {
- LOCAL_SET_GL_ERROR_INVALID_ENUM(
- "glGetMultipleCHROMIUM", enums[ii], "pname");
- return error::kNoError;
- }
- // Num will never be more than 4.
- DCHECK_LE(num, 4u);
- if (!SafeAddUint32(num_results, num, &num_results)) {
- return error::kOutOfBounds;
- }
- }
-
- uint32 result_size = 0;
- if (!SafeMultiplyUint32(num_results, sizeof(GLint), &result_size)) {
- return error::kOutOfBounds;
- }
-
- if (result_size != static_cast<uint32>(c.size)) {
- LOCAL_SET_GL_ERROR(
- GL_INVALID_VALUE,
- "glGetMultipleCHROMIUM", "bad size GL_INVALID_VALUE");
- return error::kNoError;
- }
-
- GLint* results = GetSharedMemoryAs<GLint*>(
- c.results_shm_id, c.results_shm_offset, result_size);
- if (results == NULL) {
- return error::kOutOfBounds;
- }
-
- // Check the results have been cleared in case the context was lost.
- for (uint32 ii = 0; ii < num_results; ++ii) {
- if (results[ii]) {
- return error::kInvalidArguments;
- }
- }
-
- // Get each result.
- GLint* start = results;
- for (GLuint ii = 0; ii < count; ++ii) {
- GLsizei num_written = 0;
- if (!state_.GetStateAsGLint(enums[ii], results, &num_written) &&
- !GetHelper(enums[ii], results, &num_written)) {
- DoGetIntegerv(enums[ii], results);
- }
- results += num_written;
- }
-
- // Just to verify. Should this be a DCHECK?
- if (static_cast<uint32>(results - start) != num_results) {
- return error::kOutOfBounds;
- }
-
- return error::kNoError;
-}
-
error::Error GLES2DecoderImpl::HandleGetProgramInfoCHROMIUM(
uint32 immediate_data_size,
const void* cmd_data) {
@@ -9817,11 +9904,11 @@
}
}
-bool GLES2DecoderImpl::ProcessPendingQueries() {
+bool GLES2DecoderImpl::ProcessPendingQueries(bool did_finish) {
if (query_manager_.get() == NULL) {
return false;
}
- if (!query_manager_->ProcessPendingQueries()) {
+ if (!query_manager_->ProcessPendingQueries(did_finish)) {
current_decoder_error_ = error::kOutOfBounds;
}
return query_manager_->HavePendingQueries();
@@ -10696,6 +10783,73 @@
texture_ref = texture_manager()->Consume(client_id, texture);
}
+bool GLES2DecoderImpl::DoIsValuebufferCHROMIUM(GLuint client_id) {
+ const Valuebuffer* valuebuffer = GetValuebuffer(client_id);
+ return valuebuffer && valuebuffer->IsValid();
+}
+
+void GLES2DecoderImpl::DoBindValueBufferCHROMIUM(GLenum target,
+ GLuint client_id) {
+ Valuebuffer* valuebuffer = NULL;
+ if (client_id != 0) {
+ valuebuffer = GetValuebuffer(client_id);
+ if (!valuebuffer) {
+ if (!group_->bind_generates_resource()) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_OPERATION, "glBindValuebufferCHROMIUM",
+ "id not generated by glBindValuebufferCHROMIUM");
+ return;
+ }
+
+ // It's a new id so make a valuebuffer for it.
+ CreateValuebuffer(client_id);
+ valuebuffer = GetValuebuffer(client_id);
+ }
+ valuebuffer->MarkAsValid();
+ }
+ state_.bound_valuebuffer = valuebuffer;
+}
+
+void GLES2DecoderImpl::DoSubscribeValueCHROMIUM(GLenum target,
+ GLenum subscription) {
+ if (!CheckCurrentValuebuffer("glSubscribeValueCHROMIUM")) {
+ return;
+ }
+ state_.bound_valuebuffer.get()->AddSubscription(subscription);
+}
+
+void GLES2DecoderImpl::DoPopulateSubscribedValuesCHROMIUM(GLenum target) {
+ if (!CheckCurrentValuebuffer("glPopulateSubscribedValuesCHROMIUM")) {
+ return;
+ }
+ valuebuffer_manager()->UpdateValuebufferState(state_.bound_valuebuffer.get());
+}
+
+void GLES2DecoderImpl::DoUniformValueBufferCHROMIUM(GLint location,
+ GLenum target,
+ GLenum subscription) {
+ if (!CheckCurrentValuebufferForSubscription(
+ subscription, "glPopulateSubscribedValuesCHROMIUM")) {
+ return;
+ }
+ if (!CheckSubscriptionTarget(location, subscription,
+ "glPopulateSubscribedValuesCHROMIUM")) {
+ return;
+ }
+ const ValueState* state =
+ state_.bound_valuebuffer.get()->GetState(subscription);
+ if (state) {
+ switch (subscription) {
+ case GL_MOUSE_POSITION_CHROMIUM:
+ DoUniform2iv(location, 1, state->int_value);
+ break;
+ default:
+ NOTREACHED() << "Unhandled uniform subscription target "
+ << subscription;
+ break;
+ }
+ }
+}
+
void GLES2DecoderImpl::DoInsertEventMarkerEXT(
GLsizei length, const GLchar* marker) {
if (!marker) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.h b/gpu/command_buffer/service/gles2_cmd_decoder.h
index 8d72335..63618c2 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.h
@@ -171,7 +171,7 @@
virtual ImageManager* GetImageManager() = 0;
// Process any pending queries. Returns false if there are no pending queries.
- virtual bool ProcessPendingQueries() = 0;
+ virtual bool ProcessPendingQueries(bool did_finish) = 0;
// Returns false if there are no idle work to be made.
virtual bool HasMoreIdleWork() = 0;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 86b36ca..ee3bba5 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -3109,6 +3109,146 @@
return error::kNoError;
}
+error::Error GLES2DecoderImpl::HandleGenValuebuffersCHROMIUMImmediate(
+ uint32_t immediate_data_size,
+ const void* cmd_data) {
+ const gles2::cmds::GenValuebuffersCHROMIUMImmediate& c =
+ *static_cast<const gles2::cmds::GenValuebuffersCHROMIUMImmediate*>(
+ cmd_data);
+ (void)c;
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32_t data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ GLuint* buffers =
+ GetImmediateDataAs<GLuint*>(c, data_size, immediate_data_size);
+ if (buffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ if (!GenValuebuffersCHROMIUMHelper(n, buffers)) {
+ return error::kInvalidArguments;
+ }
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleDeleteValuebuffersCHROMIUMImmediate(
+ uint32_t immediate_data_size,
+ const void* cmd_data) {
+ const gles2::cmds::DeleteValuebuffersCHROMIUMImmediate& c =
+ *static_cast<const gles2::cmds::DeleteValuebuffersCHROMIUMImmediate*>(
+ cmd_data);
+ (void)c;
+ GLsizei n = static_cast<GLsizei>(c.n);
+ uint32_t data_size;
+ if (!SafeMultiplyUint32(n, sizeof(GLuint), &data_size)) {
+ return error::kOutOfBounds;
+ }
+ const GLuint* valuebuffers =
+ GetImmediateDataAs<const GLuint*>(c, data_size, immediate_data_size);
+ if (valuebuffers == NULL) {
+ return error::kOutOfBounds;
+ }
+ DeleteValuebuffersCHROMIUMHelper(n, valuebuffers);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleIsValuebufferCHROMIUM(
+ uint32_t immediate_data_size,
+ const void* cmd_data) {
+ const gles2::cmds::IsValuebufferCHROMIUM& c =
+ *static_cast<const gles2::cmds::IsValuebufferCHROMIUM*>(cmd_data);
+ (void)c;
+ GLuint valuebuffer = c.valuebuffer;
+ typedef cmds::IsValuebufferCHROMIUM::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ *result_dst = DoIsValuebufferCHROMIUM(valuebuffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleBindValuebufferCHROMIUM(
+ uint32_t immediate_data_size,
+ const void* cmd_data) {
+ const gles2::cmds::BindValuebufferCHROMIUM& c =
+ *static_cast<const gles2::cmds::BindValuebufferCHROMIUM*>(cmd_data);
+ (void)c;
+ GLenum target = static_cast<GLenum>(c.target);
+ GLuint valuebuffer = c.valuebuffer;
+ if (!validators_->value_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glBindValuebufferCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ DoBindValueBufferCHROMIUM(target, valuebuffer);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleSubscribeValueCHROMIUM(
+ uint32_t immediate_data_size,
+ const void* cmd_data) {
+ const gles2::cmds::SubscribeValueCHROMIUM& c =
+ *static_cast<const gles2::cmds::SubscribeValueCHROMIUM*>(cmd_data);
+ (void)c;
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum subscription = static_cast<GLenum>(c.subscription);
+ if (!validators_->value_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glSubscribeValueCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ if (!validators_->subscription_target.IsValid(subscription)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glSubscribeValueCHROMIUM", subscription,
+ "subscription");
+ return error::kNoError;
+ }
+ DoSubscribeValueCHROMIUM(target, subscription);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandlePopulateSubscribedValuesCHROMIUM(
+ uint32_t immediate_data_size,
+ const void* cmd_data) {
+ const gles2::cmds::PopulateSubscribedValuesCHROMIUM& c =
+ *static_cast<const gles2::cmds::PopulateSubscribedValuesCHROMIUM*>(
+ cmd_data);
+ (void)c;
+ GLenum target = static_cast<GLenum>(c.target);
+ if (!validators_->value_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glPopulateSubscribedValuesCHROMIUM",
+ target, "target");
+ return error::kNoError;
+ }
+ DoPopulateSubscribedValuesCHROMIUM(target);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleUniformValuebufferCHROMIUM(
+ uint32_t immediate_data_size,
+ const void* cmd_data) {
+ const gles2::cmds::UniformValuebufferCHROMIUM& c =
+ *static_cast<const gles2::cmds::UniformValuebufferCHROMIUM*>(cmd_data);
+ (void)c;
+ GLint location = static_cast<GLint>(c.location);
+ GLenum target = static_cast<GLenum>(c.target);
+ GLenum subscription = static_cast<GLenum>(c.subscription);
+ if (!validators_->value_buffer_target.IsValid(target)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glUniformValuebufferCHROMIUM", target,
+ "target");
+ return error::kNoError;
+ }
+ if (!validators_->subscription_target.IsValid(subscription)) {
+ LOCAL_SET_GL_ERROR_INVALID_ENUM("glUniformValuebufferCHROMIUM",
+ subscription, "subscription");
+ return error::kNoError;
+ }
+ DoUniformValueBufferCHROMIUM(location, target, subscription);
+ return error::kNoError;
+}
+
error::Error GLES2DecoderImpl::HandleBindTexImage2DCHROMIUM(
uint32_t immediate_data_size,
const void* cmd_data) {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
index 7346d8e..d855c87 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_mock.h
@@ -57,7 +57,7 @@
MOCK_METHOD0(GetContextGroup, ContextGroup*());
MOCK_METHOD0(GetContextState, const ContextState*());
MOCK_METHOD0(GetCapabilities, Capabilities());
- MOCK_METHOD0(ProcessPendingQueries, bool());
+ MOCK_METHOD1(ProcessPendingQueries, bool(bool));
MOCK_METHOD0(HasMoreIdleWork, bool());
MOCK_METHOD0(PerformIdleWork, void());
MOCK_METHOD1(RestoreState, void(const ContextState* prev_state));
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index e97b4c4..0ef9585 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -266,154 +266,6 @@
EXPECT_FALSE(DoIsTexture(client_texture_id_));
}
-TEST_P(GLES2DecoderTest, GetMultipleIntegervCHROMIUMValidArgs) {
- const GLsizei kCount = 3;
- GLenum* pnames = GetSharedMemoryAs<GLenum*>();
- pnames[0] = GL_DEPTH_WRITEMASK;
- pnames[1] = GL_COLOR_WRITEMASK;
- pnames[2] = GL_STENCIL_WRITEMASK;
- GLint* results =
- GetSharedMemoryAsWithOffset<GLint*>(sizeof(*pnames) * kCount);
-
- GLsizei num_results = 0;
- for (GLsizei ii = 0; ii < kCount; ++ii) {
- num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]);
- }
- const GLsizei result_size = num_results * sizeof(*results);
- memset(results, 0, result_size);
-
- const GLint kSentinel = 0x12345678;
- results[num_results] = kSentinel;
-
- GetMultipleIntegervCHROMIUM cmd;
- cmd.Init(kSharedMemoryId,
- kSharedMemoryOffset,
- kCount,
- kSharedMemoryId,
- kSharedMemoryOffset + sizeof(*pnames) * kCount,
- result_size);
-
- EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
- EXPECT_EQ(GL_NO_ERROR, GetGLError());
- EXPECT_EQ(1, results[0]); // Depth writemask
- EXPECT_EQ(1, results[1]); // color writemask red
- EXPECT_EQ(1, results[2]); // color writemask green
- EXPECT_EQ(1, results[3]); // color writemask blue
- EXPECT_EQ(1, results[4]); // color writemask alpha
- EXPECT_EQ(-1, results[5]); // stencil writemask alpha
- EXPECT_EQ(kSentinel, results[num_results]); // End of results
-}
-
-TEST_P(GLES2DecoderTest, GetMultipleIntegervCHROMIUMInvalidArgs) {
- const GLsizei kCount = 3;
- // Offset the pnames because GLGetError will use the first uint32.
- const uint32 kPnameOffset = sizeof(uint32);
- const uint32 kResultsOffset = kPnameOffset + sizeof(GLint) * kCount;
- GLenum* pnames = GetSharedMemoryAsWithOffset<GLenum*>(kPnameOffset);
- pnames[0] = GL_DEPTH_WRITEMASK;
- pnames[1] = GL_COLOR_WRITEMASK;
- pnames[2] = GL_STENCIL_WRITEMASK;
- GLint* results = GetSharedMemoryAsWithOffset<GLint*>(kResultsOffset);
-
- GLsizei num_results = 0;
- for (GLsizei ii = 0; ii < kCount; ++ii) {
- num_results += decoder_->GetGLES2Util()->GLGetNumValuesReturned(pnames[ii]);
- }
- const GLsizei result_size = num_results * sizeof(*results);
- memset(results, 0, result_size);
-
- const GLint kSentinel = 0x12345678;
- results[num_results] = kSentinel;
-
- GetMultipleIntegervCHROMIUM cmd;
- // Check bad pnames pointer.
- cmd.Init(kInvalidSharedMemoryId,
- kSharedMemoryOffset + kPnameOffset,
- kCount,
- kSharedMemoryId,
- kSharedMemoryOffset + kResultsOffset,
- result_size);
- EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
- EXPECT_EQ(GL_NO_ERROR, GetGLError());
- // Check bad pnames pointer.
- cmd.Init(kSharedMemoryId,
- kInvalidSharedMemoryOffset,
- kCount,
- kSharedMemoryId,
- kSharedMemoryOffset + kResultsOffset,
- result_size);
- EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
- EXPECT_EQ(GL_NO_ERROR, GetGLError());
- // Check bad count.
- cmd.Init(kSharedMemoryId,
- kSharedMemoryOffset + kPnameOffset,
- static_cast<GLuint>(-1),
- kSharedMemoryId,
- kSharedMemoryOffset + kResultsOffset,
- result_size);
- EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
- EXPECT_EQ(GL_NO_ERROR, GetGLError());
- // Check bad results pointer.
- cmd.Init(kSharedMemoryId,
- kSharedMemoryOffset + kPnameOffset,
- kCount,
- kInvalidSharedMemoryId,
- kSharedMemoryOffset + kResultsOffset,
- result_size);
- EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
- EXPECT_EQ(GL_NO_ERROR, GetGLError());
- // Check bad results pointer.
- cmd.Init(kSharedMemoryId,
- kSharedMemoryOffset + kPnameOffset,
- kCount,
- kSharedMemoryId,
- kInvalidSharedMemoryOffset,
- result_size);
- EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
- EXPECT_EQ(GL_NO_ERROR, GetGLError());
- // Check bad size.
- cmd.Init(kSharedMemoryId,
- kSharedMemoryOffset + kPnameOffset,
- kCount,
- kSharedMemoryId,
- kSharedMemoryOffset + kResultsOffset,
- result_size + 1);
- EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
- EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
- // Check bad size.
- cmd.Init(kSharedMemoryId,
- kSharedMemoryOffset + kPnameOffset,
- kCount,
- kSharedMemoryId,
- kSharedMemoryOffset + kResultsOffset,
- result_size - 1);
- EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
- EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
- // Check bad enum.
- cmd.Init(kSharedMemoryId,
- kSharedMemoryOffset + kPnameOffset,
- kCount,
- kSharedMemoryId,
- kSharedMemoryOffset + kResultsOffset,
- result_size);
- GLenum temp = pnames[2];
- pnames[2] = GL_TRUE;
- EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
- EXPECT_EQ(GL_INVALID_ENUM, GetGLError());
- pnames[2] = temp;
- // Check results area has not been cleared by client.
- results[1] = 1;
- EXPECT_EQ(error::kInvalidArguments, ExecuteCmd(cmd));
- // Check buffer is what we expect
- EXPECT_EQ(0, results[0]);
- EXPECT_EQ(1, results[1]);
- EXPECT_EQ(0, results[2]);
- EXPECT_EQ(0, results[3]);
- EXPECT_EQ(0, results[4]);
- EXPECT_EQ(0, results[5]);
- EXPECT_EQ(kSentinel, results[num_results]); // End of results
-}
-
TEST_P(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) {
InitState init;
init.gl_version = "3.0";
@@ -636,7 +488,7 @@
QueryManager* query_manager = test->GetDecoder()->GetQueryManager();
ASSERT_TRUE(query_manager != NULL);
- bool process_success = query_manager->ProcessPendingQueries();
+ bool process_success = query_manager->ProcessPendingQueries(false);
EXPECT_TRUE(error1 != error::kNoError || error2 != error::kNoError ||
!process_success);
@@ -797,7 +649,7 @@
EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _))
.WillOnce(Return(GL_TIMEOUT_EXPIRED))
.RetiresOnSaturation();
- bool process_success = query_manager->ProcessPendingQueries();
+ bool process_success = query_manager->ProcessPendingQueries(false);
EXPECT_TRUE(process_success);
EXPECT_TRUE(query->pending());
@@ -810,7 +662,7 @@
EXPECT_CALL(*gl_, ClientWaitSync(kGlSync, _, _))
.WillOnce(Return(GL_ALREADY_SIGNALED))
.RetiresOnSaturation();
- process_success = query_manager->ProcessPendingQueries();
+ process_success = query_manager->ProcessPendingQueries(false);
EXPECT_TRUE(process_success);
EXPECT_FALSE(query->pending());
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
index b29b243..9397f45 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -664,8 +664,6 @@
// TODO(gman): RequestExtensionCHROMIUM
-// TODO(gman): GetMultipleIntegervCHROMIUM
-
// TODO(gman): GetProgramInfoCHROMIUM
// TODO(gman): GetTranslatedShaderSourceANGLE
@@ -682,6 +680,31 @@
// TODO(gman): ConsumeTextureCHROMIUMImmediate
// TODO(gman): CreateAndConsumeTextureCHROMIUMImmediate
// TODO(gman): BindUniformLocationCHROMIUMBucket
+// TODO(gman): GenValuebuffersCHROMIUMImmediate
+// TODO(gman): DeleteValuebuffersCHROMIUMImmediate
+
+TEST_P(GLES2DecoderTest2, IsValuebufferCHROMIUMValidArgs) {
+ SpecializedSetup<cmds::IsValuebufferCHROMIUM, 0>(true);
+ cmds::IsValuebufferCHROMIUM cmd;
+ cmd.Init(client_valuebuffer_id_, shared_memory_id_, shared_memory_offset_);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest2, IsValuebufferCHROMIUMInvalidArgsBadSharedMemoryId) {
+ SpecializedSetup<cmds::IsValuebufferCHROMIUM, 0>(false);
+ cmds::IsValuebufferCHROMIUM cmd;
+ cmd.Init(client_valuebuffer_id_, kInvalidSharedMemoryId,
+ shared_memory_offset_);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+ cmd.Init(client_valuebuffer_id_, shared_memory_id_,
+ kInvalidSharedMemoryOffset);
+ EXPECT_EQ(error::kOutOfBounds, ExecuteCmd(cmd));
+}
+// TODO(gman): BindValuebufferCHROMIUM
+// TODO(gman): SubscribeValueCHROMIUM
+// TODO(gman): PopulateSubscribedValuesCHROMIUM
+// TODO(gman): UniformValuebufferCHROMIUM
// TODO(gman): BindTexImage2DCHROMIUM
// TODO(gman): ReleaseTexImage2DCHROMIUM
// TODO(gman): TraceBeginCHROMIUM
@@ -695,13 +718,4 @@
// TODO(gman): WaitAllAsyncTexImage2DCHROMIUM
-// TODO(gman): LoseContextCHROMIUM
-// TODO(gman): InsertSyncPointCHROMIUM
-
-// TODO(gman): WaitSyncPointCHROMIUM
-
-// TODO(gman): DrawBuffersEXTImmediate
-// TODO(gman): DiscardBackbufferCHROMIUM
-
-// TODO(gman): ScheduleOverlayPlaneCHROMIUM
#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index 7e93f36..1c98b68 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -12,4 +12,13 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
+// TODO(gman): LoseContextCHROMIUM
+// TODO(gman): InsertSyncPointCHROMIUM
+
+// TODO(gman): WaitSyncPointCHROMIUM
+
+// TODO(gman): DrawBuffersEXTImmediate
+// TODO(gman): DiscardBackbufferCHROMIUM
+
+// TODO(gman): ScheduleOverlayPlaneCHROMIUM
#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
index 136834d..36afe38 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -96,6 +96,7 @@
client_fragment_shader_id_(122),
client_query_id_(123),
client_vertexarray_id_(124),
+ client_valuebuffer_id_(125),
service_renderbuffer_id_(0),
service_renderbuffer_valid_(false),
ignore_cached_state_for_test_(GetParam()),
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
index 1507440..1a2b54a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -19,6 +19,7 @@
#include "gpu/command_buffer/service/shader_manager.h"
#include "gpu/command_buffer/service/test_helper.h"
#include "gpu/command_buffer/service/texture_manager.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
#include "gpu/command_buffer/service/vertex_array_manager.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gl/gl_context_stub_with_extensions.h"
@@ -122,6 +123,10 @@
return group_->program_manager()->GetProgram(client_id);
}
+ Valuebuffer* GetValuebuffer(GLuint client_id) {
+ return group_->valuebuffer_manager()->GetValuebuffer(client_id);
+ }
+
QueryManager::Query* GetQueryInfo(GLuint client_id) {
return decoder_->GetQueryManager()->GetQuery(client_id);
}
@@ -136,6 +141,10 @@
return group_->program_manager();
}
+ ValuebufferManager* valuebuffer_manager() {
+ return group_->valuebuffer_manager();
+ }
+
ImageManager* GetImageManager() { return decoder_->GetImageManager(); }
void DoCreateProgram(GLuint client_id, GLuint service_id);
@@ -514,6 +523,7 @@
GLuint client_fragment_shader_id_;
GLuint client_query_id_;
GLuint client_vertexarray_id_;
+ GLuint client_valuebuffer_id_;
uint32 shared_memory_id_;
uint32 shared_memory_offset_;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
index d555f28..789b48a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -772,6 +772,7 @@
ReadPixels(0, 0, kWidth, kHeight, GL_RGB, GL_UNSIGNED_BYTE, _))
.Times(1);
EXPECT_CALL(*gl_, GenBuffersARB(1, _)).Times(1);
+ EXPECT_CALL(*gl_, DeleteBuffersARB(1, _)).Times(1);
EXPECT_CALL(*gl_, BindBuffer(GL_PIXEL_PACK_BUFFER_ARB, _)).Times(2);
EXPECT_CALL(*gl_,
BufferData(GL_PIXEL_PACK_BUFFER_ARB, _, NULL, GL_STREAM_READ))
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc
new file mode 100644
index 0000000..012d504
--- /dev/null
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc
@@ -0,0 +1,130 @@
+// 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_decoder.h"
+
+#include "base/command_line.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h"
+
+#include "gpu/command_buffer/service/test_helper.h"
+#include "gpu/command_buffer/service/valuebuffer_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_implementation.h"
+#include "ui/gl/gl_mock.h"
+#include "ui/gl/gl_surface_stub.h"
+
+using ::gfx::MockGLInterface;
+using ::testing::_;
+
+namespace gpu {
+namespace gles2 {
+
+using namespace cmds;
+
+TEST_P(GLES2DecoderWithShaderTest, ValuebufferBasic) {
+ const uint32 kBufferId = 123;
+ ValueState valuestate;
+ valuestate.int_value[0] = 111;
+ valuestate.int_value[1] = 222;
+ valuebuffer_manager()->CreateValuebuffer(kBufferId);
+ valuebuffer_manager()->UpdateValueState(
+ GL_MOUSE_POSITION_CHROMIUM, valuestate);
+ BindValuebufferCHROMIUM cmd1;
+ cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+ SubscribeValueCHROMIUM cmd2;
+ cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ PopulateSubscribedValuesCHROMIUM cmd3;
+ cmd3.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+ EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(1);
+ UniformValuebufferCHROMIUM cmd4;
+ cmd4.Init(kUniform2FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd4));
+}
+
+TEST_P(GLES2DecoderWithShaderTest, SubscribeValuebufferNotBound) {
+ const uint32 kBufferId = 123;
+ ValueState valuestate;
+ valuestate.int_value[0] = 111;
+ valuestate.int_value[1] = 222;
+ valuebuffer_manager()->CreateValuebuffer(kBufferId);
+ valuebuffer_manager()->UpdateValueState(
+ GL_MOUSE_POSITION_CHROMIUM, valuestate);
+ SubscribeValueCHROMIUM cmd1;
+ cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, PopulateValuebufferNoSubscription) {
+ const uint32 kBufferId = 123;
+ ValueState valuestate;
+ valuestate.int_value[0] = 111;
+ valuestate.int_value[1] = 222;
+ valuebuffer_manager()->CreateValuebuffer(kBufferId);
+ valuebuffer_manager()->UpdateValueState(
+ GL_MOUSE_POSITION_CHROMIUM, valuestate);
+ BindValuebufferCHROMIUM cmd1;
+ cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+ PopulateSubscribedValuesCHROMIUM cmd2;
+ cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_EQ(GL_NONE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, UniformValuebufferNoState) {
+ const uint32 kBufferId = 123;
+ ValueState valuestate;
+ valuestate.int_value[0] = 111;
+ valuestate.int_value[1] = 222;
+ valuebuffer_manager()->CreateValuebuffer(kBufferId);
+ valuebuffer_manager()->UpdateValueState(
+ GL_MOUSE_POSITION_CHROMIUM, valuestate);
+ BindValuebufferCHROMIUM cmd1;
+ cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+ SubscribeValueCHROMIUM cmd2;
+ cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(0);
+ UniformValuebufferCHROMIUM cmd3;
+ cmd3.Init(kUniform2FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+ EXPECT_EQ(GL_NONE, GetGLError());
+}
+
+TEST_P(GLES2DecoderWithShaderTest, UniformValuebufferInvalidLocation) {
+ const uint32 kBufferId = 123;
+ ValueState valuestate;
+ valuestate.int_value[0] = 111;
+ valuestate.int_value[1] = 222;
+ valuebuffer_manager()->CreateValuebuffer(kBufferId);
+ valuebuffer_manager()->UpdateValueState(
+ GL_MOUSE_POSITION_CHROMIUM, valuestate);
+ BindValuebufferCHROMIUM cmd1;
+ cmd1.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, kBufferId);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd1));
+ SubscribeValueCHROMIUM cmd2;
+ cmd2.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM, GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd2));
+ PopulateSubscribedValuesCHROMIUM cmd3;
+ cmd3.Init(GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd3));
+ EXPECT_CALL(*gl_, Uniform2iv(kUniform2RealLocation, 1, _)).Times(0);
+ UniformValuebufferCHROMIUM cmd4;
+ cmd4.Init(kUniform1FakeLocation, GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+ GL_MOUSE_POSITION_CHROMIUM);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd4));
+ EXPECT_EQ(GL_INVALID_OPERATION, GetGLError());
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index de84037..c72bcf8 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -56,6 +56,7 @@
ValueValidator<GLenum> src_blend_factor;
ValueValidator<GLenum> stencil_op;
ValueValidator<GLenum> string_type;
+ValueValidator<GLenum> subscription_target;
ValueValidator<GLenum> texture_bind_target;
ValueValidator<GLenum> texture_format;
ValueValidator<GLenum> texture_internal_format;
@@ -67,6 +68,7 @@
ValueValidator<GLenum> texture_target;
ValueValidator<GLenum> texture_usage;
ValueValidator<GLenum> texture_wrap_mode;
+ValueValidator<GLenum> value_buffer_target;
ValueValidator<GLint> vertex_attrib_size;
ValueValidator<GLenum> vertex_attrib_type;
ValueValidator<GLenum> vertex_attribute;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 790b9b3..6a646ac 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -413,6 +413,10 @@
GL_EXTENSIONS,
};
+static const GLenum valid_subscription_target_table[] = {
+ GL_MOUSE_POSITION_CHROMIUM,
+};
+
static const GLenum valid_texture_bind_target_table[] = {
GL_TEXTURE_2D,
GL_TEXTURE_CUBE_MAP,
@@ -493,6 +497,10 @@
GL_REPEAT,
};
+static const GLenum valid_value_buffer_target_table[] = {
+ GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM,
+};
+
static const GLint valid_vertex_attrib_size_table[] = {
1,
2,
@@ -593,6 +601,8 @@
arraysize(valid_src_blend_factor_table)),
stencil_op(valid_stencil_op_table, arraysize(valid_stencil_op_table)),
string_type(valid_string_type_table, arraysize(valid_string_type_table)),
+ subscription_target(valid_subscription_target_table,
+ arraysize(valid_subscription_target_table)),
texture_bind_target(valid_texture_bind_target_table,
arraysize(valid_texture_bind_target_table)),
texture_format(valid_texture_format_table,
@@ -616,6 +626,8 @@
arraysize(valid_texture_usage_table)),
texture_wrap_mode(valid_texture_wrap_mode_table,
arraysize(valid_texture_wrap_mode_table)),
+ value_buffer_target(valid_value_buffer_target_table,
+ arraysize(valid_value_buffer_target_table)),
vertex_attrib_size(valid_vertex_attrib_size_table,
arraysize(valid_vertex_attrib_size_table)),
vertex_attrib_type(valid_vertex_attrib_type_table,
diff --git a/gpu/command_buffer/service/gpu_scheduler.cc b/gpu/command_buffer/service/gpu_scheduler.cc
index 058a546..48df8dd 100644
--- a/gpu/command_buffer/service/gpu_scheduler.cc
+++ b/gpu/command_buffer/service/gpu_scheduler.cc
@@ -170,7 +170,7 @@
bool GpuScheduler::HasMoreWork() {
return !unschedule_fences_.empty() ||
- (decoder_ && decoder_->ProcessPendingQueries()) ||
+ (decoder_ && decoder_->ProcessPendingQueries(false)) ||
HasMoreIdleWork();
}
diff --git a/gpu/command_buffer/service/gpu_tracer_unittest.cc b/gpu/command_buffer/service/gpu_tracer_unittest.cc
index 59ea63e..2a7a94c 100644
--- a/gpu/command_buffer/service/gpu_tracer_unittest.cc
+++ b/gpu/command_buffer/service/gpu_tracer_unittest.cc
@@ -13,18 +13,9 @@
namespace gpu {
namespace gles2 {
-using ::testing::InvokeWithoutArgs;
using ::testing::Return;
-using ::testing::ReturnRef;
-using ::testing::ReturnPointee;
using ::testing::NotNull;
-using ::testing::ElementsAreArray;
-using ::testing::ElementsAre;
-using ::testing::SetArrayArgument;
using ::testing::AtLeast;
-using ::testing::SetArgPointee;
-using ::testing::Pointee;
-using ::testing::Unused;
using ::testing::Invoke;
using ::testing::_;
diff --git a/gpu/command_buffer/service/memory_program_cache_unittest.cc b/gpu/command_buffer/service/memory_program_cache_unittest.cc
index d3e954e..9134c78 100644
--- a/gpu/command_buffer/service/memory_program_cache_unittest.cc
+++ b/gpu/command_buffer/service/memory_program_cache_unittest.cc
@@ -16,10 +16,8 @@
#include "ui/gl/gl_mock.h"
using ::testing::_;
-using ::testing::ElementsAreArray;
using ::testing::Invoke;
using ::testing::SetArgPointee;
-using ::testing::SetArrayArgument;
namespace gpu {
namespace gles2 {
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 7bc72de..f3c447c 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -193,8 +193,7 @@
memcmp(name, kInvalidPrefix, sizeof(kInvalidPrefix)) == 0);
}
-Program::Program(
- ProgramManager* manager, GLuint service_id)
+Program::Program(ProgramManager* manager, GLuint service_id)
: manager_(manager),
use_count_(0),
max_attrib_name_length_(0),
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index dbe9c14..2f5deae 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -39,6 +39,7 @@
};
enum UniformApiType {
+ kUniformNone = 0,
kUniform1i = 1 << 0,
kUniform2i = 1 << 1,
kUniform3i = 1 << 2,
diff --git a/gpu/command_buffer/service/query_manager.cc b/gpu/command_buffer/service/query_manager.cc
index 5f518ec..fdb5fa8 100644
--- a/gpu/command_buffer/service/query_manager.cc
+++ b/gpu/command_buffer/service/query_manager.cc
@@ -64,7 +64,7 @@
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
- bool Process() override;
+ bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
protected:
@@ -105,7 +105,7 @@
return AddToPendingTransferQueue(submit_count);
}
-bool AsyncPixelTransfersCompletedQuery::Process() {
+bool AsyncPixelTransfersCompletedQuery::Process(bool did_finish) {
QuerySync* sync = manager()->decoder()->GetSharedMemoryAs<QuerySync*>(
shm_id(), shm_offset(), sizeof(*sync));
if (!sync)
@@ -141,7 +141,7 @@
GLuint service_id);
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
- bool Process() override;
+ bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
protected:
@@ -169,7 +169,7 @@
return AddToPendingQueue(submit_count);
}
-bool AllSamplesPassedQuery::Process() {
+bool AllSamplesPassedQuery::Process(bool did_finish) {
GLuint available = 0;
glGetQueryObjectuivARB(
service_id_, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
@@ -200,7 +200,7 @@
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
- bool Process() override;
+ bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
protected:
@@ -226,7 +226,7 @@
return MarkAsCompleted(elapsed.InMicroseconds());
}
-bool CommandsIssuedQuery::Process() {
+bool CommandsIssuedQuery::Process(bool did_finish) {
NOTREACHED();
return true;
}
@@ -247,7 +247,7 @@
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
- bool Process() override;
+ bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
protected:
@@ -269,7 +269,7 @@
return MarkAsCompleted(now.InMicroseconds());
}
-bool CommandLatencyQuery::Process() {
+bool CommandLatencyQuery::Process(bool did_finish) {
NOTREACHED();
return true;
}
@@ -293,7 +293,7 @@
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
- bool Process() override;
+ bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
protected:
@@ -324,7 +324,7 @@
base::Bind(&AsyncReadPixelsCompletedQuery::Complete,
AsWeakPtr()));
- return Process();
+ return Process(false);
}
void AsyncReadPixelsCompletedQuery::Complete() {
@@ -332,7 +332,7 @@
complete_result_ = MarkAsCompleted(1);
}
-bool AsyncReadPixelsCompletedQuery::Process() {
+bool AsyncReadPixelsCompletedQuery::Process(bool did_finish) {
return !completed_ || complete_result_;
}
@@ -353,7 +353,7 @@
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
- bool Process() override;
+ bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
protected:
@@ -376,7 +376,7 @@
return MarkAsCompleted(manager()->decoder()->GetErrorState()->GetGLError());
}
-bool GetErrorQuery::Process() {
+bool GetErrorQuery::Process(bool did_finish) {
NOTREACHED();
return true;
}
@@ -400,7 +400,7 @@
// Overridden from QueryManager::Query:
bool Begin() override;
bool End(base::subtle::Atomic32 submit_count) override;
- bool Process() override;
+ bool Process(bool did_finish) override;
void Destroy(bool have_context) override;
protected:
@@ -424,9 +424,16 @@
return AddToPendingQueue(submit_count);
}
-bool CommandsCompletedQuery::Process() {
- if (fence_ && !fence_->HasCompleted())
+bool CommandsCompletedQuery::Process(bool did_finish) {
+ // 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);
}
@@ -635,10 +642,10 @@
return true;
}
-bool QueryManager::ProcessPendingQueries() {
+bool QueryManager::ProcessPendingQueries(bool did_finish) {
while (!pending_queries_.empty()) {
Query* query = pending_queries_.front().get();
- if (!query->Process()) {
+ if (!query->Process(did_finish)) {
return false;
}
if (query->pending()) {
@@ -658,7 +665,7 @@
bool QueryManager::ProcessPendingTransferQueries() {
while (!pending_transfer_queries_.empty()) {
Query* query = pending_transfer_queries_.front().get();
- if (!query->Process()) {
+ if (!query->Process(false)) {
return false;
}
if (query->pending()) {
diff --git a/gpu/command_buffer/service/query_manager.h b/gpu/command_buffer/service/query_manager.h
index 62da3b8..5f14929 100644
--- a/gpu/command_buffer/service/query_manager.h
+++ b/gpu/command_buffer/service/query_manager.h
@@ -64,7 +64,7 @@
virtual bool End(base::subtle::Atomic32 submit_count) = 0;
// Returns false if shared memory for sync is invalid.
- virtual bool Process() = 0;
+ virtual bool Process(bool did_finish) = 0;
virtual void Destroy(bool have_context) = 0;
@@ -170,8 +170,9 @@
bool EndQuery(Query* query, base::subtle::Atomic32 submit_count);
// Processes pending queries. Returns false if any queries are pointing
- // to invalid shared memory.
- bool ProcessPendingQueries();
+ // to invalid shared memory. |did_finish| is true if this is called as
+ // a result of calling glFinish().
+ bool ProcessPendingQueries(bool did_finish);
// True if there are pending queries.
bool HavePendingQueries();
diff --git a/gpu/command_buffer/service/query_manager_unittest.cc b/gpu/command_buffer/service/query_manager_unittest.cc
index 80efd69..7c8e93c 100644
--- a/gpu/command_buffer/service/query_manager_unittest.cc
+++ b/gpu/command_buffer/service/query_manager_unittest.cc
@@ -214,7 +214,7 @@
const GLuint kResult = 1;
// Check nothing happens if there are no pending queries.
- EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
// Create Query.
scoped_refptr<QueryManager::Query> query(
@@ -239,7 +239,7 @@
GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
.WillOnce(SetArgumentPointee<2>(0))
.RetiresOnSaturation();
- EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
EXPECT_TRUE(query->pending());
EXPECT_EQ(0, sync->process_count);
EXPECT_EQ(0u, sync->result);
@@ -254,7 +254,7 @@
GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
.WillOnce(SetArgumentPointee<2>(kResult))
.RetiresOnSaturation();
- EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
EXPECT_FALSE(query->pending());
EXPECT_EQ(kSubmitCount, sync->process_count);
EXPECT_EQ(kResult, sync->result);
@@ -262,7 +262,7 @@
// Process with no queries.
// Expect no GL commands/
- EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
}
TEST_F(QueryManagerTest, ProcessPendingQueries) {
@@ -342,7 +342,7 @@
GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
.WillOnce(SetArgumentPointee<2>(0))
.RetiresOnSaturation();
- EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
}
EXPECT_FALSE(query1->pending());
EXPECT_FALSE(query2->pending());
@@ -361,7 +361,7 @@
GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_AVAILABLE_EXT, _))
.WillOnce(SetArgumentPointee<2>(0))
.RetiresOnSaturation();
- EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
EXPECT_TRUE(query3->pending());
EXPECT_EQ(0, sync3->process_count);
EXPECT_EQ(0u, sync3->result);
@@ -377,7 +377,7 @@
GetQueryObjectuivARB(kService3Id, GL_QUERY_RESULT_EXT, _))
.WillOnce(SetArgumentPointee<2>(kResult3))
.RetiresOnSaturation();
- EXPECT_TRUE(manager_->ProcessPendingQueries());
+ EXPECT_TRUE(manager_->ProcessPendingQueries(false));
EXPECT_FALSE(query3->pending());
EXPECT_EQ(kSubmitCount3, sync3->process_count);
EXPECT_EQ(kResult3, sync3->result);
@@ -410,7 +410,7 @@
GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
.WillOnce(SetArgumentPointee<2>(kResult))
.RetiresOnSaturation();
- EXPECT_FALSE(manager_->ProcessPendingQueries());
+ EXPECT_FALSE(manager_->ProcessPendingQueries(false));
}
TEST_F(QueryManagerTest, ProcessPendingBadSharedMemoryOffset) {
@@ -439,7 +439,7 @@
GetQueryObjectuivARB(kService1Id, GL_QUERY_RESULT_EXT, _))
.WillOnce(SetArgumentPointee<2>(kResult))
.RetiresOnSaturation();
- EXPECT_FALSE(manager_->ProcessPendingQueries());
+ EXPECT_FALSE(manager_->ProcessPendingQueries(false));
}
TEST_F(QueryManagerTest, ExitWithPendingQuery) {
diff --git a/gpu/command_buffer/service/shader_translator_cache.h b/gpu/command_buffer/service/shader_translator_cache.h
index e804ef2..6b0b1a5 100644
--- a/gpu/command_buffer/service/shader_translator_cache.h
+++ b/gpu/command_buffer/service/shader_translator_cache.h
@@ -41,6 +41,7 @@
private:
friend class base::RefCounted<ShaderTranslatorCache>;
+ friend class ShaderTranslatorCacheTest_InitParamComparable_Test;
~ShaderTranslatorCache() override;
// Parameters passed into ShaderTranslator::Init
@@ -52,18 +53,18 @@
glsl_implementation_type;
ShCompileOptions driver_bug_workarounds;
- ShaderTranslatorInitParams(
- sh::GLenum shader_type,
- ShShaderSpec shader_spec,
- const ShBuiltInResources& resources,
- ShaderTranslatorInterface::GlslImplementationType
- glsl_implementation_type,
- ShCompileOptions driver_bug_workarounds)
- : shader_type(shader_type),
- shader_spec(shader_spec),
- resources(resources),
- glsl_implementation_type(glsl_implementation_type),
- driver_bug_workarounds(driver_bug_workarounds) {
+ ShaderTranslatorInitParams(sh::GLenum shader_type,
+ ShShaderSpec shader_spec,
+ const ShBuiltInResources& resources,
+ ShaderTranslatorInterface::GlslImplementationType
+ glsl_implementation_type,
+ ShCompileOptions driver_bug_workarounds) {
+ memset(this, 0, sizeof(*this));
+ this->shader_type = shader_type;
+ this->shader_spec = shader_spec;
+ this->resources = resources;
+ this->glsl_implementation_type = glsl_implementation_type;
+ this->driver_bug_workarounds = driver_bug_workarounds;
}
ShaderTranslatorInitParams(const ShaderTranslatorInitParams& params) {
@@ -77,6 +78,10 @@
bool operator< (const ShaderTranslatorInitParams& params) const {
return memcmp(¶ms, this, sizeof(*this)) < 0;
}
+
+ private:
+ ShaderTranslatorInitParams();
+ ShaderTranslatorInitParams& operator=(const ShaderTranslatorInitParams&);
};
typedef std::map<ShaderTranslatorInitParams, ShaderTranslator* > Cache;
diff --git a/gpu/command_buffer/service/shader_translator_cache_unittest.cc b/gpu/command_buffer/service/shader_translator_cache_unittest.cc
new file mode 100644
index 0000000..c5233e5
--- /dev/null
+++ b/gpu/command_buffer/service/shader_translator_cache_unittest.cc
@@ -0,0 +1,56 @@
+// 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 <GLES2/gl2.h>
+
+#include "gpu/command_buffer/service/shader_translator_cache.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace gpu {
+namespace gles2 {
+
+TEST(ShaderTranslatorCacheTest, InitParamComparable) {
+ // Tests that ShaderTranslatorInitParams padding or padding of its
+ // members does not affect the object equality or ordering.
+
+ ShBuiltInResources a_resources;
+ memset(&a_resources, 88, sizeof(a_resources));
+ ShInitBuiltInResources(&a_resources);
+
+ ShBuiltInResources b_resources;
+ memset(&b_resources, 77, sizeof(b_resources));
+ ShInitBuiltInResources(&b_resources);
+
+ EXPECT_TRUE(memcmp(&a_resources, &b_resources, sizeof(a_resources)) == 0);
+
+ ShCompileOptions driver_bug_workarounds = SH_VALIDATE;
+
+ char a_storage[sizeof(ShaderTranslatorCache::ShaderTranslatorInitParams)];
+ memset(a_storage, 55, sizeof(a_storage));
+ ShaderTranslatorCache::ShaderTranslatorInitParams* a =
+ new (&a_storage) ShaderTranslatorCache::ShaderTranslatorInitParams(
+ GL_VERTEX_SHADER,
+ SH_GLES2_SPEC,
+ a_resources,
+ ShaderTranslatorInterface::kGlslES,
+ driver_bug_workarounds);
+
+ ShaderTranslatorCache::ShaderTranslatorInitParams b(
+ GL_VERTEX_SHADER,
+ SH_GLES2_SPEC,
+ b_resources,
+ ShaderTranslatorInterface::kGlslES,
+ driver_bug_workarounds);
+
+ EXPECT_TRUE(*a == b);
+ EXPECT_FALSE(*a < b || b < *a);
+
+ memset(a_storage, 55, sizeof(a_storage));
+ a = new (&a_storage) ShaderTranslatorCache::ShaderTranslatorInitParams(b);
+
+ EXPECT_TRUE(*a == b);
+ EXPECT_FALSE(*a < b || b < *a);
+}
+} // namespace gles2
+} // namespace gpu
diff --git a/gpu/command_buffer/service/valuebuffer_manager.cc b/gpu/command_buffer/service/valuebuffer_manager.cc
new file mode 100644
index 0000000..eb4db09
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager.cc
@@ -0,0 +1,117 @@
+// 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 "gpu/command_buffer/service/valuebuffer_manager.h"
+
+#include "gpu/command_buffer/service/program_manager.h"
+
+namespace gpu {
+namespace gles2 {
+
+Valuebuffer::Valuebuffer(ValuebufferManager* manager, GLuint client_id)
+ : manager_(manager), client_id_(client_id), has_been_bound_(false) {
+ manager_->StartTracking(this);
+}
+
+Valuebuffer::~Valuebuffer() {
+ if (manager_) {
+ manager_->StopTracking(this);
+ manager_ = NULL;
+ }
+}
+
+void Valuebuffer::AddSubscription(GLenum subscription) {
+ subscriptions_.insert(subscription);
+}
+
+void Valuebuffer::RemoveSubscription(GLenum subscription) {
+ subscriptions_.erase(subscription);
+}
+
+bool Valuebuffer::IsSubscribed(GLenum subscription) {
+ return subscriptions_.find(subscription) != subscriptions_.end();
+}
+
+const ValueState *Valuebuffer::GetState(GLenum target) const {
+ StateMap::const_iterator it = active_state_map_.find(target);
+ return it != active_state_map_.end() ? &it->second : NULL;
+}
+
+void Valuebuffer::UpdateState(const StateMap& pending_state) {
+ for (SubscriptionSet::const_iterator it = subscriptions_.begin();
+ it != subscriptions_.end(); ++it) {
+ StateMap::const_iterator pending_state_it = pending_state.find((*it));
+ if (pending_state_it != pending_state.end()) {
+ active_state_map_[pending_state_it->first] = pending_state_it->second;
+ }
+ }
+}
+
+ValuebufferManager::ValuebufferManager()
+ : valuebuffer_count_(0) {
+}
+
+ValuebufferManager::~ValuebufferManager() {
+ DCHECK(valuebuffer_map_.empty());
+ DCHECK(pending_state_map_.empty());
+ // If this triggers, that means something is keeping a reference to
+ // a Valuebuffer belonging to this.
+ CHECK_EQ(valuebuffer_count_, 0u);
+}
+
+void ValuebufferManager::Destroy() {
+ valuebuffer_map_.clear();
+ pending_state_map_.clear();
+}
+
+void ValuebufferManager::StartTracking(Valuebuffer* /* valuebuffer */) {
+ ++valuebuffer_count_;
+}
+
+void ValuebufferManager::StopTracking(Valuebuffer* /* valuebuffer */) {
+ --valuebuffer_count_;
+}
+
+void ValuebufferManager::CreateValuebuffer(GLuint client_id) {
+ scoped_refptr<Valuebuffer> valuebuffer(new Valuebuffer(this, client_id));
+ std::pair<ValuebufferMap::iterator, bool> result =
+ valuebuffer_map_.insert(std::make_pair(client_id, valuebuffer));
+ DCHECK(result.second);
+}
+
+Valuebuffer* ValuebufferManager::GetValuebuffer(GLuint client_id) {
+ ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
+ return it != valuebuffer_map_.end() ? it->second.get() : NULL;
+}
+
+void ValuebufferManager::RemoveValuebuffer(GLuint client_id) {
+ ValuebufferMap::iterator it = valuebuffer_map_.find(client_id);
+ if (it != valuebuffer_map_.end()) {
+ Valuebuffer* valuebuffer = it->second.get();
+ valuebuffer->MarkAsDeleted();
+ valuebuffer_map_.erase(it);
+ }
+}
+
+void ValuebufferManager::UpdateValuebufferState(Valuebuffer* valuebuffer) {
+ DCHECK(valuebuffer);
+ valuebuffer->UpdateState(pending_state_map_);
+}
+
+void ValuebufferManager::UpdateValueState(
+ GLenum target, const ValueState& state) {
+ pending_state_map_[target] = state;
+}
+
+uint32 ValuebufferManager::ApiTypeForSubscriptionTarget(GLenum target) {
+ switch (target) {
+ case GL_MOUSE_POSITION_CHROMIUM:
+ return Program::kUniform2i;
+ }
+ NOTREACHED() << "Unhandled uniform subscription target " << target;
+ return Program::kUniformNone;
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/gpu/command_buffer/service/valuebuffer_manager.h b/gpu/command_buffer/service/valuebuffer_manager.h
new file mode 100644
index 0000000..3cc4ac1
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager.h
@@ -0,0 +1,123 @@
+// 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 GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
+
+#include "base/basictypes.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gl_utils.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ValuebufferManager;
+
+union ValueState {
+ float float_value[4];
+ int int_value[4];
+};
+
+class GPU_EXPORT Valuebuffer : public base::RefCounted<Valuebuffer> {
+ public:
+ Valuebuffer(ValuebufferManager* manager, GLuint client_id);
+
+ GLuint client_id() const { return client_id_; }
+
+ bool IsDeleted() const { return client_id_ == 0; }
+
+ void MarkAsValid() { has_been_bound_ = true; }
+
+ bool IsValid() const { return has_been_bound_ && !IsDeleted(); }
+
+ void AddSubscription(GLenum subscription);
+ void RemoveSubscription(GLenum subscription);
+
+ // Returns true if this Valuebuffer is subscribed to subscription
+ bool IsSubscribed(GLenum subscription);
+
+ // Returns the active state for a given target in this Valuebuffer
+ // returns NULL if target state doesn't exist
+ const ValueState* GetState(GLenum target) const;
+
+ private:
+ friend class ValuebufferManager;
+ friend class base::RefCounted<Valuebuffer>;
+
+ typedef base::hash_map<GLenum, ValueState> StateMap;
+ typedef base::hash_set<GLenum> SubscriptionSet;
+
+ ~Valuebuffer();
+
+ void UpdateState(const StateMap& pending_state);
+
+ void MarkAsDeleted() { client_id_ = 0; }
+
+ // ValuebufferManager that owns this Valuebuffer.
+ ValuebufferManager* manager_;
+
+ // Client side Valuebuffer id.
+ GLuint client_id_;
+
+ // Whether this Valuebuffer has ever been bound.
+ bool has_been_bound_;
+
+ SubscriptionSet subscriptions_;
+
+ StateMap active_state_map_;
+};
+
+class GPU_EXPORT ValuebufferManager {
+ public:
+ ValuebufferManager();
+ ~ValuebufferManager();
+
+ // Must call before destruction.
+ void Destroy();
+
+ // Creates a Valuebuffer for the given Valuebuffer ids.
+ void CreateValuebuffer(GLuint client_id);
+
+ // Gets the Valuebuffer for the given Valuebuffer id.
+ Valuebuffer* GetValuebuffer(GLuint client_id);
+
+ // Removes a Valuebuffer for the given Valuebuffer id.
+ void RemoveValuebuffer(GLuint client_id);
+
+ // Updates the value state for the given Valuebuffer
+ void UpdateValuebufferState(Valuebuffer* valuebuffer);
+
+ // Gets the state for the given subscription target
+ void UpdateValueState(GLenum target, const ValueState& state);
+
+ static uint32 ApiTypeForSubscriptionTarget(GLenum target);
+
+ private:
+ friend class Valuebuffer;
+
+ typedef base::hash_map<GLuint, scoped_refptr<Valuebuffer>> ValuebufferMap;
+
+ void StartTracking(Valuebuffer* valuebuffer);
+ void StopTracking(Valuebuffer* valuebuffer);
+
+ // Counts the number of Valuebuffer allocated with 'this' as its manager.
+ // Allows to check no Valuebuffer will outlive this.
+ unsigned valuebuffer_count_;
+
+ // Info for each Valuebuffer in the system.
+ ValuebufferMap valuebuffer_map_;
+
+ // Current value state in the system
+ Valuebuffer::StateMap pending_state_map_;
+
+ DISALLOW_COPY_AND_ASSIGN(ValuebufferManager);
+};
+
+} // namespace gles2
+} // namespace gpu
+
+#endif // GPU_COMMAND_BUFFER_SERVICE_VALUEBUFFER_MANAGER_H_
diff --git a/gpu/command_buffer/service/valuebuffer_manager_unittest.cc b/gpu/command_buffer/service/valuebuffer_manager_unittest.cc
new file mode 100644
index 0000000..ead5df5
--- /dev/null
+++ b/gpu/command_buffer/service/valuebuffer_manager_unittest.cc
@@ -0,0 +1,100 @@
+// 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 "gpu/command_buffer/service/valuebuffer_manager.h"
+
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_util.h"
+#include "gpu/command_buffer/common/gles2_cmd_format.h"
+#include "gpu/command_buffer/common/gles2_cmd_utils.h"
+#include "gpu/command_buffer/service/common_decoder.h"
+#include "gpu/command_buffer/service/feature_info.h"
+#include "gpu/command_buffer/service/gpu_service_test.h"
+#include "gpu/command_buffer/service/mocks.h"
+#include "gpu/command_buffer/service/test_helper.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_mock.h"
+
+namespace gpu {
+namespace gles2 {
+
+class ValuebufferManagerTest : public GpuServiceTest {
+ public:
+ ValuebufferManagerTest() : manager_() {}
+ ~ValuebufferManagerTest() override { manager_.Destroy(); }
+
+ protected:
+ ValuebufferManager manager_;
+};
+
+TEST_F(ValuebufferManagerTest, Basic) {
+ const GLuint kClient1Id = 1;
+ const GLuint kClient2Id = 2;
+ // Check we can create a Valuebuffer
+ manager_.CreateValuebuffer(kClient1Id);
+ Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+ ASSERT_TRUE(valuebuffer0 != NULL);
+ EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+ // Check we get nothing for a non-existent Valuebuffer.
+ // Check trying to a remove non-existent Valuebuffer does not crash
+ manager_.RemoveValuebuffer(kClient2Id);
+ // Check we can't get the renderbuffer after we remove it.
+ manager_.RemoveValuebuffer(kClient1Id);
+ EXPECT_TRUE(manager_.GetValuebuffer(kClient1Id) == NULL);
+}
+
+TEST_F(ValuebufferManagerTest, Destroy) {
+ const GLuint kClient1Id = 1;
+ // Check we can create Valuebuffer.
+ manager_.CreateValuebuffer(kClient1Id);
+ Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+ ASSERT_TRUE(valuebuffer0 != NULL);
+ EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+ manager_.Destroy();
+ // Check the resources were released.
+ Valuebuffer* valuebuffer1 = manager_.GetValuebuffer(kClient1Id);
+ ASSERT_TRUE(valuebuffer1 == NULL);
+}
+
+TEST_F(ValuebufferManagerTest, ValueBuffer) {
+ const GLuint kClient1Id = 1;
+ // Check we can create a Valuebuffer
+ manager_.CreateValuebuffer(kClient1Id);
+ Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+ ASSERT_TRUE(valuebuffer0 != NULL);
+ EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+ EXPECT_FALSE(valuebuffer0->IsValid());
+}
+
+TEST_F(ValuebufferManagerTest, UpdateState) {
+ const GLuint kClient1Id = 1;
+ ValueState valuestate1;
+ valuestate1.int_value[0] = 111;
+ ValueState valuestate2;
+ valuestate2.int_value[0] = 222;
+ manager_.CreateValuebuffer(kClient1Id);
+ Valuebuffer* valuebuffer0 = manager_.GetValuebuffer(kClient1Id);
+ ASSERT_TRUE(valuebuffer0 != NULL);
+ EXPECT_EQ(kClient1Id, valuebuffer0->client_id());
+ valuebuffer0->AddSubscription(GL_MOUSE_POSITION_CHROMIUM);
+ ASSERT_TRUE(valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM) == NULL);
+ manager_.UpdateValueState(GL_MOUSE_POSITION_CHROMIUM, valuestate1);
+ manager_.UpdateValuebufferState(valuebuffer0);
+ const ValueState* new_state1 =
+ valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM);
+ ASSERT_TRUE(new_state1 != NULL);
+ ASSERT_TRUE(new_state1->int_value[0] == 111);
+ // Ensure state changes
+ manager_.UpdateValueState(GL_MOUSE_POSITION_CHROMIUM, valuestate2);
+ manager_.UpdateValuebufferState(valuebuffer0);
+ const ValueState* new_state2 =
+ valuebuffer0->GetState(GL_MOUSE_POSITION_CHROMIUM);
+ ASSERT_TRUE(new_state2 != NULL);
+ ASSERT_TRUE(new_state2->int_value[0] == 222);
+}
+
+} // namespace gles2
+} // namespace gpu
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index a8a7425..ebd821c 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -323,7 +323,11 @@
}
void GLManager::PumpCommands() {
- decoder_->MakeCurrent();
+ if (!decoder_->MakeCurrent()) {
+ command_buffer_->SetContextLostReason(decoder_->GetContextLostReason());
+ command_buffer_->SetParseError(::gpu::error::kLostContext);
+ return;
+ }
gpu_scheduler_->PutChanged();
::gpu::CommandBuffer::State state = command_buffer_->GetLastState();
if (!context_lost_allowed_) {
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index f1ed489..13ffe94 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -125,6 +125,8 @@
'command_buffer/service/texture_manager.cc',
'command_buffer/service/transfer_buffer_manager.cc',
'command_buffer/service/transfer_buffer_manager.h',
+ 'command_buffer/service/valuebuffer_manager.h',
+ 'command_buffer/service/valuebuffer_manager.cc',
'command_buffer/service/vertex_array_manager.h',
'command_buffer/service/vertex_array_manager.cc',
'command_buffer/service/vertex_attrib_manager.h',
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index 53343f6..eabf9b2 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -665,6 +665,45 @@
return;
}
+ // Track D3D Shader Model (if available)
+ const std::string& shader_version =
+ context_gpu_info.vertex_shader_version;
+
+ // Only gather if this is the first time we're seeing
+ // a non-empty shader version string.
+ if (!shader_version.empty() &&
+ basic_gpu_info->vertex_shader_version.empty()) {
+
+ // Note: do not reorder, used by UMA_HISTOGRAM below
+ enum ShaderModel {
+ SHADER_MODEL_UNKNOWN,
+ SHADER_MODEL_2_0,
+ SHADER_MODEL_3_0,
+ SHADER_MODEL_4_0,
+ SHADER_MODEL_4_1,
+ SHADER_MODEL_5_0,
+ NUM_SHADER_MODELS
+ };
+
+ ShaderModel shader_model = SHADER_MODEL_UNKNOWN;
+
+ if (shader_version == "5.0") {
+ shader_model = SHADER_MODEL_5_0;
+ } else if (shader_version == "4.1") {
+ shader_model = SHADER_MODEL_4_1;
+ } else if (shader_version == "4.0") {
+ shader_model = SHADER_MODEL_4_0;
+ } else if (shader_version == "3.0") {
+ shader_model = SHADER_MODEL_3_0;
+ } else if (shader_version == "2.0") {
+ shader_model = SHADER_MODEL_2_0;
+ }
+
+ UMA_HISTOGRAM_ENUMERATION("GPU.D3DShaderModel",
+ shader_model,
+ NUM_SHADER_MODELS);
+ }
+
MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics;
diff --git a/gpu/gpu.gyp b/gpu/gpu.gyp
index 0878a1d..ddecf45 100644
--- a/gpu/gpu.gyp
+++ b/gpu/gpu.gyp
@@ -232,6 +232,7 @@
'command_buffer/service/gles2_cmd_decoder_unittest_programs.cc',
'command_buffer/service/gles2_cmd_decoder_unittest_textures.cc',
'command_buffer/service/gles2_cmd_decoder_unittest_attribs.cc',
+ 'command_buffer/service/gles2_cmd_decoder_unittest_valuebuffer.cc',
'command_buffer/service/gl_surface_mock.cc',
'command_buffer/service/gl_surface_mock.h',
'command_buffer/service/gpu_scheduler_unittest.cc',
@@ -248,10 +249,12 @@
'command_buffer/service/program_cache_unittest.cc',
'command_buffer/service/shader_manager_unittest.cc',
'command_buffer/service/shader_translator_unittest.cc',
+ 'command_buffer/service/shader_translator_cache_unittest.cc',
'command_buffer/service/test_helper.cc',
'command_buffer/service/test_helper.h',
'command_buffer/service/texture_manager_unittest.cc',
'command_buffer/service/transfer_buffer_manager_unittest.cc',
+ 'command_buffer/service/valuebuffer_manager_unittest.cc',
'command_buffer/service/vertex_attrib_manager_unittest.cc',
'command_buffer/service/vertex_array_manager_unittest.cc',
'command_buffer/service/gpu_tracer_unittest.cc',
diff --git a/gpu/ipc/gpu_command_buffer_traits.cc b/gpu/ipc/gpu_command_buffer_traits.cc
index 46395fb..1b30034 100644
--- a/gpu/ipc/gpu_command_buffer_traits.cc
+++ b/gpu/ipc/gpu_command_buffer_traits.cc
@@ -3,8 +3,27 @@
// found in the LICENSE file.
#include "gpu/ipc/gpu_command_buffer_traits.h"
+
#include "gpu/command_buffer/common/mailbox_holder.h"
+// Generate param traits write methods.
+#include "ipc/param_traits_write_macros.h"
+namespace IPC {
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+} // namespace IPC
+
+// Generate param traits read methods.
+#include "ipc/param_traits_read_macros.h"
+namespace IPC {
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+} // namespace IPC
+
+// Generate param traits log methods.
+#include "ipc/param_traits_log_macros.h"
+namespace IPC {
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+} // namespace IPC
+
namespace IPC {
void ParamTraits<gpu::CommandBuffer::State> ::Write(Message* m,
diff --git a/gpu/ipc/gpu_command_buffer_traits.h b/gpu/ipc/gpu_command_buffer_traits.h
index ce854d2..3451639 100644
--- a/gpu/ipc/gpu_command_buffer_traits.h
+++ b/gpu/ipc/gpu_command_buffer_traits.h
@@ -5,9 +5,10 @@
#ifndef GPU_IPC_GPU_PARAM_TRAITS_H_
#define GPU_IPC_GPU_PARAM_TRAITS_H_
-#include "ipc/ipc_message_utils.h"
#include "gpu/command_buffer/common/command_buffer.h"
#include "gpu/gpu_export.h"
+#include "gpu/ipc/gpu_command_buffer_traits_multi.h"
+#include "ipc/ipc_message_utils.h"
namespace gpu {
struct Mailbox;
diff --git a/gpu/ipc/gpu_command_buffer_traits_multi.h b/gpu/ipc/gpu_command_buffer_traits_multi.h
new file mode 100644
index 0000000..0978f79
--- /dev/null
+++ b/gpu/ipc/gpu_command_buffer_traits_multi.h
@@ -0,0 +1,59 @@
+// 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.
+
+// Multiply-included message file, hence no include guard here.
+#include "gpu/command_buffer/common/capabilities.h"
+#include "gpu/gpu_export.h"
+#include "ipc/ipc_message_utils.h"
+#include "ipc/param_traits_macros.h"
+
+#undef IPC_MESSAGE_EXPORT
+#define IPC_MESSAGE_EXPORT GPU_EXPORT
+
+IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities::ShaderPrecision)
+ IPC_STRUCT_TRAITS_MEMBER(min_range)
+ IPC_STRUCT_TRAITS_MEMBER(max_range)
+ IPC_STRUCT_TRAITS_MEMBER(precision)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities::PerStagePrecisions)
+ IPC_STRUCT_TRAITS_MEMBER(low_int)
+ IPC_STRUCT_TRAITS_MEMBER(medium_int)
+ IPC_STRUCT_TRAITS_MEMBER(high_int)
+ IPC_STRUCT_TRAITS_MEMBER(low_float)
+ IPC_STRUCT_TRAITS_MEMBER(medium_float)
+ IPC_STRUCT_TRAITS_MEMBER(high_float)
+IPC_STRUCT_TRAITS_END()
+
+IPC_STRUCT_TRAITS_BEGIN(gpu::Capabilities)
+ IPC_STRUCT_TRAITS_MEMBER(vertex_shader_precisions)
+ IPC_STRUCT_TRAITS_MEMBER(fragment_shader_precisions)
+ IPC_STRUCT_TRAITS_MEMBER(max_combined_texture_image_units)
+ IPC_STRUCT_TRAITS_MEMBER(max_cube_map_texture_size)
+ IPC_STRUCT_TRAITS_MEMBER(max_fragment_uniform_vectors)
+ IPC_STRUCT_TRAITS_MEMBER(max_renderbuffer_size)
+ IPC_STRUCT_TRAITS_MEMBER(max_texture_image_units)
+ IPC_STRUCT_TRAITS_MEMBER(max_texture_size)
+ IPC_STRUCT_TRAITS_MEMBER(max_varying_vectors)
+ IPC_STRUCT_TRAITS_MEMBER(max_vertex_attribs)
+ IPC_STRUCT_TRAITS_MEMBER(max_vertex_texture_image_units)
+ IPC_STRUCT_TRAITS_MEMBER(max_vertex_uniform_vectors)
+ IPC_STRUCT_TRAITS_MEMBER(num_compressed_texture_formats)
+ IPC_STRUCT_TRAITS_MEMBER(num_shader_binary_formats)
+ IPC_STRUCT_TRAITS_MEMBER(bind_generates_resource_chromium)
+ IPC_STRUCT_TRAITS_MEMBER(post_sub_buffer)
+ IPC_STRUCT_TRAITS_MEMBER(egl_image_external)
+ IPC_STRUCT_TRAITS_MEMBER(texture_format_bgra8888)
+ IPC_STRUCT_TRAITS_MEMBER(texture_format_etc1)
+ IPC_STRUCT_TRAITS_MEMBER(texture_format_etc1_npot)
+ IPC_STRUCT_TRAITS_MEMBER(texture_rectangle)
+ IPC_STRUCT_TRAITS_MEMBER(iosurface)
+ IPC_STRUCT_TRAITS_MEMBER(texture_usage)
+ IPC_STRUCT_TRAITS_MEMBER(texture_storage)
+ IPC_STRUCT_TRAITS_MEMBER(discard_framebuffer)
+ IPC_STRUCT_TRAITS_MEMBER(sync_query)
+ IPC_STRUCT_TRAITS_MEMBER(image)
+ IPC_STRUCT_TRAITS_MEMBER(blend_equation_advanced)
+ IPC_STRUCT_TRAITS_MEMBER(blend_equation_advanced_coherent)
+IPC_STRUCT_TRAITS_END()
diff --git a/mojo/gles2/gles2_context.cc b/mojo/gles2/gles2_context.cc
index f5e8471..51e7114 100644
--- a/mojo/gles2/gles2_context.cc
+++ b/mojo/gles2/gles2_context.cc
@@ -38,7 +38,7 @@
return false;
gles2_helper_->SetAutomaticFlushes(false);
transfer_buffer_.reset(new gpu::TransferBuffer(gles2_helper_.get()));
- bool bind_generates_resource = true;
+ bool bind_generates_resource = false;
// TODO(piman): Some contexts (such as compositor) want this to be true, so
// this needs to be a public parameter.
bool lose_context_when_out_of_memory = false;
diff --git a/net/BUILD.gn b/net/BUILD.gn
index a184a4c..d95aa5e 100644
--- a/net/BUILD.gn
+++ b/net/BUILD.gn
@@ -381,16 +381,6 @@
if (!enable_websockets) {
sources -= [
- "socket_stream/socket_stream.cc",
- "socket_stream/socket_stream.h",
- "socket_stream/socket_stream_job.cc",
- "socket_stream/socket_stream_job.h",
- "socket_stream/socket_stream_job_manager.cc",
- "socket_stream/socket_stream_job_manager.h",
- "socket_stream/socket_stream_metrics.cc",
- "socket_stream/socket_stream_metrics.h",
- "spdy/spdy_websocket_stream.cc",
- "spdy/spdy_websocket_stream.h",
"websockets/websocket_basic_handshake_stream.cc",
"websockets/websocket_basic_handshake_stream.h",
"websockets/websocket_basic_stream.cc",
@@ -427,15 +417,9 @@
"websockets/websocket_handshake_stream_create_helper.h",
"websockets/websocket_inflater.cc",
"websockets/websocket_inflater.h",
- "websockets/websocket_job.cc",
- "websockets/websocket_job.h",
"websockets/websocket_mux.h",
- "websockets/websocket_net_log_params.cc",
- "websockets/websocket_net_log_params.h",
"websockets/websocket_stream.cc",
"websockets/websocket_stream.h",
- "websockets/websocket_throttle.cc",
- "websockets/websocket_throttle.h",
]
}
@@ -588,11 +572,6 @@
":net",
"//base",
]
- if (is_win) {
- cflags = [
- "/wd4267",
- ]
- }
}
executable("dump_cache") {
@@ -689,6 +668,10 @@
"test/spawned_test_server/spawned_test_server.h",
"test/spawned_test_server/spawner_communicator.cc",
"test/spawned_test_server/spawner_communicator.h",
+ "test/url_request/url_request_failed_job.cc",
+ "test/url_request/url_request_failed_job.h",
+ "test/url_request/url_request_mock_http_job.cc",
+ "test/url_request/url_request_mock_http_job.h",
"url_request/test_url_fetcher_factory.cc",
"url_request/test_url_fetcher_factory.h",
"url_request/test_url_request_interceptor.cc",
@@ -1086,7 +1069,8 @@
# TODO(GYP) make this compile on Android, we need some native test deps done.
# TODO(GYP) Also doesn't work on Windows; dependency on boringssl is wrong.
-if (!is_android && !is_win) {
+# TODO(GYP) Also doesn't work on Mac, need to figure out why not.
+if (!is_android && !is_win && !is_mac) {
source_set("quic_tools") {
sources = [
@@ -1238,9 +1222,6 @@
if (!enable_websockets) {
sources -= [
- "socket_stream/socket_stream_metrics_unittest.cc",
- "socket_stream/socket_stream_unittest.cc",
- "spdy/spdy_websocket_stream_unittest.cc",
"websockets/websocket_basic_stream_test.cc",
"websockets/websocket_channel_test.cc",
"websockets/websocket_deflate_predictor_impl_test.cc",
@@ -1254,12 +1235,9 @@
"websockets/websocket_handshake_handler_test.cc",
"websockets/websocket_handshake_stream_create_helper_test.cc",
"websockets/websocket_inflater_test.cc",
- "websockets/websocket_job_test.cc",
- "websockets/websocket_net_log_params_test.cc",
"websockets/websocket_stream_test.cc",
"websockets/websocket_test_util.cc",
"websockets/websocket_test_util.h",
- "websockets/websocket_throttle_test.cc",
]
}
@@ -1397,4 +1375,4 @@
]
}
-} # !is_android
+} # !is_android && !is_win && !is_mac
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h
index 89fbfff..87063b7 100644
--- a/net/base/net_error_list.h
+++ b/net/base/net_error_list.h
@@ -271,9 +271,7 @@
// due to a malformed frame or other protocol violation.
NET_ERROR(WS_PROTOCOL_ERROR, -145)
-// Connection was aborted for switching to another ptotocol.
-// WebSocket abort SocketStream connection when alternate protocol is found.
-NET_ERROR(PROTOCOL_SWITCHED, -146)
+// Error -146 was removed (PROTOCOL_SWITCHED)
// Returned when attempting to bind an address that is already in use.
NET_ERROR(ADDRESS_IN_USE, -147)
@@ -305,9 +303,7 @@
// pushed to the queue.
NET_ERROR(WS_THROTTLE_QUEUE_TOO_LARGE, -154)
-// There are too many active SocketStream instances, so the new connect request
-// was rejected.
-NET_ERROR(TOO_MANY_SOCKET_STREAMS, -155)
+// Error -155 was removed (TOO_MANY_SOCKET_STREAMS)
// The SSL server certificate changed in a renegotiation.
NET_ERROR(SSL_SERVER_CERT_CHANGED, -156)
diff --git a/net/base/net_errors.cc b/net/base/net_errors.cc
index 7c219af..55cdebb 100644
--- a/net/base/net_errors.cc
+++ b/net/base/net_errors.cc
@@ -56,6 +56,18 @@
(error == ERR_SSL_PINNED_KEY_NOT_IN_CERT_CHAIN);
}
+bool IsClientCertificateError(int error) {
+ switch (error) {
+ case ERR_BAD_SSL_CLIENT_AUTH_CERT:
+ case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
+ case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
+ case ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
+ return true;
+ default:
+ return false;
+ }
+}
+
std::vector<int> GetAllErrorCodesForUma() {
return base::CustomHistogram::ArrayToCustomRanges(
kAllErrorCodes, arraysize(kAllErrorCodes));
diff --git a/net/base/net_errors.h b/net/base/net_errors.h
index 4dc6042..29b7742 100644
--- a/net/base/net_errors.h
+++ b/net/base/net_errors.h
@@ -39,6 +39,11 @@
// Returns true if |error| is a certificate error code.
NET_EXPORT bool IsCertificateError(int error);
+// Returns true if |error| is a client certificate authentication error. This
+// does not include ERR_SSL_PROTOCOL_ERROR which may also signal a bad client
+// certificate.
+NET_EXPORT bool IsClientCertificateError(int error);
+
// Map system error code to Error.
NET_EXPORT Error MapSystemError(int os_error);
diff --git a/net/base/net_log.h b/net/base/net_log.h
index 1b598ed..5fb2791 100644
--- a/net/base/net_log.h
+++ b/net/base/net_log.h
@@ -27,7 +27,7 @@
// NetLog is the destination for log messages generated by the network stack.
// Each log message has a "source" field which identifies the specific entity
// that generated the message (for example, which URLRequest or which
-// SocketStream).
+// SpdySession).
//
// To avoid needing to pass in the "source ID" to the logging functions, NetLog
// is usually accessed through a BoundNetLog, which will always pass in a
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index 823cde1..6dfe8c6 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -26,22 +26,13 @@
// }
EVENT_TYPE(FAILED)
-// Marks the creation/destruction of a request (net::URLRequest or
-// SocketStream).
+// Marks the creation/destruction of a request (net::URLRequest).
EVENT_TYPE(REQUEST_ALIVE)
// ------------------------------------------------------------------------
// HostResolverImpl
// ------------------------------------------------------------------------
-// The start/end of waiting on a host resolve (DNS) request.
-// The BEGIN phase contains the following parameters:
-//
-// {
-// "source_dependency": <Source id of the request being waited on>,
-// }
-EVENT_TYPE(HOST_RESOLVER_IMPL)
-
// The start/end of a host resolve (DNS) request. Note that these events are
// logged for all DNS requests, though not all requests result in the creation
// of a HostResolvedImpl::Request object.
@@ -50,12 +41,11 @@
//
// {
// "host": <Hostname associated with the request>,
-// "address_family": <The address family to restrict results to>
+// "address_family": <The address family to restrict results to>,
// "allow_cached_response": <Whether it is ok to return a result from
-// the host cache>
+// the host cache>,
// "is_speculative": <Whether this request was started by the DNS
// prefetcher>
-// "source_dependency": <Source id, if any, of what created the request>,
// }
//
// If an error occurred, the END phase will contain these parameters:
@@ -1694,49 +1684,6 @@
EVENT_TYPE(HTTP_STREAM_PARSER_READ_HEADERS)
// ------------------------------------------------------------------------
-// SocketStream
-// ------------------------------------------------------------------------
-
-// Measures the time between SocketStream::Connect() and
-// SocketStream::DidEstablishConnection()
-//
-// For the BEGIN phase, the following parameters are attached:
-// {
-// "url": <String of URL being loaded>,
-// }
-//
-// For the END phase, if there was an error, the following parameters are
-// attached:
-// {
-// "net_error": <Net error code of the failure>,
-// }
-EVENT_TYPE(SOCKET_STREAM_CONNECT)
-
-// A message sent on the SocketStream.
-EVENT_TYPE(SOCKET_STREAM_SENT)
-
-// A message received on the SocketStream.
-EVENT_TYPE(SOCKET_STREAM_RECEIVED)
-
-// ------------------------------------------------------------------------
-// WebSocketJob
-// ------------------------------------------------------------------------
-
-// This event is sent for a WebSocket handshake request.
-// The following parameters are attached:
-// {
-// "headers": <handshake request message>,
-// }
-EVENT_TYPE(WEB_SOCKET_SEND_REQUEST_HEADERS)
-
-// This event is sent on receipt of the WebSocket handshake response headers.
-// The following parameters are attached:
-// {
-// "headers": <handshake response message>,
-// }
-EVENT_TYPE(WEB_SOCKET_READ_RESPONSE_HEADERS)
-
-// ------------------------------------------------------------------------
// SOCKS5ClientSocket
// ------------------------------------------------------------------------
diff --git a/net/base/net_log_source_type_list.h b/net/base/net_log_source_type_list.h
index 9d66c17..dc553a4 100644
--- a/net/base/net_log_source_type_list.h
+++ b/net/base/net_log_source_type_list.h
@@ -9,13 +9,11 @@
SOURCE_TYPE(NONE)
SOURCE_TYPE(URL_REQUEST)
-SOURCE_TYPE(SOCKET_STREAM)
SOURCE_TYPE(PROXY_SCRIPT_DECIDER)
SOURCE_TYPE(CONNECT_JOB)
SOURCE_TYPE(SOCKET)
SOURCE_TYPE(SPDY_SESSION)
SOURCE_TYPE(QUIC_SESSION)
-SOURCE_TYPE(HOST_RESOLVER_IMPL_REQUEST)
SOURCE_TYPE(HOST_RESOLVER_IMPL_JOB)
SOURCE_TYPE(DISK_CACHE_ENTRY)
SOURCE_TYPE(MEMORY_CACHE_ENTRY)
diff --git a/net/base/network_delegate.cc b/net/base/network_delegate.cc
index 9cad50a..5b69cfb 100644
--- a/net/base/network_delegate.cc
+++ b/net/base/network_delegate.cc
@@ -176,19 +176,6 @@
return OnAuthRequired(request, auth_info, callback, credentials);
}
-int NetworkDelegate::NotifyBeforeSocketStreamConnect(
- SocketStream* socket,
- const CompletionCallback& callback) {
- DCHECK(CalledOnValidThread());
- DCHECK(socket);
- DCHECK(!callback.is_null());
- // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
- tracked_objects::ScopedTracker tracking_profile(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "423948 NetworkDelegate::OnBeforeSocketStreamConnect"));
- return OnBeforeSocketStreamConnect(socket, callback);
-}
-
bool NetworkDelegate::CanGetCookies(const URLRequest& request,
const CookieList& cookie_list) {
DCHECK(CalledOnValidThread());
diff --git a/net/base/network_delegate.h b/net/base/network_delegate.h
index 299989c..03dee0b 100644
--- a/net/base/network_delegate.h
+++ b/net/base/network_delegate.h
@@ -105,9 +105,6 @@
bool CanEnablePrivacyMode(const GURL& url,
const GURL& first_party_for_cookies) const;
- int NotifyBeforeSocketStreamConnect(SocketStream* socket,
- const CompletionCallback& callback);
-
bool CancelURLRequestWithPolicyViolatingReferrerHeader(
const URLRequest& request,
const GURL& target_url,
diff --git a/net/base/registry_controlled_domains/effective_tld_names.dat b/net/base/registry_controlled_domains/effective_tld_names.dat
index ab13045..111ee06 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.dat
+++ b/net/base/registry_controlled_domains/effective_tld_names.dat
@@ -1601,7 +1601,7 @@
// jp : http://en.wikipedia.org/wiki/.jp
// http://jprs.co.jp/en/jpdomain.html
-// Submitted by registry <info@jprs.jp> 2014-02-28
+// Submitted by registry <info@jprs.jp> 2014-10-30
jp
// jp organizational type names
ac.jp
@@ -1613,7 +1613,7 @@
lg.jp
ne.jp
or.jp
-// jp preficture type names
+// jp prefecture type names
aichi.jp
akita.jp
aomori.jp
@@ -1661,6 +1661,53 @@
yamagata.jp
yamaguchi.jp
yamanashi.jp
+栃木.jp
+愛知.jp
+愛媛.jp
+兵庫.jp
+熊本.jp
+茨城.jp
+北海道.jp
+千葉.jp
+和歌山.jp
+長崎.jp
+長野.jp
+新潟.jp
+青森.jp
+静岡.jp
+東京.jp
+石川.jp
+埼玉.jp
+三重.jp
+京都.jp
+佐賀.jp
+大分.jp
+大阪.jp
+奈良.jp
+宮城.jp
+宮崎.jp
+富山.jp
+山口.jp
+山形.jp
+山梨.jp
+岩手.jp
+岐阜.jp
+岡山.jp
+島根.jp
+広島.jp
+徳島.jp
+沖縄.jp
+滋賀.jp
+神奈川.jp
+福井.jp
+福岡.jp
+福島.jp
+秋田.jp
+群馬.jp
+香川.jp
+高知.jp
+鳥取.jp
+鹿児島.jp
// jp geographic type names
// http://jprs.jp/doc/rule/saisoku-1.html
*.kawasaki.jp
@@ -5259,27 +5306,30 @@
gos.pk
info.pk
-// pl : http://www.dns.pl/english/
+// pl http://www.dns.pl/english/index.html
+// confirmed on 26.09.2014 from Bogna Tchórzewska <partner@dns.pl>
pl
-// NASK functional domains (nask.pl / dns.pl) : http://www.dns.pl/english/dns-funk.html
+com.pl
+net.pl
+org.pl
+info.pl
+waw.pl
+gov.pl
+// pl functional domains (http://www.dns.pl/english/index.html)
aid.pl
agro.pl
atm.pl
auto.pl
biz.pl
-com.pl
edu.pl
gmina.pl
gsm.pl
-info.pl
mail.pl
miasta.pl
media.pl
mil.pl
-net.pl
nieruchomosci.pl
nom.pl
-org.pl
pc.pl
powiat.pl
priv.pl
@@ -5295,12 +5345,7 @@
tourism.pl
travel.pl
turystyka.pl
-// ICM functional domains (icm.edu.pl)
-6bone.pl
-art.pl
-mbone.pl
// Government domains (administred by ippt.gov.pl)
-gov.pl
uw.gov.pl
um.gov.pl
ug.gov.pl
@@ -5310,11 +5355,7 @@
sr.gov.pl
po.gov.pl
pa.gov.pl
-// other functional domains
-ngo.pl
-irc.pl
-usenet.pl
-// NASK geographical domains : http://www.dns.pl/english/dns-regiony.html
+// pl regional domains (http://www.dns.pl/english/index.html)
augustow.pl
babia-gora.pl
bedzin.pl
@@ -5400,7 +5441,6 @@
rzeszow.pl
sanok.pl
sejny.pl
-siedlce.pl
slask.pl
slupsk.pl
sosnowiec.pl
@@ -5422,7 +5462,6 @@
walbrzych.pl
warmia.pl
warszawa.pl
-waw.pl
wegrow.pl
wielun.pl
wlocl.pl
@@ -5435,18 +5474,6 @@
zarow.pl
zgora.pl
zgorzelec.pl
-// TASK geographical domains (www.task.gda.pl/uslugi/dns)
-gda.pl
-gdansk.pl
-gdynia.pl
-med.pl
-sopot.pl
-// other geographical domains
-gliwice.pl
-krakow.pl
-poznan.pl
-wroc.pl
-zakopane.pl
// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
pm
@@ -5631,7 +5658,7 @@
mari-el.ru
marine.ru
mordovia.ru
-mosreg.ru
+// mosreg.ru Bug 1090800 - removed at request of Aleksey Konstantinov <konstantinovav@mosreg.ru>
msk.ru
murmansk.ru
nalchik.ru
@@ -6756,7 +6783,10 @@
*.zw
-// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2014-09-02T12:02:06Z
+// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2014-11-03T18:02:06Z
+
+// abb : 2014-10-24 ABB Ltd
+abb
// abbott : 2014-07-24 Abbott Laboratories, Inc.
abbott
@@ -6779,6 +6809,12 @@
// actor : 2013-12-12 United TLD Holdco Ltd.
actor
+// adult : 2014-10-16 ICM Registry AD LLC
+adult
+
+// afl : 2014-10-02 Australian Football League
+afl
+
// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa
africa
@@ -6788,6 +6824,9 @@
// airforce : 2014-03-06 United TLD Holdco Ltd.
airforce
+// airtel : 2014-10-24 Bharti Airtel Limited
+airtel
+
// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft
allfinanz
@@ -6812,10 +6851,10 @@
// associates : 2014-03-06 Baxter Hill, LLC
associates
-// attorney : 2014-03-20 undefined
+// attorney : 2014-03-20
attorney
-// auction : 2014-03-20 undefined
+// auction : 2014-03-20
auction
// audio : 2014-03-20 Uniregistry, Corp.
@@ -6827,9 +6866,12 @@
// axa : 2013-12-19 AXA SA
axa
-// band : 2014-06-12 Auburn Hollow, LLC
+// band : 2014-06-12
band
+// bank : 2014-09-25 fTLD Registry Services LLC
+bank
+
// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
bar
@@ -6845,6 +6887,9 @@
// bayern : 2014-01-23 Bayern Connect GmbH
bayern
+// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+bbva
+
// bcn : 2014-07-24 Municipi de Barcelona
bcn
@@ -6884,6 +6929,9 @@
// blue : 2013-11-07 Afilias Limited
blue
+// bms : 2014-10-30 Bristol-Myers Squibb Company
+bms
+
// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
bmw
@@ -6893,6 +6941,9 @@
// bnpparibas : 2014-05-29 BNP Paribas
bnpparibas
+// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+bom
+
// bond : 2014-06-05 Bond University Limited
bond
@@ -6938,6 +6989,9 @@
// cancerresearch : 2014-05-15 Australian Cancer Research Foundation
cancerresearch
+// canon : 2014-09-12 Canon Inc.
+canon
+
// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
capetown
@@ -6995,6 +7049,9 @@
// cheap : 2013-11-14 Sand Cover, LLC
cheap
+// chloe : 2014-10-16 Richemont DNS Inc.
+chloe
+
// christmas : 2013-11-21 Uniregistry, Corp.
christmas
@@ -7028,6 +7085,9 @@
// club : 2013-11-08 .CLUB DOMAINS, LLC
club
+// coach : 2014-10-09 Koko Island, LLC
+coach
+
// codes : 2013-10-31 Puff Willow, LLC
codes
@@ -7058,7 +7118,7 @@
// construction : 2013-09-16 Fox Dynamite, LLC
construction
-// consulting : 2013-12-05 undefined
+// consulting : 2013-12-05
consulting
// contractors : 2013-09-10 Magic Woods, LLC
@@ -7070,6 +7130,9 @@
// cool : 2013-11-14 Koko Lake, LLC
cool
+// corsica : 2014-09-25 Collectivité Territoriale de Corse
+corsica
+
// country : 2013-12-19 Top Level Domain Holdings Limited
country
@@ -7079,12 +7142,21 @@
// creditcard : 2014-03-20 Binky Frostbite, LLC
creditcard
+// cricket : 2014-10-09 dot Cricket Limited
+cricket
+
+// crown : 2014-10-24 Crown Equipment Corporation
+crown
+
// crs : 2014-04-03 Federated Co-operatives Limited
crs
// cruises : 2013-12-05 Spring Way, LLC
cruises
+// csc : 2014-09-25 Alliance-One Services, Inc.
+csc
+
// cuisinella : 2014-04-03 SALM S.A.S.
cuisinella
@@ -7112,21 +7184,30 @@
// deals : 2014-05-22 Sand Sunset, LLC
deals
-// degree : 2014-03-06 undefined
+// degree : 2014-03-06
degree
+// delivery : 2014-09-11 Steel Station, LLC
+delivery
+
+// dell : 2014-10-24 Dell Inc.
+dell
+
// democrat : 2013-10-24 United TLD Holdco Ltd.
democrat
// dental : 2014-03-20 Tin Birch, LLC
dental
-// dentist : 2014-03-20 undefined
+// dentist : 2014-03-20
dentist
// desi : 2013-11-14 Desi Networks LLC
desi
+// dev : 2014-10-16 Charleston Road Registry Inc.
+dev
+
// diamonds : 2013-09-22 John Edge, LLC
diamonds
@@ -7148,6 +7229,12 @@
// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
dnp
+// docs : 2014-10-16 Charleston Road Registry Inc.
+docs
+
+// doha : 2014-09-18 Communications Regulatory Authority (CRA)
+doha
+
// domains : 2013-10-17 Sugar Cross, LLC
domains
@@ -7172,6 +7259,9 @@
// emerck : 2014-04-03 Merck KGaA
emerck
+// energy : 2014-09-11 Binky Birch, LLC
+energy
+
// engineer : 2014-03-06 United TLD Holdco Ltd.
engineer
@@ -7217,7 +7307,7 @@
// fail : 2014-03-06 Atomic Pipe, LLC
fail
-// fan : 2014-03-06 undefined
+// fan : 2014-03-06
fan
// farm : 2013-11-07 Just Maple, LLC
@@ -7229,6 +7319,9 @@
// feedback : 2013-12-19 Top Level Spectrum, Inc.
feedback
+// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+final
+
// finance : 2014-03-20 Cotton Cypress, LLC
finance
@@ -7253,6 +7346,9 @@
// florist : 2013-11-07 Half Cypress, LLC
florist
+// flowers : 2014-10-09 Uniregistry, Corp.
+flowers
+
// flsmidth : 2014-07-24 FLSmidth A/S
flsmidth
@@ -7262,7 +7358,7 @@
// foo : 2014-01-23 Charleston Road Registry Inc.
foo
-// forsale : 2014-05-22 undefined
+// forsale : 2014-05-22
forsale
// foundation : 2013-12-05 John Dale, LLC
@@ -7280,7 +7376,7 @@
// furniture : 2014-03-20 Lone Fields, LLC
furniture
-// futbol : 2013-09-20 undefined
+// futbol : 2013-09-20
futbol
// gal : 2013-11-07 Asociación puntoGAL
@@ -7370,7 +7466,7 @@
// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH
hamburg
-// haus : 2013-12-05 undefined
+// haus : 2013-12-05
haus
// healthcare : 2014-06-12 Silver Glen, LLC
@@ -7388,6 +7484,9 @@
// hiphop : 2014-03-06 Uniregistry, Corp.
hiphop
+// hitachi : 2014-10-31 Hitachi, Ltd.
+hitachi
+
// hiv : 2014-03-13 dotHIV gemeinnuetziger e.V.
hiv
@@ -7415,9 +7514,15 @@
// how : 2014-01-23 Charleston Road Registry Inc.
how
+// hsbc : 2014-10-24 HSBC Holdings PLC
+hsbc
+
// ibm : 2014-07-31 International Business Machines Corporation
ibm
+// ice : 2014-10-30 IntercontinentalExchange, Inc.
+ice
+
// ifm : 2014-01-30 ifm electronic gmbh
ifm
@@ -7466,6 +7571,9 @@
// istanbul : 2014-08-28 Istanbul Metropolitan Municipality
istanbul
+// itau : 2014-10-02 Itau Unibanco Holding S.A.
+itau
+
// iwc : 2014-06-23 Richemont DNS Inc.
iwc
@@ -7478,12 +7586,18 @@
// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
joburg
+// jprs : 2014-09-18 Japan Registry Services Co., Ltd.
+jprs
+
// juegos : 2014-03-20 Uniregistry, Corp.
juegos
// kaufen : 2013-11-07 United TLD Holdco Ltd.
kaufen
+// kddi : 2014-09-12 KDDI CORPORATION
+kddi
+
// kim : 2013-09-23 Afilias Limited
kim
@@ -7508,10 +7622,13 @@
// land : 2013-09-10 Pine Moon, LLC
land
+// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico
+lat
+
// latrobe : 2014-06-16 La Trobe University
latrobe
-// lawyer : 2014-03-20 undefined
+// lawyer : 2014-03-20
lawyer
// lds : 2014-03-20 IRI Domain Management, LLC (\
@@ -7523,9 +7640,18 @@
// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
leclerc
+// legal : 2014-10-16 Blue Falls, LLC
+legal
+
// lgbt : 2014-05-08 Afilias Limited
lgbt
+// liaison : 2014-10-02 Liaison Technologies, Incorporated
+liaison
+
+// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+lidl
+
// life : 2014-02-06 Trixy Oaks, LLC
life
@@ -7550,6 +7676,9 @@
// lotto : 2014-04-10 Afilias Limited
lotto
+// ltd : 2014-09-25 Over Corner, LLC
+ltd
+
// ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA
ltda
@@ -7562,6 +7691,9 @@
// madrid : 2014-05-01 Comunidad de Madrid
madrid
+// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF)
+maif
+
// maison : 2013-12-05 Victor Frostbite, LLC
maison
@@ -7571,12 +7703,15 @@
// mango : 2013-10-24 PUNTO FA S.L.
mango
-// market : 2014-03-06 undefined
+// market : 2014-03-06
market
// marketing : 2013-11-07 Fern Pass, LLC
marketing
+// marriott : 2014-10-09 Marriott Worldwide Corporation
+marriott
+
// media : 2014-03-06 Grand Glen, LLC
media
@@ -7589,6 +7724,9 @@
// meme : 2014-01-30 Charleston Road Registry Inc.
meme
+// memorial : 2014-10-16 Dog Beach, LLC
+memorial
+
// menu : 2013-09-11 Wedding TLD2, LLC
menu
@@ -7607,13 +7745,16 @@
// monash : 2013-09-30 Monash University
monash
+// money : 2014-10-16 Outer McCook, LLC
+money
+
// montblanc : 2014-06-23 Richemont DNS Inc.
montblanc
// mormon : 2013-12-05 IRI Domain Management, LLC (\
mormon
-// mortgage : 2014-03-20 undefined
+// mortgage : 2014-03-20
mortgage
// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
@@ -7625,6 +7766,9 @@
// mov : 2014-01-30 Charleston Road Registry Inc.
mov
+// movistar : 2014-10-16 Telefónica S.A.
+movistar
+
// nagoya : 2013-10-24 GMO Registry, Inc.
nagoya
@@ -7658,16 +7802,25 @@
// nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
nissan
+// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+nowruz
+
// nra : 2014-05-22 NRA Holdings Company, INC.
nra
// nrw : 2013-11-21 Minds + Machines GmbH
nrw
+// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+ntt
+
// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications
nyc
-// okinawa : 2013-12-05 BusinessRalliart inc.
+// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA
+obi
+
+// okinawa : 2013-12-05 BusinessRalliart Inc.
okinawa
// ong : 2014-03-06 Public Interest Registry
@@ -7685,6 +7838,9 @@
// organic : 2014-03-27 Afilias Limited
organic
+// osaka : 2014-09-04 Interlink Co., Ltd.
+osaka
+
// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd.
otsuka
@@ -7694,12 +7850,18 @@
// paris : 2014-01-30 City of Paris
paris
+// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+pars
+
// partners : 2013-12-05 Magic Glen, LLC
partners
// parts : 2013-12-05 Sea Goodbye, LLC
parts
+// party : 2014-09-11 Blue Sky Registry Limited
+party
+
// pharmacy : 2014-06-19 National Association of Boards of Pharmacy
pharmacy
@@ -7715,6 +7877,9 @@
// physio : 2014-05-01 PhysBiz Pty Ltd
physio
+// piaget : 2014-10-16 Richemont DNS Inc.
+piaget
+
// pics : 2013-11-14 Uniregistry, Corp.
pics
@@ -7742,6 +7907,9 @@
// poker : 2014-07-03 Afilias Domains No. 5 Limited
poker
+// porn : 2014-10-16 ICM Registry PN LLC
+porn
+
// praxi : 2013-12-05 Praxi S.p.A.
praxi
@@ -7781,6 +7949,9 @@
// red : 2013-11-07 Afilias Limited
red
+// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd.
+redstone
+
// rehab : 2014-03-06 United TLD Holdco Ltd.
rehab
@@ -7790,6 +7961,9 @@
// reisen : 2014-03-06 New Cypress, LLC
reisen
+// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc.
+reit
+
// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd.
ren
@@ -7811,7 +7985,7 @@
// restaurant : 2014-07-03 Snow Avenue, LLC
restaurant
-// reviews : 2013-09-13 undefined
+// reviews : 2013-09-13
reviews
// rich : 2013-11-21 I-Registry Ltd.
@@ -7823,7 +7997,7 @@
// rip : 2014-07-10 United TLD Holdco Ltd.
rip
-// rocks : 2013-11-14 undefined
+// rocks : 2013-11-14
rocks
// rodeo : 2013-12-19 Top Level Domain Holdings Limited
@@ -7835,21 +8009,30 @@
// ruhr : 2013-10-02 regiodot GmbH & Co. KG
ruhr
-// ryukyu : 2014-01-09 BusinessRalliart inc.
+// ryukyu : 2014-01-09 BusinessRalliart Inc.
ryukyu
// saarland : 2013-12-12 dotSaarland GmbH
saarland
+// sale : 2014-10-16 Half Bloom, LLC
+sale
+
// samsung : 2014-04-03 SAMSUNG SDS CO., LTD
samsung
+// sanofi : 2014-10-09 Sanofi
+sanofi
+
// sap : 2014-03-27 SAP AG
sap
// sarl : 2014-07-03 Delta Orchard, LLC
sarl
+// saxo : 2014-10-31 Saxo Bank A/S
+saxo
+
// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ)
sca
@@ -7865,12 +8048,24 @@
// schule : 2014-03-06 Outer Moon, LLC
schule
+// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+schwarz
+
+// science : 2014-09-11 dot Science Limited
+science
+
+// scor : 2014-10-31 SCOR SE
+scor
+
// scot : 2014-01-23 Dot Scot Registry Limited
scot
// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal)
seat
+// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A.
+sener
+
// services : 2014-02-27 Fox Castle, LLC
services
@@ -7883,6 +8078,9 @@
// sharp : 2014-05-01 Sharp Corporation
sharp
+// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+shia
+
// shiksha : 2013-11-14 Afilias Limited
shiksha
@@ -7901,7 +8099,7 @@
// social : 2013-11-07 United TLD Holdco Ltd.
social
-// software : 2014-03-20 undefined
+// software : 2014-03-20
software
// sohu : 2013-12-19 Sohu.com Limited
@@ -7922,6 +8120,12 @@
// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG
spiegel
+// stc : 2014-10-09 Saudi Telecom Company
+stc
+
+// stcgroup : 2014-10-09 Saudi Telecom Company
+stcgroup
+
// supplies : 2013-12-19 Atomic Fields, LLC
supplies
@@ -7940,6 +8144,12 @@
// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION
suzuki
+// swiss : 2014-10-16 Swiss Confederation
+swiss
+
+// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet
+sydney
+
// systems : 2013-11-07 Dash Cypress, LLC
systems
@@ -7955,9 +8165,15 @@
// tax : 2014-03-20 Storm Orchard, LLC
tax
+// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+tci
+
// technology : 2013-09-13 Auburn Falls
technology
+// telefonica : 2014-10-16 Telefónica S.A.
+telefonica
+
// temasek : 2014-08-07 Temasek Holdings (Private) Limited
temasek
@@ -7997,6 +8213,9 @@
// training : 2013-11-07 Wild Willow, LLC
training
+// trust : 2014-10-16
+trust
+
// tui : 2014-07-03 TUI AG
tui
@@ -8021,18 +8240,30 @@
// versicherung : 2014-03-20 dotversicherung-registry GmbH
versicherung
-// vet : 2014-03-06 undefined
+// vet : 2014-03-06
vet
// viajes : 2013-10-17 Black Madison, LLC
viajes
+// video : 2014-10-16 Lone Tigers, LLC
+video
+
// villas : 2013-12-05 New Sky, LLC
villas
+// virgin : 2014-09-25 Virgin Enterprises Limited
+virgin
+
// vision : 2013-12-05 Koko Station, LLC
vision
+// vista : 2014-09-18 Vistaprint Limited
+vista
+
+// vistaprint : 2014-09-18 Vistaprint Limited
+vistaprint
+
// vlaanderen : 2014-02-06 DNS.be vzw
vlaanderen
@@ -8102,6 +8333,9 @@
// wtf : 2014-03-06 Hidden Way, LLC
wtf
+// xerox : 2014-10-24 Xerox DNHC LLC
+xerox
+
// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd.
佛山
@@ -8195,6 +8429,9 @@
// xn--mgbab2bd : 2013-10-31 CORE Association
بازار
+// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+همراه
+
// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd.
政府
@@ -8234,6 +8471,9 @@
// xn--vhquv : 2013-08-27 Dash McCook, LLC
企业
+// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd.
+信息
+
// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd.
广东
@@ -8706,6 +8946,7 @@
// Google, Inc.
// Submitted by Eduardo Vela <evn@google.com> 2012-10-24
appspot.com
+blogspot.ae
blogspot.be
blogspot.bj
blogspot.ca
@@ -8720,6 +8961,7 @@
blogspot.com.au
blogspot.com.br
blogspot.com.es
+blogspot.com.tr
blogspot.cv
blogspot.cz
blogspot.de
@@ -8741,6 +8983,7 @@
blogspot.pt
blogspot.re
blogspot.ro
+blogspot.ru
blogspot.se
blogspot.sg
blogspot.sk
@@ -8793,6 +9036,14 @@
// Submitted by Duarte Santos <domain-admin@outsystemscloud.com> 2014-03-11
outsystemscloud.com
+// .pl domains (grandfathered)
+art.pl
+gliwice.pl
+krakow.pl
+poznan.pl
+wroc.pl
+zakopane.pl
+
// Red Hat, Inc. OpenShift : https://openshift.redhat.com/
// Submitted by Tim Kramer <tkramer@rhcloud.com> 2012-10-24
rhcloud.com
@@ -8805,6 +9056,13 @@
// Submitted by registry <lendl@nic.at> 2008-06-09
priv.at
+// TASK geographical domains (www.task.gda.pl/uslugi/dns)
+gda.pl
+gdansk.pl
+gdynia.pl
+med.pl
+sopot.pl
+
// Yola : https://www.yola.com/
// Submitted by Stefano Rivera <stefano@yola.com> 2014-07-09
yolasite.com
diff --git a/net/base/registry_controlled_domains/effective_tld_names.gperf b/net/base/registry_controlled_domains/effective_tld_names.gperf
index 1ef69e4..b3b6afd 100644
--- a/net/base/registry_controlled_domains/effective_tld_names.gperf
+++ b/net/base/registry_controlled_domains/effective_tld_names.gperf
@@ -19,7 +19,6 @@
4.bg, 0
5.bg, 0
6.bg, 0
-6bone.pl, 0
7.bg, 0
8.bg, 0
9.bg, 0
@@ -31,6 +30,7 @@
aarborte.no, 0
ab.ca, 0
abashiri.hokkaido.jp, 0
+abb, 0
abbott, 0
abeno.osaka.jp, 0
abiko.chiba.jp, 0
@@ -88,6 +88,7 @@
ad.jp, 0
adachi.tokyo.jp, 0
adm.br, 0
+adult, 0
adult.ht, 0
adv.br, 0
adygeya.ru, 0
@@ -103,6 +104,7 @@
aeroport.fr, 0
af, 0
afjord.no, 0
+afl, 0
africa, 0
africa.com, 4
ag, 0
@@ -138,6 +140,7 @@
airguard.museum, 0
airline.aero, 0
airport.aero, 0
+airtel, 0
airtraffic.aero, 0
aisai.aichi.jp, 0
aisho.shiga.jp, 0
@@ -276,7 +279,7 @@
art.dz, 0
art.ht, 0
art.museum, 0
-art.pl, 0
+art.pl, 4
art.sn, 0
artanddesign.museum, 0
artcenter.museum, 0
@@ -421,6 +424,7 @@
band, 0
bandai.fukushima.jp, 0
bando.ibaraki.jp, 0
+bank, 0
bar, 0
bar.pro, 0
barcelona, 0
@@ -447,6 +451,7 @@
bayern, 0
bb, 0
bbs.tr, 0
+bbva, 0
bc.ca, 0
bcn, 0
bd, 2
@@ -541,6 +546,7 @@
blogdns.net, 4
blogdns.org, 4
blogsite.org, 4
+blogspot.ae, 4
blogspot.be, 4
blogspot.bj, 4
blogspot.ca, 4
@@ -555,6 +561,7 @@
blogspot.com.au, 4
blogspot.com.br, 4
blogspot.com.es, 4
+blogspot.com.tr, 4
blogspot.cv, 4
blogspot.cz, 4
blogspot.de, 4
@@ -576,6 +583,7 @@
blogspot.pt, 4
blogspot.re, 4
blogspot.ro, 4
+blogspot.ru, 4
blogspot.se, 4
blogspot.sg, 4
blogspot.sk, 4
@@ -585,6 +593,7 @@
blue, 0
bm, 0
bmd.br, 0
+bms, 0
bmw, 0
bn, 2
bn.it, 0
@@ -601,6 +610,7 @@
bologna.it, 0
bolt.hu, 0
bolzano.it, 0
+bom, 0
bomlo.no, 0
bond, 0
bonn.museum, 0
@@ -698,6 +708,7 @@
can.museum, 0
canada.museum, 0
cancerresearch, 0
+canon, 0
capebreton.museum, 0
capetown, 0
capital, 0
@@ -849,6 +860,7 @@
chiyoda.gunma.jp, 0
chiyoda.tokyo.jp, 0
chizu.tottori.jp, 0
+chloe, 0
chocolate.museum, 0
chofu.tokyo.jp, 0
chonan.chiba.jp, 0
@@ -973,6 +985,7 @@
co.uz, 0
co.ve, 0
co.vi, 0
+coach, 0
coal.museum, 0
coastaldefence.museum, 0
codes, 0
@@ -1155,6 +1168,7 @@
coop.tt, 0
copenhagen.museum, 0
corporation.museum, 0
+corsica, 0
corvette.museum, 0
cosenza.it, 0
costume.museum, 0
@@ -1175,11 +1189,14 @@
cremona.it, 0
crew.aero, 0
cri.nz, 0
+cricket, 0
crimea.ua, 0
crotone.it, 0
+crown, 0
crs, 0
cruises, 0
cs.it, 0
+csc, 0
ct.it, 0
ct.us, 0
cu, 0
@@ -1235,6 +1252,8 @@
defense.tn, 0
degree, 0
delaware.museum, 0
+delivery, 0
+dell, 0
dell-ogliastra.it, 0
dellogliastra.it, 0
delmenhorst.museum, 0
@@ -1249,6 +1268,7 @@
design.aero, 0
design.museum, 0
detroit.museum, 0
+dev, 0
dgca.aero, 0
diamonds, 0
dielddanuorri.no, 0
@@ -1277,9 +1297,11 @@
dnsdojo.net, 4
dnsdojo.org, 4
do, 0
+docs, 0
does-it.net, 4
doesntexist.com, 4
doesntexist.org, 4
+doha, 0
dolls.museum, 0
domains, 0
dominic.ua, 0
@@ -1509,6 +1531,7 @@
endofinternet.org, 4
endoftheinternet.org, 4
enebakk.no, 0
+energy, 0
eng.br, 0
eng.pro, 0
engerdal.no, 0
@@ -1616,6 +1639,7 @@
film.museum, 0
fin.ec, 0
fin.tn, 0
+final, 0
finance, 0
financial, 0
fineart.museum, 0
@@ -1655,6 +1679,7 @@
florida.museum, 0
florist, 0
floro.no, 0
+flowers, 0
flsmidth, 0
fly, 0
flynnhub.com, 4
@@ -1867,10 +1892,10 @@
gc.ca, 0
gd, 0
gd.cn, 0
-gda.pl, 0
-gdansk.pl, 0
+gda.pl, 4
+gdansk.pl, 4
gdn, 0
-gdynia.pl, 0
+gdynia.pl, 4
ge, 0
ge.it, 0
geek.nz, 0
@@ -1920,7 +1945,7 @@
glass.museum, 0
gle, 0
gliding.aero, 0
-gliwice.pl, 0
+gliwice.pl, 4
global, 0
global.prod.fastly.net, 4
global.ssl.fastly.net, 4
@@ -2360,6 +2385,7 @@
history.museum, 0
historyofscience.museum, 0
hita.oita.jp, 0
+hitachi, 0
hitachi.ibaraki.jp, 0
hitachinaka.ibaraki.jp, 0
hitachiomiya.ibaraki.jp, 0
@@ -2432,6 +2458,7 @@
hoylandet.no, 0
hr, 0
hs.kr, 0
+hsbc, 0
ht, 0
hu, 0
hu.com, 4
@@ -2456,6 +2483,7 @@
ibestad.no, 0
ibigawa.gifu.jp, 0
ibm, 0
+ice, 0
ichiba.tokushima.jp, 0
ichihara.chiba.jp, 0
ichikai.tochigi.jp, 0
@@ -2620,7 +2648,6 @@
iq, 0
ir, 0
iraq.museum, 0
-irc.pl, 0
iris.arpa, 0
irish, 0
irkutsk.ru, 0
@@ -2737,6 +2764,7 @@
itakura.gunma.jp, 0
itami.hyogo.jp, 0
itano.tokushima.jp, 0
+itau, 0
itayanagi.aomori.jp, 0
ito.shizuoka.jp, 0
itoigawa.niigata.jp, 0
@@ -2821,6 +2849,7 @@
jp, 0
jp.net, 4
jpn.com, 4
+jprs, 0
js.cn, 0
judaica.museum, 0
judygarland.museum, 0
@@ -3042,6 +3071,7 @@
kazo.saitama.jp, 0
kazuno.akita.jp, 0
kchr.ru, 0
+kddi, 0
ke, 2
keisen.fukuoka.jp, 0
kembuchi.hokkaido.jp, 0
@@ -3203,7 +3233,7 @@
kr.ua, 0
kraanghke.no, 0
kragero.no, 0
-krakow.pl, 0
+krakow.pl, 4
krasnoyarsk.ru, 0
krd, 0
kred, 0
@@ -3315,6 +3345,7 @@
larsson.museum, 0
larvik.no, 0
laspezia.it, 0
+lat, 0
latina.it, 0
latrobe, 0
lavagis.no, 0
@@ -3338,6 +3369,7 @@
lecco.it, 0
leclerc, 0
leg.br, 0
+legal, 0
legnica.pl, 0
leikanger.no, 0
leirfjord.no, 0
@@ -3357,6 +3389,7 @@
lgbt, 0
li, 0
li.it, 0
+liaison, 0
lib.ak.us, 0
lib.al.us, 0
lib.ar.us, 0
@@ -3412,6 +3445,7 @@
lib.wa.us, 0
lib.wi.us, 0
lib.wy.us, 0
+lidl, 0
lier.no, 0
lierne.no, 0
life, 0
@@ -3463,6 +3497,7 @@
lt, 0
lt.it, 0
lt.ua, 0
+ltd, 0
ltd.co.im, 0
ltd.gi, 0
ltd.lk, 0
@@ -3505,6 +3540,7 @@
magazine.aero, 0
magnitka.ru, 0
maibara.shiga.jp, 0
+maif, 0
mail.pl, 0
maintenance.aero, 0
maison, 0
@@ -3542,6 +3578,7 @@
marketing, 0
marketplace.aero, 0
marnardal.no, 0
+marriott, 0
marugame.kagawa.jp, 0
marumori.miyagi.jp, 0
maryland.museum, 0
@@ -3578,7 +3615,6 @@
mazury.pl, 0
mb.ca, 0
mb.it, 0
-mbone.pl, 0
mc, 0
mc.it, 0
md, 0
@@ -3596,7 +3632,7 @@
med.ly, 0
med.om, 0
med.pa, 0
-med.pl, 0
+med.pl, 4
med.pro, 0
med.sa, 0
med.sd, 0
@@ -3622,6 +3658,7 @@
melhus.no, 0
meloy.no, 0
meme, 0
+memorial, 0
memorial.museum, 0
menu, 0
meraker.no, 0
@@ -3840,6 +3877,7 @@
moma.museum, 0
mombetsu.hokkaido.jp, 0
monash, 0
+money, 0
money.museum, 0
monmouth.museum, 0
montblanc, 0
@@ -3867,7 +3905,6 @@
moseushi.hokkaido.jp, 0
mosjoen.no, 0
moskenes.no, 0
-mosreg.ru, 0
moss.no, 0
mosvik.no, 0
motegi.tochigi.jp, 0
@@ -3877,6 +3914,7 @@
motosu.gifu.jp, 0
motoyama.kochi.jp, 0
mov, 0
+movistar, 0
mp, 0
mp.br, 0
mq, 0
@@ -4228,7 +4266,6 @@
ngo, 0
ngo.lk, 0
ngo.ph, 0
-ngo.pl, 0
nh.us, 0
nhk, 0
nhs.uk, 0
@@ -4340,6 +4377,7 @@
novara.it, 0
novosibirsk.ru, 0
nowaruda.pl, 0
+nowruz, 0
nozawaonsen.nagano.jp, 0
np, 2
nr, 0
@@ -4357,6 +4395,7 @@
nt.no, 0
nt.ro, 0
ntr.br, 0
+ntt, 0
nu, 0
nu.ca, 0
nu.it, 0
@@ -4383,6 +4422,7 @@
obama.fukui.jp, 0
obama.nagasaki.jp, 0
obanazawa.yamagata.jp, 0
+obi, 0
obihiro.hokkaido.jp, 0
obira.hokkaido.jp, 0
obu.aichi.jp, 0
@@ -4672,6 +4712,7 @@
oryol.ru, 0
os.hedmark.no, 0
os.hordaland.no, 0
+osaka, 0
osaka.jp, 0
osakasayama.osaka.jp, 0
osaki.miyagi.jp, 0
@@ -4757,9 +4798,11 @@
parliament.nz, 0
parma.it, 0
paroch.k12.ma.us, 0
+pars, 0
parti.se, 0
partners, 0
parts, 0
+party, 0
pasadena.museum, 0
passenger-association.aero, 0
pavia.it, 0
@@ -4802,6 +4845,7 @@
physio, 0
pi.it, 0
piacenza.it, 0
+piaget, 0
pics, 0
pictet, 0
pictures, 0
@@ -4851,6 +4895,7 @@
pomorskie.pl, 0
pomorze.pl, 0
pordenone.it, 0
+porn, 0
porsanger.no, 0
porsangu.no, 0
porsgrunn.no, 0
@@ -4862,7 +4907,7 @@
posts-and-telecommunications.museum, 0
potenza.it, 0
powiat.pl, 0
-poznan.pl, 0
+poznan.pl, 4
pp.az, 0
pp.ru, 0
pp.se, 0
@@ -4989,6 +5034,7 @@
recreation.aero, 0
red, 0
red.sv, 0
+redstone, 0
reggio-calabria.it, 0
reggio-emilia.it, 0
reggiocalabria.it, 0
@@ -4996,6 +5042,7 @@
rehab, 0
reise, 0
reisen, 0
+reit, 0
reklam.hu, 0
rel.ht, 0
rel.pl, 0
@@ -5158,6 +5205,7 @@
sakyo.kyoto.jp, 0
salangen.no, 0
salat.no, 0
+sale, 0
salem.museum, 0
salerno.it, 0
saltdal.no, 0
@@ -5184,6 +5232,7 @@
sannan.hyogo.jp, 0
sannohe.aomori.jp, 0
sano.tochigi.jp, 0
+sanofi, 0
sanok.pl, 0
santabarbara.museum, 0
santacruz.museum, 0
@@ -5214,6 +5263,7 @@
savannahga.museum, 0
saves-the-whales.com, 4
savona.it, 0
+saxo, 0
sayama.osaka.jp, 0
sayama.saitama.jp, 0
sayo.hyogo.jp, 0
@@ -5246,8 +5296,10 @@
school.na, 0
school.nz, 0
schule, 0
+schwarz, 0
schweiz.museum, 0
sci.eg, 0
+science, 0
science-fiction.museum, 0
science.museum, 0
scienceandhistory.museum, 0
@@ -5258,6 +5310,7 @@
sciences.museum, 0
sciencesnaturelles.museum, 0
scientist.aero, 0
+scor, 0
scot, 0
scotland.museum, 0
scrapper-site.net, 4
@@ -5297,6 +5350,7 @@
semboku.akita.jp, 0
semine.miyagi.jp, 0
sendai.jp, 2
+sener, 0
sennan.osaka.jp, 0
seoul.kr, 0
sera.hiroshima.jp, 0
@@ -5331,6 +5385,7 @@
sharp, 0
shell.museum, 0
sherbrooke.museum, 0
+shia, 0
shibata.miyagi.jp, 0
shibata.niigata.jp, 0
shibecha.hokkaido.jp, 0
@@ -5435,7 +5490,6 @@
sic.it, 0
sicilia.it, 0
sicily.it, 0
-siedlce.pl, 0
siellak.no, 0
siena.it, 0
sigdal.no, 0
@@ -5514,7 +5568,7 @@
songdalen.no, 0
soni.nara.jp, 0
soo.kagoshima.jp, 0
-sopot.pl, 0
+sopot.pl, 4
sor-aurdal.no, 0
sor-fron.no, 0
sor-odal.no, 0
@@ -5565,6 +5619,8 @@
stavanger.no, 0
stavern.no, 0
stavropol.ru, 0
+stc, 0
+stcgroup, 0
steam.museum, 0
steiermark.museum, 0
steigen.no, 0
@@ -5640,9 +5696,11 @@
swidnica.pl, 0
swiebodzin.pl, 0
swinoujscie.pl, 0
+swiss, 0
sx, 0
sx.cn, 0
sy, 0
+sydney, 0
sydney.museum, 0
sykkylven.no, 0
systems, 0
@@ -5758,6 +5816,7 @@
taxi.aero, 0
taxi.br, 0
tc, 0
+tci, 0
tcm.museum, 0
td, 0
te.it, 0
@@ -5769,6 +5828,7 @@
tel, 0
tel.tr, 0
teledata.mz, 1
+telefonica, 0
telekommunikation.museum, 0
television.museum, 0
temasek, 0
@@ -5977,6 +6037,7 @@
tromsa.no, 0
tromso.no, 0
trondheim.no, 0
+trust, 0
trust.museum, 0
trustee.museum, 0
trysil.no, 0
@@ -6127,7 +6188,6 @@
uscountryestate.museum, 0
usculture.museum, 0
usdecorativearts.museum, 0
-usenet.pl, 0
usgarden.museum, 0
ushiku.ibaraki.jp, 0
ushistory.museum, 0
@@ -6235,6 +6295,7 @@
vic.edu.au, 0
vic.gov.au, 0
vicenza.it, 0
+video, 0
video.hu, 0
vik.no, 0
viking.museum, 0
@@ -6244,10 +6305,13 @@
vindafjord.no, 0
vinnica.ua, 0
vinnytsia.ua, 0
+virgin, 0
virginia.museum, 0
virtual.museum, 0
virtuel.museum, 0
vision, 0
+vista, 0
+vistaprint, 0
viterbo.it, 0
vlaanderen, 0
vlaanderen.museum, 0
@@ -6360,7 +6424,7 @@
world, 0
worse-than.tv, 4
writesthisblog.com, 4
-wroc.pl, 0
+wroc.pl, 4
wroclaw.pl, 0
ws, 0
ws.na, 0
@@ -6372,27 +6436,45 @@
wy.us, 0
x.bg, 0
x.se, 0
+xerox, 0
xj.cn, 0
+xn--0trq7p7nn.jp, 0
+xn--1ctwo.jp, 0
+xn--1lqs03n.jp, 0
+xn--1lqs71d.jp, 0
xn--1qqw23a, 0
+xn--2m4a15e.jp, 0
xn--30rr7y, 0
+xn--32vp30h.jp, 0
xn--3bst00m, 0
xn--3ds443g, 0
xn--3e0b707e, 0
xn--45brj9c, 0
xn--45q11c, 0
xn--4gbrim, 0
+xn--4it168d.jp, 0
+xn--4it797k.jp, 0
+xn--4pvxs.jp, 0
xn--54b7fta0cc, 0
xn--55qw42g, 0
xn--55qx5d, 0
xn--55qx5d.cn, 0
xn--55qx5d.hk, 0
+xn--5js045d.jp, 0
+xn--5rtp49c.jp, 0
+xn--5rtq34k.jp, 0
+xn--6btw5a.jp, 0
xn--6frz82g, 0
+xn--6orx2r.jp, 0
xn--6qq986b3xl, 0
+xn--7t0a264c.jp, 0
xn--80adxhks, 0
xn--80ao21a, 0
xn--80asehdb, 0
xn--80aswg, 0
xn--80au.xn--90a3ac, 0
+xn--8ltr62k.jp, 0
+xn--8pvr4u.jp, 0
xn--90a3ac, 0
xn--90azh.xn--90a3ac, 0
xn--9dbhblg6di.museum, 0
@@ -6423,6 +6505,7 @@
xn--btsfjord-9za.no, 0
xn--c1avg, 0
xn--c1avg.xn--90a3ac, 0
+xn--c3s14m.jp, 0
xn--cg4bki, 0
xn--ciqpn.hk, 0
xn--clchc0ea0b2g2a9gcd, 0
@@ -6434,12 +6517,19 @@
xn--czrw28b.tw, 0
xn--d1acj3b, 0
xn--d1at.xn--90a3ac, 0
+xn--d5qv7z876c.jp, 0
xn--davvenjrga-y4a.no, 0
+xn--djrs72d6uy.jp, 0
+xn--djty4k.jp, 0
xn--dnna-gra.no, 0
xn--drbak-wua.no, 0
xn--dyry-ira.no, 0
+xn--efvn9s.jp, 0
xn--efvy88h, 0
+xn--ehqz56n.jp, 0
+xn--elqq16h.jp, 0
xn--eveni-0qa01ga.no, 0
+xn--f6qx53a.jp, 0
xn--finny-yua.no, 0
xn--fiq228c5hs, 0
xn--fiq64b, 0
@@ -6488,9 +6578,15 @@
xn--j6w193g, 0
xn--jlster-bya.no, 0
xn--jrpeland-54a.no, 0
+xn--k7yn95e.jp, 0
xn--karmy-yua.no, 0
+xn--kbrq7o.jp, 0
xn--kfjord-iua.no, 0
xn--klbu-woa.no, 0
+xn--klt787d.jp, 0
+xn--kltp7d.jp, 0
+xn--kltx9a.jp, 0
+xn--klty5x.jp, 0
xn--koluokta-7ya57h.no, 0
xn--kprw13d, 0
xn--kpry57d, 0
@@ -6540,10 +6636,12 @@
xn--mgberp4a5d4ar, 0
xn--mgbqly7c0a67fbc, 0
xn--mgbqly7cvafr, 0
+xn--mgbt3dhd, 0
xn--mgbtf8fl, 0
xn--mgbx4cd0ab, 0
xn--mjndalen-64a.no, 0
xn--mk0axi.hk, 0
+xn--mkru45i.jp, 0
xn--mlatvuopmi-s4a.no, 0
xn--mli-tla.no, 0
xn--mlselv-iua.no, 0
@@ -6557,12 +6655,15 @@
xn--mxtq1m, 0
xn--mxtq1m.hk, 0
xn--ngbc5azd, 0
+xn--nit225k.jp, 0
xn--nmesjevuemie-tcba.no, 0
xn--nnx388a, 0
xn--node, 0
xn--nqv7f, 0
xn--nqv7fs00ema, 0
xn--nry-yla5g.no, 0
+xn--ntso0iqx3a.jp, 0
+xn--ntsq17g.jp, 0
xn--nttery-byae.no, 0
xn--nvuotna-hwa.no, 0
xn--o1ac.xn--90a3ac, 0
@@ -6579,8 +6680,10 @@
xn--p1ai, 0
xn--pgbs0dh, 0
xn--porsgu-sta26f.no, 0
+xn--pssu33l.jp, 0
xn--q9jyb4c, 0
xn--qcka1pmc, 0
+xn--qqqt11m.jp, 0
xn--rady-ira.no, 0
xn--rdal-poa.no, 0
xn--rde-ula.no, 0
@@ -6589,11 +6692,15 @@
xn--rhkkervju-01af.no, 0
xn--rholt-mra.no, 0
xn--rhqv96g, 0
+xn--rht27z.jp, 0
+xn--rht3d.jp, 0
+xn--rht61e.jp, 0
xn--risa-5na.no, 0
xn--risr-ira.no, 0
xn--rland-uua.no, 0
xn--rlingen-mxa.no, 0
xn--rmskog-bya.no, 0
+xn--rny31h.jp, 0
xn--rros-gra.no, 0
xn--rskog-uua.no, 0
xn--rst-0na.no, 0
@@ -6633,6 +6740,7 @@
xn--tjme-hra.no, 0
xn--tn0ag.hk, 0
xn--tnsberg-q1a.no, 0
+xn--tor131o.jp, 0
xn--trany-yua.no, 0
xn--trgstad-r1a.no, 0
xn--trna-woa.no, 0
@@ -6641,8 +6749,11 @@
xn--uc0atv.hk, 0
xn--uc0atv.tw, 0
xn--uc0ay4a.hk, 0
+xn--uist22h.jp, 0
+xn--uisz3g.jp, 0
xn--unjrga-rta.no, 0
xn--unup4y, 0
+xn--uuwu58a.jp, 0
xn--vads-jra.no, 0
xn--vard-jra.no, 0
xn--vegrshei-c0a.no, 0
@@ -6652,12 +6763,14 @@
xn--vg-yiab.no, 0
xn--vgan-qoa.no, 0
xn--vgsy-qoa0j.no, 0
+xn--vgu402c.jp, 0
xn--vhquv, 0
xn--vler-qoa.hedmark.no, 0
xn--vler-qoa.xn--stfold-9xa.no, 0
xn--vre-eiker-k8a.no, 0
xn--vrggt-xqad.no, 0
xn--vry-yla5g.no, 0
+xn--vuq861b, 0
xn--wcvs22d.hk, 0
xn--wgbh1c, 0
xn--wgbl6a, 0
@@ -6669,6 +6782,7 @@
xn--ygarden-p1a.no, 0
xn--ygbi2ammx, 0
xn--ystre-slidre-ujb.no, 0
+xn--zbx025d.jp, 0
xn--zf0ao64a.tw, 0
xn--zf0avx.hk, 0
xn--zfr164b, 0
@@ -6805,7 +6919,7 @@
za.org, 4
zachpomor.pl, 0
zagan.pl, 0
-zakopane.pl, 0
+zakopane.pl, 4
zama.kanagawa.jp, 0
zamami.okinawa.jp, 0
zao.miyagi.jp, 0
diff --git a/net/base/request_priority.h b/net/base/request_priority.h
index e663610..dcf7793 100644
--- a/net/base/request_priority.h
+++ b/net/base/request_priority.h
@@ -11,6 +11,10 @@
// Prioritization used in various parts of the networking code such
// as connection prioritization and resource loading prioritization.
+// A Java counterpart will be generated for this enum.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.net
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: RequestPriority
+// GENERATED_JAVA_PREFIX_TO_STRIP:
enum RequestPriority {
IDLE = 0,
MINIMUM_PRIORITY = IDLE,
diff --git a/net/cert/ct_known_logs_static.h b/net/cert/ct_known_logs_static.h
index 7171271..a99944d 100644
--- a/net/cert/ct_known_logs_static.h
+++ b/net/cert/ct_known_logs_static.h
@@ -27,9 +27,17 @@
"\x6b\xbd\x27\xbc\x96\x21\x3e\x34\xf5\x87\x76\x31\xb1\x7f\x1d\xc9\x85"
"\x3b\x0d\xf7\x1f\x3f\xe9",
"Google 'Aviator' log"
+ },
+ {"\x30\x59\x30\x13\x06\x07\x2a\x86\x48\xce\x3d\x02\x01\x06\x08\x2a\x86"
+ "\x48\xce\x3d\x03\x01\x07\x03\x42\x00\x04\xa2\xf7\xed\x13\xe1\xd3\x5c"
+ "\x02\x08\xc4\x8e\x8b\x9b\x8b\x3b\x39\x68\xc7\x92\x6a\x38\xa1\x4f\x23"
+ "\xc5\xa5\x6f\x6f\xd7\x65\x81\xf8\xc1\x9b\xf4\x9f\xa9\x8b\x45\xf4\xb9"
+ "\x4e\x1b\xc9\xa2\x69\x17\xa5\x78\x87\xd9\xce\x88\x6f\x41\x03\xbb\xa3"
+ "\x2a\xe3\x77\x97\x8d\x78",
+ "SSLWatcher.com CT log 'alpha'"
}
};
-const size_t kNumKnownCTLogs = 2;
+const size_t kNumKnownCTLogs = 3;
#endif // NET_CERT_CT_KNOWN_LOGS_STATIC_H_
diff --git a/net/cert/ct_log_verifier_openssl.cc b/net/cert/ct_log_verifier_openssl.cc
index 884ae8a..55bc3e1 100644
--- a/net/cert/ct_log_verifier_openssl.cc
+++ b/net/cert/ct_log_verifier_openssl.cc
@@ -56,13 +56,10 @@
const base::StringPiece& description) {
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE);
- crypto::ScopedBIO bio(
- BIO_new_mem_buf(const_cast<char*>(public_key.data()), public_key.size()));
- if (!bio.get())
- return false;
-
- public_key_ = d2i_PUBKEY_bio(bio.get(), NULL);
- if (!public_key_)
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(public_key.data());
+ const uint8_t* end = ptr + public_key.size();
+ public_key_ = d2i_PUBKEY(nullptr, &ptr, public_key.size());
+ if (!public_key_ || ptr != end)
return false;
key_id_ = crypto::SHA256HashString(public_key);
diff --git a/net/cert/ct_log_verifier_unittest.cc b/net/cert/ct_log_verifier_unittest.cc
index 373f69e..e8d1bc4 100644
--- a/net/cert/ct_log_verifier_unittest.cc
+++ b/net/cert/ct_log_verifier_unittest.cc
@@ -89,4 +89,13 @@
ASSERT_FALSE(log_->SetSignedTreeHead(sth.Pass()));
}
+// Test that excess data after the public key is rejected.
+TEST_F(CTLogVerifierTest, ExcessDataInPublicKey) {
+ std::string key = ct::GetTestPublicKey();
+ key += "extra";
+
+ scoped_ptr<CTLogVerifier> log = CTLogVerifier::Create(key, "testlog");
+ EXPECT_FALSE(log);
+}
+
} // namespace net
diff --git a/net/data/url_request_unittest/simple.html b/net/data/url_request_unittest/simple.html
new file mode 100644
index 0000000..ce01362
--- /dev/null
+++ b/net/data/url_request_unittest/simple.html
@@ -0,0 +1 @@
+hello
diff --git a/net/data/url_request_unittest/simple.html.mock-http-headers b/net/data/url_request_unittest/simple.html.mock-http-headers
new file mode 100644
index 0000000..be8f7b5
--- /dev/null
+++ b/net/data/url_request_unittest/simple.html.mock-http-headers
@@ -0,0 +1,3 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 5
diff --git a/net/data/url_request_unittest/two-content-lengths.html b/net/data/url_request_unittest/two-content-lengths.html
new file mode 100644
index 0000000..364322d
--- /dev/null
+++ b/net/data/url_request_unittest/two-content-lengths.html
@@ -0,0 +1 @@
+This file is boring; all the action's in the .mock-http-headers.
diff --git a/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers b/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers
new file mode 100644
index 0000000..707c0b0
--- /dev/null
+++ b/net/data/url_request_unittest/two-content-lengths.html.mock-http-headers
@@ -0,0 +1,4 @@
+HTTP/1.1 200 OK
+Content-Type: text/html
+Content-Length: 42
+Content-Length: 41
diff --git a/net/dns/host_resolver_impl.cc b/net/dns/host_resolver_impl.cc
index 8913f17..fe63820 100644
--- a/net/dns/host_resolver_impl.cc
+++ b/net/dns/host_resolver_impl.cc
@@ -329,11 +329,9 @@
// Creates NetLog parameters containing the information in a RequestInfo object,
// along with the associated NetLog::Source.
-base::Value* NetLogRequestInfoCallback(const NetLog::Source& source,
- const HostResolver::RequestInfo* info,
+base::Value* NetLogRequestInfoCallback(const HostResolver::RequestInfo* info,
NetLog::LogLevel /* log_level */) {
base::DictionaryValue* dict = new base::DictionaryValue();
- source.AddToEventParameters(dict);
dict->SetString("host", info->host_port_pair().ToString());
dict->SetInteger("address_family",
@@ -374,34 +372,25 @@
// Logs when a request has just been started.
void LogStartRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
const HostResolver::RequestInfo& info) {
source_net_log.BeginEvent(
- NetLog::TYPE_HOST_RESOLVER_IMPL,
- request_net_log.source().ToEventParametersCallback());
-
- request_net_log.BeginEvent(
NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST,
- base::Bind(&NetLogRequestInfoCallback, source_net_log.source(), &info));
+ base::Bind(&NetLogRequestInfoCallback, &info));
}
// Logs when a request has just completed (before its callback is run).
void LogFinishRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
const HostResolver::RequestInfo& info,
int net_error) {
- request_net_log.EndEventWithNetErrorCode(
+ source_net_log.EndEventWithNetErrorCode(
NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST, net_error);
- source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
}
// Logs when a request has been cancelled.
void LogCancelRequest(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
const HostResolverImpl::RequestInfo& info) {
- request_net_log.AddEvent(NetLog::TYPE_CANCELLED);
- request_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
- source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL);
+ source_net_log.AddEvent(NetLog::TYPE_CANCELLED);
+ source_net_log.EndEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_REQUEST);
}
//-----------------------------------------------------------------------------
@@ -461,13 +450,11 @@
class HostResolverImpl::Request {
public:
Request(const BoundNetLog& source_net_log,
- const BoundNetLog& request_net_log,
const RequestInfo& info,
RequestPriority priority,
const CompletionCallback& callback,
AddressList* addresses)
: source_net_log_(source_net_log),
- request_net_log_(request_net_log),
info_(info),
priority_(priority),
job_(NULL),
@@ -511,11 +498,6 @@
return source_net_log_;
}
- // NetLog for this request.
- const BoundNetLog& request_net_log() {
- return request_net_log_;
- }
-
const RequestInfo& info() const {
return info_;
}
@@ -525,8 +507,7 @@
base::TimeTicks request_time() const { return request_time_; }
private:
- BoundNetLog source_net_log_;
- BoundNetLog request_net_log_;
+ const BoundNetLog source_net_log_;
// The request info that started the request.
const RequestInfo info_;
@@ -1200,7 +1181,7 @@
Job(const base::WeakPtr<HostResolverImpl>& resolver,
const Key& key,
RequestPriority priority,
- const BoundNetLog& request_net_log)
+ const BoundNetLog& source_net_log)
: resolver_(resolver),
key_(key),
priority_tracker_(priority),
@@ -1210,14 +1191,14 @@
dns_task_error_(OK),
creation_time_(base::TimeTicks::Now()),
priority_change_time_(creation_time_),
- net_log_(BoundNetLog::Make(request_net_log.net_log(),
+ net_log_(BoundNetLog::Make(source_net_log.net_log(),
NetLog::SOURCE_HOST_RESOLVER_IMPL_JOB)) {
- request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
+ source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CREATE_JOB);
net_log_.BeginEvent(
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB,
base::Bind(&NetLogJobCreationCallback,
- request_net_log.source(),
+ source_net_log.source(),
&key_.hostname));
}
@@ -1248,8 +1229,7 @@
if (req->was_canceled())
continue;
DCHECK_EQ(this, req->job());
- LogCancelRequest(req->source_net_log(), req->request_net_log(),
- req->info());
+ LogCancelRequest(req->source_net_log(), req->info());
}
}
@@ -1278,14 +1258,14 @@
req->set_job(this);
priority_tracker_.Add(req->priority());
- req->request_net_log().AddEvent(
+ req->source_net_log().AddEvent(
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_ATTACH,
net_log_.source().ToEventParametersCallback());
net_log_.AddEvent(
NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_ATTACH,
base::Bind(&NetLogJobAttachCallback,
- req->request_net_log().source(),
+ req->source_net_log().source(),
priority()));
// TODO(szym): Check if this is still needed.
@@ -1308,13 +1288,12 @@
// Don't remove it from |requests_| just mark it canceled.
req->MarkAsCanceled();
- LogCancelRequest(req->source_net_log(), req->request_net_log(),
- req->info());
+ LogCancelRequest(req->source_net_log(), req->info());
priority_tracker_.Remove(req->priority());
net_log_.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_JOB_REQUEST_DETACH,
base::Bind(&NetLogJobAttachCallback,
- req->request_net_log().source(),
+ req->source_net_log().source(),
priority()));
if (num_active_requests() > 0) {
@@ -1700,8 +1679,7 @@
DCHECK_EQ(this, req->job());
// Update the net log and notify registered observers.
- LogFinishRequest(req->source_net_log(), req->request_net_log(),
- req->info(), entry.error);
+ LogFinishRequest(req->source_net_log(), req->info(), entry.error);
if (did_complete) {
// Record effective total time from creation to completion.
RecordTotalTime(had_dns_config_, req->info().is_speculative(),
@@ -1871,19 +1849,15 @@
if (!DNSDomainFromDot(info.hostname(), &labeled_hostname))
return ERR_NAME_NOT_RESOLVED;
- // Make a log item for the request.
- BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
- NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
-
- LogStartRequest(source_net_log, request_net_log, info);
+ LogStartRequest(source_net_log, info);
// Build a key that identifies the request in the cache and in the
// outstanding jobs map.
- Key key = GetEffectiveKeyForRequest(info, request_net_log);
+ Key key = GetEffectiveKeyForRequest(info, source_net_log);
- int rv = ResolveHelper(key, info, addresses, request_net_log);
+ int rv = ResolveHelper(key, info, addresses, source_net_log);
if (rv != ERR_DNS_CACHE_MISS) {
- LogFinishRequest(source_net_log, request_net_log, info, rv);
+ LogFinishRequest(source_net_log, info, rv);
RecordTotalTime(HaveDnsConfig(), info.is_speculative(), base::TimeDelta());
return rv;
}
@@ -1895,7 +1869,7 @@
Job* job;
if (jobit == jobs_.end()) {
job =
- new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, request_net_log);
+ new Job(weak_ptr_factory_.GetWeakPtr(), key, priority, source_net_log);
job->Schedule(false);
// Check for queue overflow.
@@ -1905,7 +1879,7 @@
evicted->OnEvicted(); // Deletes |evicted|.
if (evicted == job) {
rv = ERR_HOST_RESOLVER_QUEUE_TOO_LARGE;
- LogFinishRequest(source_net_log, request_net_log, info, rv);
+ LogFinishRequest(source_net_log, info, rv);
return rv;
}
}
@@ -1916,7 +1890,7 @@
// Can't complete synchronously. Create and attach request.
scoped_ptr<Request> req(new Request(
- source_net_log, request_net_log, info, priority, callback, addresses));
+ source_net_log, info, priority, callback, addresses));
if (out_req)
*out_req = reinterpret_cast<RequestHandle>(req.get());
@@ -1928,7 +1902,7 @@
int HostResolverImpl::ResolveHelper(const Key& key,
const RequestInfo& info,
AddressList* addresses,
- const BoundNetLog& request_net_log) {
+ const BoundNetLog& source_net_log) {
// The result of |getaddrinfo| for empty hosts is inconsistent across systems.
// On Windows it gives the default interface's address, whereas on Linux it
// gives an error. We will make it fail on all platforms for consistency.
@@ -1939,13 +1913,13 @@
if (ResolveAsIP(key, info, &net_error, addresses))
return net_error;
if (ServeFromCache(key, info, &net_error, addresses)) {
- request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
+ source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_CACHE_HIT);
return net_error;
}
// TODO(szym): Do not do this if nsswitch.conf instructs not to.
// http://crbug.com/117655
if (ServeFromHosts(key, info, addresses)) {
- request_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
+ source_net_log.AddEvent(NetLog::TYPE_HOST_RESOLVER_IMPL_HOSTS_HIT);
return OK;
}
return ERR_DNS_CACHE_MISS;
@@ -1957,17 +1931,13 @@
DCHECK(CalledOnValidThread());
DCHECK(addresses);
- // Make a log item for the request.
- BoundNetLog request_net_log = BoundNetLog::Make(net_log_,
- NetLog::SOURCE_HOST_RESOLVER_IMPL_REQUEST);
-
// Update the net log and notify registered observers.
- LogStartRequest(source_net_log, request_net_log, info);
+ LogStartRequest(source_net_log, info);
- Key key = GetEffectiveKeyForRequest(info, request_net_log);
+ Key key = GetEffectiveKeyForRequest(info, source_net_log);
- int rv = ResolveHelper(key, info, addresses, request_net_log);
- LogFinishRequest(source_net_log, request_net_log, info, rv);
+ int rv = ResolveHelper(key, info, addresses, source_net_log);
+ LogFinishRequest(source_net_log, info, rv);
return rv;
}
diff --git a/net/http/disk_cache_based_quic_server_info.cc b/net/http/disk_cache_based_quic_server_info.cc
index 2e116da..148df3f 100644
--- a/net/http/disk_cache_based_quic_server_info.cc
+++ b/net/http/disk_cache_based_quic_server_info.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/callback.h"
+#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/metrics/histogram.h"
#include "net/base/completion_callback.h"
@@ -17,44 +18,6 @@
namespace net {
-// Histogram that tracks number of times data read/parse/write API calls of
-// QuicServerInfo to and from disk cache is called.
-enum QuicServerInfoAPICall {
- QUIC_SERVER_INFO_START = 0,
- QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1,
- QUIC_SERVER_INFO_PARSE = 2,
- QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3,
- QUIC_SERVER_INFO_READY_TO_PERSIST = 4,
- QUIC_SERVER_INFO_PERSIST = 5,
- QUIC_SERVER_INFO_NUM_OF_API_CALLS = 6,
-};
-
-// Histogram that tracks failure reasons to read/load/write of QuicServerInfo to
-// and from disk cache.
-enum FailureReason {
- WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0,
- GET_BACKEND_FAILURE = 1,
- OPEN_FAILURE = 2,
- CREATE_OR_OPEN_FAILURE = 3,
- PARSE_NO_DATA_FAILURE = 4,
- PARSE_FAILURE = 5,
- READ_FAILURE = 6,
- READY_TO_PERSIST_FAILURE = 7,
- PERSIST_NO_BACKEND_FAILURE = 8,
- WRITE_FAILURE = 9,
- NUM_OF_FAILURES = 10,
-};
-
-void RecordQuicServerInfoStatus(QuicServerInfoAPICall call) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall", call,
- QUIC_SERVER_INFO_NUM_OF_API_CALLS);
-}
-
-void RecordQuicServerInfoFailure(FailureReason failure) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason", failure,
- NUM_OF_FAILURES);
-}
-
// Some APIs inside disk_cache take a handle that the caller must keep alive
// until the API has finished its asynchronous execution.
//
@@ -94,6 +57,7 @@
http_cache_(http_cache),
backend_(NULL),
entry_(NULL),
+ last_failure_(NO_FAILURE),
weak_factory_(this) {
io_callback_ =
base::Bind(&DiskCacheBasedQuicServerInfo::OnIOComplete,
@@ -104,6 +68,7 @@
void DiskCacheBasedQuicServerInfo::Start() {
DCHECK(CalledOnValidThread());
DCHECK_EQ(GET_BACKEND, state_);
+ DCHECK_EQ(last_failure_, NO_FAILURE);
RecordQuicServerInfoStatus(QUIC_SERVER_INFO_START);
load_start_time_ = base::TimeTicks::Now();
DoLoop(OK);
@@ -115,17 +80,19 @@
DCHECK_NE(GET_BACKEND, state_);
RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY);
- if (ready_)
+ if (ready_) {
+ RecordLastFailure();
return OK;
+ }
if (!callback.is_null()) {
// Prevent a new callback for WaitForDataReady overwriting an existing
- // pending callback (|user_callback_|).
- if (!user_callback_.is_null()) {
+ // pending callback (|wait_for_ready_callback_|).
+ if (!wait_for_ready_callback_.is_null()) {
RecordQuicServerInfoFailure(WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE);
return ERR_INVALID_ARGUMENT;
}
- user_callback_ = callback;
+ wait_for_ready_callback_ = callback;
}
return ERR_IO_PENDING;
@@ -135,8 +102,10 @@
DCHECK(CalledOnValidThread());
RecordQuicServerInfoStatus(QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL);
- if (!user_callback_.is_null())
- user_callback_.Reset();
+ if (!wait_for_ready_callback_.is_null()) {
+ RecordLastFailure();
+ wait_for_ready_callback_.Reset();
+ }
}
bool DiskCacheBasedQuicServerInfo::IsDataReady() {
@@ -144,10 +113,6 @@
}
bool DiskCacheBasedQuicServerInfo::IsReadyToPersist() {
- // TODO(rtenneti): Handle updates while a write is pending. Change
- // Persist() to save the data to be written into a temporary buffer
- // and then persist that data when we are ready to persist.
- //
// The data can be persisted if it has been loaded from the disk cache
// and there are no pending writes.
RecordQuicServerInfoStatus(QUIC_SERVER_INFO_READY_TO_PERSIST);
@@ -159,12 +124,29 @@
void DiskCacheBasedQuicServerInfo::Persist() {
DCHECK(CalledOnValidThread());
- DCHECK_NE(GET_BACKEND, state_);
+ if (!IsReadyToPersist()) {
+ // Handle updates while a write is pending or if we haven't loaded from disk
+ // cache. Save the data to be written into a temporary buffer and then
+ // persist that data when we are ready to persist.
+ pending_write_data_ = Serialize();
+ return;
+ }
+ PersistInternal();
+}
+void DiskCacheBasedQuicServerInfo::PersistInternal() {
+ DCHECK(CalledOnValidThread());
+ DCHECK_NE(GET_BACKEND, state_);
DCHECK(new_data_.empty());
CHECK(ready_);
- DCHECK(user_callback_.is_null());
- new_data_ = Serialize();
+ DCHECK(wait_for_ready_callback_.is_null());
+
+ if (pending_write_data_.empty()) {
+ new_data_ = Serialize();
+ } else {
+ new_data_ = pending_write_data_;
+ pending_write_data_.clear();
+ }
RecordQuicServerInfoStatus(QUIC_SERVER_INFO_PERSIST);
if (!backend_) {
@@ -176,8 +158,21 @@
DoLoop(OK);
}
+void DiskCacheBasedQuicServerInfo::OnExternalCacheHit() {
+ DCHECK(CalledOnValidThread());
+ DCHECK_NE(GET_BACKEND, state_);
+
+ RecordQuicServerInfoStatus(QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT);
+ if (!backend_) {
+ RecordQuicServerInfoFailure(PERSIST_NO_BACKEND_FAILURE);
+ return;
+ }
+
+ backend_->OnExternalCacheHit(key());
+}
+
DiskCacheBasedQuicServerInfo::~DiskCacheBasedQuicServerInfo() {
- DCHECK(user_callback_.is_null());
+ DCHECK(wait_for_ready_callback_.is_null());
if (entry_)
entry_->Close();
}
@@ -190,10 +185,15 @@
int rv) {
DCHECK_NE(NONE, state_);
rv = DoLoop(rv);
- if (rv != ERR_IO_PENDING && !user_callback_.is_null()) {
- CompletionCallback callback = user_callback_;
- user_callback_.Reset();
- callback.Run(rv);
+ if (rv == ERR_IO_PENDING)
+ return;
+ if (!wait_for_ready_callback_.is_null()) {
+ RecordLastFailure();
+ base::ResetAndReturn(&wait_for_ready_callback_).Run(rv);
+ }
+ if (ready_ && !pending_write_data_.empty()) {
+ DCHECK_EQ(NONE, state_);
+ PersistInternal();
}
}
@@ -381,4 +381,43 @@
return OK;
}
+void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoStatus(
+ QuicServerInfoAPICall call) {
+ if (!backend_) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.NoBackend", call,
+ QUIC_SERVER_INFO_NUM_OF_API_CALLS);
+ } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.MemoryCache", call,
+ QUIC_SERVER_INFO_NUM_OF_API_CALLS);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.APICall.DiskCache", call,
+ QUIC_SERVER_INFO_NUM_OF_API_CALLS);
+ }
+}
+
+void DiskCacheBasedQuicServerInfo::RecordLastFailure() {
+ if (last_failure_ != NO_FAILURE) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicDiskCache.FailureReason.WaitForDataReady",
+ last_failure_, NUM_OF_FAILURES);
+ }
+ last_failure_ = NO_FAILURE;
+}
+
+void DiskCacheBasedQuicServerInfo::RecordQuicServerInfoFailure(
+ FailureReason failure) {
+ last_failure_ = failure;
+
+ if (!backend_) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.NoBackend",
+ failure, NUM_OF_FAILURES);
+ } else if (backend_->GetCacheType() == net::MEMORY_CACHE) {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.MemoryCache",
+ failure, NUM_OF_FAILURES);
+ } else {
+ UMA_HISTOGRAM_ENUMERATION("Net.QuicDiskCache.FailureReason.DiskCache",
+ failure, NUM_OF_FAILURES);
+ }
+}
+
} // namespace net
diff --git a/net/http/disk_cache_based_quic_server_info.h b/net/http/disk_cache_based_quic_server_info.h
index 97fe95e..e95d535 100644
--- a/net/http/disk_cache_based_quic_server_info.h
+++ b/net/http/disk_cache_based_quic_server_info.h
@@ -38,9 +38,11 @@
bool IsDataReady() override;
bool IsReadyToPersist() override;
void Persist() override;
+ void OnExternalCacheHit() override;
private:
struct CacheOperationDataShim;
+
enum State {
GET_BACKEND,
GET_BACKEND_COMPLETE,
@@ -57,8 +59,42 @@
NONE,
};
+ // Enum to track number of times data read/parse/write API calls of
+ // QuicServerInfo to and from disk cache is called.
+ enum QuicServerInfoAPICall {
+ QUIC_SERVER_INFO_START = 0,
+ QUIC_SERVER_INFO_WAIT_FOR_DATA_READY = 1,
+ QUIC_SERVER_INFO_PARSE = 2,
+ QUIC_SERVER_INFO_WAIT_FOR_DATA_READY_CANCEL = 3,
+ QUIC_SERVER_INFO_READY_TO_PERSIST = 4,
+ QUIC_SERVER_INFO_PERSIST = 5,
+ QUIC_SERVER_INFO_EXTERNAL_CACHE_HIT = 6,
+ QUIC_SERVER_INFO_NUM_OF_API_CALLS = 7,
+ };
+
+ // Enum to track failure reasons to read/load/write of QuicServerInfo to
+ // and from disk cache.
+ enum FailureReason {
+ WAIT_FOR_DATA_READY_INVALID_ARGUMENT_FAILURE = 0,
+ GET_BACKEND_FAILURE = 1,
+ OPEN_FAILURE = 2,
+ CREATE_OR_OPEN_FAILURE = 3,
+ PARSE_NO_DATA_FAILURE = 4,
+ PARSE_FAILURE = 5,
+ READ_FAILURE = 6,
+ READY_TO_PERSIST_FAILURE = 7,
+ PERSIST_NO_BACKEND_FAILURE = 8,
+ WRITE_FAILURE = 9,
+ NO_FAILURE = 10,
+ NUM_OF_FAILURES = 11,
+ };
+
~DiskCacheBasedQuicServerInfo() override;
+ // Persists |pending_write_data_| if it is not empty, otherwise serializes the
+ // data and pesists it.
+ void PersistInternal();
+
std::string key() const;
// The |unused| parameter is a small hack so that we can have the
@@ -86,23 +122,39 @@
// DoSetDone is the terminal state of the write operation.
int DoSetDone();
+ // Tracks in a histogram the number of times data read/parse/write API calls
+ // of QuicServerInfo to and from disk cache is called.
+ void RecordQuicServerInfoStatus(QuicServerInfoAPICall call);
+
+ // Tracks in a histogram the failure reasons to read/load/write of
+ // QuicServerInfo to and from disk cache. It also saves the |failure| in
+ // |last_failure_|.
+ void RecordQuicServerInfoFailure(FailureReason failure);
+
+ // Tracks in a histogram if |last_failure_| is not NO_FAILURE.
+ void RecordLastFailure();
+
CacheOperationDataShim* data_shim_; // Owned by |io_callback_|.
CompletionCallback io_callback_;
State state_;
bool ready_;
bool found_entry_; // Controls the behavior of DoCreateOrOpen.
std::string new_data_;
+ std::string pending_write_data_;
const QuicServerId server_id_;
HttpCache* const http_cache_;
disk_cache::Backend* backend_;
disk_cache::Entry* entry_;
- CompletionCallback user_callback_;
+ CompletionCallback wait_for_ready_callback_;
scoped_refptr<IOBuffer> read_buffer_;
scoped_refptr<IOBuffer> write_buffer_;
std::string data_;
base::TimeTicks load_start_time_;
+ FailureReason last_failure_;
base::WeakPtrFactory<DiskCacheBasedQuicServerInfo> weak_factory_;
+
+ DISALLOW_COPY_AND_ASSIGN(DiskCacheBasedQuicServerInfo);
};
} // namespace net
diff --git a/net/http/disk_cache_based_quic_server_info_unittest.cc b/net/http/disk_cache_based_quic_server_info_unittest.cc
index 845fdc9..847b3d8 100644
--- a/net/http/disk_cache_based_quic_server_info_unittest.cc
+++ b/net/http/disk_cache_based_quic_server_info_unittest.cc
@@ -395,4 +395,191 @@
RemoveMockTransaction(&kHostInfoTransaction1);
}
+// Test Start() followed by Persist() without calling WaitForDataReady.
+TEST(DiskCacheBasedQuicServerInfo, StartAndPersist) {
+ MockHttpCache cache;
+ AddMockTransaction(&kHostInfoTransaction1);
+
+ QuicServerId server_id("www.google.com", 443, true, PRIVACY_MODE_DISABLED);
+ scoped_ptr<QuicServerInfo> quic_server_info(
+ new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+ EXPECT_FALSE(quic_server_info->IsDataReady());
+ quic_server_info->Start();
+ // Wait until Start() does the work.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ EXPECT_TRUE(quic_server_info->IsDataReady());
+
+ QuicServerInfo::State* state = quic_server_info->mutable_state();
+ EXPECT_TRUE(state->certs.empty());
+ const string server_config_a = "server_config_a";
+ const string source_address_token_a = "source_address_token_a";
+ const string server_config_sig_a = "server_config_sig_a";
+ const string cert_a = "cert_a";
+
+ state->server_config = server_config_a;
+ state->source_address_token = source_address_token_a;
+ state->server_config_sig = server_config_sig_a;
+ state->certs.push_back(cert_a);
+ EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+ quic_server_info->Persist();
+ quic_server_info->OnExternalCacheHit();
+
+ // Once we call Persist, IsReadyToPersist should return false until Persist
+ // has completed.
+ EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+
+ // Wait until Persist() does the work.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+
+ // Verify that the state was updated.
+ quic_server_info.reset(
+ new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+ quic_server_info->Start();
+ TestCompletionCallback callback;
+ int rv = quic_server_info->WaitForDataReady(callback.callback());
+ EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_TRUE(quic_server_info->IsDataReady());
+
+ const QuicServerInfo::State& state1 = quic_server_info->state();
+ EXPECT_EQ(server_config_a, state1.server_config);
+ EXPECT_EQ(source_address_token_a, state1.source_address_token);
+ EXPECT_EQ(server_config_sig_a, state1.server_config_sig);
+ EXPECT_EQ(1U, state1.certs.size());
+ EXPECT_EQ(cert_a, state1.certs[0]);
+
+ RemoveMockTransaction(&kHostInfoTransaction1);
+}
+
+// Test Persisting data when we are not ready to persist and then verify it
+// persists the data when Start() finishes.
+TEST(DiskCacheBasedQuicServerInfo, PersistWhenNotReadyToPersist) {
+ MockBlockingBackendFactory* factory = new MockBlockingBackendFactory();
+ MockHttpCache cache(factory);
+ AddMockTransaction(&kHostInfoTransaction1);
+ TestCompletionCallback callback;
+
+ QuicServerId server_id("www.google.com", 443, true, PRIVACY_MODE_DISABLED);
+ scoped_ptr<QuicServerInfo> quic_server_info(
+ new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+ EXPECT_FALSE(quic_server_info->IsDataReady());
+ // We do a Start(), but don't call WaitForDataReady(). Because we haven't
+ // created the backend, we will wait and data wouldn't be ready.
+ quic_server_info->Start();
+ EXPECT_FALSE(quic_server_info->IsDataReady());
+
+ // Persist data once, even though the backend is not ready.
+ QuicServerInfo::State* state = quic_server_info->mutable_state();
+ EXPECT_TRUE(state->certs.empty());
+ const string server_config_init = "server_config_init";
+ const string source_address_token_init = "source_address_token_init";
+ const string server_config_sig_init = "server_config_sig_init";
+ const string cert_init = "cert_init";
+
+ state->server_config = server_config_init;
+ state->source_address_token = source_address_token_init;
+ state->server_config_sig = server_config_sig_init;
+ state->certs.push_back(cert_init);
+ EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+ quic_server_info->Persist();
+ EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+
+ // Now complete the backend creation and let the callback run.
+ factory->FinishCreation();
+ EXPECT_TRUE(quic_server_info->IsDataReady());
+
+ // Wait until Persist() does the work.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ // Verify that the state was updated.
+ quic_server_info.reset(
+ new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+ quic_server_info->Start();
+ int rv = quic_server_info->WaitForDataReady(callback.callback());
+ EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_TRUE(quic_server_info->IsDataReady());
+
+ const QuicServerInfo::State& state1 = quic_server_info->state();
+ EXPECT_EQ(server_config_init, state1.server_config);
+ EXPECT_EQ(source_address_token_init, state1.source_address_token);
+ EXPECT_EQ(server_config_sig_init, state1.server_config_sig);
+ EXPECT_EQ(1U, state1.certs.size());
+ EXPECT_EQ(cert_init, state1.certs[0]);
+ RemoveMockTransaction(&kHostInfoTransaction1);
+}
+
+// Test multiple calls to Persist without waiting for the data to be written.
+TEST(DiskCacheBasedQuicServerInfo, MultiplePersistsWithoutWaiting) {
+ MockHttpCache cache;
+ AddMockTransaction(&kHostInfoTransaction1);
+ TestCompletionCallback callback;
+
+ QuicServerId server_id("www.google.com", 443, true, PRIVACY_MODE_DISABLED);
+ scoped_ptr<QuicServerInfo> quic_server_info(
+ new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+ EXPECT_FALSE(quic_server_info->IsDataReady());
+ quic_server_info->Start();
+ int rv = quic_server_info->WaitForDataReady(callback.callback());
+ EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_TRUE(quic_server_info->IsDataReady());
+
+ // Persist data once.
+ QuicServerInfo::State* state = quic_server_info->mutable_state();
+ EXPECT_TRUE(state->certs.empty());
+ const string server_config_init = "server_config_init";
+ const string source_address_token_init = "source_address_token_init";
+ const string server_config_sig_init = "server_config_sig_init";
+ const string cert_init = "cert_init";
+
+ state->server_config = server_config_init;
+ state->source_address_token = source_address_token_init;
+ state->server_config_sig = server_config_sig_init;
+ state->certs.push_back(cert_init);
+ EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+ quic_server_info->Persist();
+
+ // Once we call Persist, IsReadyToPersist should return false until Persist
+ // has completed.
+ EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+
+ // Persist one more time using the same |quic_server_info| object and without
+ // doing another Start() and WaitForDataReady.
+ const string server_config_a = "server_config_a";
+ const string source_address_token_a = "source_address_token_a";
+ const string server_config_sig_a = "server_config_sig_a";
+ const string cert_a = "cert_a";
+
+ state->server_config = server_config_a;
+ state->source_address_token = source_address_token_a;
+ state->server_config_sig = server_config_sig_a;
+ state->certs.push_back(cert_a);
+ EXPECT_FALSE(quic_server_info->IsReadyToPersist());
+ quic_server_info->Persist();
+
+ // Wait until Persist() does the work.
+ base::MessageLoop::current()->RunUntilIdle();
+
+ EXPECT_TRUE(quic_server_info->IsReadyToPersist());
+
+ // Verify that the state was updated.
+ quic_server_info.reset(
+ new DiskCacheBasedQuicServerInfo(server_id, cache.http_cache()));
+ quic_server_info->Start();
+ rv = quic_server_info->WaitForDataReady(callback.callback());
+ EXPECT_EQ(OK, callback.GetResult(rv));
+ EXPECT_TRUE(quic_server_info->IsDataReady());
+
+ // Verify the second time persisted data is persisted.
+ const QuicServerInfo::State& state1 = quic_server_info->state();
+ EXPECT_EQ(server_config_a, state1.server_config);
+ EXPECT_EQ(source_address_token_a, state1.source_address_token);
+ EXPECT_EQ(server_config_sig_a, state1.server_config_sig);
+ EXPECT_EQ(1U, state1.certs.size());
+ EXPECT_EQ(cert_a, state1.certs[0]);
+
+ RemoveMockTransaction(&kHostInfoTransaction1);
+}
+
} // namespace net
diff --git a/net/http/http_auth_handler.cc b/net/http/http_auth_handler.cc
index 7369ea5..4de2226 100644
--- a/net/http/http_auth_handler.cc
+++ b/net/http/http_auth_handler.cc
@@ -64,7 +64,7 @@
int HttpAuthHandler::GenerateAuthToken(
const AuthCredentials* credentials, const HttpRequestInfo* request,
const CompletionCallback& callback, std::string* auth_token) {
- // TODO(cbentzel): Enforce non-NULL callback after cleaning up SocketStream.
+ DCHECK(!callback.is_null());
DCHECK(request);
DCHECK(credentials != NULL || AllowsDefaultCredentials());
DCHECK(auth_token != NULL);
@@ -96,8 +96,8 @@
void HttpAuthHandler::OnGenerateAuthTokenComplete(int rv) {
CompletionCallback callback = callback_;
FinishGenerateAuthToken();
- if (!callback.is_null())
- callback.Run(rv);
+ DCHECK(!callback.is_null());
+ callback.Run(rv);
}
void HttpAuthHandler::FinishGenerateAuthToken() {
diff --git a/net/http/http_auth_handler_basic_unittest.cc b/net/http/http_auth_handler_basic_unittest.cc
index a369df3..60e5882 100644
--- a/net/http/http_auth_handler_basic_unittest.cc
+++ b/net/http/http_auth_handler_basic_unittest.cc
@@ -9,6 +9,7 @@
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "net/base/net_errors.h"
+#include "net/base/test_completion_callback.h"
#include "net/http/http_auth_challenge_tokenizer.h"
#include "net/http/http_auth_handler_basic.h"
#include "net/http/http_request_info.h"
@@ -41,8 +42,9 @@
base::ASCIIToUTF16(tests[i].password));
HttpRequestInfo request_info;
std::string auth_token;
+ TestCompletionCallback callback;
int rv = basic->GenerateAuthToken(&credentials, &request_info,
- CompletionCallback(), &auth_token);
+ callback.callback(), &auth_token);
EXPECT_EQ(OK, rv);
EXPECT_STREQ(tests[i].expected_credentials, auth_token.c_str());
}
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 3ec607e..28b3b22 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -89,7 +89,6 @@
force_spdy_always(false),
use_alternate_protocols(false),
alternate_protocol_probability_threshold(1),
- enable_websocket_over_spdy(false),
enable_quic(false),
enable_quic_port_selection(true),
quic_always_require_handshake_confirmation(false),
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index a3f70aa..557b84e 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -109,7 +109,6 @@
// trying SSL and then falling back to http.
bool use_alternate_protocols;
double alternate_protocol_probability_threshold;
- bool enable_websocket_over_spdy;
bool enable_quic;
bool enable_quic_port_selection;
diff --git a/net/http/http_network_transaction.cc b/net/http/http_network_transaction.cc
index eea7294..20ffdd1 100644
--- a/net/http/http_network_transaction.cc
+++ b/net/http/http_network_transaction.cc
@@ -90,19 +90,6 @@
*session);
}
-// Returns true if |error| is a client certificate authentication error.
-bool IsClientCertificateError(int error) {
- switch (error) {
- case ERR_BAD_SSL_CLIENT_AUTH_CERT:
- case ERR_SSL_CLIENT_AUTH_PRIVATE_KEY_ACCESS_DENIED:
- case ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY:
- case ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED:
- return true;
- default:
- return false;
- }
-}
-
base::Value* NetLogSSLVersionFallbackCallback(
const GURL* url,
int net_error,
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index 938f1b0..d08d162 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -408,7 +408,7 @@
NextProto,
HttpNetworkTransactionTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
namespace {
diff --git a/net/http/http_proxy_client_socket_pool_unittest.cc b/net/http/http_proxy_client_socket_pool_unittest.cc
index 19df6a0..694d394 100644
--- a/net/http/http_proxy_client_socket_pool_unittest.cc
+++ b/net/http/http_proxy_client_socket_pool_unittest.cc
@@ -351,9 +351,12 @@
HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY31),
HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY31),
HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY31),
- HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4),
- HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4),
- HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4)));
+ HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4_14),
+ HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4_14),
+ HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4_14),
+ HttpProxyClientSocketPoolTestParams(HTTP, kProtoSPDY4_15),
+ HttpProxyClientSocketPoolTestParams(HTTPS, kProtoSPDY4_15),
+ HttpProxyClientSocketPoolTestParams(SPDY, kProtoSPDY4_15)));
TEST_P(HttpProxyClientSocketPoolTest, NoTunnel) {
Initialize(NULL, 0, NULL, 0, NULL, 0, NULL, 0);
diff --git a/net/http/http_response_info.cc b/net/http/http_response_info.cc
index 2ec0fb5..6967d79 100644
--- a/net/http/http_response_info.cc
+++ b/net/http/http_response_info.cc
@@ -369,8 +369,10 @@
case kProtoSPDY3:
case kProtoSPDY31:
return CONNECTION_INFO_SPDY3;
- case kProtoSPDY4:
- return CONNECTION_INFO_SPDY4;
+ case kProtoSPDY4_14:
+ return CONNECTION_INFO_HTTP2_14;
+ case kProtoSPDY4_15:
+ return CONNECTION_INFO_HTTP2_15;
case kProtoQUIC1SPDY3:
return CONNECTION_INFO_QUIC1_SPDY3;
@@ -395,9 +397,12 @@
return "spdy/2";
case CONNECTION_INFO_SPDY3:
return "spdy/3";
- case CONNECTION_INFO_SPDY4:
- // This is the HTTP/2 draft-15 identifier. For internal
- // consistency, HTTP/2 is named SPDY4 within Chromium.
+ case CONNECTION_INFO_HTTP2_14:
+ // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
+ // This is the HTTP/2 draft-14 identifier.
+ return "h2-14";
+ case CONNECTION_INFO_HTTP2_15:
+ // This is the HTTP/2 draft-15 identifier.
return "h2-15";
case CONNECTION_INFO_QUIC1_SPDY3:
return "quic/1+spdy/3";
diff --git a/net/http/http_response_info.h b/net/http/http_response_info.h
index efd76fe..df3e300 100644
--- a/net/http/http_response_info.h
+++ b/net/http/http_response_info.h
@@ -37,8 +37,10 @@
CONNECTION_INFO_HTTP1 = 1,
CONNECTION_INFO_DEPRECATED_SPDY2 = 2,
CONNECTION_INFO_SPDY3 = 3,
- CONNECTION_INFO_SPDY4 = 4,
+ // CONNECTION_INFO_HTTP2 = 4, // TODO(bnc): This will be HTTP/2.
CONNECTION_INFO_QUIC1_SPDY3 = 5,
+ CONNECTION_INFO_HTTP2_14 = 6, // HTTP/2 draft-14.
+ CONNECTION_INFO_HTTP2_15 = 7, // HTTP/2 draft-15.
NUM_OF_CONNECTION_INFOS,
};
diff --git a/net/http/http_server_properties.cc b/net/http/http_server_properties.cc
index cc41ea8..25725a8 100644
--- a/net/http/http_server_properties.cc
+++ b/net/http/http_server_properties.cc
@@ -20,6 +20,7 @@
"npn-spdy/2",
"npn-spdy/3",
"npn-spdy/3.1",
+ "npn-h2-14", // HTTP/2 draft-14. Called SPDY4 internally.
"npn-h2-15", // HTTP/2 draft-15. Called SPDY4 internally.
"quic"
};
@@ -51,7 +52,8 @@
case DEPRECATED_NPN_SPDY_2:
case NPN_SPDY_3:
case NPN_SPDY_3_1:
- case NPN_SPDY_4:
+ case NPN_SPDY_4_14:
+ case NPN_SPDY_4_15:
case QUIC:
DCHECK(IsAlternateProtocolValid(protocol));
return kAlternateProtocolStrings[
@@ -81,8 +83,10 @@
return NPN_SPDY_3;
case kProtoSPDY31:
return NPN_SPDY_3_1;
- case kProtoSPDY4:
- return NPN_SPDY_4;
+ case kProtoSPDY4_14:
+ return NPN_SPDY_4_14;
+ case kProtoSPDY4_15:
+ return NPN_SPDY_4_15;
case kProtoQUIC1SPDY3:
return QUIC;
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h
index 337f22d..a63dc6a 100644
--- a/net/http/http_server_properties.h
+++ b/net/http/http_server_properties.h
@@ -57,8 +57,9 @@
NPN_SPDY_MINIMUM_VERSION = DEPRECATED_NPN_SPDY_2,
NPN_SPDY_3,
NPN_SPDY_3_1,
- NPN_SPDY_4, // SPDY4 is HTTP/2.
- NPN_SPDY_MAXIMUM_VERSION = NPN_SPDY_4,
+ NPN_SPDY_4_14, // HTTP/2 draft-14
+ NPN_SPDY_4_15, // HTTP/2 draft-15
+ NPN_SPDY_MAXIMUM_VERSION = NPN_SPDY_4_15,
QUIC,
ALTERNATE_PROTOCOL_MAXIMUM_VALID_VERSION = QUIC,
UNINITIALIZED_ALTERNATE_PROTOCOL,
diff --git a/net/http/http_stream_factory_impl_request_unittest.cc b/net/http/http_stream_factory_impl_request_unittest.cc
index 4695067..587358d 100644
--- a/net/http/http_stream_factory_impl_request_unittest.cc
+++ b/net/http/http_stream_factory_impl_request_unittest.cc
@@ -20,7 +20,7 @@
NextProto,
HttpStreamFactoryImplRequestTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
namespace {
diff --git a/net/http/http_stream_factory_impl_unittest.cc b/net/http/http_stream_factory_impl_unittest.cc
index 4bf1659..68e9114 100644
--- a/net/http/http_stream_factory_impl_unittest.cc
+++ b/net/http/http_stream_factory_impl_unittest.cc
@@ -425,7 +425,7 @@
NextProto,
HttpStreamFactoryTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
TEST_P(HttpStreamFactoryTest, PreconnectDirect) {
for (size_t i = 0; i < arraysize(kTests); ++i) {
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index 907e6d8..baf38bf 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -415,7 +415,8 @@
// hostname_offset contains the number of bytes from the start of the given
// hostname where the name of the matching entry starts.
size_t hostname_offset;
- bool include_subdomains;
+ bool sts_include_subdomains;
+ bool pkp_include_subdomains;
bool force_https;
bool has_pins;
};
@@ -509,15 +510,19 @@
if (c == kEndOfString) {
PreloadResult tmp;
- if (!reader.Next(&tmp.include_subdomains) ||
+ if (!reader.Next(&tmp.sts_include_subdomains) ||
!reader.Next(&tmp.force_https) ||
!reader.Next(&tmp.has_pins)) {
return false;
}
+ tmp.pkp_include_subdomains = tmp.sts_include_subdomains;
+
if (tmp.has_pins) {
if (!reader.Read(4, &tmp.pinset_id) ||
- !reader.Read(9, &tmp.domain_id)) {
+ !reader.Read(9, &tmp.domain_id) ||
+ (!tmp.sts_include_subdomains &&
+ !reader.Next(&tmp.pkp_include_subdomains))) {
return false;
}
}
@@ -525,13 +530,16 @@
tmp.hostname_offset = hostname_offset;
if (hostname_offset == 0 || hostname[hostname_offset - 1] == '.') {
- *out_found = tmp.include_subdomains;
+ *out_found =
+ tmp.sts_include_subdomains || tmp.pkp_include_subdomains;
*out = tmp;
- }
- if (hostname_offset == 0) {
- *out_found = true;
- return true;
+ if (hostname_offset > 0) {
+ out->force_https &= tmp.sts_include_subdomains;
+ } else {
+ *out_found = true;
+ return true;
+ }
}
continue;
@@ -768,7 +776,7 @@
return false;
out->domain = host.substr(result.hostname_offset);
- out->sts.include_subdomains = result.include_subdomains;
+ out->sts.include_subdomains = result.sts_include_subdomains;
out->sts.last_observed = base::GetBuildTime();
out->sts.upgrade_mode =
TransportSecurityState::DomainState::MODE_DEFAULT;
@@ -778,7 +786,7 @@
}
if (enable_static_pins_ && result.has_pins) {
- out->pkp.include_subdomains = result.include_subdomains;
+ out->pkp.include_subdomains = result.pkp_include_subdomains;
out->pkp.last_observed = base::GetBuildTime();
if (result.pinset_id >= arraysize(kPinsets))
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index e757950..867cafd 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -698,10 +698,10 @@
0xf6, 0x07, 0xeb, 0x08, 0xed, 0x09, 0xae, 0xe3,
0x0a, 0x0b, 0x03, 0x0c, 0x02, 0x0d, 0xe2, 0xe8,
0x0f, 0xf3, 0xee, 0xf4, 0x10, 0x11, 0xff, 0x12,
- 0xb8, 0xb9, 0xb6, 0x14, 0xb7, 0x15, 0xb5, 0x16,
- 0xb0, 0x17, 0xb2, 0x18, 0x19, 0xea, 0xf8, 0x1a,
- 0x1b, 0xe6, 0xf5, 0x1c, 0xad, 0xf9, 0xe4, 0x1e,
- 0x1d, 0x1f, 0xe5, 0x20, 0xe9, 0xf2, 0xef, 0x22,
+ 0xad, 0xe6, 0x14, 0xf5, 0xb8, 0xb9, 0xb6, 0x16,
+ 0xb7, 0x17, 0xb5, 0x18, 0xb0, 0x19, 0xb2, 0x1a,
+ 0x1b, 0xea, 0xf8, 0x1c, 0x1d, 0xf9, 0xe4, 0x1e,
+ 0x15, 0x1f, 0xe5, 0x20, 0xe9, 0xf2, 0xef, 0x22,
0x21, 0x23, 0x13, 0x24, 0x0e, 0x25,
};
@@ -711,11 +711,11 @@
0x4a, 0x54, 0x80, 0x26, 0x94, 0x02, 0xd3, 0xfa,
0xf8, 0x20, 0x67, 0xaa, 0x53, 0x8d, 0x34, 0xfc,
0xfb, 0x79, 0xb6, 0x34, 0x74, 0x29, 0xf9, 0x72,
- 0x14, 0x9d, 0x89, 0x86, 0xea, 0x43, 0xb6, 0x7f,
+ 0x14, 0x9d, 0x89, 0x86, 0xee, 0x43, 0xb6, 0x7f,
0x3b, 0x05, 0x3b, 0x90, 0xd1, 0x51, 0x4f, 0xff,
- 0x5b, 0xd6, 0x76, 0xbc, 0xca, 0x36, 0x5c, 0xd8,
+ 0x5b, 0xd6, 0x76, 0x9c, 0xca, 0x36, 0x5c, 0xd8,
0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x2b, 0xd9, 0xf7,
- 0x9b, 0xd3, 0x4a, 0x0e, 0x93, 0xb0, 0xf7, 0x04,
+ 0x9b, 0xd3, 0x5a, 0x0e, 0x93, 0xb0, 0xf7, 0x04,
0xc2, 0x7f, 0xe7, 0x73, 0xdd, 0x82, 0x9d, 0xc8,
0x68, 0x91, 0xa7, 0xff, 0x39, 0x9c, 0xf7, 0x60,
0xa7, 0x72, 0x1a, 0x27, 0x89, 0xff, 0xce, 0x67,
@@ -725,18 +725,18 @@
0xc8, 0x68, 0xa2, 0x27, 0xfd, 0xcf, 0x76, 0x0a,
0x77, 0x21, 0xa2, 0x91, 0x9f, 0xff, 0xb3, 0x6b,
0x2e, 0xf7, 0x5f, 0xfc, 0x0a, 0xd5, 0x40, 0x54,
- 0x9c, 0xc4, 0x51, 0xea, 0x23, 0x4f, 0xfc, 0xee,
+ 0x9c, 0xc4, 0x51, 0xee, 0x23, 0x4f, 0xfc, 0xee,
0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x12, 0x84, 0x50,
- 0xba, 0x70, 0xf8, 0xd2, 0x10, 0xc7, 0x56, 0x76,
+ 0xba, 0x70, 0xf8, 0xd2, 0x10, 0xc7, 0x76, 0x76,
0x30, 0xaf, 0x61, 0x35, 0x93, 0x00, 0xa4, 0xdd,
- 0xa9, 0x55, 0x4b, 0x48, 0x7a, 0xb7, 0x96, 0x4f,
+ 0xa9, 0x55, 0x4b, 0x58, 0x7a, 0xb7, 0x96, 0x4f,
0xfe, 0x73, 0x39, 0xee, 0xc1, 0x4e, 0xe4, 0x34,
0x4e, 0x73, 0xff, 0x9c, 0xce, 0x7b, 0xb0, 0x53,
0xb9, 0x0d, 0x14, 0x4c, 0xff, 0xc2, 0xf7, 0x5b,
0xd5, 0x69, 0xfe, 0x01, 0xd0, 0x28, 0xea, 0xaa,
- 0x96, 0x8a, 0x53, 0xf9, 0xd8, 0x29, 0xdc, 0x86,
+ 0x96, 0xaa, 0x53, 0xf9, 0xd8, 0x29, 0xdc, 0x86,
0x88, 0x72, 0x7c, 0x29, 0xdc, 0x86, 0x88, 0xbe,
- 0x7d, 0xd7, 0x7a, 0xeb, 0x2a, 0x4e, 0xc3, 0xd8,
+ 0x7d, 0xd7, 0x7a, 0xe9, 0x2a, 0x4e, 0xc3, 0xd8,
0xf9, 0x84, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14,
0xee, 0x43, 0x44, 0xc9, 0x3f, 0x9d, 0x82, 0x9d,
0xc8, 0x68, 0xb7, 0xa7, 0xff, 0x39, 0x9c, 0xf7,
@@ -745,1449 +745,1501 @@
0xfc, 0xec, 0x14, 0xee, 0x43, 0x44, 0x3b, 0x3f,
0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1,
0x2c, 0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x23,
- 0x09, 0xff, 0x9d, 0xcf, 0x76, 0x0a, 0x77, 0x21,
- 0xa2, 0x3d, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
+ 0x09, 0xf0, 0xa7, 0x72, 0x1a, 0x23, 0xd9, 0xea,
+ 0xf5, 0x2d, 0x8e, 0x9e, 0x77, 0x3d, 0xd8, 0x7a,
+ 0x97, 0x30, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
0x58, 0x73, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b,
- 0x9e, 0x15, 0x38, 0xaa, 0x0e, 0xde, 0xa5, 0xe3,
- 0xb6, 0x26, 0x5c, 0xee, 0x7f, 0x3b, 0x05, 0x3b,
- 0x90, 0xd1, 0x0f, 0x4f, 0x85, 0x3b, 0x90, 0xd1,
- 0x13, 0x4d, 0x76, 0x1d, 0x3f, 0xfb, 0x2d, 0xbe,
- 0x8a, 0xaf, 0xa9, 0xba, 0xb0, 0xe8, 0xa4, 0xf8,
- 0xec, 0x2d, 0x3d, 0x7d, 0x3b, 0x79, 0xa2, 0x17,
- 0x93, 0xb1, 0x1c, 0xf5, 0x84, 0x9e, 0x84, 0x73,
- 0xd7, 0xb7, 0xae, 0x74, 0xff, 0xef, 0x34, 0xfc,
- 0xa5, 0xfb, 0x99, 0xdd, 0xf3, 0xa6, 0xe6, 0xf3,
- 0xa5, 0xaa, 0x62, 0x21, 0xec, 0x45, 0xc9, 0xb3,
- 0xeb, 0x75, 0xf9, 0xe7, 0x4f, 0x7a, 0xbe, 0x01,
- 0xd3, 0x82, 0x10, 0x95, 0x3e, 0xef, 0xde, 0xd8,
- 0x53, 0x8b, 0xc9, 0xf7, 0x5d, 0xac, 0xb9, 0xd1,
- 0xb2, 0x26, 0x80, 0x7d, 0xf3, 0x59, 0xff, 0x81,
- 0xe6, 0xb7, 0x59, 0x7c, 0x3a, 0x6a, 0xce, 0x9f,
- 0xf7, 0xb5, 0xaf, 0xd6, 0xab, 0xe6, 0x1d, 0x3f,
- 0x63, 0x6d, 0x1f, 0x95, 0x3a, 0x7b, 0x36, 0xca,
- 0x0e, 0x8c, 0x4f, 0x37, 0xd0, 0xc0, 0x68, 0xc6,
- 0xc9, 0x9f, 0x3f, 0xb9, 0x7c, 0xfd, 0x81, 0x5c,
- 0xdb, 0xc7, 0x4f, 0xff, 0xfe, 0xff, 0xe9, 0x5d,
- 0x7f, 0xcd, 0xad, 0xe6, 0xb7, 0x57, 0x29, 0x78,
- 0xe0, 0x4e, 0x9f, 0x7a, 0xfa, 0x2d, 0x07, 0x4f,
- 0xea, 0x5f, 0x5d, 0x7a, 0x2d, 0x27, 0x4f, 0xee,
- 0x0e, 0x8d, 0x2d, 0xf8, 0xe8, 0xf1, 0xf5, 0xfc,
- 0xe2, 0x15, 0x33, 0x5c, 0x7f, 0x18, 0x4a, 0x4d,
- 0xa3, 0xce, 0x9d, 0xd7, 0xa9, 0xd3, 0x69, 0x41,
- 0xd3, 0xcb, 0xfb, 0xb4, 0xf3, 0x66, 0x23, 0x73,
- 0xff, 0xed, 0x16, 0xfb, 0xbf, 0xa3, 0x7e, 0xec,
- 0xbe, 0xa6, 0x5c, 0xe9, 0xff, 0xac, 0xba, 0xf7,
- 0x5f, 0xfd, 0x75, 0xb9, 0xd3, 0xfb, 0x75, 0x2f,
- 0xf5, 0xb4, 0x61, 0xd0, 0x03, 0xff, 0xfa, 0x3c,
- 0xff, 0x85, 0xad, 0xd5, 0x5f, 0x51, 0xd7, 0x3a,
- 0x14, 0xf8, 0xf4, 0x22, 0x9f, 0xff, 0xfe, 0xd3,
- 0xf5, 0x1f, 0xab, 0x5b, 0xb7, 0xdf, 0xcf, 0xca,
- 0x6f, 0x8d, 0xbf, 0x95, 0x3a, 0x4a, 0x74, 0xfe,
- 0x7f, 0x0f, 0xaa, 0xb4, 0x9d, 0x3f, 0xff, 0xff,
- 0xbc, 0x0a, 0xff, 0x3a, 0x9d, 0xdb, 0x5b, 0x4d,
- 0xdf, 0xca, 0x5f, 0x9a, 0x51, 0xfc, 0xea, 0x4e,
- 0x9d, 0xdc, 0x86, 0x8a, 0x62, 0x31, 0x17, 0xe9,
- 0x09, 0x99, 0xff, 0x67, 0xe9, 0x7d, 0x6e, 0xa2,
- 0xd1, 0xd3, 0xea, 0x7f, 0x8d, 0xb0, 0xe8, 0xf1,
- 0xf4, 0x71, 0xfc, 0xff, 0x73, 0x36, 0xb2, 0xd1,
- 0x81, 0x3a, 0x7f, 0xff, 0x7f, 0x12, 0xf7, 0x5b,
- 0xd5, 0xaf, 0xe0, 0x77, 0x2b, 0x75, 0x3a, 0x7f,
- 0xc8, 0xac, 0xb6, 0x57, 0x3d, 0xf3, 0xa1, 0x51,
- 0x49, 0x66, 0x89, 0xf0, 0xab, 0x65, 0x13, 0xa7,
- 0xee, 0xfe, 0xed, 0x97, 0xe7, 0x46, 0x1f, 0xbf,
- 0x88, 0xb4, 0x26, 0x8a, 0x17, 0x67, 0xf6, 0x4a,
- 0xd6, 0x70, 0x91, 0xa1, 0xd2, 0x45, 0xe8, 0x43,
- 0x34, 0x1e, 0x30, 0xf1, 0x64, 0x23, 0xbe, 0x43,
- 0x78, 0xd5, 0x27, 0xfd, 0xac, 0x78, 0x3b, 0xbb,
- 0x6e, 0xa0, 0xe9, 0xec, 0xfe, 0xbd, 0x59, 0xd3,
- 0xff, 0xff, 0xeb, 0x7a, 0xf6, 0xc1, 0x56, 0xdb,
- 0x99, 0xa3, 0x7e, 0xec, 0xa5, 0xf9, 0xa7, 0xc1,
- 0x53, 0xa5, 0x7f, 0x22, 0xda, 0xa4, 0xf3, 0xff,
- 0xec, 0xcb, 0x79, 0x2d, 0x9b, 0xab, 0xa5, 0x97,
- 0x56, 0x74, 0xff, 0xf5, 0xed, 0x80, 0xdc, 0xc5,
- 0xcb, 0xed, 0x9f, 0x3a, 0x7f, 0xa9, 0xdc, 0xc5,
- 0xcf, 0xdf, 0x50, 0xe9, 0x57, 0x11, 0x1f, 0xca,
- 0x32, 0xf7, 0xd3, 0x10, 0xbc, 0x3a, 0x67, 0xcf,
- 0x5a, 0x5f, 0x53, 0xa7, 0xff, 0xff, 0xfd, 0x9f,
- 0xd7, 0xbb, 0xd6, 0xd1, 0xcd, 0x7a, 0xea, 0xcf,
- 0xf6, 0xbb, 0x79, 0xd9, 0x6a, 0x40, 0xbb, 0x15,
- 0x3f, 0xff, 0xf2, 0x78, 0x3b, 0x68, 0x3b, 0xb4,
- 0x5a, 0x2a, 0x96, 0xd2, 0xd4, 0xf0, 0x4e, 0x9b,
- 0x4a, 0x29, 0x4d, 0x1b, 0xc5, 0x15, 0x85, 0x2c,
- 0x2a, 0xaf, 0x3b, 0x46, 0x73, 0xf8, 0xdd, 0x67,
- 0xff, 0x31, 0x37, 0x5b, 0x9f, 0x8c, 0xef, 0x80,
- 0xe9, 0xff, 0xf7, 0xbf, 0x7b, 0x63, 0x7d, 0xda,
- 0xcd, 0x5f, 0x7c, 0x07, 0x4f, 0xfc, 0xbf, 0xa3,
- 0xf8, 0xda, 0xba, 0x2d, 0x27, 0x45, 0x51, 0x4b,
- 0xa2, 0xec, 0xf6, 0x5f, 0x1b, 0xb3, 0xa7, 0x6a,
- 0x65, 0x8e, 0x9b, 0x36, 0x3a, 0x28, 0x4d, 0xb1,
- 0xf0, 0xef, 0xa9, 0x25, 0xc9, 0x5b, 0x0f, 0x4f,
- 0xdb, 0x2f, 0xed, 0xcf, 0x3a, 0x72, 0xec, 0xa7,
- 0x4f, 0xe6, 0x9f, 0x97, 0xaf, 0x35, 0xb8, 0xf2,
- 0x18, 0x5b, 0x3f, 0x37, 0xdb, 0xb5, 0x6a, 0x03,
- 0xa7, 0xf0, 0xb5, 0xfc, 0xb7, 0x5c, 0xe8, 0xc3,
- 0xe5, 0xf1, 0x9c, 0xfc, 0xa0, 0xcb, 0xef, 0xa0,
- 0xe8, 0x79, 0xe8, 0x7c, 0x86, 0x7f, 0xff, 0xd7,
- 0xff, 0x02, 0xb4, 0x67, 0xbf, 0x7f, 0xe3, 0x6d,
- 0xd5, 0x0f, 0xce, 0x9f, 0xf7, 0xb1, 0xad, 0xd5,
- 0x5b, 0x76, 0xac, 0xe9, 0xfd, 0xd4, 0xd6, 0xd9,
- 0xc2, 0x74, 0x6c, 0x7e, 0xb7, 0x44, 0x93, 0x0e,
- 0x9d, 0xfc, 0xd8, 0xe8, 0x53, 0x59, 0x48, 0x84,
- 0xfd, 0x4d, 0x73, 0x3f, 0xac, 0xe9, 0xe6, 0x6f,
- 0x50, 0x1d, 0x18, 0x7a, 0x5e, 0x2f, 0x85, 0x4f,
- 0x2b, 0x21, 0xcf, 0xe4, 0xf1, 0x73, 0x9f, 0xd7,
- 0xf5, 0x19, 0x6d, 0x2e, 0x74, 0xf6, 0x52, 0xad,
- 0x1d, 0x3f, 0x5b, 0x9e, 0xc1, 0xf1, 0xd3, 0xef,
- 0x00, 0x72, 0x93, 0xa3, 0x5a, 0x2a, 0xbc, 0x6a,
- 0x02, 0x2d, 0x0b, 0x27, 0xff, 0xe1, 0x7d, 0xb1,
- 0xab, 0x2f, 0xf5, 0xff, 0x2f, 0x6d, 0x0e, 0x9f,
- 0xff, 0xde, 0xca, 0x5f, 0x5b, 0xd9, 0x58, 0xbe,
- 0xdb, 0x72, 0xb7, 0x53, 0xa7, 0xff, 0xff, 0xda,
- 0x7f, 0x70, 0x7a, 0x97, 0x8f, 0x03, 0x75, 0x74,
- 0x5a, 0x6d, 0x9e, 0xfe, 0x6b, 0x3a, 0x7f, 0xfd,
- 0xa0, 0x8e, 0x5e, 0xb6, 0xf6, 0x6e, 0xb0, 0x14,
- 0xe8, 0xc4, 0x71, 0x5a, 0x11, 0x93, 0xff, 0xcf,
- 0x6f, 0xb6, 0x2f, 0xda, 0xfe, 0x5e, 0xbc, 0x74,
- 0xff, 0xfb, 0x6c, 0x66, 0xe6, 0xfb, 0xad, 0x5a,
- 0x7f, 0x0d, 0x07, 0x4f, 0xf6, 0x7e, 0x8d, 0xc0,
- 0xee, 0x68, 0xe9, 0xff, 0x57, 0x4f, 0xee, 0xae,
- 0x9a, 0x9a, 0x09, 0xd3, 0xff, 0xa8, 0xdd, 0x5b,
- 0x69, 0xba, 0xf5, 0xaa, 0x89, 0xd3, 0xff, 0xfe,
- 0xca, 0x6b, 0xec, 0x0e, 0xeb, 0x65, 0xeb, 0x94,
- 0x6e, 0xcf, 0x6c, 0x74, 0x62, 0x30, 0xbc, 0xa1,
- 0x14, 0x2b, 0x87, 0x48, 0xd3, 0x29, 0x27, 0xf2,
- 0x93, 0x17, 0x2a, 0x77, 0x78, 0xc2, 0x67, 0xfd,
- 0xc3, 0x6c, 0xba, 0xff, 0xc0, 0x3a, 0x7f, 0xb0,
- 0x34, 0xbe, 0xbb, 0xaf, 0xe3, 0xa7, 0xff, 0xfc,
- 0xa8, 0xac, 0xdc, 0xd5, 0xbd, 0xfd, 0xb7, 0x6f,
- 0x4f, 0xe5, 0xb0, 0xe8, 0x44, 0x75, 0x7c, 0xf1,
- 0xbc, 0xf2, 0x7b, 0xd7, 0xf2, 0x9d, 0x3f, 0xff,
- 0xff, 0x5d, 0x59, 0xff, 0x6b, 0xb7, 0x35, 0xbb,
- 0xfa, 0x37, 0xee, 0xca, 0x5f, 0x9a, 0x7c, 0x15,
- 0x3a, 0x1e, 0x8b, 0x8f, 0x10, 0xc2, 0xaf, 0x27,
- 0xe4, 0xbe, 0x5f, 0x46, 0xbb, 0xd0, 0xea, 0x9e,
- 0xbd, 0x78, 0x07, 0x4f, 0xfd, 0x6f, 0x6e, 0xf0,
- 0xe9, 0x47, 0x0a, 0x1d, 0x3f, 0x5f, 0x87, 0xf4,
- 0xf8, 0xe8, 0xc4, 0x4a, 0x6b, 0x21, 0xba, 0x34,
- 0xf6, 0xfd, 0x3a, 0xa7, 0x4f, 0xff, 0xde, 0x1d,
- 0xd9, 0xec, 0xfe, 0xbb, 0x7b, 0x19, 0x88, 0x74,
- 0xff, 0xff, 0x7a, 0x81, 0x56, 0x57, 0x45, 0xdc,
- 0xa2, 0xbb, 0x59, 0x58, 0x74, 0x62, 0x31, 0x05,
- 0x72, 0x7f, 0xff, 0xf0, 0x8f, 0xa8, 0xdd, 0x6c,
- 0xbf, 0xd5, 0xab, 0x65, 0x0b, 0x4d, 0xf4, 0x43,
- 0xa7, 0xff, 0xfe, 0x5d, 0x76, 0x5d, 0xdf, 0xcd,
- 0x35, 0xee, 0xa5, 0xf5, 0xf7, 0xf7, 0xad, 0x07,
- 0x4f, 0xa9, 0xaf, 0xb3, 0xe7, 0x46, 0x22, 0x9f,
- 0x47, 0xf8, 0xf2, 0x68, 0xd6, 0x8c, 0x8e, 0x7f,
- 0xbf, 0xa3, 0x5f, 0xcb, 0x75, 0xce, 0x9f, 0xed,
- 0xac, 0xa1, 0xda, 0xdc, 0xc3, 0xa7, 0xff, 0xfb,
- 0x86, 0xd9, 0x7f, 0x67, 0xe8, 0xaa, 0xe7, 0xf6,
- 0xb2, 0x9d, 0x3d, 0x7d, 0xd4, 0x09, 0xd1, 0x4a,
- 0x22, 0x79, 0x96, 0x7e, 0x6a, 0x97, 0xe8, 0xb7,
- 0x3a, 0x7f, 0xad, 0xcc, 0xfe, 0x5b, 0xae, 0x74,
- 0x29, 0xf3, 0xd4, 0xc2, 0x7e, 0xcb, 0x88, 0xe3,
- 0xce, 0x9f, 0xbf, 0x96, 0xfe, 0x21, 0xd3, 0xdf,
- 0xca, 0xee, 0x68, 0xf5, 0x6e, 0x55, 0x1b, 0x2b,
- 0xca, 0x48, 0xd9, 0xfc, 0x54, 0x27, 0x56, 0x86,
- 0x1d, 0xe1, 0x14, 0xd9, 0xda, 0x7f, 0xef, 0xff,
- 0x37, 0x0e, 0x5b, 0xf8, 0xd1, 0xd0, 0xab, 0xad,
- 0xd9, 0x39, 0x65, 0xce, 0xf3, 0xef, 0xab, 0x3b,
- 0x63, 0xa7, 0xf6, 0x35, 0x6c, 0xba, 0xec, 0x74,
- 0xff, 0xff, 0xf5, 0xb2, 0xf5, 0xe6, 0xb7, 0x7f,
- 0x29, 0x7e, 0x69, 0x47, 0xf3, 0x6b, 0x79, 0xa3,
- 0xa6, 0xd3, 0x59, 0xd0, 0x28, 0x9e, 0xbc, 0x21,
- 0x67, 0xec, 0xa3, 0xf9, 0x4d, 0x4e, 0x9f, 0xfc,
- 0x34, 0xbe, 0xb8, 0xca, 0x56, 0xd6, 0x53, 0xa5,
- 0x53, 0xa3, 0x43, 0xda, 0xde, 0x95, 0x3f, 0x95,
- 0x9f, 0xcb, 0x75, 0xce, 0x9f, 0xff, 0xf5, 0xfe,
- 0xa0, 0xa5, 0xf5, 0xd1, 0x6f, 0xfc, 0xdb, 0xd8,
- 0x2d, 0x1d, 0x1e, 0x54, 0xd8, 0xd1, 0x3f, 0x43,
- 0x47, 0xe4, 0xf5, 0x84, 0x46, 0x84, 0xbb, 0xcc,
- 0x67, 0xcf, 0xf0, 0xe5, 0x27, 0x4f, 0xb2, 0xb4,
- 0x60, 0x4e, 0x8a, 0x4f, 0x3a, 0xc4, 0xf3, 0xff,
- 0xef, 0x51, 0x89, 0xb5, 0xbd, 0x9a, 0xf7, 0x6b,
- 0xd1, 0x4e, 0x9e, 0x6f, 0xbe, 0x58, 0xe9, 0xff,
- 0xff, 0x9b, 0xe9, 0x7f, 0x53, 0xbb, 0xfa, 0x37,
- 0xee, 0xca, 0x5f, 0x9a, 0x7c, 0x15, 0x3a, 0x28,
- 0x45, 0x36, 0x12, 0x4f, 0xff, 0xff, 0x96, 0x9a,
- 0xe8, 0xb4, 0xee, 0xb6, 0x6d, 0xbb, 0xf9, 0xa6,
- 0xbd, 0xd5, 0x00, 0x3d, 0x73, 0xa7, 0xcb, 0xfa,
- 0x7a, 0x83, 0xa7, 0xff, 0xff, 0xff, 0x63, 0x31,
- 0x16, 0xca, 0xcb, 0xe5, 0x6a, 0xa2, 0x2b, 0xfc,
- 0xa3, 0x34, 0xae, 0x8d, 0x7d, 0x58, 0x74, 0xff,
- 0x03, 0x36, 0xfe, 0x5b, 0xae, 0x74, 0xfe, 0xa3,
- 0x45, 0xbb, 0x3d, 0x73, 0xa7, 0xfc, 0xba, 0xdb,
- 0xf4, 0xcf, 0xb5, 0xbd, 0x87, 0x46, 0x1f, 0xe5,
- 0x26, 0xb3, 0xff, 0xd9, 0x7d, 0xb3, 0x01, 0x5d,
- 0xc3, 0x5d, 0xaa, 0x74, 0xf5, 0x1e, 0xfd, 0xce,
- 0x85, 0x57, 0xe1, 0x84, 0x7e, 0x8c, 0x0c, 0x48,
- 0xd9, 0x09, 0x1b, 0x14, 0x74, 0x28, 0xff, 0x0b,
- 0x4a, 0x91, 0x68, 0xa5, 0x3b, 0x6d, 0xcd, 0x1d,
- 0x3f, 0xfd, 0x4b, 0xfe, 0xbb, 0x99, 0xf5, 0xd7,
- 0x7f, 0x50, 0x74, 0x61, 0xfb, 0x78, 0x82, 0x7e,
- 0xa1, 0xa7, 0xb7, 0x06, 0x83, 0xa7, 0xcc, 0xf6,
- 0xd9, 0xb1, 0xd2, 0x68, 0xe9, 0x95, 0x87, 0x4a,
- 0xe7, 0x40, 0x9a, 0x5e, 0x15, 0x8d, 0x8f, 0x56,
- 0xc6, 0xd3, 0xd7, 0xaf, 0x52, 0x74, 0xcd, 0x71,
- 0xd3, 0xfa, 0xde, 0x1a, 0x5f, 0xf5, 0x3a, 0x35,
- 0x52, 0x68, 0x0a, 0x69, 0x8f, 0xde, 0x23, 0x61,
- 0x16, 0x82, 0xd3, 0xfa, 0xbe, 0xa4, 0x3d, 0xf0,
- 0x1d, 0x3f, 0xfe, 0x51, 0x54, 0xc6, 0x2a, 0x3f,
- 0xd5, 0xd1, 0x87, 0x43, 0x48, 0x86, 0xd4, 0x34,
- 0x9d, 0xfe, 0x61, 0xd3, 0x01, 0x4e, 0x8f, 0x1b,
- 0x0f, 0x8d, 0xc9, 0xcd, 0xc7, 0x59, 0x1e, 0xb2,
- 0x81, 0xa8, 0x5d, 0xda, 0x36, 0x1c, 0x9d, 0xd2,
- 0xd7, 0x0b, 0xa4, 0x97, 0xd7, 0x4c, 0x75, 0x3e,
- 0x84, 0xdb, 0x51, 0x81, 0x8c, 0x7d, 0x8c, 0x87,
- 0x55, 0xa7, 0xa3, 0xfa, 0x1c, 0x7f, 0x9d, 0x9f,
- 0xac, 0xaa, 0x4b, 0xce, 0x58, 0xb6, 0x8c, 0x57,
- 0x52, 0x36, 0x1d, 0xf0, 0xe3, 0x6f, 0x57, 0x9f,
- 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x53, 0xb3, 0xe1,
- 0x4e, 0xe4, 0x34, 0x54, 0x73, 0xfe, 0xe7, 0xbb,
- 0x05, 0x3b, 0x90, 0xd1, 0x34, 0x49, 0xd8, 0x7e,
- 0xcc, 0x30, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
- 0x55, 0xf3, 0xe1, 0x4e, 0xe4, 0x34, 0x56, 0xd3,
- 0xfc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x24, 0x19,
- 0x3b, 0x0f, 0xc7, 0x8c, 0x27, 0xfe, 0x77, 0x3d,
- 0xd8, 0x29, 0xdc, 0x86, 0x89, 0x0e, 0x7c, 0x29,
- 0xdc, 0x86, 0x8b, 0x12, 0x7d, 0x82, 0xbf, 0xd6,
- 0x74, 0xff, 0xcb, 0x95, 0xcf, 0xed, 0xe0, 0x2f,
- 0xce, 0x9d, 0xf5, 0xa0, 0xe9, 0x3f, 0xe7, 0xbf,
- 0xa2, 0x1c, 0xed, 0x4f, 0x00, 0xe9, 0xc2, 0xaf,
- 0x3a, 0x7d, 0xcf, 0xdf, 0x65, 0x3a, 0x7e, 0xad,
- 0x47, 0xc1, 0xd5, 0x9d, 0x1e, 0x3d, 0x9e, 0x28,
- 0x9f, 0xeb, 0x27, 0xf1, 0xb7, 0xf2, 0xa7, 0x4f,
- 0xe0, 0x2e, 0x5f, 0xdf, 0x09, 0x51, 0x89, 0xfe,
- 0xeb, 0x30, 0xa6, 0x10, 0xde, 0x29, 0x11, 0xfb,
- 0x39, 0xf1, 0x08, 0x0e, 0x67, 0xfe, 0xb7, 0x96,
- 0xf6, 0xed, 0x79, 0xf0, 0x1d, 0x3f, 0xfd, 0x94,
- 0xbe, 0xfa, 0x50, 0xeb, 0x73, 0x3d, 0x53, 0xa6,
- 0xb3, 0xb1, 0x13, 0x1f, 0x45, 0x87, 0x26, 0x7a,
- 0xb1, 0x87, 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a,
- 0x2c, 0xd9, 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29,
- 0xdc, 0x86, 0x8a, 0x02, 0x7f, 0x7f, 0x2e, 0x0d,
- 0xff, 0x68, 0xe9, 0xb7, 0x54, 0xe9, 0xe4, 0xee,
- 0x43, 0x45, 0xbf, 0x3f, 0x6f, 0xbf, 0x27, 0x09,
- 0xd0, 0x27, 0xae, 0x02, 0xb9, 0xf5, 0xdf, 0x5d,
- 0xf5, 0x3a, 0x7f, 0x2b, 0x6d, 0xf7, 0xfa, 0x80,
- 0xe9, 0xee, 0xf7, 0xee, 0x74, 0xfe, 0xd2, 0x9a,
- 0xaa, 0x63, 0x0e, 0x9d, 0xfc, 0x79, 0xd2, 0x72,
- 0xa7, 0x2a, 0xf3, 0x6c, 0x6f, 0x12, 0x1b, 0x15,
- 0x00, 0xdb, 0xe4, 0x37, 0x33, 0x9f, 0xf7, 0x3d,
- 0xd8, 0x29, 0xdc, 0x86, 0x8a, 0x52, 0x7f, 0x9e,
- 0xec, 0x14, 0xee, 0x43, 0x44, 0x9d, 0x27, 0x31,
- 0x10, 0xfc, 0x8d, 0x0a, 0xee, 0x2e, 0x68, 0x8c,
- 0x8b, 0x6b, 0x5a, 0xa3, 0x91, 0xd3, 0xa4, 0x2c,
- 0x7c, 0x4f, 0xab, 0x85, 0x63, 0x44, 0xcc, 0x97,
- 0x0d, 0x62, 0x90, 0x1d, 0xd6, 0x3e, 0x76, 0xd0,
- 0xfc, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0x1f, 0x9f,
- 0xf7, 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89, 0x4e,
- 0x4e, 0xc3, 0xf6, 0x61, 0x84, 0xfe, 0x76, 0x0a,
- 0x77, 0x21, 0xa2, 0x27, 0x9f, 0xce, 0xc1, 0x4e,
- 0xe4, 0x34, 0x46, 0x33, 0xff, 0x9c, 0xce, 0x7b,
- 0xb0, 0x53, 0xb9, 0x0d, 0x13, 0xcc, 0x2a, 0x3b,
- 0xe8, 0x27, 0x79, 0xdd, 0x8e, 0xe7, 0xc2, 0x9d,
- 0xc8, 0x68, 0x88, 0x27, 0xfd, 0xcf, 0x76, 0x0a,
- 0x77, 0x21, 0xa2, 0x54, 0x93, 0xb0, 0xfd, 0x98,
- 0x61, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0x8a,
- 0x27, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x11, 0x94,
- 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee, 0x43,
- 0x44, 0xcb, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
- 0xa9, 0x27, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x15,
- 0xd4, 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xc5,
- 0x9f, 0xf9, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a,
- 0x27, 0xa9, 0xfe, 0x0b, 0xb9, 0x7d, 0xa9, 0xe6,
- 0xf3, 0xa1, 0xc8, 0x8a, 0x54, 0xc9, 0xfb, 0x55,
- 0xd9, 0x7f, 0x69, 0x53, 0xa7, 0x85, 0x97, 0xa4,
- 0xe9, 0xc9, 0x96, 0x2a, 0x7f, 0xfe, 0xb7, 0xfb,
- 0x5f, 0x85, 0x5e, 0xfc, 0xa8, 0x00, 0xa7, 0x4f,
- 0xff, 0xc3, 0xe6, 0xfe, 0x63, 0x94, 0x47, 0xcd,
- 0xe9, 0xa5, 0x07, 0x4f, 0x93, 0xd6, 0xde, 0xc3,
- 0xa7, 0xff, 0x75, 0x7f, 0x80, 0x75, 0xbc, 0x9c,
- 0x27, 0x4f, 0xaf, 0x65, 0x62, 0x1d, 0x3f, 0xfb,
- 0xfb, 0x95, 0x7e, 0xac, 0xdd, 0xba, 0xda, 0x87,
- 0x4d, 0xd4, 0x9d, 0x3f, 0xba, 0xbd, 0x6d, 0x3f,
- 0x41, 0xd1, 0xf3, 0xca, 0xd0, 0x5a, 0x3c, 0xa8,
- 0x40, 0x56, 0xd8, 0xc1, 0x62, 0x9f, 0xa3, 0xdc,
- 0x99, 0xbe, 0x13, 0x93, 0xbf, 0xd7, 0x35, 0x42,
- 0xd3, 0xbf, 0xea, 0x9d, 0x20, 0xea, 0x87, 0x88,
- 0xa5, 0x13, 0xc2, 0xdb, 0x98, 0x74, 0x61, 0xe7,
- 0x78, 0xb2, 0x7f, 0xde, 0xb7, 0x5d, 0x5a, 0xaf,
- 0x98, 0x74, 0xfd, 0xef, 0xeb, 0xf6, 0x54, 0xe9,
- 0xef, 0xed, 0xbb, 0x59, 0xd3, 0xf6, 0x54, 0x3d,
- 0xfa, 0x0e, 0x8e, 0x3d, 0x4f, 0x93, 0xcf, 0xb4,
- 0xd7, 0x5d, 0x94, 0xe8, 0xc4, 0x67, 0xfa, 0x10,
- 0x76, 0x21, 0x9f, 0xff, 0xfd, 0x65, 0xf0, 0x8a,
- 0xef, 0xbf, 0xbf, 0xa3, 0xf2, 0xbb, 0x69, 0xc2,
- 0xf3, 0xa7, 0xd4, 0x6c, 0x3e, 0x09, 0xd3, 0xf6,
- 0xdc, 0x20, 0xd4, 0xc3, 0xa7, 0xfd, 0xff, 0x3e,
- 0xf6, 0xc1, 0xf5, 0x4e, 0x9f, 0xf7, 0x60, 0x17,
- 0xfd, 0xb6, 0x6b, 0x3a, 0x1e, 0x7f, 0x80, 0x3e,
- 0x9f, 0xfc, 0xb9, 0x4d, 0xec, 0xb7, 0xfa, 0x82,
- 0xa7, 0x4e, 0xad, 0x98, 0x74, 0x5c, 0xf9, 0x74,
- 0x49, 0x9f, 0xb4, 0xad, 0xeb, 0x97, 0x3a, 0x70,
- 0x42, 0x12, 0xa7, 0xff, 0x5f, 0xd7, 0xad, 0xbd,
- 0xa9, 0xbc, 0x55, 0xe5, 0x38, 0xbc, 0x8f, 0x22,
- 0xa3, 0x44, 0xa8, 0x7a, 0xac, 0x4c, 0x7a, 0xf1,
- 0x48, 0xc2, 0xaf, 0xf0, 0x87, 0xbc, 0x32, 0xe6,
- 0xd7, 0x87, 0x4f, 0x83, 0x75, 0xa4, 0x27, 0x4f,
- 0xe5, 0xe1, 0xb0, 0x7b, 0x62, 0xa6, 0x08, 0x4a,
- 0x8d, 0x8f, 0x1c, 0x26, 0x33, 0xd5, 0xbf, 0xb5,
- 0x65, 0x38, 0xd1, 0xcf, 0xfe, 0xd2, 0xb5, 0xdb,
- 0xeb, 0xb5, 0x96, 0xf5, 0x3a, 0x7f, 0xd7, 0xf0,
- 0xf0, 0x1b, 0xef, 0x96, 0x3a, 0x1e, 0x88, 0xdf,
- 0x26, 0xcf, 0xb2, 0x8c, 0xf0, 0x9d, 0x3f, 0x5d,
- 0x47, 0x6c, 0xf9, 0xd3, 0xfb, 0x6b, 0x2f, 0xc3,
- 0xd4, 0x9d, 0x3f, 0xff, 0xef, 0x33, 0xbf, 0x4b,
- 0xdc, 0x1c, 0xf3, 0x6c, 0xfe, 0x6d, 0xcf, 0x3c,
- 0x5e, 0xb0, 0xa8, 0xdc, 0xe2, 0xcd, 0x0d, 0x27,
- 0xff, 0xb2, 0xf5, 0xc6, 0xac, 0xad, 0xb2, 0xd6,
- 0x53, 0xa7, 0xff, 0xff, 0xde, 0xca, 0x6b, 0xec,
- 0x0e, 0xec, 0xa5, 0xf5, 0xf5, 0xeb, 0xea, 0x76,
- 0xdb, 0x4a, 0x0e, 0x8f, 0xa3, 0x7a, 0xea, 0x13,
- 0x78, 0x27, 0x4d, 0xbc, 0x07, 0x43, 0x46, 0xb8,
- 0x02, 0xd3, 0x9f, 0xdb, 0x1d, 0x30, 0x42, 0x74,
- 0x78, 0xf5, 0x2a, 0x44, 0x11, 0xc9, 0xd7, 0xde,
- 0x02, 0x9c, 0x6b, 0xe7, 0xff, 0xff, 0x5d, 0x76,
- 0xb6, 0x9d, 0xad, 0x9d, 0xb6, 0x67, 0xf5, 0xd6,
- 0xb9, 0xf0, 0x1d, 0x14, 0xa2, 0xaf, 0xc5, 0xd3,
- 0xfd, 0x97, 0xb2, 0x8d, 0xf1, 0x0e, 0x9c, 0xa2,
- 0xd1, 0xd1, 0x89, 0xf9, 0xf4, 0x6f, 0xff, 0x24,
- 0xd4, 0x35, 0x9f, 0x7f, 0x2f, 0xcd, 0xe7, 0x4f,
- 0xfd, 0x82, 0x38, 0xd5, 0xb2, 0xbd, 0xf3, 0xa7,
- 0xf7, 0xd4, 0x74, 0x4b, 0x29, 0xd3, 0xef, 0x6b,
- 0xb7, 0x3c, 0xe9, 0xfb, 0xca, 0xca, 0x30, 0x27,
- 0x4c, 0x10, 0x9d, 0x08, 0x7d, 0x82, 0x52, 0x12,
- 0xd9, 0xfe, 0xc6, 0xb9, 0xae, 0xa5, 0xf5, 0x29,
- 0xc6, 0xb6, 0x7f, 0xf6, 0x7c, 0x19, 0x6f, 0x53,
- 0x5b, 0x69, 0x53, 0xa7, 0xef, 0xf0, 0x36, 0xcf,
- 0x9d, 0x3f, 0x33, 0xda, 0x98, 0x3a, 0xce, 0x9c,
- 0x10, 0x84, 0xa9, 0xff, 0x94, 0x7f, 0xa7, 0x6f,
- 0xc6, 0x95, 0x87, 0x38, 0xbc, 0x8d, 0x5a, 0xa2,
- 0xe6, 0xa1, 0x95, 0x54, 0xab, 0xa6, 0x68, 0x5a,
- 0x14, 0xd9, 0xdc, 0x34, 0x1e, 0x41, 0x29, 0xe7,
- 0xe5, 0x2f, 0x3c, 0x82, 0x53, 0xab, 0xed, 0x8f,
- 0x20, 0x94, 0xc1, 0x09, 0xe4, 0x12, 0x84, 0x45,
- 0x23, 0x45, 0x17, 0x2f, 0x09, 0x54, 0xdd, 0x72,
- 0xc8, 0x24, 0xe3, 0x7b, 0x3f, 0x65, 0xb3, 0x3f,
- 0xac, 0xe9, 0xdd, 0xf0, 0x7c, 0xf7, 0xee, 0x65,
- 0x3d, 0xa9, 0x9d, 0x63, 0xa5, 0x9a, 0xb3, 0xd6,
- 0x01, 0x9c, 0xfe, 0x69, 0xfa, 0x51, 0x7f, 0x50,
- 0x54, 0xfe, 0xf3, 0xf4, 0xea, 0xdb, 0xc7, 0x49,
- 0xe5, 0x4e, 0xe1, 0xa0, 0xa8, 0x2a, 0x14, 0xda,
- 0xa0, 0x83, 0x06, 0xe7, 0xbe, 0xa0, 0x42, 0x9c,
- 0x6b, 0x21, 0x51, 0x8b, 0x90, 0x95, 0x9e, 0xd3,
- 0x85, 0xe7, 0x49, 0x87, 0x4d, 0x8f, 0xd8, 0xd8,
- 0xb4, 0x43, 0x3e, 0x0e, 0x35, 0xe6, 0x1d, 0x3f,
- 0x22, 0xb4, 0xf5, 0x01, 0x52, 0xf1, 0xd3, 0xfd,
- 0x46, 0x8f, 0xda, 0xda, 0x77, 0xce, 0x9f, 0xbc,
- 0xac, 0xa3, 0x02, 0x74, 0xfb, 0x28, 0x66, 0x30,
- 0xe9, 0xd5, 0xf0, 0x9d, 0x1f, 0x3c, 0x2b, 0x93,
- 0xcf, 0xdf, 0xe0, 0x03, 0x4a, 0x9d, 0x3f, 0x7b,
- 0x5e, 0xf5, 0x63, 0xb6, 0x4c, 0x33, 0x04, 0x04,
- 0xf6, 0xad, 0xf7, 0x22, 0x8c, 0x4f, 0x47, 0xc5,
- 0x1f, 0x8c, 0xe2, 0x7b, 0xf9, 0x46, 0x87, 0x43,
- 0xd5, 0xeb, 0xe1, 0x5d, 0xa1, 0xfb, 0xf5, 0x7a,
- 0xc7, 0xff, 0x73, 0x69, 0xff, 0xf5, 0x02, 0x39,
- 0xb7, 0x32, 0xdd, 0x7f, 0xab, 0x47, 0x4e, 0x08,
- 0x42, 0x54, 0xcf, 0x52, 0x9c, 0x5e, 0x42, 0xa2,
- 0x54, 0x5c, 0x67, 0xea, 0x1a, 0x7b, 0x70, 0x68,
- 0x3a, 0x7a, 0xdd, 0x48, 0x4e, 0x9f, 0x50, 0x3e,
- 0x56, 0x1d, 0x3f, 0xfc, 0xbb, 0xef, 0xf5, 0x07,
- 0x5c, 0x1b, 0xfe, 0xf3, 0xa3, 0x55, 0x23, 0x43,
- 0xc6, 0x9c, 0x45, 0x72, 0x79, 0xcf, 0xf7, 0xce,
- 0x9f, 0xae, 0xad, 0x7f, 0x4a, 0x9d, 0x0f, 0x3c,
- 0xbb, 0x8e, 0x4e, 0xd3, 0x46, 0xec, 0xe9, 0xb9,
- 0xcd, 0xd1, 0xb9, 0x08, 0xd5, 0x63, 0x6d, 0x57,
- 0xe4, 0x4b, 0x28, 0xaa, 0x88, 0x7f, 0xbc, 0x87,
- 0x68, 0xc3, 0xb2, 0x57, 0xc6, 0xb6, 0x64, 0x17,
- 0xf4, 0x24, 0x9a, 0x86, 0x18, 0x91, 0xb2, 0x30,
- 0x2b, 0x4b, 0x00, 0xe4, 0x5f, 0x94, 0xd6, 0x53,
- 0x7d, 0xe7, 0x74, 0x74, 0x87, 0xc6, 0xa4, 0x3c,
- 0x77, 0xc2, 0x35, 0xbc, 0x8a, 0x7f, 0xf3, 0x99,
- 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x8a, 0x9f,
- 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x5d, 0x13, 0xff,
- 0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x97,
- 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xbc, 0xa1,
- 0x5b, 0xe1, 0xaa, 0x09, 0xde, 0x77, 0x87, 0x68,
- 0xa4, 0xd1, 0xdb, 0x0e, 0xed, 0x0c, 0x5f, 0xd7,
- 0x25, 0x55, 0x8e, 0xca, 0xea, 0x5a, 0x1d, 0xb6,
- 0x4c, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d,
- 0xc8, 0x68, 0x96, 0x67, 0x93, 0xb9, 0x0d, 0x11,
- 0x9c, 0xfd, 0xe5, 0x65, 0x18, 0x13, 0xa6, 0xfb,
- 0xce, 0x93, 0x0e, 0x9f, 0x78, 0x6d, 0xce, 0x13,
- 0xd3, 0x61, 0x6e, 0xf1, 0x69, 0xfb, 0x9f, 0xe1,
- 0xe1, 0x3a, 0x75, 0x56, 0x93, 0xa0, 0x53, 0x10,
- 0x63, 0xf7, 0xd3, 0x2e, 0x55, 0x3f, 0xf5, 0xfc,
- 0x3c, 0x0d, 0xd4, 0xbd, 0x58, 0x74, 0xfb, 0xea,
- 0xfa, 0xf1, 0xd1, 0xe3, 0xec, 0x6c, 0x8d, 0x3f,
- 0xff, 0x7b, 0x6d, 0x2f, 0x5a, 0x5e, 0xbf, 0x05,
- 0x77, 0x69, 0xf3, 0xa7, 0xfe, 0xc6, 0x5f, 0xc1,
- 0xaa, 0xdb, 0xb5, 0x67, 0x4f, 0xfa, 0xcb, 0xeb,
- 0x79, 0x7e, 0xd6, 0x87, 0x49, 0xd8, 0x9d, 0xbb,
- 0x50, 0xa9, 0xe2, 0x4f, 0xb1, 0xd5, 0x1e, 0x7f,
- 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
- 0x69, 0x9f, 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d,
- 0xc8, 0x68, 0x9c, 0x67, 0xff, 0x39, 0x9c, 0xf7,
- 0x60, 0xa7, 0x72, 0x1a, 0x28, 0x19, 0xf0, 0xa7,
- 0x72, 0x1a, 0x2e, 0x09, 0x97, 0xc7, 0x4f, 0xef,
- 0xbd, 0x7d, 0xb6, 0x30, 0xe9, 0x3b, 0x0f, 0xe2,
- 0xc6, 0x1a, 0x0a, 0xcf, 0xef, 0x3b, 0x7a, 0x83,
- 0x02, 0x74, 0xff, 0x3d, 0xd8, 0x29, 0xdc, 0x86,
- 0x89, 0x26, 0x4e, 0xb1, 0xfa, 0xf1, 0xa4, 0x50,
- 0xbb, 0x5a, 0xf9, 0x63, 0x28, 0xaa, 0xd2, 0x90,
- 0x14, 0xab, 0x0c, 0xab, 0xc2, 0xaa, 0x7f, 0xda,
- 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x52, 0x7f,
- 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x25, 0x58,
- 0x3a, 0x4e, 0xd6, 0x89, 0x86, 0x24, 0x37, 0xa3,
- 0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x22, 0x99,
- 0xfc, 0xec, 0x14, 0xee, 0x43, 0x44, 0x69, 0x3f,
- 0x9d, 0x82, 0x9d, 0xc8, 0x68, 0xa7, 0xe7, 0xff,
- 0x39, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x26,
- 0xa9, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45, 0x77,
- 0x3c, 0x9d, 0xc8, 0x68, 0xaf, 0xa7, 0x04, 0x21,
- 0x2a, 0x5f, 0x29, 0xc5, 0xe4, 0x09, 0xf3, 0x31,
- 0x1e, 0x73, 0xd6, 0x93, 0xa7, 0xfd, 0x96, 0x0f,
- 0x5e, 0xab, 0x94, 0x1d, 0x3f, 0xee, 0xf0, 0xe5,
- 0x1e, 0x7e, 0x6c, 0x74, 0x9d, 0x88, 0xb8, 0x68,
- 0x87, 0xe3, 0x95, 0x3d, 0x9f, 0xfc, 0xe6, 0x73,
- 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9e, 0xe7, 0xf3,
- 0xb0, 0x53, 0xb9, 0x0d, 0x17, 0x0c, 0xff, 0xce,
- 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x27, 0xc2,
- 0xab, 0xb3, 0xa0, 0xed, 0xe7, 0x7a, 0xce, 0xd0,
- 0xed, 0xa5, 0x21, 0x8d, 0x66, 0xc8, 0x75, 0x52,
- 0x6c, 0x77, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
- 0x8a, 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x14,
- 0xcc, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee,
- 0x43, 0x44, 0xcf, 0x3f, 0xf9, 0xcc, 0xe7, 0xbb,
- 0x05, 0x3b, 0x90, 0xd1, 0x46, 0xc5, 0x09, 0x8d,
- 0x6c, 0x77, 0xac, 0xee, 0xea, 0x53, 0xff, 0x3b,
- 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x75, 0x3f,
- 0x7b, 0x3f, 0xb6, 0x50, 0x74, 0xf8, 0x53, 0xb9,
- 0x0d, 0x14, 0xd4, 0xfd, 0xe5, 0x65, 0x18, 0x13,
- 0xa7, 0xff, 0xb2, 0xf6, 0xc7, 0x8f, 0x7e, 0xf6,
- 0xe7, 0x9d, 0x32, 0x80, 0xe9, 0xfe, 0xaf, 0x52,
- 0xa9, 0xe4, 0x70, 0xa2, 0x3f, 0xe5, 0xbb, 0xd3,
- 0x64, 0xed, 0x93, 0x4b, 0xc2, 0xeb, 0xc2, 0xfe,
- 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xaa, 0x7f, 0xdc,
- 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x26, 0xd9, 0x3b,
- 0x0f, 0xd9, 0x86, 0x13, 0xf9, 0xd8, 0x29, 0xdc,
- 0x86, 0x8a, 0xfe, 0x7f, 0x3b, 0x05, 0x3b, 0x90,
- 0xd1, 0x63, 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x6a,
- 0xcf, 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x45,
- 0x05, 0x27, 0x61, 0xfb, 0x30, 0xc2, 0x7f, 0x3b,
- 0x05, 0x3b, 0x90, 0xd1, 0x71, 0x4f, 0xe7, 0x60,
- 0xa7, 0x72, 0x1a, 0x2e, 0x99, 0xff, 0xfc, 0xb6,
- 0xfe, 0x9d, 0xab, 0xc7, 0xdb, 0x35, 0xe6, 0xcd,
- 0x68, 0x74, 0xff, 0x9f, 0x82, 0x3c, 0xfa, 0x30,
- 0x27, 0x4e, 0xff, 0x38, 0x51, 0x4b, 0x76, 0x99,
- 0xff, 0x0a, 0xd3, 0x6e, 0xad, 0xd4, 0x27, 0x4f,
- 0xda, 0xa7, 0xf2, 0xdd, 0x73, 0xa7, 0xe0, 0x73,
- 0x4f, 0xf5, 0xce, 0x9f, 0xff, 0xf6, 0xb5, 0xda,
- 0xd9, 0x4d, 0xff, 0xd6, 0x07, 0x56, 0xbc, 0x28,
- 0x74, 0xf2, 0x77, 0x21, 0xa2, 0x4c, 0x9f, 0xe1,
- 0xca, 0x6f, 0x7e, 0x7d, 0x4e, 0x81, 0x3e, 0x36,
- 0x15, 0xcf, 0xdb, 0x03, 0x54, 0xa8, 0x35, 0x0e,
- 0x9f, 0x65, 0xfc, 0xce, 0x3a, 0x7f, 0xfd, 0xc8,
- 0x2b, 0x6f, 0xe5, 0xf1, 0xc1, 0x08, 0x4a, 0x87,
- 0x9f, 0xc5, 0xc9, 0xa7, 0xff, 0x69, 0xfe, 0xba,
- 0x8d, 0x6c, 0xbf, 0xb9, 0xd3, 0x82, 0x10, 0x95,
- 0x3f, 0x0f, 0x50, 0xcf, 0x54, 0xa7, 0x17, 0x93,
- 0xec, 0x60, 0xe6, 0xac, 0xe9, 0xff, 0x31, 0x52,
- 0xdf, 0xd2, 0xeb, 0x53, 0xa7, 0xfb, 0x38, 0x1b,
- 0xb3, 0x6e, 0x79, 0xd3, 0xff, 0xba, 0x8b, 0x79,
- 0x7f, 0x8d, 0x78, 0x7c, 0x74, 0x62, 0x30, 0x6e,
- 0x7c, 0x13, 0x99, 0xf7, 0xf2, 0xdd, 0x73, 0xa7,
- 0xfc, 0xf5, 0xfd, 0x1b, 0xc7, 0xfa, 0x3c, 0xe8,
- 0xd5, 0x9f, 0x43, 0x44, 0xd3, 0xd7, 0xa3, 0x36,
- 0x3a, 0x7f, 0xbd, 0xaf, 0x78, 0x81, 0x9e, 0xa9,
- 0xd0, 0xd1, 0xf0, 0x6a, 0x11, 0xce, 0x08, 0x42,
- 0x74, 0xff, 0xfb, 0x19, 0x7f, 0xa8, 0x33, 0x6a,
- 0xe3, 0x15, 0x0a, 0x71, 0x79, 0x18, 0x99, 0x5f,
- 0xa1, 0x0f, 0x64, 0x29, 0xfa, 0xcb, 0xb9, 0x3d,
- 0x41, 0xd3, 0xf0, 0xf0, 0xfd, 0x5e, 0x74, 0x6c,
- 0x7b, 0x22, 0x5f, 0x33, 0xdc, 0xdc, 0x5e, 0x1e,
- 0x53, 0x17, 0x97, 0x64, 0x34, 0x35, 0x90, 0xd3,
- 0x0a, 0xf6, 0x88, 0xb9, 0x97, 0xe7, 0x95, 0x87,
- 0x55, 0xe3, 0xc2, 0xdf, 0x08, 0xe9, 0xf6, 0x30,
- 0x73, 0x56, 0x74, 0xff, 0xd9, 0x6f, 0xad, 0x1b,
- 0xed, 0x6e, 0xd5, 0x9d, 0x3f, 0x72, 0x38, 0x21,
- 0x09, 0xd2, 0x72, 0x32, 0x00, 0x84, 0xcf, 0xa7,
- 0x96, 0xff, 0x0d, 0x5a, 0x94, 0xb6, 0x4a, 0x87,
- 0xb3, 0x43, 0x76, 0x8e, 0x5e, 0x98, 0x59, 0x09,
- 0x3b, 0x0e, 0xc1, 0x0b, 0x1a, 0x93, 0xdc, 0xef,
- 0x4a, 0x47, 0x14, 0xfe, 0x76, 0x0a, 0x77, 0x21,
- 0xa2, 0x35, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0xa5,
- 0x9b, 0x90, 0xd1, 0x0d, 0x49, 0xd8, 0x7a, 0x3c,
- 0x61, 0x3f, 0xf3, 0xb9, 0xee, 0xc1, 0x4e, 0xe4,
- 0x34, 0x47, 0xd3, 0xf9, 0xd8, 0x29, 0xdc, 0x86,
- 0x8b, 0x1e, 0x7e, 0xd5, 0x3f, 0x96, 0xeb, 0x9d,
- 0x3f, 0xdf, 0xe0, 0x57, 0xaf, 0x7e, 0x3a, 0x78,
- 0x0c, 0xf0, 0x9d, 0x3f, 0xff, 0xca, 0x3f, 0xcd,
- 0xb2, 0xd6, 0xf2, 0x5b, 0xd7, 0xaf, 0x52, 0x74,
- 0x79, 0x10, 0xf6, 0x21, 0x9d, 0xdc, 0x86, 0x8b,
- 0x42, 0x7f, 0xdc, 0x16, 0xf4, 0xe1, 0xa3, 0x02,
- 0x74, 0x85, 0x0f, 0x94, 0x49, 0xa7, 0xe6, 0xdb,
- 0xef, 0xf5, 0x01, 0xd3, 0xe5, 0xbe, 0x59, 0x4e,
- 0x9f, 0xfe, 0xcb, 0xd7, 0x1a, 0xb2, 0xb6, 0xcb,
- 0x59, 0x4e, 0x8a, 0x0f, 0xd7, 0xe4, 0xb0, 0xa8,
- 0xc9, 0xc8, 0x53, 0x4f, 0xfd, 0x95, 0xf6, 0x9f,
- 0x78, 0xae, 0x6c, 0x74, 0xfa, 0xf6, 0xef, 0xeb,
- 0x3a, 0x7f, 0xbf, 0xa5, 0x1b, 0x5b, 0x3e, 0xa7,
- 0x4d, 0xfc, 0xc3, 0xe4, 0x42, 0x99, 0xfd, 0x96,
- 0x6b, 0xd6, 0xf3, 0x0e, 0x9f, 0xcf, 0xc1, 0xaf,
- 0xd6, 0x83, 0xa7, 0xb6, 0xcb, 0x71, 0xd3, 0xfd,
- 0x98, 0x1c, 0x44, 0xc0, 0x9d, 0x18, 0x8b, 0xba,
- 0x4d, 0x38, 0xca, 0xa4, 0x33, 0xd9, 0x6e, 0xb9,
- 0xd3, 0xfb, 0x5f, 0xbf, 0xa3, 0xf2, 0xa7, 0x49,
- 0xcd, 0xc5, 0xca, 0xb5, 0x31, 0xda, 0x17, 0xd9,
- 0x08, 0x8b, 0x43, 0xbb, 0xe4, 0xd5, 0x85, 0x45,
- 0xe1, 0xcd, 0xa8, 0x79, 0xbc, 0x82, 0x7e, 0x6f,
- 0xf6, 0xdf, 0x56, 0x8e, 0x9e, 0xcb, 0x75, 0xce,
- 0x96, 0xa9, 0x87, 0xa5, 0xf3, 0x29, 0xf0, 0xa7,
- 0x72, 0x1a, 0x2d, 0x69, 0xff, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0xa0, 0xe4, 0xe6, 0xe2, 0x28,
- 0xb0, 0xb1, 0x86, 0x13, 0xff, 0x9c, 0xce, 0x7b,
- 0xb0, 0x53, 0xb9, 0x0d, 0x14, 0x5c, 0xfe, 0x76,
- 0x0a, 0x77, 0x21, 0xa2, 0xea, 0x87, 0xb2, 0x14,
- 0xd2, 0x11, 0x9e, 0x26, 0x62, 0x65, 0xa7, 0x39,
- 0x81, 0x1d, 0x4d, 0x4e, 0x6e, 0xa5, 0x3e, 0x14,
- 0xee, 0x43, 0x44, 0x43, 0x3a, 0xd9, 0xb1, 0xd2,
- 0x76, 0x1e, 0x65, 0x26, 0x13, 0xf9, 0xd8, 0x29,
- 0xdc, 0x86, 0x88, 0xda, 0x7f, 0x3b, 0x05, 0x3b,
- 0x90, 0xd1, 0x4d, 0xcf, 0xe7, 0x60, 0xa7, 0x72,
- 0x1a, 0x2a, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43,
- 0x45, 0x4d, 0x3e, 0x14, 0xee, 0x43, 0x45, 0x61,
- 0x3e, 0xf0, 0x76, 0xd0, 0x4e, 0x9f, 0xe7, 0xbb,
- 0x05, 0x3b, 0x90, 0xd1, 0x1f, 0xce, 0xc5, 0xa0,
- 0xe9, 0x3b, 0x11, 0x6a, 0x86, 0x1c, 0x53, 0xf4,
- 0x19, 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc,
- 0x86, 0x89, 0xbe, 0x7f, 0xe6, 0x73, 0xdd, 0x82,
- 0x9d, 0xc8, 0x68, 0x9f, 0xa7, 0xe6, 0xeb, 0xaa,
- 0xb5, 0x4d, 0x4c, 0xa4, 0xe9, 0xff, 0xe5, 0x55,
- 0x55, 0x55, 0x55, 0x5a, 0x6a, 0x74, 0xf8, 0x7d,
- 0x47, 0x30, 0xa9, 0x82, 0x12, 0xa3, 0x0d, 0xe8,
- 0x49, 0xe5, 0xa1, 0x4e, 0x34, 0x10, 0xa8, 0xc7,
- 0xac, 0x29, 0xa7, 0xe1, 0xe4, 0xb7, 0x84, 0xe9,
- 0xea, 0x19, 0xe7, 0x9d, 0x3e, 0xaf, 0xf4, 0xe7,
- 0x9d, 0x3f, 0xac, 0xac, 0x70, 0x00, 0xa7, 0x48,
- 0x54, 0xff, 0x70, 0x8f, 0xc5, 0x13, 0x81, 0x5c,
- 0x3a, 0x7f, 0xed, 0x96, 0xfd, 0x5c, 0xb5, 0xbc,
- 0xc3, 0xa7, 0x5f, 0xcd, 0x1d, 0x0a, 0x7c, 0x35,
- 0x44, 0x85, 0x4e, 0x77, 0xc4, 0xe3, 0x0a, 0x7f,
- 0x99, 0x5d, 0xf2, 0x7b, 0x9a, 0xde, 0xc3, 0xa6,
- 0xef, 0x9d, 0x02, 0x6e, 0x58, 0x49, 0x38, 0x21,
- 0x09, 0xd3, 0xd4, 0x7f, 0xca, 0x53, 0x8b, 0xc9,
- 0xea, 0x6f, 0xe4, 0x3a, 0x15, 0x11, 0xf6, 0x3c,
- 0xd0, 0xc6, 0x7f, 0xea, 0x34, 0x06, 0x7f, 0x46,
- 0x96, 0xfc, 0x74, 0xf2, 0xde, 0xa8, 0x68, 0x83,
- 0xa7, 0xee, 0xb2, 0xea, 0xf4, 0x79, 0xd0, 0x28,
- 0xa5, 0xba, 0x3b, 0x62, 0xd9, 0x87, 0x63, 0xa6,
- 0x08, 0x4e, 0x87, 0x9a, 0xc0, 0x8b, 0x4f, 0x55,
- 0x7c, 0xd8, 0xa7, 0x1a, 0x19, 0xf5, 0x77, 0xec,
- 0x0a, 0x9d, 0x1e, 0x3d, 0xed, 0xe6, 0x73, 0x82,
- 0x10, 0x95, 0x05, 0x38, 0xbc, 0x9e, 0xf0, 0x7c,
- 0xd1, 0x50, 0x86, 0xf3, 0xc3, 0x31, 0xe4, 0xde,
- 0x2d, 0x0d, 0xcf, 0xbe, 0x4e, 0xff, 0xaa, 0x74,
- 0xf6, 0xdd, 0xf0, 0x1d, 0x3f, 0xf2, 0xfc, 0x1f,
- 0x5a, 0x5a, 0x5f, 0x80, 0xe8, 0xf2, 0x20, 0xc0,
- 0x39, 0x52, 0x29, 0xf9, 0xa5, 0xc1, 0xb7, 0x8e,
- 0x9f, 0xaf, 0x8d, 0x7d, 0x58, 0x78, 0x80, 0xa7,
- 0xdd, 0xfd, 0xac, 0xa6, 0x88, 0x09, 0xc6, 0xea,
- 0x7c, 0xa0, 0xf5, 0x35, 0x3a, 0x7f, 0x0b, 0x55,
- 0xf7, 0xef, 0xe3, 0xa7, 0xa9, 0x00, 0xa9, 0x53,
- 0x04, 0x25, 0x42, 0x9b, 0x70, 0x90, 0xcf, 0xdc,
- 0x2f, 0x7f, 0xfc, 0x53, 0x8d, 0x04, 0x2a, 0x79,
- 0x38, 0x61, 0xe6, 0x6f, 0xa2, 0x5c, 0xa3, 0x48,
- 0x45, 0xcf, 0xb4, 0xbe, 0x9d, 0xbc, 0xd1, 0x03,
- 0xcf, 0xfa, 0xda, 0x50, 0xbb, 0x96, 0xeb, 0xb1,
- 0xd3, 0xb8, 0x68, 0x3a, 0x60, 0x84, 0xe9, 0xfc,
- 0x3e, 0xc6, 0xdb, 0xde, 0xe4, 0x36, 0x21, 0x1b,
- 0x8d, 0x91, 0x7e, 0x2e, 0x73, 0xff, 0x7f, 0x35,
- 0xdb, 0x9f, 0xbf, 0xa9, 0x53, 0xa1, 0x4f, 0xab,
- 0x08, 0xe7, 0xff, 0x63, 0x19, 0xcf, 0xc1, 0x4e,
- 0xe4, 0x34, 0x43, 0x11, 0x63, 0xf1, 0xf9, 0x04,
- 0xfd, 0x82, 0x9d, 0xc8, 0x68, 0x82, 0xa7, 0xaf,
- 0x55, 0x01, 0x53, 0xb8, 0x68, 0x2a, 0x7b, 0x4f,
- 0xf6, 0xb2, 0xa7, 0xf7, 0xa8, 0xcb, 0xd5, 0x40,
- 0x54, 0x15, 0x3f, 0x62, 0x2d, 0x95, 0x85, 0x4c,
- 0x10, 0x95, 0x3f, 0x7d, 0x7f, 0x47, 0x84, 0xa8,
- 0xc4, 0xc2, 0x90, 0x85, 0x83, 0x76, 0x24, 0x01,
- 0x9f, 0xc2, 0x82, 0x55, 0xbc, 0x5a, 0x6f, 0x09,
- 0x4e, 0x3f, 0x29, 0x73, 0xd3, 0xd7, 0xb4, 0x76,
- 0x33, 0xfe, 0x57, 0xf7, 0xf2, 0xa2, 0xb5, 0x3a,
- 0x7f, 0xaf, 0x65, 0x6d, 0xb2, 0x81, 0x4e, 0x9f,
- 0xe5, 0xa5, 0xfa, 0x8a, 0x98, 0xc3, 0xa1, 0x4f,
- 0xd2, 0xc7, 0x53, 0xff, 0xf3, 0x5d, 0xcf, 0xeb,
- 0x6e, 0xca, 0x34, 0xbe, 0x9d, 0xbc, 0xd1, 0x7d,
- 0xcf, 0xbd, 0x7f, 0xe3, 0xce, 0x9f, 0xf7, 0xfc,
- 0xfb, 0xdb, 0x07, 0xd5, 0x3a, 0x7f, 0x5c, 0x1b,
- 0xfe, 0xfb, 0x61, 0xe2, 0x01, 0x9d, 0xc2, 0xf3,
- 0xc4, 0x03, 0x18, 0x7d, 0x3a, 0x21, 0x4d, 0xcf,
- 0x3c, 0x40, 0x33, 0xdd, 0xfa, 0x5e, 0x78, 0x80,
- 0x67, 0xf7, 0x92, 0xd8, 0x00, 0x29, 0xe2, 0x01,
- 0x9d, 0xef, 0xec, 0x78, 0x80, 0x63, 0x64, 0x5c,
- 0xb0, 0x8a, 0xc5, 0xed, 0x8f, 0xa7, 0x0a, 0xdc,
- 0xf1, 0x00, 0xc1, 0xe2, 0x01, 0x99, 0x58, 0x78,
- 0x80, 0x63, 0x63, 0x73, 0xe1, 0x79, 0xef, 0x33,
- 0x65, 0x3c, 0x40, 0x33, 0xaf, 0xc8, 0x78, 0x80,
- 0x67, 0xfd, 0xfe, 0x7b, 0xad, 0xe4, 0xe1, 0x3c,
- 0x40, 0x33, 0x76, 0xc7, 0x88, 0x06, 0x7f, 0x7f,
- 0x83, 0x5a, 0xa8, 0x0f, 0x10, 0x0c, 0xfb, 0xda,
- 0xfb, 0xe0, 0x3c, 0x40, 0x33, 0x7a, 0xa7, 0x88,
- 0x06, 0x04, 0xf6, 0x6e, 0x6d, 0x3e, 0xbf, 0xd6,
- 0x97, 0x9a, 0x20, 0x19, 0x80, 0xa7, 0x88, 0x05,
- 0xc6, 0xd6, 0x7d, 0xe5, 0x67, 0x6c, 0x78, 0x80,
- 0x67, 0xb4, 0xef, 0xa1, 0xe2, 0x01, 0x9c, 0xa2,
- 0x87, 0x88, 0x06, 0x7f, 0xd9, 0x4d, 0x76, 0x5c,
- 0xf8, 0x2a, 0x78, 0x80, 0x67, 0xda, 0x73, 0xde,
- 0xa7, 0x88, 0x06, 0x31, 0x10, 0x16, 0x4c, 0x98,
- 0x40, 0x78, 0x80, 0x61, 0xea, 0xa3, 0xf6, 0x23,
- 0xc8, 0x4c, 0x79, 0x5a, 0xc6, 0x40, 0x34, 0xa9,
- 0x75, 0xe1, 0x4d, 0xa1, 0x14, 0xfb, 0x2f, 0x5e,
- 0xa4, 0xf1, 0x00, 0xcf, 0xed, 0x95, 0x1a, 0x15,
- 0xb9, 0xe2, 0x01, 0xd8, 0xda, 0x4e, 0x15, 0x09,
- 0xe2, 0x01, 0x84, 0x3f, 0x71, 0x50, 0x9e, 0xf7,
- 0xdf, 0x53, 0xc4, 0x03, 0x3f, 0x73, 0x4f, 0xca,
- 0x5e, 0x78, 0x80, 0x63, 0x11, 0x14, 0x02, 0x0d,
- 0x0b, 0xe7, 0xfa, 0xcb, 0x57, 0x57, 0x41, 0x01,
- 0xe2, 0x01, 0x97, 0x8f, 0x10, 0x0c, 0xdd, 0x46,
- 0xc7, 0xc7, 0x64, 0x69, 0x84, 0x07, 0x88, 0x06,
- 0x7d, 0xd7, 0xaf, 0xa9, 0x3c, 0x40, 0x33, 0xf7,
- 0xbf, 0xa3, 0xf2, 0xa7, 0x88, 0x06, 0x15, 0x12,
- 0x5f, 0x22, 0xb9, 0xac, 0x6c, 0xc8, 0x0e, 0xc8,
- 0x6d, 0xb4, 0x80, 0x2c, 0x16, 0x22, 0xe2, 0xf0,
- 0x13, 0xd6, 0x56, 0xc5, 0xe3, 0xc0, 0xd4, 0x84,
- 0x9e, 0xf8, 0x60, 0xce, 0xee, 0x43, 0x44, 0x02,
- 0xe4, 0x5e, 0x4f, 0x6b, 0xd5, 0x6d, 0x98, 0x74,
- 0xc0, 0x52, 0xa5, 0xac, 0xa9, 0xd6, 0x5a, 0x0e,
- 0x98, 0x21, 0x2a, 0x3c, 0x7b, 0x3a, 0xb1, 0x56,
- 0x84, 0x82, 0x39, 0x39, 0x9e, 0xa9, 0x4e, 0x3c,
- 0x19, 0xeb, 0xd5, 0xbf, 0x43, 0xa2, 0x86, 0x57,
- 0x4b, 0xc9, 0xd2, 0x92, 0xe3, 0xe3, 0x80, 0x43,
- 0x1b, 0x79, 0x6c, 0xfc, 0x2d, 0x3d, 0x46, 0x83,
- 0xa7, 0xfc, 0xfa, 0xee, 0xfe, 0x31, 0x47, 0x59,
- 0xd3, 0xff, 0x0d, 0xbb, 0x1e, 0xa2, 0x0d, 0xec,
- 0x3a, 0x7e, 0xde, 0x11, 0xf6, 0x58, 0xa9, 0xe6,
- 0xad, 0xcd, 0x1d, 0x3e, 0xc6, 0x9e, 0xb4, 0x9d,
- 0x3d, 0x9f, 0x57, 0x95, 0x02, 0x7d, 0x7f, 0x23,
- 0x6f, 0x28, 0x85, 0x4d, 0xef, 0x0b, 0x7c, 0x83,
- 0x64, 0x3e, 0x84, 0xcc, 0xf7, 0xbf, 0x7a, 0x9d,
- 0x3b, 0x46, 0xee, 0xa7, 0x4f, 0xfc, 0x06, 0x62,
- 0x5b, 0xdb, 0x5b, 0x4d, 0x67, 0x4f, 0xfd, 0x7a,
- 0xe6, 0xcb, 0x4d, 0x72, 0x9b, 0x9d, 0x3f, 0x9f,
- 0x95, 0xdf, 0x5b, 0xe1, 0xd0, 0xa8, 0xe4, 0xf1,
- 0x17, 0x24, 0x68, 0x8d, 0x3e, 0xe6, 0xdb, 0x6c,
- 0xa7, 0x4d, 0x5a, 0x9d, 0x38, 0x21, 0x09, 0xd3,
- 0x03, 0x8a, 0x71, 0x79, 0x02, 0x7a, 0xd5, 0x32,
- 0x9d, 0xc0, 0xc2, 0xa1, 0xe8, 0xbb, 0x64, 0x20,
- 0x35, 0x08, 0x67, 0xf5, 0xff, 0x94, 0x83, 0x7b,
- 0xce, 0x9f, 0xef, 0xe3, 0x6c, 0x70, 0x42, 0x12,
- 0xa7, 0x33, 0xae, 0x74, 0x58, 0xf5, 0x5b, 0x1d,
- 0x42, 0xa3, 0x9f, 0xc7, 0x1d, 0x08, 0xb9, 0xad,
- 0xc7, 0x4c, 0xd5, 0x4e, 0x9f, 0x9d, 0x8d, 0xbd,
- 0xfd, 0xb0, 0xd6, 0x6f, 0x15, 0x9e, 0xdb, 0x2d,
- 0xc7, 0x4f, 0xfc, 0xb9, 0xf7, 0xdb, 0x3f, 0xf5,
- 0x09, 0xd2, 0xf0, 0xa2, 0xaf, 0xe9, 0x17, 0x21,
- 0x8a, 0x1b, 0x67, 0x77, 0xc7, 0xa5, 0xb4, 0x7f,
- 0x3a, 0xcb, 0xd2, 0x15, 0xfe, 0x21, 0x1a, 0x5a,
- 0xbd, 0xa3, 0xe6, 0x02, 0x6f, 0xe3, 0x06, 0xbc,
- 0x7b, 0xcd, 0xa3, 0x0a, 0x9f, 0xec, 0x1f, 0xad,
- 0xdf, 0x96, 0x3a, 0x7e, 0xf8, 0x33, 0x6e, 0x79,
- 0xd3, 0xed, 0xed, 0x3d, 0x75, 0x65, 0x42, 0xa2,
- 0x47, 0x0d, 0xb7, 0x96, 0xcf, 0xfe, 0x1d, 0x7f,
- 0xd3, 0xb7, 0xe5, 0x7c, 0xbf, 0x3a, 0x5b, 0xcd,
- 0x10, 0x2c, 0xae, 0x6a, 0x05, 0x25, 0xeb, 0x9b,
- 0xc0, 0x8f, 0xcf, 0xfb, 0xda, 0x96, 0xf6, 0xf7,
- 0x00, 0x0a, 0x54, 0xff, 0xeb, 0xd7, 0xa9, 0xdc,
- 0xc5, 0xcf, 0xdf, 0x50, 0xe8, 0x54, 0x49, 0xf9,
- 0x12, 0x75, 0x1f, 0x79, 0xd0, 0xa9, 0xc1, 0x32,
- 0x11, 0x36, 0x85, 0xd6, 0x84, 0x53, 0xf9, 0xed,
- 0x67, 0xfa, 0xd8, 0x74, 0xff, 0xe1, 0x4f, 0xe3,
- 0x6f, 0xe2, 0x8a, 0xd4, 0xe9, 0xfd, 0xcd, 0x5b,
- 0x19, 0x95, 0x3a, 0x30, 0xfe, 0x5b, 0x23, 0xcf,
- 0xde, 0xd7, 0x7c, 0xc6, 0x1d, 0x3e, 0xcd, 0xbc,
- 0x35, 0x3a, 0x7f, 0xfa, 0xb7, 0xa5, 0x3d, 0x6d,
- 0xcd, 0xf9, 0x6f, 0x30, 0xe9, 0x2d, 0x07, 0xfa,
- 0x12, 0x78, 0xf2, 0x3d, 0xac, 0x47, 0x78, 0x55,
- 0xce, 0xdb, 0x84, 0xe9, 0xf0, 0x3b, 0xf8, 0xde,
- 0x74, 0x29, 0xe2, 0x68, 0x37, 0x3c, 0xac, 0xa5,
- 0xa3, 0xa1, 0x55, 0x2f, 0xbe, 0x3a, 0x1a, 0xbc,
- 0xdc, 0x8a, 0x78, 0x1d, 0x4d, 0x4e, 0x98, 0x21,
- 0x3a, 0x2a, 0x6e, 0x02, 0x45, 0x3f, 0x57, 0xd6,
- 0xec, 0xb1, 0x4e, 0x34, 0x33, 0x82, 0x10, 0x95,
- 0x3c, 0xfb, 0xe2, 0x14, 0xe2, 0xf2, 0x7d, 0x9b,
- 0x78, 0x15, 0x3a, 0x5c, 0x27, 0xaf, 0xf2, 0xf9,
- 0xfb, 0xf4, 0xd5, 0xac, 0xb9, 0xd3, 0xea, 0x35,
- 0x7e, 0xca, 0x4e, 0x9f, 0x7a, 0xab, 0x43, 0x0f,
- 0x97, 0xec, 0xf9, 0x78, 0x41, 0xa1, 0xf2, 0xfd,
- 0x9b, 0x9e, 0x7c, 0xbf, 0x67, 0xb4, 0x7e, 0x54,
- 0xf9, 0x7e, 0xc6, 0xc7, 0xa3, 0xf2, 0x29, 0xf2,
- 0xe5, 0x73, 0xe7, 0xcb, 0xf6, 0x0f, 0x97, 0xec,
- 0xdd, 0x73, 0xe5, 0xfa, 0xc2, 0xde, 0x4f, 0xf9,
- 0xfd, 0x68, 0x93, 0x3d, 0x9a, 0x9e, 0x01, 0xf2,
- 0xfd, 0x83, 0xe5, 0xfb, 0x30, 0x14, 0xf9, 0x7e,
- 0xcf, 0xf6, 0x03, 0x87, 0x1b, 0x66, 0xc7, 0xcb,
- 0xf6, 0x7e, 0xcb, 0x7a, 0xba, 0x50, 0x7c, 0xbf,
- 0x60, 0x08, 0xa3, 0xf9, 0x15, 0x51, 0x67, 0x86,
- 0x85, 0xb9, 0xf2, 0xfd, 0x83, 0xe5, 0xfb, 0x86,
- 0xba, 0x60, 0x84, 0xf9, 0x7e, 0xc3, 0xd5, 0x88,
- 0xec, 0x6b, 0x90, 0x84, 0xa6, 0x13, 0xa2, 0x52,
- 0xc3, 0x1a, 0xc2, 0xea, 0xeb, 0xc1, 0x26, 0x9e,
- 0xc7, 0xae, 0xb2, 0xe5, 0xfa, 0xe4, 0x47, 0xcf,
- 0xfb, 0x13, 0x6c, 0x10, 0xf5, 0x9a, 0x3a, 0x67,
- 0xd0, 0x54, 0x50, 0x89, 0x5a, 0x50, 0x7e, 0x7b,
- 0x02, 0xb9, 0x29, 0xd3, 0x8c, 0x53, 0xff, 0xf5,
- 0x2f, 0x15, 0x6d, 0xcd, 0x2e, 0xd6, 0x56, 0x73,
- 0x47, 0x42, 0xae, 0xb9, 0xe1, 0x37, 0x4e, 0x61,
- 0xe8, 0x59, 0x3f, 0xed, 0x6b, 0x4f, 0xd6, 0xd6,
- 0xd1, 0x0e, 0x9f, 0xbf, 0xda, 0xed, 0xcf, 0x3a,
- 0x70, 0x42, 0x12, 0xa7, 0x6f, 0x50, 0x14, 0xe2,
- 0xf2, 0x7f, 0xdf, 0xe7, 0xef, 0x1c, 0x6d, 0xc2,
- 0x74, 0xff, 0x7f, 0x81, 0xb9, 0xea, 0x0a, 0x4e,
- 0x8d, 0x93, 0x31, 0x62, 0x08, 0x12, 0xbe, 0x59,
- 0x73, 0xf9, 0xff, 0x7f, 0xfe, 0xd1, 0xbb, 0xae,
- 0xa2, 0xdc, 0xe9, 0xc1, 0x08, 0x4b, 0x10, 0x84,
- 0xf8, 0x53, 0xb9, 0x0b, 0x10, 0x83, 0x8d, 0x4c,
- 0xe0, 0x84, 0x25, 0x88, 0x3e, 0x0b, 0x10, 0x7b,
- 0x8d, 0x4c, 0xca, 0xcc, 0x44, 0x82, 0x34, 0xcf,
- 0xae, 0xb7, 0x56, 0x1d, 0x3d, 0xff, 0x2e, 0xb3,
- 0xa7, 0x6f, 0x50, 0x1d, 0x14, 0x1e, 0x03, 0x08,
- 0xe7, 0xc8, 0xb6, 0x56, 0x15, 0x3e, 0xff, 0x7f,
- 0xf8, 0x54, 0xd8, 0x85, 0x4c, 0x10, 0x95, 0x18,
- 0x7e, 0xb5, 0x25, 0xb9, 0x30, 0x45, 0x27, 0xf7,
- 0xf7, 0xa8, 0x2d, 0x8d, 0xe5, 0x38, 0xdd, 0xc2,
- 0xa7, 0x01, 0xe6, 0x6e, 0x86, 0x9c, 0xff, 0xeb,
- 0x28, 0x2b, 0x99, 0xb7, 0x7f, 0xb5, 0x9d, 0x3f,
- 0xab, 0xbd, 0x95, 0x0f, 0x52, 0x74, 0x2a, 0xba,
- 0xdc, 0x4c, 0xf4, 0x60, 0x23, 0x1d, 0x67, 0x1a,
- 0x55, 0x2a, 0x70, 0x42, 0x12, 0xa7, 0xcf, 0x07,
- 0x7f, 0x62, 0x9c, 0x5e, 0x4f, 0xff, 0x7e, 0x9d,
- 0xd4, 0x81, 0x7e, 0x9d, 0x47, 0xf8, 0xe9, 0xff,
- 0xec, 0x57, 0x6d, 0xf5, 0xd1, 0x33, 0x5f, 0x84,
- 0xe9, 0xe6, 0xfb, 0x01, 0xb1, 0xd0, 0xf3, 0xf7,
- 0xe5, 0x09, 0xff, 0xcf, 0xc1, 0x03, 0x3d, 0x5d,
- 0xf5, 0x5c, 0x3a, 0x7b, 0xdb, 0x63, 0x0e, 0x85,
- 0x4e, 0x39, 0xe6, 0xfd, 0x0c, 0xaf, 0x90, 0xe8,
- 0x95, 0x3f, 0x6a, 0xeb, 0xef, 0xd2, 0xf3, 0xa7,
- 0xfd, 0xc3, 0xa9, 0xeb, 0x67, 0x52, 0x03, 0xa7,
- 0xfd, 0x5a, 0xa8, 0xdd, 0x5d, 0xb7, 0x8e, 0x9f,
- 0xf7, 0xf9, 0xab, 0x70, 0x8f, 0xb6, 0x3a, 0x31,
- 0x1d, 0xe8, 0x67, 0xe4, 0x06, 0x1f, 0x4f, 0x3f,
- 0x7e, 0x34, 0x74, 0xf8, 0x76, 0xcc, 0xf9, 0xd3,
- 0xff, 0x6a, 0xfd, 0x96, 0x56, 0xd5, 0xb2, 0xd2,
- 0x74, 0x71, 0xf8, 0x54, 0x9a, 0x7f, 0xfb, 0x2f,
- 0x5c, 0x6a, 0xca, 0xdb, 0x2d, 0x65, 0x3a, 0x7f,
- 0x5d, 0xba, 0xb5, 0xf6, 0xe9, 0x46, 0x87, 0x46,
- 0xc8, 0xb4, 0xf9, 0x0d, 0xd4, 0x27, 0xff, 0xbd,
- 0x5c, 0xda, 0xf5, 0xf6, 0xbb, 0x77, 0xfc, 0x74,
- 0xff, 0xfe, 0xfd, 0xf2, 0xde, 0x5b, 0xf8, 0x0a,
- 0xf7, 0x04, 0x21, 0x2a, 0x7b, 0x6c, 0xcd, 0x65,
- 0x4e, 0x7f, 0xf4, 0x34, 0x43, 0x33, 0x82, 0x10,
- 0x95, 0x3b, 0x3e, 0x85, 0x38, 0xbc, 0x9f, 0xf6,
- 0x51, 0x9b, 0x73, 0xfe, 0xb4, 0x1d, 0x00, 0x3e,
- 0x8f, 0x94, 0xcf, 0xe7, 0xff, 0x2f, 0x7d, 0x28,
- 0x3a, 0x15, 0x38, 0x9a, 0x18, 0x69, 0x23, 0x18,
- 0x57, 0x71, 0x14, 0xf7, 0xaf, 0xe5, 0x3a, 0x7f,
- 0x69, 0x82, 0x00, 0x7b, 0xe7, 0x4f, 0xff, 0x95,
- 0xfe, 0xda, 0xdb, 0xeb, 0x82, 0x9d, 0xc8, 0x68,
- 0x83, 0x22, 0xc8, 0x94, 0xb9, 0x9c, 0xfe, 0xd4,
- 0xca, 0xea, 0x60, 0xa9, 0xd0, 0xf4, 0xc3, 0xbd,
- 0x0b, 0x5b, 0x91, 0xcf, 0xff, 0x2f, 0xe8, 0xdc,
- 0xd7, 0xbf, 0x9b, 0x67, 0xf5, 0x9d, 0x39, 0x45,
- 0xa3, 0xa1, 0x57, 0x65, 0x36, 0x3b, 0xc8, 0xd2,
- 0x10, 0xc7, 0xd1, 0xee, 0x74, 0x6b, 0xba, 0x1b,
- 0x6a, 0x2b, 0x4f, 0xef, 0xfd, 0x5e, 0xc5, 0xf1,
- 0xd3, 0xfa, 0xfe, 0x6d, 0xeb, 0xbd, 0x4a, 0x93,
- 0x0e, 0x9f, 0xb3, 0xfa, 0xc5, 0x5d, 0xe3, 0xc5,
- 0xde, 0x6b, 0x1e, 0x45, 0xf5, 0x5d, 0xe7, 0x87,
- 0x4a, 0x5e, 0x74, 0xfe, 0xfb, 0xff, 0x8c, 0x54,
- 0x3a, 0x73, 0x36, 0xc3, 0xa1, 0x4f, 0xc3, 0x08,
- 0xf8, 0xc6, 0x75, 0xfd, 0x41, 0xd3, 0xfe, 0xd2,
- 0xf5, 0xde, 0x20, 0x67, 0xaa, 0x74, 0xff, 0xcb,
- 0xfe, 0xb2, 0x81, 0xc3, 0x5a, 0x95, 0x1b, 0x22,
- 0x11, 0x88, 0x53, 0xeb, 0x7b, 0xd4, 0xd4, 0xe8,
- 0x2a, 0x7e, 0xae, 0xf5, 0x15, 0x61, 0x50, 0x54,
- 0x15, 0x05, 0x41, 0x50, 0xf3, 0xdf, 0xf0, 0x50,
- 0x0b, 0x74, 0x0a, 0xd4, 0x0a, 0x6f, 0x0a, 0x9a,
- 0xd8, 0x54, 0xfd, 0xdd, 0x76, 0x95, 0x85, 0x6e,
- 0x2d, 0x64, 0xdd, 0x95, 0x05, 0x41, 0x50, 0xf2,
- 0xd3, 0xc1, 0x50, 0x54, 0x15, 0x05, 0x41, 0x50,
- 0x54, 0x15, 0x14, 0x1b, 0xcd, 0x82, 0xbc, 0x14,
- 0x00, 0xaa, 0x85, 0x36, 0x0a, 0x82, 0xa0, 0xa8,
- 0x79, 0x69, 0x50, 0xa8, 0x2a, 0x0a, 0x82, 0xa0,
- 0xa8, 0x79, 0xa8, 0x00, 0x55, 0xc2, 0x9b, 0xc2,
- 0xa0, 0xa8, 0x2a, 0x0a, 0x82, 0xa2, 0x83, 0x51,
- 0xac, 0x28, 0x42, 0xac, 0x15, 0x2d, 0x65, 0x41,
- 0x50, 0x54, 0x15, 0x05, 0x46, 0xc6, 0xa2, 0x90,
- 0xa0, 0x05, 0x68, 0x15, 0x05, 0x41, 0x50, 0x54,
- 0xfa, 0xca, 0x0a, 0xe1, 0x50, 0x54, 0x3c, 0xf3,
- 0x90, 0x2a, 0xc1, 0x5c, 0x14, 0x02, 0x69, 0x21,
- 0x50, 0x54, 0x15, 0x05, 0x41, 0x50, 0xf3, 0x51,
- 0x48, 0x57, 0x82, 0x9b, 0x05, 0x41, 0x50, 0x54,
- 0x15, 0x05, 0x43, 0xcd, 0x46, 0xc1, 0x56, 0x0a,
- 0xf8, 0x54, 0xac, 0x54, 0x15, 0x05, 0x49, 0xe5,
- 0x41, 0x54, 0x96, 0x10, 0x54, 0x15, 0x05, 0x41,
- 0x51, 0x41, 0xf3, 0x3c, 0x2b, 0x58, 0xd2, 0x0d,
- 0x34, 0x14, 0x00, 0xab, 0x85, 0x4b, 0x0a, 0x82,
- 0xa0, 0xa9, 0x3c, 0xa8, 0x2a, 0x92, 0xc2, 0x0a,
- 0x82, 0xa1, 0x4f, 0x49, 0xe1, 0x5e, 0x1a, 0x11,
- 0xa6, 0x05, 0x41, 0x50, 0x54, 0x15, 0x05, 0x41,
- 0x50, 0xa6, 0xca, 0x90, 0xa1, 0x0a, 0x60, 0x57,
- 0xc2, 0xa0, 0xa8, 0x2a, 0x0a, 0x81, 0x2f, 0xaa,
- 0x15, 0x70, 0xa8, 0x2a, 0x0a, 0x82, 0xa1, 0x85,
- 0xf7, 0xc2, 0xae, 0x15, 0x26, 0x15, 0x05, 0x41,
- 0x50, 0x02, 0xd3, 0x40, 0xa8, 0x2a, 0x0a, 0x82,
- 0xa0, 0xa8, 0x53, 0x50, 0xd0, 0x55, 0x82, 0xb4,
- 0x0a, 0x85, 0x5f, 0xad, 0xa1, 0xc9, 0xe7, 0xbb,
- 0x14, 0xe2, 0xe2, 0x36, 0xd2, 0x91, 0xe6, 0x6d,
- 0x59, 0xeb, 0x47, 0x43, 0x08, 0xc6, 0x23, 0xd8,
- 0xdf, 0x99, 0x80, 0x79, 0xf7, 0x6a, 0xb3, 0x5d,
- 0x87, 0x47, 0x96, 0xcc, 0xa1, 0x4a, 0xd4, 0x2d,
- 0xde, 0x48, 0xde, 0x93, 0x3e, 0x7f, 0xd7, 0x2a,
- 0x53, 0x93, 0x57, 0x9d, 0xe5, 0x61, 0x53, 0xde,
- 0x4e, 0x13, 0xa7, 0x7b, 0x6c, 0x3a, 0x72, 0xef,
- 0x75, 0x28, 0x8f, 0x13, 0x9b, 0x0d, 0xdc, 0x7e,
- 0x7f, 0x5b, 0xc1, 0xd8, 0x56, 0x83, 0xa2, 0x94,
- 0x42, 0x34, 0xa1, 0x30, 0x14, 0xe9, 0xf8, 0x7b,
- 0xfb, 0xd4, 0x07, 0x4d, 0xc2, 0x74, 0xbc, 0x72,
- 0x16, 0x92, 0x43, 0xa4, 0xc3, 0xa7, 0x66, 0xa3,
- 0xbc, 0x89, 0x31, 0x15, 0xb2, 0x0f, 0x0f, 0x6f,
- 0x0f, 0x9f, 0xff, 0x68, 0xbb, 0xb8, 0x47, 0x80,
- 0xae, 0x08, 0x42, 0x74, 0x3d, 0x9b, 0x1d, 0xb4,
- 0x24, 0xd0, 0xb3, 0xd0, 0xa1, 0x68, 0x93, 0xa9,
- 0x53, 0xff, 0x85, 0xc5, 0xd7, 0xa7, 0xf2, 0xfe,
- 0xfd, 0xfd, 0x30, 0xe9, 0xf9, 0xff, 0xf3, 0xed,
- 0x87, 0x4f, 0xa8, 0xf0, 0xab, 0xce, 0x81, 0x3d,
- 0x4f, 0x96, 0xcf, 0xfa, 0xca, 0x20, 0xfe, 0x07,
- 0x80, 0x74, 0xec, 0xc6, 0x8e, 0x96, 0x58, 0xf5,
- 0xc0, 0x79, 0x3f, 0x57, 0x1b, 0x7d, 0x69, 0x3a,
- 0x79, 0x7f, 0x74, 0x3a, 0x4b, 0x88, 0xee, 0xfb,
- 0xc5, 0xc9, 0xf5, 0x0b, 0xe7, 0xb4, 0xe1, 0x79,
- 0xd3, 0xcb, 0xa3, 0x77, 0x52, 0xa7, 0xcf, 0x70,
- 0x42, 0x13, 0xa3, 0xe7, 0x9f, 0xa1, 0x3c, 0x6c,
- 0x89, 0x3c, 0x70, 0x86, 0x2a, 0x6e, 0x04, 0x6e,
- 0x9a, 0x43, 0x5e, 0x7e, 0x1d, 0x01, 0x9f, 0x43,
- 0xa7, 0xfa, 0x8f, 0xe3, 0xed, 0x80, 0xa9, 0xd3,
- 0xdb, 0x6c, 0xad, 0x8e, 0x9f, 0xff, 0x2d, 0x95,
- 0x88, 0xb7, 0xc1, 0x4e, 0xe4, 0x34, 0x5f, 0x13,
- 0xf8, 0x3d, 0x7a, 0xae, 0x50, 0x74, 0xff, 0xfd,
- 0x97, 0xde, 0xf5, 0x6d, 0xef, 0x80, 0x7c, 0xac,
- 0xc2, 0xa6, 0xbe, 0x1d, 0x3e, 0x1f, 0x51, 0xcc,
- 0x34, 0xc2, 0x73, 0xd7, 0xd1, 0x78, 0xd3, 0x09,
- 0xcc, 0x05, 0x35, 0x02, 0x73, 0xfb, 0xfd, 0xae,
- 0xea, 0x20, 0x35, 0x02, 0x73, 0xfa, 0xb9, 0x6f,
- 0x57, 0x4a, 0x0d, 0x30, 0x9c, 0xd9, 0xb1, 0xa6,
- 0x13, 0x98, 0x21, 0x3c, 0xc2, 0x71, 0x89, 0xa6,
- 0x52, 0x69, 0xe2, 0xe6, 0x11, 0x55, 0x01, 0xb2,
- 0x10, 0x48, 0xe5, 0x72, 0xcc, 0x26, 0xe3, 0xe7,
- 0x97, 0xa9, 0x4f, 0xd8, 0x31, 0xe4, 0x45, 0x55,
- 0x42, 0x5e, 0x52, 0x9c, 0x2a, 0xb9, 0xbd, 0x8e,
- 0x50, 0x96, 0xcb, 0x77, 0x95, 0x6d, 0x3e, 0xdb,
- 0x07, 0xda, 0xce, 0x9f, 0x7f, 0x37, 0xe3, 0x47,
- 0x4f, 0xf5, 0xb9, 0x96, 0xf2, 0xd2, 0xf3, 0xa7,
- 0xed, 0xff, 0x7e, 0xa7, 0x50, 0x74, 0x78, 0xfb,
- 0x00, 0x73, 0x1f, 0x45, 0xbd, 0xe1, 0x2b, 0x0a,
- 0xba, 0x43, 0x92, 0xf1, 0xfc, 0xa5, 0xd0, 0xe0,
- 0x9f, 0xfc, 0xcb, 0xd7, 0xdf, 0xa5, 0xf7, 0xf5,
- 0x7c, 0x74, 0xff, 0xfe, 0xfe, 0x53, 0x95, 0xef,
- 0xdb, 0xcb, 0x7b, 0x69, 0xcc, 0x3a, 0x7e, 0xfe,
- 0x8c, 0xf5, 0x94, 0xe9, 0xff, 0xf7, 0x7e, 0xfd,
- 0xd6, 0xfa, 0xde, 0xa1, 0xcb, 0x1d, 0x38, 0x6b,
- 0x53, 0xc4, 0x07, 0x3f, 0xfd, 0xbc, 0x56, 0xcb,
- 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x01, 0xb8, 0xd4,
- 0x40, 0x11, 0xcb, 0x77, 0xb8, 0xc4, 0xcd, 0xbd,
- 0x18, 0x9c, 0xff, 0xfe, 0xe7, 0xe5, 0x7c, 0x23,
- 0xe6, 0x6f, 0xbd, 0xb0, 0x37, 0x3a, 0x7f, 0xff,
- 0xb9, 0xf9, 0xf6, 0x9f, 0x94, 0xbf, 0x7a, 0x81,
- 0xc1, 0x08, 0x4a, 0x8b, 0x23, 0x2f, 0xec, 0x33,
- 0xf9, 0x70, 0x53, 0xb9, 0x0d, 0x10, 0x4c, 0xff,
- 0x2d, 0xf0, 0x53, 0xb9, 0x0d, 0x17, 0xcc, 0xfb,
- 0xcd, 0xbf, 0x95, 0xd8, 0xfe, 0x90, 0xea, 0x7f,
- 0xd4, 0x75, 0x3a, 0x99, 0x7f, 0xf3, 0x63, 0xa7,
- 0x04, 0x21, 0x2a, 0x7e, 0xbd, 0xb1, 0x38, 0x4a,
- 0x71, 0x79, 0x14, 0x22, 0x67, 0xec, 0x13, 0xff,
- 0x50, 0xc5, 0xa6, 0xbf, 0xca, 0x37, 0xbc, 0xe9,
- 0xff, 0xed, 0xf4, 0xff, 0x72, 0x5b, 0xc0, 0x02,
- 0x8b, 0xce, 0x9c, 0x10, 0x84, 0xa9, 0xfd, 0xbc,
- 0x0b, 0xfc, 0xa6, 0xe5, 0x38, 0xbc, 0x9f, 0xff,
- 0x9b, 0xbd, 0xc9, 0x6f, 0x6d, 0xb6, 0x07, 0x75,
- 0xeb, 0x94, 0x1d, 0x2e, 0xb2, 0x2a, 0xf4, 0x44,
- 0x87, 0xaa, 0x8b, 0xf4, 0x36, 0x84, 0x91, 0x89,
- 0x37, 0x8c, 0x6e, 0x7f, 0xd9, 0x75, 0x1a, 0xd9,
- 0x7f, 0x73, 0xc4, 0x11, 0x3f, 0x97, 0x05, 0x3b,
- 0x90, 0xd1, 0x04, 0x38, 0xf2, 0x67, 0xee, 0xb0,
- 0x8f, 0x82, 0x74, 0xfd, 0xab, 0xd8, 0x3d, 0xf7,
- 0x9d, 0x1f, 0x3d, 0xdd, 0x0a, 0xe0, 0x08, 0xcb,
- 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, 0xa5, 0x1f, 0x5c,
- 0xb3, 0x96, 0xf9, 0x6d, 0x04, 0xe9, 0xf6, 0x5e,
- 0xbb, 0xeb, 0xb1, 0xfc, 0xef, 0x23, 0x9f, 0x92,
- 0xde, 0xd4, 0xf6, 0xb3, 0xa7, 0xe6, 0x2e, 0xae,
- 0xd9, 0x41, 0xd3, 0xff, 0xff, 0xde, 0xbf, 0x33,
- 0xbe, 0x07, 0xfa, 0xba, 0x32, 0xde, 0x5b, 0xdb,
- 0x4e, 0x61, 0xd1, 0xb2, 0x38, 0xfc, 0x65, 0xc6,
- 0x33, 0x87, 0x7d, 0x4e, 0x9f, 0xf7, 0x7d, 0x30,
- 0x53, 0xb9, 0x0d, 0x10, 0x8c, 0x29, 0xf1, 0x68,
- 0x3b, 0x3f, 0xf9, 0x72, 0x9d, 0xf7, 0xf7, 0xf4,
- 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, 0x43, 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, 0xab,
- 0x9b, 0xa9, 0xd3, 0xff, 0xb3, 0x57, 0xdf, 0x06,
- 0x22, 0xd9, 0x58, 0x74, 0xfc, 0x9e, 0xad, 0xbc,
- 0xd1, 0x53, 0xfb, 0xf9, 0x4b, 0xeb, 0xed, 0x67,
- 0x4f, 0x77, 0x0e, 0xb3, 0xa3, 0x71, 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, 0x38, 0x5e, 0x74, 0xf9,
- 0x6f, 0x56, 0xd8, 0x74, 0x29, 0xfe, 0x5d, 0x52,
- 0x7f, 0xfb, 0xcd, 0xb3, 0xfb, 0x7f, 0x83, 0x9f,
- 0xed, 0x67, 0x4f, 0xff, 0xf6, 0xd6, 0xf0, 0x71,
- 0xbf, 0xcc, 0xeb, 0xd7, 0x47, 0xe5, 0x37, 0x3a,
- 0x31, 0x18, 0x1c, 0xa7, 0x0a, 0xd8, 0xef, 0xd0,
- 0x9a, 0xf8, 0xe5, 0xf6, 0x87, 0xa6, 0x4b, 0x28,
- 0xf4, 0x6d, 0x4d, 0x42, 0xc0, 0x48, 0xd9, 0x0a,
- 0xfb, 0x46, 0x4e, 0x08, 0x49, 0x7e, 0x18, 0x15,
- 0x95, 0x3b, 0x79, 0x41, 0x5a, 0x43, 0x44, 0x30,
- 0xe1, 0x9c, 0xd9, 0x7e, 0x74, 0xff, 0xf6, 0x7d,
- 0xd7, 0xd7, 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, 0x09, 0xd3, 0xfe, 0xef,
- 0x0e, 0x52, 0xe0, 0x84, 0x27, 0x47, 0x1e, 0xdd,
- 0x47, 0x67, 0xff, 0xbe, 0xaf, 0xdd, 0xbe, 0xfe,
- 0xfe, 0x8f, 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, 0x59, 0xd3, 0xfa,
- 0xf6, 0xf3, 0x81, 0xde, 0x3a, 0x28, 0x4c, 0x8f,
- 0x65, 0xff, 0xa6, 0x5c, 0x9b, 0x41, 0xf9, 0xfd,
- 0xa0, 0x16, 0xde, 0xe7, 0x9d, 0x3f, 0xff, 0x7f,
- 0x2b, 0xa6, 0xec, 0xb7, 0x7f, 0x1a, 0x7a, 0xd2,
- 0x74, 0xff, 0xb2, 0xba, 0x60, 0xa7, 0x72, 0x1a,
- 0x20, 0x69, 0xf6, 0x5e, 0xdc, 0xfd, 0xc8, 0xa5,
- 0xfa, 0xf4, 0xff, 0xff, 0xfd, 0x97, 0xb7, 0x7f,
- 0x5e, 0xea, 0x8f, 0x75, 0xdb, 0x66, 0xdb, 0xb1,
- 0x9d, 0xfa, 0x5e, 0x78, 0x82, 0xe7, 0xfd, 0xdd,
- 0xad, 0x3b, 0x6d, 0xda, 0xc2, 0x78, 0x82, 0xe7,
- 0xfe, 0xb7, 0xad, 0xe5, 0xfd, 0xf7, 0x6b, 0x09,
- 0xe2, 0x0b, 0x9f, 0xcb, 0xef, 0xdf, 0x76, 0xb0,
- 0x9e, 0x20, 0xb9, 0xf9, 0x99, 0xb6, 0xed, 0x61,
- 0x3c, 0x41, 0x73, 0xff, 0xfd, 0xdf, 0xff, 0x99,
- 0xba, 0xa9, 0x6f, 0x0f, 0xb5, 0xd1, 0x81, 0x3c,
- 0x41, 0x73, 0x53, 0xbb, 0x64, 0xe8, 0x51, 0x40,
- 0x55, 0xb9, 0x13, 0xe7, 0xf1, 0x65, 0x52, 0xdf,
- 0x94, 0x7d, 0x3d, 0xc2, 0x0e, 0x3a, 0x7f, 0xeb,
- 0x7a, 0xde, 0x5f, 0xdf, 0x76, 0xb0, 0x9e, 0x20,
- 0xb9, 0xfe, 0x6a, 0xa9, 0xea, 0x37, 0x6b, 0x09,
- 0xe2, 0x0b, 0x9f, 0x5e, 0xaa, 0xcd, 0xc8, 0x8a,
- 0x2d, 0xea, 0xd3, 0xff, 0xb7, 0x25, 0xbc, 0x8b,
- 0x7a, 0xee, 0xd6, 0x13, 0xc4, 0x17, 0x3f, 0xff,
- 0xf7, 0xff, 0xe6, 0x6e, 0xd3, 0x37, 0x55, 0x2d,
- 0xe1, 0xf6, 0xba, 0x30, 0x27, 0x88, 0x2e, 0x31,
- 0x32, 0x6a, 0x50, 0xf9, 0x72, 0x7f, 0xad, 0xe1,
- 0xf6, 0xba, 0x30, 0x27, 0x88, 0x2e, 0x7f, 0xfb,
- 0xba, 0x97, 0xd6, 0xde, 0xdb, 0x65, 0x15, 0x2a,
- 0x7f, 0xd8, 0xf7, 0xe9, 0x51, 0xfd, 0x1a, 0x87,
- 0x88, 0x2e, 0x11, 0x1d, 0x02, 0x91, 0x55, 0x09,
- 0xff, 0x27, 0x86, 0xfc, 0x0a, 0xee, 0x09, 0xe2,
- 0x0b, 0x9f, 0xad, 0xeb, 0x5b, 0xc0, 0x34, 0x01,
- 0x73, 0xec, 0x06, 0xed, 0x61, 0x3c, 0x41, 0x73,
- 0x65, 0xd0, 0xfc, 0xec, 0x77, 0x14, 0xa3, 0xae,
- 0xb0, 0xbf, 0x9f, 0x99, 0x9b, 0x6e, 0xd6, 0x13,
- 0xc4, 0x17, 0x3f, 0xe4, 0xb7, 0x87, 0xda, 0xe8,
- 0xc0, 0x9e, 0x20, 0xb9, 0xb3, 0x77, 0x22, 0x32,
- 0xa7, 0xf3, 0xfb, 0x4f, 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, 0x74, 0x85, 0xa8, 0x5c, 0x67, 0xc0, 0xa8,
- 0x00, 0xa6, 0x88, 0x2d, 0xc8, 0x80, 0x9f, 0xf6,
- 0x3e, 0xdc, 0xf6, 0xf6, 0xfd, 0x28, 0x3a, 0x7f,
- 0x0f, 0xf3, 0x6b, 0x68, 0x13, 0xa7, 0xd4, 0xdf,
- 0x84, 0x07, 0x4f, 0xd9, 0x47, 0x59, 0x75, 0x67,
- 0x47, 0x91, 0x17, 0xc6, 0x9f, 0x27, 0x9d, 0xc3,
- 0x41, 0xd3, 0x01, 0x4e, 0x9e, 0xf2, 0xb3, 0x0e,
- 0x83, 0xa7, 0xee, 0xd7, 0x75, 0x10, 0x1d, 0x1b,
- 0x1b, 0x7f, 0x85, 0x4f, 0xff, 0xe5, 0xf6, 0xdf,
- 0x5d, 0x12, 0xf8, 0x9b, 0x2a, 0x6f, 0x61, 0xd3,
- 0x01, 0x4e, 0x99, 0x75, 0x9d, 0x3f, 0xd9, 0x7a,
- 0xab, 0x37, 0xe3, 0x47, 0x4f, 0xea, 0xe5, 0xbd,
- 0x5d, 0x28, 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, 0x35, 0xa0, 0xd2,
- 0x63, 0xe8, 0xd5, 0x45, 0x3a, 0xd0, 0xd8, 0xea,
- 0x48, 0xf7, 0xd1, 0xab, 0x0d, 0x1d, 0x25, 0x7f,
- 0xb6, 0x4b, 0x9e, 0xc4, 0x5b, 0x9d, 0x3d, 0x8c,
- 0xcb, 0x9d, 0x3d, 0xd4, 0x6f, 0x79, 0xd0, 0xa7,
- 0xc7, 0x48, 0xfb, 0x79, 0x04, 0xfd, 0xfd, 0x36,
- 0x67, 0x3c, 0xe9, 0xff, 0xea, 0x5f, 0xf5, 0xdc,
- 0xcf, 0xae, 0xbb, 0xfa, 0x83, 0xa7, 0xf5, 0x6e,
- 0xdb, 0x3f, 0x9b, 0x1d, 0x0a, 0x8b, 0xaf, 0x17,
- 0xf2, 0xb4, 0xee, 0xdd, 0xbc, 0xe9, 0xff, 0xef,
- 0xbf, 0x76, 0x6d, 0xea, 0xd3, 0x7d, 0x3a, 0xa7,
- 0x46, 0xe3, 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, 0x9c, 0x6a, 0x63, 0x64,
- 0x4a, 0x01, 0x6e, 0x7f, 0xfd, 0x9f, 0xf6, 0xb7,
- 0x56, 0xf6, 0xd3, 0x9e, 0xf5, 0x3a, 0x28, 0x3f,
- 0xcd, 0x64, 0x91, 0xaa, 0x95, 0x77, 0xbc, 0xd3,
- 0x21, 0x95, 0xe8, 0x46, 0xf4, 0x67, 0xf3, 0xef,
- 0x5d, 0x6f, 0x52, 0xa7, 0x91, 0x6f, 0x52, 0xa6,
- 0x08, 0x4a, 0x87, 0x9e, 0xee, 0x13, 0x84, 0x82,
- 0x6c, 0x09, 0x4e, 0x35, 0xd3, 0xff, 0xec, 0xba,
- 0xa6, 0x67, 0xef, 0x6f, 0x2f, 0xe8, 0x3a, 0x00,
- 0x7f, 0x01, 0x25, 0x9f, 0xff, 0xca, 0xdb, 0xdf,
- 0x06, 0xeb, 0xd7, 0x12, 0xdd, 0xfb, 0xd4, 0xe9,
- 0xfc, 0xd5, 0x2f, 0xb6, 0x8a, 0x27, 0x4e, 0x7f,
- 0x09, 0xd3, 0xe7, 0xe5, 0xf3, 0x62, 0xa5, 0xe6,
- 0x8f, 0x06, 0xe3, 0x53, 0x01, 0x4e, 0x98, 0x0a,
- 0x74, 0xfd, 0xfd, 0x1f, 0x9f, 0x77, 0x8d, 0x50,
- 0x05, 0x67, 0xfe, 0xbd, 0xb1, 0x9b, 0xd4, 0x19,
- 0x4d, 0xce, 0x9f, 0xd4, 0xa7, 0x87, 0x7a, 0xec,
- 0x74, 0xf0, 0x19, 0xcf, 0xa9, 0xfd, 0xdd, 0x1a,
- 0x76, 0xa6, 0x52, 0x74, 0x29, 0xec, 0x71, 0xcc,
- 0xe0, 0x84, 0x25, 0x4f, 0xb3, 0x5f, 0xf4, 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,
- 0xae, 0xde, 0xb9, 0x4e, 0x2f, 0x27, 0xd8, 0x0c,
- 0xc6, 0x8e, 0x95, 0x77, 0x22, 0x54, 0x4c, 0x7e,
- 0x7d, 0x3d, 0xef, 0xe8, 0xfd, 0x91, 0xdb, 0x90,
- 0xb6, 0x85, 0x5c, 0x52, 0x79, 0x16, 0x32, 0x6b,
- 0x76, 0x15, 0x3b, 0x46, 0x31, 0x58, 0x4e, 0x5e,
- 0x30, 0xe9, 0xf9, 0x58, 0x23, 0xd7, 0x3a, 0x7f,
- 0xfb, 0xcc, 0xa5, 0xf5, 0xdd, 0x9f, 0xfe, 0x78,
- 0x07, 0x45, 0x8f, 0xf6, 0xe5, 0x52, 0x73, 0x74,
- 0x84, 0x1c, 0x4a, 0xca, 0xa6, 0xa2, 0x31, 0x67,
- 0xca, 0x4d, 0xda, 0x54, 0x16, 0x56, 0xda, 0x7a,
- 0xe3, 0x71, 0x48, 0xec, 0xa9, 0x95, 0x4f, 0xe8,
- 0x4e, 0xb5, 0x3c, 0x44, 0x33, 0xa4, 0x8c, 0x94,
- 0x17, 0x69, 0xed, 0x2e, 0xa7, 0x69, 0x82, 0x57,
- 0xdf, 0xe7, 0x57, 0xeb, 0x59, 0x14, 0x5e, 0xb3,
- 0x9f, 0xd2, 0x33, 0x56, 0xd0, 0xec, 0x0c, 0x28,
- 0xb5, 0x25, 0x89, 0x6f, 0x9d, 0xb5, 0x6f, 0x8c,
- 0x06, 0x1d, 0x08, 0x5f, 0x07, 0xe2, 0x0f, 0x56,
- 0x7f, 0x3b, 0x05, 0x3b, 0x90, 0xd1, 0x71, 0xcf,
- 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2e, 0xb9, 0xff,
- 0x9d, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x51,
- 0x85, 0x84, 0x4a, 0x2b, 0xca, 0x36, 0x3b, 0xd6,
- 0x76, 0x87, 0x7e, 0x87, 0x86, 0xad, 0x03, 0xb1,
- 0x0c, 0x85, 0x53, 0x8b, 0x9d, 0xb7, 0x9d, 0xcf,
- 0xfe, 0x73, 0x39, 0xee, 0xc1, 0x4e, 0xe4, 0x34,
- 0x4b, 0x53, 0xe1, 0x4e, 0xe4, 0x34, 0x46, 0xf3,
- 0xfe, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x2f,
- 0xc9, 0xd8, 0x7e, 0xcc, 0x30, 0x9f, 0xce, 0xc1,
- 0x4e, 0xe4, 0x34, 0x55, 0x73, 0xfd, 0xaf, 0x3f,
- 0x94, 0xdf, 0x98, 0x74, 0xdb, 0x78, 0xe9, 0xfb,
- 0x05, 0x3b, 0x90, 0xd1, 0x20, 0x46, 0xe3, 0xcc,
- 0x70, 0xbc, 0xfa, 0xbd, 0xfe, 0xa4, 0xe8, 0x79,
- 0xe5, 0xd2, 0x49, 0x1a, 0xd1, 0xe9, 0xd0, 0xd1,
- 0x9f, 0xfb, 0xf9, 0x43, 0xb5, 0x17, 0xff, 0xcb,
- 0x9d, 0x0e, 0x3f, 0x01, 0x29, 0x9f, 0xce, 0xc1,
- 0x4e, 0xe4, 0x34, 0x59, 0x13, 0xf9, 0xd8, 0x29,
- 0xdc, 0x86, 0x8b, 0x5e, 0x7f, 0x3b, 0x05, 0x3b,
- 0x90, 0xd1, 0x72, 0x4f, 0x85, 0x3b, 0x90, 0xd1,
- 0x76, 0x4f, 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43,
- 0x45, 0x1d, 0x27, 0x61, 0xfb, 0x30, 0xc2, 0x7c,
- 0x29, 0xdc, 0x86, 0x8a, 0x56, 0x7f, 0xff, 0xfa,
- 0xcb, 0x42, 0xdb, 0xcd, 0xbb, 0x6b, 0x79, 0xc9,
- 0x6f, 0x35, 0x65, 0xa3, 0x0e, 0x9f, 0x39, 0x9c,
- 0xf7, 0x62, 0x2c, 0x9a, 0x30, 0x8a, 0x17, 0x3b,
- 0xdf, 0x0c, 0x8a, 0x49, 0xfd, 0x1c, 0xfb, 0x08,
- 0x40, 0x77, 0x53, 0xbb, 0xc2, 0xc5, 0xb4, 0x36,
- 0x67, 0xf9, 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x47,
- 0x13, 0xfd, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2b,
- 0x59, 0x3b, 0x91, 0x05, 0x74, 0x19, 0xff, 0xce,
- 0x67, 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89, 0x6e,
- 0x6c, 0xa4, 0xe9, 0xfd, 0xb6, 0x31, 0x8b, 0xea,
- 0x9d, 0x14, 0x9e, 0x4f, 0x85, 0xa7, 0x5b, 0x67,
- 0x9d, 0x39, 0xec, 0x43, 0xa0, 0xd1, 0x0d, 0xcf,
- 0xfb, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xc1,
- 0x38, 0x74, 0x01, 0x53, 0xfb, 0xf9, 0x7b, 0xa8,
- 0xd4, 0xe9, 0x39, 0x53, 0x05, 0xa0, 0x8f, 0x61,
- 0xd4, 0x1b, 0x60, 0xbd, 0xd1, 0xb7, 0x8e, 0x4e,
- 0x66, 0x82, 0x54, 0xff, 0xb9, 0xee, 0xc1, 0x4e,
- 0xe4, 0x34, 0x4c, 0x72, 0x77, 0x8f, 0x89, 0x83,
- 0x93, 0xf2, 0xd7, 0x75, 0xf2, 0xc7, 0x4f, 0xff,
- 0xff, 0x3e, 0xb6, 0xcd, 0x03, 0x5b, 0x62, 0x65,
- 0x77, 0x65, 0x2f, 0xaf, 0xbf, 0xe3, 0xa7, 0x93,
- 0xb9, 0x0d, 0x15, 0x8c, 0xff, 0xb5, 0x32, 0xff,
- 0xcd, 0x17, 0xf7, 0x3a, 0x35, 0xa6, 0x37, 0x49,
- 0x70, 0xc2, 0x06, 0xe5, 0x73, 0xff, 0x97, 0xf7,
- 0xd7, 0xa2, 0xff, 0x11, 0x44, 0xe9, 0xff, 0x66,
- 0xd6, 0xca, 0xd2, 0xf5, 0xb1, 0xd3, 0xff, 0xff,
- 0x7f, 0x4a, 0x31, 0x37, 0x7f, 0x46, 0xfd, 0xd9,
- 0x4b, 0xf3, 0x4f, 0x82, 0xa7, 0x4f, 0xed, 0x55,
- 0x43, 0x4f, 0x6e, 0x0d, 0x07, 0x4e, 0xb7, 0x9d,
- 0x89, 0xc5, 0xa2, 0x2d, 0x92, 0x6e, 0x7f, 0xa8,
- 0xfd, 0x36, 0x8d, 0x1d, 0x3e, 0xef, 0xd1, 0xa5,
- 0x4e, 0x8f, 0x9e, 0x0d, 0x46, 0x27, 0x94, 0x7b,
- 0xe7, 0x4f, 0x56, 0xaa, 0x03, 0xa2, 0xc7, 0x80,
- 0x11, 0xf9, 0xf2, 0xbc, 0x1a, 0x3c, 0xe9, 0xcb,
- 0xf7, 0x9d, 0x0d, 0x1e, 0x1d, 0xca, 0x27, 0xe5,
- 0x66, 0x7f, 0xda, 0xce, 0x95, 0x4e, 0x8f, 0x1b,
- 0xee, 0x2e, 0x98, 0x0a, 0x54, 0xc1, 0x09, 0x51,
- 0xe3, 0x56, 0x11, 0x59, 0xfd, 0xcf, 0xfe, 0x5e,
- 0xde, 0x29, 0xc6, 0x86, 0x7b, 0x6e, 0xa6, 0xa7,
- 0x4e, 0x5f, 0xb4, 0x74, 0xdf, 0x53, 0xa1, 0xa3,
- 0x62, 0x23, 0x93, 0xc2, 0x0c, 0x6f, 0x3a, 0x76,
- 0xf1, 0xd6, 0x74, 0x2a, 0x2d, 0xf1, 0x53, 0xc4,
- 0x36, 0x23, 0x9a, 0xd7, 0x3a, 0x70, 0x42, 0x12,
- 0xa7, 0xfe, 0xc4, 0xd9, 0x68, 0xdf, 0x96, 0xea,
- 0x4a, 0x71, 0x79, 0x3d, 0xe1, 0x6f, 0xd8, 0xe9,
- 0x09, 0xd3, 0xe6, 0x7a, 0xe0, 0xe3, 0xa2, 0x83,
- 0xdb, 0xd5, 0x92, 0xe8, 0x1f, 0x3f, 0x93, 0xd5,
- 0xfe, 0x36, 0xe3, 0xa6, 0xcb, 0x9d, 0x14, 0x9e,
- 0x45, 0x8c, 0xe7, 0xff, 0xaf, 0xea, 0xdb, 0x36,
- 0xfe, 0x36, 0xfe, 0x54, 0xe9, 0x39, 0x57, 0x27,
- 0x36, 0x62, 0xc6, 0x51, 0x61, 0x63, 0x65, 0xa1,
- 0xf3, 0xc7, 0x7f, 0x32, 0xac, 0x2c, 0x2e, 0xfb,
- 0xbc, 0x8e, 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xde,
- 0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27,
- 0x09, 0x3b, 0x0f, 0xd9, 0x86, 0x13, 0xe1, 0x4e,
- 0xe4, 0x34, 0x5a, 0x33, 0xd8, 0xd7, 0xb5, 0x9d,
- 0x27, 0x61, 0xea, 0x58, 0xc2, 0x79, 0x3b, 0x90,
- 0xd1, 0x6d, 0x4f, 0xd6, 0x56, 0x2f, 0xb6, 0x3a,
- 0x67, 0x60, 0x9e, 0xc5, 0xca, 0xe7, 0xf3, 0xb0,
- 0x53, 0xb9, 0x0d, 0x17, 0x2c, 0xfe, 0x76, 0x0a,
- 0x77, 0x21, 0xa2, 0xed, 0x85, 0x66, 0xae, 0x50,
- 0x50, 0xf8, 0xe8, 0x36, 0x86, 0x7e, 0xb9, 0x59,
- 0xde, 0x9d, 0x3b, 0xd5, 0xc6, 0x41, 0x67, 0xbf,
- 0xbf, 0xd4, 0xb2, 0xe7, 0x73, 0xf9, 0xd8, 0x29,
- 0xdc, 0x86, 0x8a, 0x9e, 0x79, 0x3b, 0x90, 0xd1,
- 0x5c, 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x2c,
- 0xe8, 0x13, 0xe6, 0xb1, 0x5c, 0xf8, 0x53, 0xb9,
- 0x0d, 0x12, 0x14, 0xff, 0x7a, 0x9a, 0xdf, 0xea,
- 0xca, 0x9d, 0x33, 0xdd, 0x87, 0xd4, 0x03, 0x09,
- 0xe6, 0xe9, 0x65, 0x61, 0xd3, 0xfb, 0x2d, 0x5a,
- 0xe0, 0xd0, 0x74, 0x9d, 0x89, 0x88, 0xf4, 0x22,
- 0xea, 0x5b, 0x72, 0x79, 0xff, 0xce, 0x67, 0x3d,
- 0xd8, 0x29, 0xdc, 0x86, 0x89, 0xf2, 0x11, 0x52,
- 0x5e, 0xae, 0x3b, 0x2b, 0x23, 0xcf, 0x85, 0x3b,
- 0x90, 0xd1, 0x59, 0x4f, 0xfb, 0x9e, 0xec, 0x14,
- 0xee, 0x43, 0x44, 0xdd, 0x37, 0x9d, 0x87, 0xec,
- 0xc3, 0x09, 0xf0, 0xa7, 0x72, 0x1a, 0x25, 0x69,
- 0xfe, 0xd7, 0x6f, 0x6e, 0xd1, 0x32, 0xa7, 0x4f,
- 0x9c, 0xce, 0x7b, 0xb0, 0xfb, 0x78, 0xc2, 0x7c,
- 0x29, 0xdc, 0x86, 0x89, 0x72, 0x7f, 0xbd, 0xcf,
- 0xbf, 0xd5, 0x95, 0x3a, 0x79, 0xb7, 0xbe, 0xa7,
- 0x4f, 0x9c, 0xce, 0x7b, 0xb1, 0x11, 0x76, 0x30,
- 0xe3, 0x89, 0xff, 0x9d, 0xcf, 0x76, 0x0a, 0x77,
- 0x21, 0xa2, 0x3b, 0x9f, 0xeb, 0xdb, 0x1e, 0xee,
- 0xfd, 0x4e, 0x9f, 0x9b, 0x9f, 0x54, 0xcf, 0x9d,
- 0x3f, 0x6a, 0x9f, 0xcb, 0x75, 0xce, 0x9f, 0x0a,
- 0x77, 0x21, 0xa2, 0xa1, 0x9f, 0x65, 0xaf, 0x94,
- 0x1d, 0x27, 0x6a, 0x88, 0xb7, 0x6e, 0x17, 0xe1,
- 0x8d, 0xcc, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xaa,
- 0x27, 0xfd, 0xcf, 0x76, 0x0a, 0x77, 0x21, 0xa2,
- 0x6b, 0x93, 0xb0, 0xfd, 0x98, 0x61, 0x3f, 0x9d,
- 0x82, 0x9d, 0xc8, 0x68, 0xab, 0x27, 0xfe, 0x77,
- 0x3d, 0xd8, 0x29, 0xdc, 0x86, 0x89, 0x12, 0x7c,
- 0x29, 0xdc, 0x86, 0x8b, 0x4a, 0x7f, 0xdc, 0xf7,
- 0x60, 0xa7, 0x72, 0x1a, 0x27, 0xd9, 0x3b, 0x0f,
- 0xd9, 0x86, 0x13, 0xff, 0x9c, 0xce, 0x7b, 0xb0,
- 0x53, 0xb9, 0x0d, 0x14, 0x24, 0xfa, 0xde, 0xa1,
- 0x44, 0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x28, 0xf9,
- 0xff, 0xfb, 0x36, 0xb2, 0xef, 0x75, 0xff, 0xc0,
- 0xad, 0x54, 0x05, 0x4f, 0x9c, 0xce, 0x7b, 0x95,
- 0x16, 0x98, 0x4f, 0xa8, 0x61, 0x0a, 0xbb, 0x5d,
- 0x44, 0x32, 0x1e, 0x97, 0x89, 0x9a, 0xe1, 0xde,
- 0x90, 0xc1, 0xa4, 0x9d, 0xa3, 0xbb, 0x43, 0x08,
- 0x04, 0xf7, 0x8c, 0x1a, 0x7f, 0x3b, 0x05, 0x3b,
- 0x90, 0xd1, 0x11, 0x4f, 0xd8, 0x29, 0xdc, 0x86,
- 0x88, 0xae, 0x7f, 0xb5, 0x6e, 0xc1, 0x4e, 0xe4,
- 0x34, 0x57, 0x10, 0xe3, 0xfa, 0xe3, 0x59, 0xec,
- 0xb7, 0x5c, 0xe9, 0xfd, 0x9e, 0x10, 0x03, 0x4a,
- 0x9d, 0x2d, 0x53, 0xe7, 0xa7, 0x52, 0x09, 0xff,
- 0xbb, 0xcf, 0xf7, 0xef, 0xa5, 0x87, 0x0e, 0x9f,
- 0x67, 0xb6, 0x1c, 0x3a, 0x75, 0xeb, 0xeb, 0x1f,
- 0x55, 0xd1, 0x27, 0xc2, 0x9d, 0xc8, 0x68, 0xa7,
- 0xa1, 0xb8, 0x8f, 0xb5, 0x84, 0xbe, 0x1a, 0x4f,
- 0xfe, 0xe7, 0xbb, 0x6f, 0xf0, 0x6b, 0x55, 0x01,
- 0xd0, 0xe4, 0x40, 0xec, 0x6f, 0x39, 0xdb, 0x61,
- 0xd3, 0xe5, 0x78, 0x34, 0x79, 0xd3, 0xc9, 0xdc,
- 0x86, 0x8a, 0xce, 0x1a, 0x3d, 0x31, 0x28, 0x9f,
- 0xa8, 0x62, 0xfd, 0xf5, 0x3a, 0x72, 0xd1, 0xe3,
- 0xa7, 0xd7, 0x06, 0xff, 0xbc, 0xe9, 0xf6, 0x35,
- 0x46, 0x80, 0x3a, 0x4e, 0xc4, 0x60, 0x09, 0x15,
- 0x8b, 0xb8, 0x73, 0x79, 0x54, 0xff, 0xce, 0xe7,
- 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x22, 0xcf, 0xe7,
- 0x60, 0xa7, 0x72, 0x1a, 0x2c, 0x99, 0xfc, 0xec,
- 0x14, 0xee, 0x43, 0x45, 0xb1, 0x3b, 0x2b, 0x87,
- 0x4f, 0x85, 0x3b, 0x90, 0xd1, 0x6d, 0xc9, 0xcf,
- 0x3c, 0xac, 0x1a, 0x9f, 0xf3, 0x71, 0xb9, 0xaa,
- 0xd7, 0xb6, 0x7d, 0x40, 0x74, 0xfc, 0xbf, 0x7e,
- 0xda, 0x30, 0xe9, 0xf0, 0xa7, 0x72, 0x1a, 0x2f,
- 0x09, 0xeb, 0xea, 0x65, 0x8e, 0x9f, 0xf9, 0x77,
- 0xb2, 0x97, 0xdf, 0x3f, 0x7a, 0x9d, 0x3e, 0xcf,
- 0x81, 0xbd, 0x4e, 0x9f, 0x2e, 0xfd, 0x3a, 0xa7,
- 0x4e, 0xba, 0x80, 0xe9, 0x3b, 0x55, 0xe4, 0xe1,
- 0x28, 0x4d, 0xc2, 0xfa, 0x4c, 0x2c, 0x48, 0x04,
- 0x7f, 0x94, 0xdc, 0xa6, 0x77, 0xb2, 0x93, 0xa7,
- 0xc2, 0x9d, 0xc8, 0x68, 0xbd, 0x27, 0xfd, 0xfe,
- 0xbb, 0xd7, 0x5d, 0xfd, 0x41, 0xd3, 0xec, 0x65,
- 0xbb, 0x63, 0xa4, 0xed, 0x91, 0x69, 0x83, 0x9b,
- 0xcc, 0x1b, 0xd0, 0x61, 0x59, 0x0f, 0x94, 0x42,
- 0xd7, 0x23, 0xf0, 0x42, 0x4f, 0x46, 0x5e, 0x29,
- 0xec, 0x4c, 0x01, 0xdf, 0xe1, 0x0b, 0xa4, 0x75,
- 0x61, 0x8c, 0xda, 0x7b, 0x2d, 0xd7, 0x3a, 0x7f,
- 0x67, 0x84, 0x00, 0xd2, 0xa7, 0x4b, 0x54, 0xf9,
- 0xe9, 0xd4, 0x82, 0x7c, 0x29, 0xdc, 0x86, 0x88,
- 0x8e, 0x7f, 0xfa, 0xda, 0x56, 0xb8, 0xcf, 0xe3,
- 0x6d, 0xca, 0xdd, 0x4e, 0x9f, 0xf3, 0xd6, 0x81,
- 0xcb, 0xdf, 0xd7, 0x3a, 0x7f, 0xff, 0x96, 0xdd,
- 0xeb, 0xad, 0xbf, 0x97, 0xb7, 0xad, 0x9e, 0x09,
- 0xd3, 0x50, 0xc2, 0xa6, 0x08, 0x4a, 0x9f, 0xf9,
- 0xee, 0x4b, 0x79, 0xab, 0x2d, 0x0e, 0x01, 0xad,
- 0x08, 0xbc, 0xfe, 0xcd, 0x5f, 0xf2, 0xdd, 0x73,
- 0xa7, 0xff, 0xe4, 0x70, 0xf7, 0xfd, 0x77, 0x0a,
- 0xdf, 0xfc, 0x03, 0xa1, 0xb8, 0xa9, 0xc7, 0x0b,
- 0x50, 0xc2, 0x95, 0xa1, 0x3e, 0xe8, 0x49, 0x5d,
- 0x75, 0xb1, 0xac, 0xf8, 0x53, 0xb9, 0x0d, 0x11,
- 0x74, 0xfa, 0xe0, 0xdf, 0xf7, 0x96, 0xcf, 0x69,
- 0x3b, 0x0f, 0x9f, 0x8c, 0x21, 0xc9, 0x84, 0x3e,
- 0x1c, 0x53, 0xff, 0x33, 0x9e, 0xec, 0x14, 0xee,
- 0x43, 0x44, 0xcd, 0x3a, 0x95, 0xa9, 0xd3, 0x93,
- 0xcc, 0x3a, 0x76, 0xaa, 0xd4, 0xd5, 0x47, 0x4f,
- 0x93, 0xad, 0xe6, 0x8e, 0x9f, 0xf9, 0xbf, 0xd7,
- 0xf2, 0x7b, 0x6b, 0xe2, 0x1d, 0x3f, 0xff, 0xda,
- 0x77, 0xd3, 0xf9, 0xb5, 0xb4, 0xdd, 0x65, 0x78,
- 0xad, 0x07, 0x46, 0x22, 0xc6, 0xc8, 0xf3, 0xff,
- 0xed, 0xbd, 0xfa, 0x32, 0xbe, 0xeb, 0x38, 0x21,
- 0x09, 0x53, 0xc9, 0xdc, 0x86, 0x8b, 0x3e, 0x7f,
- 0xfb, 0xc3, 0x6e, 0xdd, 0x8d, 0xbf, 0x95, 0xcf,
- 0x9d, 0x38, 0x21, 0x09, 0x53, 0xfe, 0xe7, 0xd7,
- 0xf8, 0x9b, 0x60, 0x94, 0xe2, 0xf2, 0x7f, 0x96,
- 0xde, 0xdb, 0xfd, 0xcd, 0x1d, 0x3f, 0xde, 0xfe,
- 0xdb, 0xf6, 0xd2, 0xf5, 0x3a, 0x11, 0x3b, 0x31,
- 0x58, 0xb1, 0x58, 0x1b, 0x6e, 0x96, 0xd8, 0xe6,
- 0x7f, 0xff, 0xfe, 0xcc, 0x05, 0x73, 0x3f, 0xaf,
- 0x78, 0xfd, 0x72, 0xce, 0xaf, 0xf2, 0x86, 0x63,
- 0x0e, 0x9d, 0x55, 0xa0, 0xe9, 0xda, 0x99, 0x63,
- 0xa1, 0xe8, 0xc4, 0xac, 0x22, 0xae, 0x39, 0x3d,
- 0x48, 0x34, 0x43, 0xa7, 0xd6, 0xfa, 0xe0, 0x99,
- 0x3f, 0xef, 0x0b, 0xf0, 0x68, 0xd3, 0xb6, 0x34,
- 0x41, 0xae, 0x34, 0xb3, 0xee, 0x4f, 0x31, 0x4e,
- 0x9f, 0x9f, 0x6f, 0xf5, 0x37, 0x3a, 0x58, 0x87,
- 0xa7, 0xf2, 0x59, 0xff, 0xff, 0x70, 0x6f, 0x96,
- 0xba, 0xe7, 0xe9, 0xbe, 0x0f, 0xa8, 0xe6, 0x1d,
- 0x0f, 0x4d, 0x03, 0x21, 0x5f, 0xf2, 0x69, 0xf8,
- 0x73, 0x6a, 0xd9, 0x4e, 0x9f, 0xff, 0xda, 0x7f,
- 0xb5, 0xee, 0xdf, 0xfe, 0xbd, 0x7d, 0x4d, 0xbc,
- 0x13, 0xa7, 0xff, 0xfa, 0xb5, 0x51, 0xba, 0xb9,
- 0x99, 0x7a, 0xef, 0xaf, 0x3f, 0x0e, 0x9e, 0xb6,
- 0x79, 0xb1, 0xd1, 0xe4, 0x44, 0xd9, 0x9a, 0x66,
- 0x6a, 0x86, 0x8b, 0xf2, 0x7f, 0xe7, 0xdf, 0x47,
- 0xbd, 0x97, 0xba, 0xb0, 0xe9, 0xff, 0xbd, 0x9f,
- 0xcc, 0xae, 0xe7, 0xd5, 0x87, 0x45, 0x28, 0x8b,
- 0xaa, 0x34, 0xf7, 0xfe, 0xa8, 0x74, 0x2a, 0x63,
- 0x5b, 0x11, 0xe4, 0x2c, 0xf8, 0x92, 0x7f, 0xff,
- 0xe6, 0xf5, 0xb7, 0x98, 0xe6, 0x9f, 0xc3, 0xbe,
- 0xde, 0xa6, 0xa9, 0xea, 0x0e, 0x9f, 0x69, 0x95,
- 0xf7, 0xce, 0x9e, 0xdf, 0xa7, 0x54, 0xe9, 0xff,
- 0x5e, 0xa0, 0xf5, 0x34, 0xbf, 0x2e, 0x74, 0x29,
- 0xf2, 0xe1, 0x24, 0xcd, 0x68, 0x74, 0x98, 0x74,
- 0x52, 0x6a, 0x1b, 0xb1, 0x89, 0xff, 0xff, 0x5b,
- 0xd4, 0xdf, 0x29, 0xb8, 0x8a, 0xdc, 0x1b, 0xfe,
- 0xfb, 0x61, 0xd3, 0x82, 0x10, 0x95, 0x3d, 0xb6,
- 0xdd, 0xf2, 0x9c, 0x5e, 0x4f, 0xfb, 0xac, 0x9e,
- 0xed, 0xd5, 0xeb, 0x1d, 0x0a, 0x99, 0x12, 0x13,
- 0xfa, 0x11, 0x76, 0x32, 0x9f, 0xfb, 0x3f, 0x4d,
- 0xf0, 0x7d, 0x47, 0x30, 0xe9, 0xf6, 0x5d, 0xec,
- 0xb1, 0xd0, 0xa7, 0xd7, 0x54, 0x49, 0x81, 0x63,
- 0xa7, 0xea, 0x1a, 0x7b, 0x70, 0x68, 0x3a, 0x7f,
- 0x6b, 0xb6, 0x5e, 0xde, 0xb9, 0xd3, 0x78, 0x4e,
- 0x8d, 0x54, 0x7f, 0xde, 0x34, 0xb1, 0xac, 0xff,
- 0xed, 0xb6, 0x5d, 0x85, 0x6f, 0xe4, 0xf6, 0xc7,
- 0x49, 0xcd, 0xd1, 0x99, 0xd5, 0xaa, 0xc3, 0x8a,
- 0x37, 0x41, 0x5e, 0xd0, 0xd8, 0xc8, 0xf5, 0x69,
- 0x8c, 0x73, 0xc6, 0xad, 0x47, 0x10, 0x26, 0xac,
- 0x2c, 0xb4, 0xa0, 0xde, 0x41, 0x03, 0xd7, 0xe1,
- 0x1b, 0x58, 0xda, 0xaf, 0x0a, 0xc0, 0x90, 0xea,
- 0x42, 0x53, 0x79, 0xac, 0x39, 0x9d, 0x25, 0x6a,
- 0x69, 0xb4, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14,
- 0xee, 0x43, 0x44, 0xd9, 0x3f, 0x9d, 0x82, 0x9d,
- 0xc8, 0x68, 0xab, 0x67, 0xf3, 0xdf, 0xa5, 0xfe,
- 0xaf, 0x3a, 0x7b, 0x2d, 0xd7, 0x3a, 0x5a, 0xa6,
- 0x1e, 0xa7, 0xcd, 0x27, 0xc2, 0x9d, 0xc8, 0x68,
- 0xad, 0x27, 0xff, 0x91, 0x47, 0x01, 0xcc, 0xe7,
- 0xaf, 0x90, 0xe9, 0xff, 0xe7, 0xd7, 0x3e, 0xac,
- 0xec, 0xbd, 0xd5, 0x87, 0x4d, 0x7b, 0xaa, 0x25,
- 0xf9, 0x2a, 0x7f, 0x2b, 0x6d, 0xf7, 0xfa, 0x80,
- 0xe9, 0xfa, 0x8c, 0xb7, 0xb1, 0x87, 0x4f, 0xf6,
- 0x37, 0xfd, 0x43, 0x4b, 0xea, 0x74, 0xfe, 0x7e,
- 0x5f, 0xbe, 0x0d, 0x0e, 0x93, 0x9b, 0x89, 0xf9,
- 0x61, 0x67, 0xa1, 0x8f, 0x62, 0xde, 0x36, 0xf9,
- 0x6d, 0xcf, 0x27, 0xf3, 0xb0, 0x53, 0xb9, 0x0d,
- 0x16, 0x04, 0xf8, 0x53, 0xb9, 0x0d, 0x13, 0xac,
- 0xff, 0xfe, 0xb2, 0xd1, 0xb6, 0x31, 0xd5, 0xae,
- 0x5b, 0xd5, 0xd2, 0x83, 0xa7, 0xce, 0x67, 0x3d,
- 0xd8, 0x89, 0x56, 0x8c, 0x27, 0xc2, 0x9d, 0xc8,
- 0x68, 0xb6, 0x67, 0xfc, 0x05, 0xab, 0xad, 0xe4,
- 0xe1, 0x3a, 0x4e, 0xc3, 0xec, 0xe3, 0x09, 0xe4,
- 0xee, 0x43, 0x45, 0xcd, 0x26, 0x1d, 0x33, 0xb0,
- 0x4d, 0xd8, 0x4a, 0xe7, 0xf3, 0xb0, 0x53, 0xb9,
- 0x0d, 0x17, 0x7c, 0xf3, 0xb5, 0xec, 0x03, 0xa1,
- 0x5b, 0x49, 0x8c, 0xa7, 0x5d, 0xa1, 0x85, 0x2a,
- 0x5e, 0x95, 0x02, 0x2e, 0x4c, 0x86, 0x80, 0x21,
- 0x59, 0x56, 0x1b, 0x95, 0xef, 0x3b, 0x9f, 0xf7,
- 0xf9, 0xcb, 0x5a, 0xb3, 0x9e, 0x74, 0xfe, 0xfd,
- 0x18, 0xdf, 0x75, 0xd6, 0x74, 0xf8, 0x53, 0xb9,
- 0x0d, 0x12, 0xbc, 0xf6, 0x9c, 0x2f, 0x3a, 0x7f,
- 0xff, 0x7a, 0xfc, 0xce, 0xf8, 0x2c, 0x1e, 0xfd,
- 0x09, 0xea, 0x0e, 0x95, 0xb6, 0x44, 0x1f, 0x10,
- 0xce, 0xe7, 0xb9, 0x53, 0x14, 0xc3, 0x8a, 0xc2,
- 0xce, 0x75, 0xd7, 0x62, 0xa7, 0xff, 0x5b, 0xbd,
- 0x75, 0x7f, 0x86, 0x8d, 0x00, 0x54, 0xfe, 0xe4,
- 0x76, 0xc2, 0xdd, 0xb9, 0x4f, 0x9e, 0xa3, 0x92,
- 0x72, 0x2a, 0x4b, 0x64, 0x6a, 0x2d, 0xa1, 0x59,
- 0x3f, 0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90,
- 0xd1, 0x30, 0xcf, 0xff, 0xd8, 0xed, 0xe3, 0xc0,
- 0x76, 0xbb, 0xbc, 0x2b, 0x57, 0x9d, 0x3f, 0xf6,
- 0xa9, 0x94, 0xbf, 0x4e, 0xbf, 0xd5, 0xe7, 0x4f,
- 0xf7, 0xd7, 0xa8, 0xbe, 0xbe, 0x13, 0xa7, 0xe6,
- 0x2e, 0x7e, 0xfa, 0x87, 0x4f, 0x97, 0x3f, 0x7d,
- 0x43, 0xa7, 0xeb, 0x7a, 0xf5, 0xea, 0x77, 0x1e,
- 0xc3, 0x0b, 0xe7, 0xff, 0xfd, 0xfc, 0x0b, 0x7d,
- 0xf2, 0xdb, 0xbf, 0x94, 0x7b, 0x3f, 0x4b, 0xea,
- 0x74, 0xfc, 0xdb, 0x7d, 0xfe, 0xa0, 0x3a, 0x7f,
- 0xf2, 0xdc, 0x0a, 0xfc, 0xa6, 0xf4, 0x68, 0x13,
- 0xa1, 0x4f, 0xf7, 0xc6, 0x33, 0xf5, 0x7d, 0xad,
- 0x9d, 0x73, 0xa7, 0xff, 0xfc, 0x38, 0xd9, 0x7f,
- 0x7d, 0xdb, 0xfe, 0xb6, 0xef, 0x5d, 0x6f, 0x53,
- 0xa5, 0x94, 0xa2, 0x7c, 0x4b, 0xe7, 0xbe, 0xa0,
- 0xde, 0x74, 0xf7, 0x6f, 0xdb, 0x0e, 0x93, 0x9b,
- 0x8a, 0xd0, 0x76, 0x4a, 0x48, 0x48, 0xb4, 0x91,
- 0x68, 0x78, 0x7e, 0x18, 0x17, 0x28, 0xd0, 0x8e,
- 0x7c, 0x29, 0xdc, 0x86, 0x8a, 0xba, 0x7f, 0x9e,
- 0xec, 0x14, 0xee, 0x43, 0x44, 0x79, 0x27, 0x61,
- 0xf8, 0xf1, 0x84, 0xfe, 0x76, 0x0a, 0x77, 0x21,
- 0xa2, 0xc1, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
- 0x59, 0x53, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b,
- 0x4e, 0x79, 0x3b, 0x90, 0xd1, 0x6e, 0x4f, 0xfc,
- 0xb8, 0x39, 0xfd, 0xd6, 0xca, 0x42, 0x74, 0x09,
- 0xf7, 0xd4, 0xae, 0x7f, 0xdc, 0xf7, 0x60, 0xa7,
- 0x72, 0x1a, 0x28, 0x79, 0xfb, 0xed, 0xcc, 0x15,
- 0xa9, 0xd3, 0xff, 0xf6, 0x6d, 0x65, 0xde, 0xeb,
- 0xff, 0x81, 0x5a, 0xa8, 0x0a, 0x93, 0xb1, 0x1e,
- 0x6c, 0x21, 0xd1, 0x1b, 0x50, 0xbe, 0x7f, 0x3b,
- 0x05, 0x3b, 0x90, 0xd1, 0x79, 0xc2, 0xaf, 0xf7,
- 0x3d, 0x13, 0x65, 0x2c, 0x97, 0x3f, 0x4c, 0x3f,
- 0xc4, 0x99, 0x87, 0x76, 0x3b, 0xfc, 0x73, 0xad,
- 0x91, 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x14,
- 0xb4, 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xc2,
- 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x59, 0x73,
- 0xce, 0xd7, 0xaa, 0xf9, 0xba, 0x9d, 0x39, 0xdb,
- 0xd8, 0x74, 0xf2, 0x39, 0x6a, 0x87, 0xa5, 0xa1,
- 0xa4, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee,
- 0x43, 0x45, 0x19, 0x3f, 0x9c, 0xad, 0x94, 0x54,
- 0x07, 0x43, 0xd3, 0xbf, 0x13, 0xb6, 0x1d, 0xf4,
- 0x23, 0x6a, 0x71, 0x75, 0x29, 0xff, 0x9d, 0xcf,
- 0x76, 0x0a, 0x77, 0x21, 0xa2, 0x39, 0x9f, 0xfc,
- 0xe6, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9c,
- 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x16, 0x64,
- 0xfe, 0x76, 0x0a, 0x77, 0x21, 0xa2, 0xdd, 0x9f,
- 0xfc, 0xe6, 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68,
- 0xa4, 0x27, 0xfe, 0x77, 0x3d, 0xd8, 0x29, 0xdc,
- 0x86, 0x89, 0x4a, 0x28, 0x4e, 0xc9, 0xa4, 0xc6,
- 0x29, 0x7c, 0xee, 0xe7, 0x6d, 0xea, 0x53, 0xfe,
- 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x3b, 0x4f,
- 0xff, 0xbd, 0xb6, 0x8c, 0x56, 0xfe, 0xdb, 0xeb,
- 0xfc, 0x43, 0xa4, 0xe6, 0x22, 0x7f, 0x91, 0xa7,
- 0xfe, 0xe6, 0x5b, 0x13, 0xac, 0xbb, 0xde, 0x74,
- 0xff, 0xdf, 0xcb, 0x75, 0x19, 0x5f, 0xf5, 0x27,
- 0x4d, 0xa8, 0xed, 0x91, 0x0f, 0x54, 0x38, 0x62,
- 0x38, 0xb5, 0x21, 0x5f, 0x3e, 0x14, 0xee, 0x43,
- 0x44, 0x59, 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9,
- 0x0d, 0x12, 0xec, 0xff, 0xfd, 0x9b, 0x59, 0x77,
- 0xba, 0xff, 0xe0, 0x56, 0xaa, 0x02, 0xa4, 0xec,
- 0x46, 0x9b, 0x0c, 0x35, 0x11, 0xa7, 0xff, 0x39,
- 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x26, 0x29,
- 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45, 0x53, 0x3f,
- 0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1,
- 0x3a, 0x4f, 0xef, 0x70, 0xab, 0xf9, 0xb1, 0xd3,
- 0xe6, 0x95, 0xa5, 0xa9, 0xd3, 0xf0, 0x73, 0xcd,
- 0xb3, 0xe7, 0x4f, 0x7a, 0xca, 0xef, 0x1e, 0xb5,
- 0x4a, 0x27, 0xfe, 0xd2, 0xb7, 0x5a, 0x5d, 0xa3,
- 0x5e, 0x61, 0xd0, 0xc4, 0x41, 0x58, 0xe6, 0x7f,
- 0xdc, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27, 0x79,
- 0xf5, 0xf4, 0xe6, 0x78, 0xa9, 0x3b, 0x64, 0xe6,
- 0xf2, 0x30, 0xa6, 0x11, 0xf2, 0x34, 0xff, 0xe7,
- 0x33, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x45, 0x0b,
- 0x3f, 0xf9, 0xcc, 0xe7, 0xbb, 0x05, 0x3b, 0x90,
- 0xd1, 0x49, 0x4f, 0xff, 0xec, 0xab, 0xb7, 0xe3,
- 0x56, 0xe6, 0x5e, 0xcb, 0x7d, 0x18, 0x74, 0x50,
- 0xb8, 0x06, 0xf3, 0x84, 0x52, 0x13, 0xb6, 0x47,
- 0xda, 0x04, 0x9d, 0x14, 0xb5, 0x14, 0xa7, 0xf3,
- 0xb0, 0x53, 0xb9, 0x0d, 0x11, 0x24, 0xff, 0xe7,
- 0x33, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0xbd,
- 0x3e, 0x14, 0xee, 0x43, 0x45, 0x2f, 0x3f, 0x97,
- 0x66, 0xff, 0x31, 0x6a, 0x74, 0x9d, 0x87, 0xcd,
- 0x73, 0x09, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
- 0x39, 0x3f, 0xef, 0x0f, 0x56, 0xd9, 0x9f, 0x43,
- 0xa7, 0xfd, 0x96, 0x51, 0xc7, 0x04, 0x21, 0x2a,
- 0x6f, 0x04, 0xe9, 0xa8, 0x76, 0xc8, 0x8d, 0xd4,
- 0x3b, 0x6f, 0x3c, 0x9f, 0x0a, 0x77, 0x21, 0xa2,
- 0xbc, 0x9f, 0xff, 0xb3, 0x6b, 0x2e, 0xf7, 0x5f,
- 0xfc, 0x0a, 0xd5, 0x40, 0x54, 0x9d, 0x88, 0x8d,
- 0xd4, 0x30, 0x9f, 0xf9, 0xdc, 0xf7, 0x60, 0xa7,
- 0x72, 0x1a, 0x24, 0x79, 0xde, 0x02, 0x9d, 0x39,
- 0x31, 0x85, 0x38, 0xbb, 0x9f, 0x0a, 0x77, 0x21,
- 0xa2, 0x48, 0x9e, 0x77, 0x3d, 0xca, 0x7b, 0x38,
- 0x53, 0x3f, 0xf3, 0xb9, 0xee, 0xc1, 0x4e, 0xe4,
- 0x34, 0x49, 0x53, 0xe1, 0x4e, 0xe4, 0x34, 0x5e,
- 0x33, 0xf6, 0x9f, 0xa7, 0xa9, 0xa9, 0xd3, 0xea,
- 0xd6, 0xf8, 0x87, 0x4f, 0xf3, 0xdd, 0x82, 0x9d,
- 0xc8, 0x68, 0x93, 0x64, 0xec, 0x46, 0x3d, 0x26,
- 0x02, 0x61, 0xc4, 0xd0, 0xab, 0xa5, 0x34, 0x1d,
- 0xbe, 0x17, 0x1b, 0x13, 0xfa, 0x19, 0x0d, 0x43,
- 0x45, 0x85, 0x76, 0x86, 0x05, 0xcd, 0xf4, 0x8c,
- 0x4e, 0x16, 0x36, 0x9d, 0x1a, 0x23, 0xae, 0x7c,
- 0x79, 0x3b, 0x47, 0xb5, 0x96, 0xe4, 0x47, 0x5c,
- 0xa5, 0x64, 0xaf, 0xb3, 0x69, 0x9e, 0x7b, 0xf4,
- 0xe6, 0x26, 0xae, 0x3b, 0x06, 0xa9, 0xa9, 0xe3,
- 0x48, 0xf0, 0x66, 0x22, 0x86, 0x2d, 0x3b, 0x51,
- 0xd4, 0xe7, 0x80, 0x4b, 0x0e, 0x6e, 0xe1, 0x63,
- 0xf9, 0xe4, 0x8a, 0xd2, 0x4c, 0xef, 0x5c, 0x90,
- 0x69, 0x4a, 0xef, 0x6d, 0x29, 0x80, 0x32, 0x83,
- 0x75, 0x23, 0xde, 0xdf, 0x3a, 0x02, 0xdf, 0x3b,
- 0x4d, 0x00,
+ 0x9e, 0x15, 0x3c, 0xaa, 0x0e, 0xde, 0xa5, 0xe8,
+ 0x47, 0xb0, 0xe2, 0xe7, 0x73, 0xf9, 0xd8, 0x29,
+ 0xdc, 0x86, 0x88, 0x7a, 0x7c, 0x29, 0xdc, 0x86,
+ 0x88, 0x9a, 0x6b, 0xb0, 0xe9, 0xff, 0xd9, 0x6d,
+ 0xf4, 0x55, 0x7d, 0x4d, 0xd5, 0x87, 0x45, 0x27,
+ 0xc7, 0x61, 0x69, 0xeb, 0xeb, 0xdb, 0xcd, 0x10,
+ 0xbc, 0x9d, 0x88, 0xe7, 0xac, 0x24, 0xf5, 0x23,
+ 0x9e, 0xbd, 0xbd, 0x73, 0xa7, 0xff, 0x79, 0xa7,
+ 0xe5, 0x2f, 0xd0, 0xce, 0xef, 0x9d, 0x37, 0x37,
+ 0x9d, 0x2d, 0xd3, 0x11, 0x0f, 0x62, 0x2e, 0x4d,
+ 0x9f, 0x5b, 0xaf, 0xcf, 0x3a, 0x7b, 0xd5, 0xf0,
+ 0x0e, 0x9c, 0x10, 0x84, 0xa9, 0xf7, 0x7e, 0xf6,
+ 0xc2, 0x9c, 0x5e, 0x4f, 0xba, 0xed, 0x65, 0xce,
+ 0x8d, 0x91, 0x34, 0x03, 0xef, 0x9a, 0xcf, 0xfc,
+ 0x0f, 0x35, 0xa2, 0xcb, 0xe1, 0xd7, 0x76, 0x74,
+ 0xff, 0xbd, 0xa5, 0x7e, 0xb5, 0x5f, 0x30, 0xe9,
+ 0xfb, 0x1b, 0x6a, 0xfc, 0xa9, 0xd3, 0xd9, 0xb6,
+ 0x50, 0x74, 0x62, 0x79, 0xbe, 0x86, 0x03, 0x46,
+ 0x36, 0x4c, 0xf9, 0xfd, 0xcb, 0xe7, 0xec, 0x0a,
+ 0xe6, 0xde, 0x3a, 0x7f, 0xff, 0xf7, 0xff, 0x4a,
+ 0xe9, 0xfe, 0x6d, 0x6f, 0x35, 0xa2, 0xb9, 0x4b,
+ 0xc7, 0x02, 0x74, 0xfb, 0xd7, 0xd5, 0x68, 0x3a,
+ 0x7f, 0x52, 0xfa, 0xe9, 0xd5, 0x69, 0x3a, 0x7f,
+ 0x70, 0x75, 0x69, 0x6f, 0xc7, 0x47, 0x8f, 0xaf,
+ 0xe7, 0x10, 0xa9, 0x9a, 0xe3, 0xf8, 0xc2, 0x52,
+ 0x6d, 0x5e, 0x74, 0xee, 0xbd, 0x4e, 0x9b, 0x5a,
+ 0x0e, 0x9e, 0x5f, 0xdd, 0xa7, 0x9b, 0x31, 0x1b,
+ 0x9f, 0xff, 0x6a, 0xb7, 0xd1, 0xfd, 0x5b, 0xf4,
+ 0x65, 0xf7, 0x32, 0xe7, 0x4f, 0xfd, 0x65, 0xd3,
+ 0xa2, 0xff, 0xeb, 0xad, 0xce, 0x9f, 0xda, 0x29,
+ 0x7f, 0xad, 0xab, 0x0e, 0x80, 0x1f, 0xff, 0xd1,
+ 0xe7, 0xfc, 0x2d, 0x68, 0xaa, 0xfa, 0x8e, 0xb9,
+ 0xd0, 0xa7, 0xc7, 0xa9, 0x14, 0xff, 0xff, 0xf6,
+ 0xbf, 0xa8, 0xfd, 0x5a, 0xd1, 0xbe, 0xfe, 0x7e,
+ 0x53, 0x7c, 0x6d, 0xfc, 0xa9, 0xd2, 0x53, 0xa7,
+ 0xf3, 0xf8, 0x7d, 0x55, 0xa4, 0xe9, 0xff, 0xff,
+ 0xfd, 0xe0, 0x57, 0xf9, 0xd4, 0xe8, 0xda, 0xda,
+ 0xe8, 0xfe, 0x52, 0xfc, 0xd6, 0x8f, 0xe7, 0x52,
+ 0x74, 0xee, 0xe4, 0x34, 0x53, 0x11, 0x88, 0xbf,
+ 0x48, 0x4c, 0xcf, 0xfb, 0x3f, 0x4b, 0xeb, 0x75,
+ 0x16, 0x8e, 0x9f, 0x53, 0xfc, 0x6d, 0x87, 0x47,
+ 0x8f, 0xa3, 0x8f, 0xe7, 0xfb, 0x99, 0xb5, 0x96,
+ 0x8c, 0x09, 0xd3, 0xff, 0xfb, 0xf8, 0x97, 0xba,
+ 0xde, 0xad, 0x7f, 0x03, 0xa1, 0x5b, 0xa9, 0xd3,
+ 0xfe, 0x45, 0x65, 0xb2, 0xb9, 0xef, 0x9d, 0x0a,
+ 0x8a, 0x4b, 0x34, 0x4f, 0x85, 0x5b, 0x28, 0x9d,
+ 0x3f, 0x77, 0xf4, 0x6c, 0xbf, 0x3a, 0x30, 0xfd,
+ 0xfc, 0x45, 0xa9, 0x34, 0x50, 0xbb, 0x3f, 0xb2,
+ 0x56, 0x93, 0x84, 0x8d, 0x0e, 0x92, 0x2f, 0x42,
+ 0x19, 0xa0, 0xf1, 0x87, 0x8b, 0x21, 0x1d, 0xf2,
+ 0x1b, 0xc6, 0xa9, 0x3f, 0xed, 0x23, 0xc1, 0xd1,
+ 0xdb, 0x75, 0x07, 0x4f, 0x67, 0xf4, 0xee, 0xce,
+ 0x9f, 0xff, 0xff, 0x5b, 0xd7, 0xb6, 0x0a, 0xb6,
+ 0xd0, 0xcd, 0x5b, 0xf4, 0x65, 0x2f, 0xcd, 0x7e,
+ 0x0a, 0x9d, 0x2b, 0xf9, 0x16, 0xd5, 0x27, 0x9f,
+ 0xff, 0x66, 0x5b, 0xc9, 0x6c, 0xd1, 0x5d, 0x6c,
+ 0xbb, 0xb3, 0xa7, 0xff, 0xaf, 0x6c, 0x06, 0x86,
+ 0x2e, 0x5f, 0x6c, 0xf9, 0xd3, 0xfd, 0x4e, 0x86,
+ 0x2e, 0x7e, 0xfb, 0x87, 0x4a, 0xb8, 0x88, 0xfe,
+ 0x51, 0x97, 0xbe, 0x98, 0x85, 0xe1, 0xd3, 0x3e,
+ 0x7a, 0xd2, 0xfa, 0x9d, 0x3f, 0xff, 0xff, 0xec,
+ 0xfe, 0x9d, 0x1e, 0xb6, 0xae, 0x6b, 0xd7, 0x56,
+ 0x7f, 0xb4, 0xdb, 0xce, 0xcb, 0x52, 0x05, 0xd8,
+ 0xa9, 0xff, 0xff, 0x93, 0xc1, 0xdb, 0x51, 0xd1,
+ 0xaa, 0xd1, 0x54, 0xb6, 0xb6, 0xa7, 0x82, 0x74,
+ 0xda, 0xd1, 0x4a, 0x68, 0xde, 0x28, 0xac, 0x29,
+ 0x61, 0x55, 0x79, 0xda, 0x33, 0x9f, 0xc6, 0xeb,
+ 0x3f, 0xf9, 0x89, 0xa2, 0xdc, 0xfc, 0x67, 0x7c,
+ 0x07, 0x4f, 0xff, 0xbd, 0xfb, 0xdb, 0x1b, 0xee,
+ 0xd6, 0x6e, 0xfb, 0xe0, 0x3a, 0x7f, 0xe5, 0xfd,
+ 0x1f, 0xc6, 0xd5, 0xd5, 0x69, 0x3a, 0x2a, 0x8a,
+ 0x5d, 0x57, 0x67, 0xb2, 0xf8, 0xdd, 0x9d, 0x3b,
+ 0x73, 0x2c, 0x74, 0xd9, 0xb1, 0xd1, 0x42, 0x6d,
+ 0x8f, 0x87, 0x7d, 0x49, 0x2e, 0x4a, 0xd8, 0x7a,
+ 0x7e, 0xd9, 0x7f, 0x6e, 0x79, 0xd3, 0x97, 0x65,
+ 0x3a, 0x7f, 0x34, 0xfc, 0xbd, 0x79, 0xad, 0x07,
+ 0x90, 0xc2, 0xd9, 0xf9, 0xbe, 0xdd, 0xbb, 0x50,
+ 0x1d, 0x3f, 0x85, 0xaf, 0xe5, 0xba, 0xe7, 0x46,
+ 0x1f, 0x2f, 0x8c, 0xe7, 0xe5, 0x06, 0x5f, 0x7d,
+ 0x07, 0x43, 0xcf, 0x43, 0xe4, 0x33, 0xff, 0xfe,
+ 0xbf, 0xf8, 0x15, 0xa3, 0x3d, 0xfb, 0xff, 0x1b,
+ 0x68, 0xa8, 0x7e, 0x74, 0xff, 0xbd, 0x8d, 0x68,
+ 0xaa, 0xdb, 0xb7, 0x67, 0x4f, 0xee, 0xa6, 0xb6,
+ 0xce, 0x13, 0xa3, 0x63, 0xf5, 0xba, 0x24, 0x98,
+ 0x74, 0xef, 0xe6, 0xc7, 0x42, 0x9a, 0xca, 0x44,
+ 0x27, 0xea, 0x6b, 0x99, 0xfd, 0x27, 0x4f, 0x33,
+ 0x7a, 0x80, 0xe8, 0xc3, 0xd2, 0xf1, 0x7c, 0x2a,
+ 0x79, 0x59, 0x0e, 0x7f, 0x27, 0x8b, 0x9c, 0xfe,
+ 0xbf, 0xa8, 0xcb, 0x6b, 0x73, 0xa7, 0xb2, 0x95,
+ 0x68, 0xe9, 0xfa, 0xdc, 0xf6, 0x0f, 0x8e, 0x9f,
+ 0x78, 0x03, 0x94, 0x9d, 0x1a, 0x51, 0x55, 0xe3,
+ 0x50, 0x11, 0x6a, 0x59, 0x3f, 0xff, 0x0b, 0xed,
+ 0x8d, 0x59, 0x7f, 0xa7, 0xf9, 0x7b, 0x6a, 0x74,
+ 0xff, 0xfe, 0xf6, 0x52, 0xfa, 0xde, 0xca, 0xc5,
+ 0xf6, 0xda, 0x15, 0xba, 0x9d, 0x3f, 0xff, 0xfe,
+ 0xd7, 0xfa, 0x03, 0xd4, 0xbc, 0x78, 0x1a, 0x2b,
+ 0xaa, 0xd3, 0x6c, 0xf7, 0xf3, 0x49, 0xd3, 0xff,
+ 0xed, 0x44, 0x72, 0xf5, 0xb7, 0xb3, 0x45, 0x80,
+ 0xa7, 0x46, 0x23, 0x8a, 0xd0, 0x8c, 0x9f, 0xfe,
+ 0x7b, 0x7d, 0xb1, 0x7e, 0xd7, 0xf2, 0xf5, 0xe3,
+ 0xa7, 0xff, 0xdb, 0x63, 0x34, 0x37, 0xdd, 0x6a,
+ 0xd3, 0xf8, 0x68, 0x3a, 0x7f, 0xb3, 0xf4, 0x68,
+ 0x07, 0x73, 0x47, 0x4f, 0xfa, 0xba, 0xff, 0x45,
+ 0x75, 0xdc, 0xd4, 0x4e, 0x9f, 0xfd, 0x46, 0x8a,
+ 0xdb, 0x5d, 0x17, 0xad, 0x54, 0x4e, 0x9f, 0xff,
+ 0xf6, 0x53, 0x5f, 0x60, 0x74, 0x5b, 0x2f, 0x5c,
+ 0xa3, 0x46, 0x7b, 0x63, 0xa3, 0x11, 0x85, 0xe5,
+ 0x08, 0xa1, 0x5c, 0x3a, 0x46, 0x99, 0x49, 0x3f,
+ 0x94, 0x98, 0xb9, 0x53, 0xbb, 0xc6, 0x13, 0x3f,
+ 0xee, 0x1b, 0x65, 0xd7, 0xfe, 0x01, 0xd3, 0xfd,
+ 0x81, 0xa5, 0xf5, 0xd1, 0x7f, 0x1d, 0x3f, 0xff,
+ 0xe5, 0x45, 0x66, 0x86, 0xad, 0xef, 0xed, 0xa3,
+ 0x7a, 0x7f, 0x2d, 0x87, 0x42, 0x23, 0xab, 0xe7,
+ 0x8d, 0xe7, 0x93, 0xde, 0xbf, 0x94, 0xe9, 0xff,
+ 0xff, 0xfa, 0xea, 0xcf, 0xfb, 0x4d, 0xb9, 0xad,
+ 0x1f, 0xd5, 0xbf, 0x46, 0x52, 0xfc, 0xd7, 0xe0,
+ 0xa9, 0xd0, 0xf4, 0x5c, 0x78, 0x86, 0x15, 0x79,
+ 0x3f, 0x25, 0xf2, 0xfa, 0x35, 0xde, 0x87, 0x54,
+ 0xf5, 0xeb, 0xc0, 0x3a, 0x7f, 0xeb, 0x7b, 0x47,
+ 0x87, 0x5a, 0x38, 0x50, 0xe9, 0xef, 0x5b, 0xa8,
+ 0x3a, 0x7e, 0xbf, 0x0f, 0xe9, 0xf1, 0xd1, 0x88,
+ 0xb6, 0xd2, 0x42, 0x88, 0xd7, 0x22, 0x9e, 0xdf,
+ 0xaf, 0x54, 0xe9, 0xff, 0xfb, 0xc3, 0xa3, 0x3d,
+ 0x9f, 0xd3, 0x6f, 0x63, 0x31, 0x0e, 0x9f, 0xff,
+ 0xef, 0x50, 0x2a, 0xca, 0xea, 0xba, 0x14, 0x57,
+ 0x6b, 0x2b, 0x0e, 0x8c, 0x46, 0x20, 0xae, 0x4f,
+ 0xff, 0xfe, 0x11, 0xf5, 0x1a, 0x2d, 0x97, 0xfa,
+ 0xb5, 0x6c, 0xa1, 0x69, 0xbe, 0xa8, 0x74, 0xff,
+ 0xff, 0xcb, 0xa6, 0xcb, 0xa3, 0xf9, 0xae, 0x9d,
+ 0x14, 0xbe, 0xbe, 0xfe, 0xf5, 0xa0, 0xe9, 0xf5,
+ 0x35, 0xf6, 0x7c, 0xe8, 0xc4, 0x53, 0xea, 0xff,
+ 0x1e, 0x4d, 0x1a, 0xd1, 0x91, 0xcf, 0xfc, 0xfa,
+ 0xfb, 0x4d, 0x97, 0xd4, 0x2e, 0x93, 0xa7, 0xfb,
+ 0xfa, 0xb5, 0xfc, 0xb7, 0x5c, 0xe9, 0xfe, 0xda,
+ 0xca, 0x1d, 0xad, 0xcc, 0x3a, 0x7f, 0xff, 0xb8,
+ 0x6d, 0x97, 0xf6, 0x7e, 0x8a, 0xae, 0x7f, 0x6b,
+ 0x29, 0xd3, 0xd7, 0xd1, 0x40, 0x9d, 0x14, 0xa2,
+ 0x27, 0x99, 0x67, 0xe6, 0xa9, 0x7e, 0xab, 0x73,
+ 0xa7, 0xfa, 0xdc, 0xcf, 0xe5, 0xba, 0xe7, 0x42,
+ 0x9f, 0x3d, 0x4c, 0x27, 0xec, 0xb8, 0x8e, 0x3c,
+ 0xe9, 0xfb, 0xf9, 0x6f, 0xe2, 0x1d, 0x3d, 0xfc,
+ 0xae, 0x86, 0x8f, 0x56, 0xe5, 0x51, 0xb2, 0xe0,
+ 0x9a, 0x46, 0xcf, 0x49, 0x57, 0x92, 0x44, 0xea,
+ 0xd0, 0xc3, 0xbc, 0x22, 0x9b, 0x3b, 0x4f, 0xfd,
+ 0xff, 0xe6, 0x81, 0xcb, 0x7f, 0x1a, 0x3a, 0x15,
+ 0x77, 0x1b, 0x27, 0x3e, 0xfa, 0x10, 0xd3, 0xef,
+ 0xab, 0x3b, 0x63, 0xa7, 0xf6, 0x35, 0x6c, 0xba,
+ 0xec, 0x74, 0xff, 0xff, 0xf5, 0xb2, 0xf5, 0xe6,
+ 0xb4, 0x7f, 0x29, 0x7e, 0x6b, 0x47, 0xf3, 0x6b,
+ 0x79, 0xa3, 0xa6, 0xd7, 0x49, 0xd0, 0x28, 0x9e,
+ 0xbc, 0x21, 0x67, 0xec, 0xa3, 0xf9, 0x4d, 0x4e,
+ 0x9f, 0xfc, 0x34, 0xbe, 0xb8, 0xca, 0x56, 0xd6,
+ 0x53, 0xa5, 0x53, 0xa3, 0x53, 0xda, 0xde, 0x95,
+ 0x3f, 0x95, 0x9f, 0xcb, 0x75, 0xce, 0x9f, 0xff,
+ 0xf5, 0xfe, 0xa0, 0xa5, 0xf5, 0xd5, 0x6f, 0xfc,
+ 0xdb, 0xd8, 0x2d, 0x1d, 0x1e, 0x54, 0xd8, 0xd1,
+ 0x3f, 0x43, 0x47, 0xe4, 0xf5, 0x84, 0x46, 0xa4,
+ 0xbb, 0xcc, 0x67, 0xcf, 0xf0, 0xe5, 0x27, 0x4f,
+ 0xb2, 0xb4, 0x60, 0x4e, 0x8a, 0x4f, 0x3a, 0xc4,
+ 0xf3, 0xff, 0xef, 0x51, 0x89, 0xb5, 0xbd, 0x9a,
+ 0x74, 0x69, 0xd5, 0x4e, 0x9e, 0x6f, 0xbe, 0x58,
+ 0xe9, 0xff, 0xff, 0x9b, 0xe9, 0x7f, 0x53, 0xa3,
+ 0xfa, 0xb7, 0xe8, 0xca, 0x5f, 0x9a, 0xfc, 0x15,
+ 0x3a, 0x28, 0x45, 0x36, 0x12, 0x4f, 0xff, 0xff,
+ 0x96, 0x9a, 0xea, 0xb4, 0xe8, 0xb6, 0x6d, 0xa3,
+ 0xf9, 0xae, 0x9d, 0x15, 0x00, 0x3d, 0x73, 0xa7,
+ 0xcb, 0xfa, 0x7a, 0x83, 0xa7, 0xff, 0xff, 0xff,
+ 0x63, 0x31, 0x16, 0xca, 0xcb, 0xe5, 0x6a, 0xa2,
+ 0x2b, 0xfc, 0xa3, 0x35, 0xae, 0xad, 0x7d, 0x58,
+ 0x74, 0xff, 0x03, 0x36, 0xfe, 0x5b, 0xae, 0x74,
+ 0xfe, 0xa3, 0x55, 0xbb, 0x3d, 0x73, 0xa7, 0xfc,
+ 0xba, 0x5b, 0xf5, 0xcf, 0xb5, 0xbd, 0x87, 0x46,
+ 0x1f, 0xe5, 0x26, 0xb3, 0xff, 0xd9, 0x7d, 0xb3,
+ 0x01, 0x5d, 0x03, 0x5d, 0xaa, 0x74, 0xf5, 0x1e,
+ 0xfd, 0xce, 0x85, 0x57, 0xe1, 0x84, 0x7e, 0x8c,
+ 0x0c, 0x48, 0xd9, 0x09, 0x1b, 0x14, 0x74, 0x28,
+ 0xff, 0x0b, 0x4a, 0x91, 0x6a, 0xa5, 0x3b, 0x6d,
+ 0x0d, 0x1d, 0x3f, 0xfd, 0x4b, 0xfe, 0xba, 0x19,
+ 0xf5, 0xd3, 0x7f, 0x50, 0x74, 0x61, 0xfb, 0x78,
+ 0x82, 0x7e, 0xa1, 0xa7, 0xb7, 0x06, 0x83, 0xa7,
+ 0xcc, 0xf6, 0xd9, 0xb1, 0xd2, 0x68, 0xe9, 0x95,
+ 0x87, 0x4a, 0xe7, 0x40, 0x9a, 0x5e, 0x15, 0x8d,
+ 0x8f, 0x56, 0xc6, 0xd3, 0xd7, 0xaf, 0x52, 0x74,
+ 0xcd, 0x71, 0xd3, 0xfa, 0xde, 0x1a, 0x5f, 0xf5,
+ 0x3a, 0x37, 0x52, 0x68, 0x0a, 0x69, 0x8f, 0xde,
+ 0x23, 0x61, 0x16, 0xa2, 0xd3, 0xfa, 0xbe, 0xa4,
+ 0x3d, 0xf0, 0x1d, 0x3f, 0xfe, 0x51, 0x54, 0xc6,
+ 0x2a, 0x3f, 0xd5, 0xd5, 0x87, 0x43, 0x48, 0x86,
+ 0xdc, 0x34, 0x9d, 0xfe, 0x61, 0xd3, 0x01, 0x4e,
+ 0x8f, 0x1b, 0x0f, 0x8d, 0xc9, 0xcd, 0xc7, 0x5a,
+ 0x34, 0xb2, 0x81, 0xa8, 0x5d, 0xda, 0x36, 0x1c,
+ 0x9d, 0xd2, 0xd3, 0x0b, 0xa4, 0x97, 0xd7, 0x4c,
+ 0x75, 0x3e, 0x84, 0xdb, 0x51, 0x81, 0x8c, 0x7d,
+ 0x8c, 0x87, 0x55, 0xa7, 0xa3, 0xfa, 0x30, 0x5f,
+ 0xcf, 0x01, 0xd6, 0x55, 0x4d, 0xe7, 0x2c, 0x5b,
+ 0x46, 0x2b, 0xb9, 0x1b, 0x0e, 0xf8, 0x71, 0xb7,
+ 0xab, 0xcf, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x29,
+ 0xd9, 0xf0, 0xa7, 0x72, 0x1a, 0x2a, 0x39, 0xff,
+ 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9a, 0x24,
+ 0xec, 0x3f, 0x66, 0x18, 0x4f, 0xe7, 0x60, 0xa7,
+ 0x72, 0x1a, 0x2a, 0xf9, 0xf0, 0xa7, 0x72, 0x1a,
+ 0x2b, 0x69, 0xfe, 0x7b, 0xb0, 0x53, 0xb9, 0x0d,
+ 0x12, 0x0c, 0x9d, 0x87, 0xe3, 0xc6, 0x13, 0xff,
+ 0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x87,
+ 0x3e, 0x14, 0xee, 0x43, 0x45, 0x89, 0x3e, 0xc1,
+ 0x5f, 0xe9, 0x3a, 0x7f, 0x59, 0x77, 0xee, 0x60,
+ 0xa9, 0xd3, 0xff, 0x2e, 0x57, 0x3f, 0xb7, 0x80,
+ 0xbf, 0x3a, 0x77, 0xd6, 0x83, 0xa4, 0xff, 0x9e,
+ 0xfe, 0xa8, 0x73, 0xb7, 0x3c, 0x03, 0xa7, 0x0a,
+ 0xbc, 0xe9, 0xfd, 0x82, 0xf0, 0x66, 0x34, 0x74,
+ 0xfb, 0x9f, 0xbe, 0xca, 0x74, 0xfd, 0x5a, 0x8f,
+ 0x83, 0xbb, 0x3a, 0x15, 0x11, 0x5e, 0x31, 0xe2,
+ 0x89, 0xff, 0xe7, 0xab, 0x15, 0xfb, 0x7d, 0x6d,
+ 0xd8, 0x27, 0x4f, 0xe4, 0xfe, 0x36, 0xfe, 0x54,
+ 0xe8, 0xa5, 0x10, 0x16, 0x4d, 0x9f, 0xc0, 0x5c,
+ 0xbf, 0xbe, 0x12, 0xa3, 0x15, 0x6d, 0xe9, 0x30,
+ 0x42, 0x7a, 0x61, 0x29, 0xe2, 0x91, 0x1f, 0xb4,
+ 0x29, 0x3a, 0x15, 0xc0, 0x24, 0x9f, 0xfa, 0xde,
+ 0x5b, 0xdb, 0xb4, 0xe7, 0xc0, 0x74, 0xff, 0xf6,
+ 0x52, 0xfb, 0xeb, 0x43, 0xad, 0xcc, 0xf5, 0x4e,
+ 0x9a, 0xce, 0xc4, 0x4c, 0x7d, 0x16, 0x1c, 0x9a,
+ 0xa2, 0xc6, 0x4d, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
+ 0x68, 0xb3, 0x67, 0xff, 0x39, 0x9c, 0xf7, 0x60,
+ 0xa7, 0x72, 0x1a, 0x28, 0x09, 0xfd, 0xfc, 0xb8,
+ 0x37, 0xfd, 0xa3, 0xa6, 0xd1, 0x53, 0xa7, 0x93,
+ 0xb9, 0x0d, 0x16, 0xfc, 0xfd, 0xbe, 0xfc, 0x9c,
+ 0x27, 0x40, 0x9e, 0xb8, 0x0a, 0xe7, 0xd7, 0x7d,
+ 0x77, 0xd4, 0xe9, 0xfc, 0xad, 0xb7, 0xdf, 0xea,
+ 0x03, 0xa7, 0xbb, 0xdf, 0xb9, 0xd3, 0xfb, 0x5a,
+ 0x6a, 0xa9, 0x8c, 0x3a, 0x7a, 0xda, 0x76, 0x61,
+ 0xd3, 0x63, 0xce, 0x8c, 0x37, 0x5f, 0x25, 0x93,
+ 0x95, 0x3d, 0x47, 0x9b, 0x63, 0x78, 0x90, 0xd8,
+ 0xa8, 0x06, 0xdf, 0x21, 0xbb, 0x6c, 0xff, 0xb9,
+ 0xee, 0xc1, 0x4e, 0xe4, 0x34, 0x52, 0x93, 0xfc,
+ 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x24, 0xe9, 0x39,
+ 0x88, 0x87, 0xe4, 0x68, 0x57, 0x74, 0xf3, 0x44,
+ 0x64, 0x5b, 0x5a, 0xdd, 0xcc, 0x8e, 0xa1, 0x21,
+ 0x63, 0xe2, 0x7d, 0xdc, 0x2b, 0x1a, 0x26, 0x64,
+ 0xe3, 0xdd, 0x8a, 0x40, 0x77, 0x59, 0x44, 0xcd,
+ 0xa1, 0xf9, 0x3e, 0x14, 0xee, 0x43, 0x44, 0x3f,
+ 0x3f, 0xee, 0x7b, 0xb0, 0x53, 0xb9, 0x0d, 0x12,
+ 0x9c, 0x9d, 0x87, 0xec, 0xc3, 0x09, 0xfc, 0xec,
+ 0x14, 0xee, 0x43, 0x44, 0x4f, 0x3f, 0x9d, 0x82,
+ 0x9d, 0xc8, 0x68, 0x8c, 0x67, 0xff, 0x39, 0x9c,
+ 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x27, 0x98, 0x54,
+ 0x77, 0xd0, 0x4e, 0xf3, 0xbb, 0x1d, 0xcf, 0x85,
+ 0x3b, 0x90, 0xd1, 0x10, 0x4f, 0xfb, 0x9e, 0xec,
+ 0x14, 0xee, 0x43, 0x44, 0xa9, 0x27, 0x61, 0xfb,
+ 0x30, 0xc2, 0x7f, 0x3b, 0x05, 0x3b, 0x90, 0xd1,
+ 0x14, 0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a, 0x23,
+ 0x29, 0xff, 0xce, 0x67, 0x3d, 0xd8, 0x29, 0xdc,
+ 0x86, 0x89, 0x96, 0x7f, 0x3b, 0x05, 0x3b, 0x90,
+ 0xd1, 0x52, 0x4f, 0xe7, 0x60, 0xa7, 0x72, 0x1a,
+ 0x2b, 0xa9, 0xfc, 0xec, 0x14, 0xee, 0x43, 0x45,
+ 0x8b, 0x3f, 0xf3, 0x39, 0xee, 0xc1, 0x4e, 0xe4,
+ 0x34, 0x4f, 0x53, 0xfc, 0x17, 0x72, 0xfb, 0x73,
+ 0xcd, 0xe7, 0x43, 0x91, 0x14, 0xa9, 0x93, 0xf6,
+ 0xeb, 0xb2, 0xfe, 0xd6, 0xa7, 0x4f, 0x0b, 0x2f,
+ 0x49, 0xd3, 0x93, 0x2c, 0x54, 0xff, 0xfd, 0x6f,
+ 0xf6, 0x9f, 0x0a, 0xbd, 0xf9, 0x50, 0x01, 0x4e,
+ 0x9f, 0xff, 0x87, 0xcd, 0xfc, 0xc7, 0x28, 0x8f,
+ 0x9b, 0xd3, 0x5a, 0x0e, 0x9f, 0x27, 0xad, 0xbd,
+ 0x87, 0x4f, 0xfe, 0xea, 0xff, 0x00, 0xeb, 0x79,
+ 0x38, 0x4e, 0x9f, 0x5e, 0xca, 0xc4, 0x3a, 0x7f,
+ 0xf7, 0xf4, 0x2a, 0xfd, 0x59, 0xa3, 0x45, 0xb7,
+ 0x0e, 0x9b, 0xa9, 0x3a, 0x7f, 0x75, 0x7a, 0xda,
+ 0xfe, 0x83, 0xa3, 0xe7, 0x95, 0xa8, 0xb4, 0x79,
+ 0x50, 0x80, 0xad, 0xb1, 0x82, 0xc5, 0x3f, 0x47,
+ 0xb9, 0x33, 0x7c, 0x27, 0x27, 0x7f, 0xae, 0x6a,
+ 0x85, 0xa7, 0x7f, 0xd5, 0x3a, 0x41, 0xdd, 0x0f,
+ 0x11, 0x4a, 0x27, 0x85, 0xb7, 0x30, 0xe8, 0xc3,
+ 0xce, 0xf1, 0x64, 0xff, 0xbd, 0x6e, 0xba, 0xb5,
+ 0x5f, 0x30, 0xe9, 0xf7, 0xf4, 0xfb, 0x2a, 0x74,
+ 0xff, 0xd8, 0x1e, 0x06, 0x25, 0xb8, 0x15, 0x3a,
+ 0x3c, 0x7d, 0x5f, 0x29, 0x9e, 0xfe, 0xda, 0x34,
+ 0x9d, 0x3f, 0x65, 0x43, 0xdf, 0xa0, 0xe8, 0xe3,
+ 0xd4, 0xf9, 0x3c, 0xfb, 0x5d, 0x35, 0xd9, 0x4e,
+ 0x8c, 0x46, 0x17, 0x9d, 0xac, 0x43, 0x3f, 0xff,
+ 0xfa, 0xcb, 0xe1, 0x15, 0xdf, 0x7f, 0x7f, 0x57,
+ 0xe5, 0x76, 0xd7, 0x85, 0xe7, 0x4f, 0xa8, 0xd8,
+ 0x7c, 0x13, 0xa7, 0xed, 0xb8, 0x41, 0xb9, 0x87,
+ 0x4f, 0xfb, 0xfe, 0x7d, 0xed, 0x83, 0xea, 0x9d,
+ 0x3f, 0xee, 0xc0, 0x2f, 0xfb, 0x6c, 0xd2, 0x74,
+ 0x3c, 0xff, 0x00, 0x7d, 0x3f, 0xf9, 0x72, 0x9b,
+ 0xd9, 0x6f, 0xf5, 0x05, 0x4e, 0x9d, 0x5b, 0x30,
+ 0xe8, 0xb9, 0xf2, 0xea, 0x93, 0x3f, 0x6b, 0x5b,
+ 0xd7, 0x2e, 0x74, 0xe0, 0x84, 0x25, 0x4f, 0xfe,
+ 0xbf, 0xaf, 0x5b, 0x7b, 0x73, 0x78, 0xab, 0xca,
+ 0x71, 0x79, 0x1e, 0x45, 0x46, 0xa9, 0x50, 0xf5,
+ 0x58, 0x98, 0xf5, 0xe2, 0x91, 0x85, 0x5f, 0xe1,
+ 0x0f, 0x78, 0x65, 0xcd, 0xa7, 0x0e, 0x9f, 0x06,
+ 0xeb, 0x48, 0x4e, 0x9f, 0xcb, 0xc3, 0x60, 0xf6,
+ 0xc5, 0x4c, 0x10, 0x95, 0x1b, 0x1e, 0x38, 0x4c,
+ 0x67, 0xab, 0x7f, 0x6e, 0xca, 0x71, 0xa3, 0x98,
+ 0x35, 0x3a, 0x58, 0x74, 0xa9, 0xc3, 0x4b, 0x71,
+ 0x69, 0xff, 0xab, 0x5d, 0xbe, 0xbb, 0x59, 0x6f,
+ 0x53, 0xa1, 0x4f, 0xb7, 0x52, 0x79, 0xff, 0x5f,
+ 0xc3, 0xc0, 0x6f, 0xbe, 0x58, 0xe8, 0x79, 0xf1,
+ 0x78, 0x8a, 0x7d, 0x94, 0x67, 0x84, 0xe9, 0xfa,
+ 0xea, 0x3b, 0x67, 0xce, 0x9f, 0xdb, 0x59, 0x7e,
+ 0x1e, 0xa4, 0xe9, 0xff, 0xbd, 0xb5, 0x95, 0x14,
+ 0x1d, 0xf0, 0x1d, 0x3f, 0xff, 0xef, 0x33, 0xbf,
+ 0x4b, 0xdc, 0x1c, 0xf3, 0x6c, 0xfe, 0x6d, 0xcf,
+ 0x3c, 0x5e, 0xb0, 0xa9, 0x8f, 0xf1, 0x65, 0x4d,
+ 0x35, 0x43, 0x9f, 0xfe, 0xcb, 0xd7, 0x1a, 0xb2,
+ 0xb6, 0xcb, 0x59, 0x4e, 0x9f, 0xff, 0xff, 0x7b,
+ 0x29, 0xaf, 0xb0, 0x3a, 0x32, 0x97, 0xd7, 0xd7,
+ 0xaf, 0xa9, 0xdb, 0x6d, 0x68, 0x3a, 0x3e, 0x8d,
+ 0xeb, 0xa8, 0x4d, 0xe0, 0x9d, 0x36, 0xf0, 0x1d,
+ 0x0d, 0x1a, 0xe0, 0x0b, 0x4e, 0x7f, 0x6c, 0x74,
+ 0xc1, 0x09, 0xd1, 0xe3, 0xd4, 0xa9, 0x10, 0x47,
+ 0x27, 0x5f, 0x78, 0x0a, 0x71, 0xaf, 0x9f, 0xff,
+ 0xfd, 0x75, 0xda, 0xda, 0xf6, 0x96, 0x76, 0xd9,
+ 0x9f, 0xd3, 0x5a, 0xe7, 0xc0, 0x74, 0x52, 0x8a,
+ 0xbf, 0x17, 0x4f, 0xf6, 0x5e, 0xca, 0x37, 0xc4,
+ 0x3a, 0x72, 0x8b, 0x47, 0x46, 0x27, 0xe7, 0xd1,
+ 0xbf, 0xfc, 0x93, 0x70, 0xd6, 0x7d, 0xfc, 0xbf,
+ 0x37, 0x9d, 0x3f, 0xf6, 0x08, 0xe3, 0x56, 0xca,
+ 0xf7, 0xce, 0x9f, 0xdf, 0x51, 0xd5, 0x2c, 0xa7,
+ 0x4f, 0xbd, 0xa6, 0xdc, 0xf3, 0xa7, 0xef, 0x2b,
+ 0x28, 0xc0, 0x9d, 0x30, 0x42, 0x74, 0x21, 0xf6,
+ 0x09, 0x48, 0x4b, 0x67, 0xfb, 0x1a, 0xe6, 0xba,
+ 0x97, 0xd4, 0xa7, 0x1a, 0xd9, 0xff, 0xd9, 0xf0,
+ 0x65, 0xbd, 0x4d, 0x6d, 0xad, 0x4e, 0x9f, 0xbf,
+ 0xc0, 0xdb, 0x3e, 0x74, 0xfc, 0xcf, 0x6e, 0x60,
+ 0xe9, 0x3a, 0x70, 0x42, 0x12, 0xa7, 0xfe, 0x51,
+ 0xfe, 0xbd, 0xbf, 0x1a, 0x56, 0x1c, 0xe2, 0xf2,
+ 0x37, 0x6a, 0x8b, 0x9a, 0x86, 0x55, 0x52, 0xae,
+ 0x99, 0xa9, 0x68, 0x53, 0x67, 0x70, 0xd0, 0x79,
+ 0x04, 0xa7, 0x9f, 0x94, 0xbc, 0xf2, 0x09, 0x4e,
+ 0xaf, 0xb6, 0x3c, 0x82, 0x53, 0x04, 0x27, 0x90,
+ 0x4a, 0x11, 0x14, 0x8d, 0x14, 0x5c, 0xbc, 0x25,
+ 0x53, 0x75, 0xcb, 0x20, 0x91, 0xc6, 0xf6, 0x7e,
+ 0xcb, 0x66, 0x7f, 0x49, 0xd3, 0xbb, 0xe0, 0xf9,
+ 0xf0, 0x5c, 0xce, 0x7b, 0x73, 0x3a, 0xc7, 0x4b,
+ 0x37, 0x67, 0xac, 0x03, 0x39, 0xfc, 0xd3, 0xf5,
+ 0xa2, 0xfe, 0xa0, 0xa9, 0xfd, 0xe7, 0xeb, 0xd5,
+ 0xb7, 0x8e, 0x93, 0xca, 0x9d, 0xc3, 0x41, 0x50,
+ 0x54, 0x29, 0xb5, 0x41, 0x06, 0x0d, 0xcf, 0x7d,
+ 0x40, 0x85, 0x38, 0xd6, 0x42, 0xa3, 0x17, 0x21,
+ 0x2b, 0x3d, 0xaf, 0x0b, 0xce, 0x93, 0x0e, 0x9b,
+ 0x1f, 0xb1, 0xb1, 0x68, 0x86, 0x7c, 0x1c, 0x6b,
+ 0xcc, 0x3a, 0x7e, 0x45, 0x69, 0xea, 0x02, 0xa5,
+ 0xe3, 0xa7, 0xfa, 0x8d, 0x5f, 0xb5, 0xb5, 0xef,
+ 0x9d, 0x3f, 0x79, 0x59, 0x46, 0x04, 0xe9, 0xf6,
+ 0x50, 0xcc, 0x61, 0xd3, 0xab, 0xe1, 0x3a, 0x3e,
+ 0x78, 0x57, 0x27, 0x9f, 0xbf, 0xc0, 0x06, 0xb5,
+ 0x3a, 0x7e, 0xf6, 0x9d, 0xea, 0xc7, 0x6c, 0x98,
+ 0x66, 0x08, 0x09, 0xed, 0x5b, 0xee, 0x45, 0x18,
+ 0x9e, 0x8f, 0x8a, 0x3f, 0x19, 0xc4, 0xf7, 0xf2,
+ 0x8d, 0x4e, 0x87, 0xab, 0xd7, 0xc2, 0xbb, 0x43,
+ 0xf7, 0xea, 0xf5, 0x8f, 0xfe, 0xe6, 0xd3, 0xff,
+ 0xea, 0x04, 0x73, 0x6e, 0x65, 0xba, 0xff, 0x56,
+ 0x8e, 0x9c, 0x10, 0x84, 0xa9, 0x9e, 0xa5, 0x38,
+ 0xbc, 0x85, 0x44, 0xa8, 0xb8, 0xcf, 0xd4, 0x34,
+ 0xf6, 0xe0, 0xd0, 0x74, 0xf5, 0xba, 0x90, 0x9d,
+ 0x3e, 0xa0, 0x7c, 0xac, 0x3a, 0x7f, 0xf9, 0x77,
+ 0xdf, 0xea, 0x0e, 0xb8, 0x37, 0xfd, 0xe7, 0x46,
+ 0xea, 0x46, 0x87, 0x8d, 0x38, 0x8a, 0xe4, 0xf3,
+ 0x9f, 0xef, 0x9d, 0x3f, 0x5d, 0x5a, 0xfe, 0xb5,
+ 0x3a, 0x1e, 0x79, 0x77, 0x1c, 0x9d, 0xae, 0xad,
+ 0xd9, 0xd3, 0x73, 0x9b, 0xa3, 0x74, 0x31, 0xba,
+ 0xc6, 0xdb, 0xaf, 0xc8, 0x96, 0x51, 0x55, 0x10,
+ 0xff, 0x79, 0x0e, 0xd1, 0xb5, 0xe4, 0xaf, 0x3d,
+ 0x2c, 0xc8, 0x2f, 0xe8, 0x49, 0x35, 0x19, 0x50,
+ 0x91, 0x32, 0x34, 0x5b, 0x4b, 0x0e, 0xe4, 0x5f,
+ 0x94, 0xd6, 0x53, 0x7d, 0xe7, 0x74, 0xb5, 0x87,
+ 0xc6, 0xe4, 0x3c, 0x77, 0xc2, 0x35, 0xbc, 0x8a,
+ 0x7f, 0xf3, 0x99, 0xcf, 0x76, 0x0a, 0x77, 0x21,
+ 0xa2, 0x8a, 0x9f, 0xce, 0xc1, 0x4e, 0xe4, 0x34,
+ 0x5d, 0x13, 0xff, 0x3b, 0x9e, 0xec, 0x14, 0xee,
+ 0x43, 0x44, 0x97, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
+ 0x68, 0xbc, 0xa1, 0x5b, 0xf2, 0xba, 0x09, 0xde,
+ 0x77, 0x87, 0x68, 0xa4, 0xd1, 0xdb, 0x0e, 0xed,
+ 0x0c, 0x5f, 0xd7, 0x47, 0x55, 0x8e, 0xce, 0xea,
+ 0x5a, 0x9d, 0xb6, 0x4c, 0x9f, 0xfc, 0xe6, 0x73,
+ 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x96, 0x67, 0x93,
+ 0xb9, 0x0d, 0x11, 0x9c, 0xfd, 0xe5, 0x65, 0x18,
+ 0x13, 0xa6, 0xfb, 0xce, 0x93, 0x0e, 0x9f, 0x78,
+ 0x6d, 0xce, 0x13, 0xd3, 0x61, 0x6e, 0xf1, 0x69,
+ 0xfb, 0x9f, 0xe1, 0xe1, 0x3a, 0x75, 0x56, 0x93,
+ 0xa0, 0x53, 0x10, 0x63, 0xf7, 0xd3, 0x2e, 0x55,
+ 0x3f, 0xf5, 0xfc, 0x3c, 0x0d, 0x14, 0xbd, 0x58,
+ 0x74, 0xfb, 0xea, 0xfa, 0xf1, 0xd1, 0xe3, 0xec,
+ 0x6c, 0x8d, 0x3f, 0xff, 0x7b, 0x6d, 0x6f, 0x5a,
+ 0x5e, 0xbf, 0x05, 0x74, 0x6b, 0xf3, 0xa7, 0xfe,
+ 0xc6, 0x5f, 0xc1, 0xaa, 0xdb, 0xb7, 0x67, 0x4f,
+ 0xfa, 0xcb, 0xeb, 0x79, 0x7e, 0xd6, 0xa7, 0x49,
+ 0xd8, 0x9d, 0xbb, 0x50, 0xa9, 0xe2, 0x4f, 0xb1,
+ 0xd5, 0x1e, 0x7f, 0xf3, 0x99, 0xcf, 0x76, 0x0a,
+ 0x77, 0x21, 0xa2, 0x69, 0x9f, 0xfc, 0xe6, 0x73,
+ 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9c, 0x67, 0xff,
+ 0x39, 0x9c, 0xf7, 0x60, 0xa7, 0x72, 0x1a, 0x28,
+ 0x19, 0xf0, 0xa7, 0x72, 0x1a, 0x2e, 0x09, 0x97,
+ 0xc7, 0x4f, 0xef, 0xbd, 0x7d, 0xb6, 0x30, 0xe9,
+ 0x3b, 0x0f, 0xe2, 0xc6, 0x1a, 0x8a, 0xcf, 0xef,
+ 0x3b, 0x7a, 0x83, 0x02, 0x74, 0xff, 0x3d, 0xd8,
+ 0x29, 0xdc, 0x86, 0x89, 0x26, 0x4e, 0xb1, 0xfa,
+ 0xf1, 0xa4, 0x50, 0xbb, 0x5a, 0xf9, 0x63, 0x28,
+ 0xaa, 0xd2, 0x90, 0x14, 0xab, 0x0c, 0xab, 0xc2,
+ 0xaa, 0x7f, 0xda, 0x79, 0xd8, 0x29, 0xdc, 0x86,
+ 0x8b, 0x52, 0x7f, 0xdc, 0xf7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x25, 0x58, 0x3a, 0x4e, 0xd2, 0x89, 0x86,
+ 0x24, 0x37, 0xa3, 0x4f, 0xe7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x22, 0x99, 0xfc, 0xec, 0x14, 0xee, 0x43,
+ 0x44, 0x69, 0x3f, 0x9d, 0x82, 0x9d, 0xc8, 0x68,
+ 0xa7, 0xe7, 0xff, 0x39, 0x9c, 0xf7, 0x60, 0xa7,
+ 0x72, 0x1a, 0x26, 0xa9, 0xfc, 0xec, 0x14, 0xee,
+ 0x43, 0x45, 0x77, 0x3c, 0x9d, 0xc8, 0x68, 0xaf,
+ 0xa7, 0x04, 0x21, 0x2a, 0x5f, 0x29, 0xc5, 0xe4,
+ 0x09, 0xf3, 0x31, 0x1e, 0x73, 0xd6, 0x93, 0xa7,
+ 0xfd, 0x96, 0x0f, 0x5e, 0xab, 0x94, 0x1d, 0x2b,
+ 0x9d, 0x3f, 0xde, 0x1c, 0xa3, 0xcf, 0xcd, 0x8e,
+ 0x81, 0x3c, 0x9e, 0x10, 0x93, 0xb1, 0x1c, 0x6d,
+ 0x10, 0xfc, 0x72, 0xb0, 0x86, 0x9f, 0xfc, 0xe6,
+ 0x73, 0xdd, 0x82, 0x9d, 0xc8, 0x68, 0x9e, 0xe7,
+ 0xf3, 0xb0, 0x53, 0xb9, 0x0d, 0x17, 0x0c, 0xff,
+ 0xce, 0xe7, 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x27,
+ 0xc2, 0xab, 0xe3, 0xa0, 0xed, 0xe7, 0x7a, 0x4e,
+ 0xd0, 0xed, 0xa5, 0x21, 0x8e, 0x12, 0xc9, 0x15,
+ 0x52, 0x6c, 0x77, 0x3f, 0x9d, 0x82, 0x9d, 0xc8,
+ 0x68, 0x8a, 0xa7, 0xf3, 0xb0, 0x53, 0xb9, 0x0d,
+ 0x14, 0xcc, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14,
+ 0xee, 0x43, 0x44, 0xcf, 0x3f, 0xf9, 0xcc, 0xe7,
+ 0xbb, 0x05, 0x3b, 0x90, 0xd1, 0x46, 0xc5, 0x09,
+ 0x8d, 0x6c, 0x77, 0xa4, 0xee, 0xea, 0x53, 0xff,
+ 0x3b, 0x9e, 0xec, 0x14, 0xee, 0x43, 0x44, 0x75,
+ 0x3f, 0x7b, 0x3f, 0xb6, 0x50, 0x74, 0xf8, 0x53,
+ 0xb9, 0x0d, 0x14, 0xd4, 0xff, 0xcf, 0xb7, 0xbf,
+ 0x45, 0x75, 0x51, 0x68, 0xe9, 0xfb, 0xca, 0xca,
+ 0x30, 0x27, 0x4f, 0xff, 0x65, 0xed, 0x8f, 0x1e,
+ 0xfd, 0xed, 0xcf, 0x3a, 0x65, 0x01, 0xd3, 0xfd,
+ 0x5e, 0xa5, 0x53, 0xc8, 0xe1, 0x44, 0x7f, 0xcb,
+ 0x77, 0xa6, 0xc9, 0xdb, 0x27, 0x25, 0x85, 0xd4,
+ 0x98, 0x5e, 0x1a, 0xd3, 0xe1, 0x4e, 0xe4, 0x34,
+ 0x55, 0x53, 0xfe, 0xe7, 0xbb, 0x05, 0x3b, 0x90,
+ 0xd1, 0x36, 0xc9, 0xd8, 0x7e, 0xcc, 0x30, 0x9f,
+ 0xce, 0xc1, 0x4e, 0xe4, 0x34, 0x57, 0xf3, 0xf9,
+ 0xd8, 0x29, 0xdc, 0x86, 0x8b, 0x1a, 0x7c, 0x29,
+ 0xdc, 0x86, 0x8b, 0x56, 0x7f, 0xdc, 0xf7, 0x60,
+ 0xa7, 0x72, 0x1a, 0x28, 0x29, 0x3b, 0x0f, 0xd9,
+ 0x86, 0x13, 0xe1, 0x4e, 0xe4, 0x34, 0x5c, 0x53,
+ 0xcd, 0xed, 0xfe, 0x43, 0xa7, 0xf2, 0xb3, 0x9b,
+ 0x28, 0xb7, 0x9d, 0x27, 0x62, 0x23, 0x38, 0xc2,
+ 0xe4, 0xf3, 0xf9, 0xd8, 0x29, 0xdc, 0x86, 0x8b,
+ 0xa6, 0x7f, 0xff, 0x2d, 0xbf, 0xaf, 0x6e, 0xf1,
+ 0xf6, 0xcd, 0x39, 0xb3, 0x5a, 0x9d, 0x3f, 0xe7,
+ 0xe0, 0x8f, 0x3e, 0x8c, 0x09, 0xd3, 0xbf, 0xce,
+ 0x14, 0x52, 0xdd, 0xa6, 0x7f, 0xc2, 0xb4, 0xdb,
+ 0xab, 0x75, 0x09, 0xd3, 0xf6, 0xe9, 0xfc, 0xb7,
+ 0x5c, 0xe9, 0xf8, 0x1c, 0xd3, 0xfd, 0x73, 0xa7,
+ 0xff, 0xfd, 0xa5, 0x76, 0xb6, 0x53, 0x7f, 0xf5,
+ 0x81, 0xd5, 0xaf, 0x0a, 0x1d, 0x3c, 0x9d, 0xc8,
+ 0x68, 0x93, 0x27, 0xf8, 0x72, 0x9b, 0xdf, 0x9f,
+ 0x53, 0xa0, 0x4f, 0x8d, 0x85, 0x73, 0xf6, 0xc0,
+ 0xdd, 0x2a, 0x0d, 0xc3, 0xa7, 0xff, 0x5b, 0xd7,
+ 0xa5, 0x3c, 0x35, 0x69, 0x78, 0xe9, 0xf6, 0x5f,
+ 0xcc, 0xe3, 0xa7, 0xff, 0xdc, 0x82, 0xb6, 0xfe,
+ 0x5f, 0x1c, 0x10, 0x84, 0xa8, 0x79, 0xfc, 0x5c,
+ 0x9a, 0x7f, 0xf6, 0xbf, 0xeb, 0xa8, 0xd6, 0xcb,
+ 0xfb, 0x9d, 0x38, 0x21, 0x09, 0x53, 0xf0, 0xf5,
+ 0x0c, 0xf5, 0x4a, 0x71, 0x79, 0x3e, 0xc6, 0x0e,
+ 0x6e, 0xce, 0x9f, 0x7a, 0xf4, 0x60, 0x4e, 0x9f,
+ 0xe5, 0x4b, 0x7f, 0x5b, 0xad, 0x4e, 0x81, 0x3e,
+ 0x06, 0x14, 0x4f, 0xf6, 0x70, 0x34, 0x66, 0xdc,
+ 0xf3, 0xa7, 0xff, 0x75, 0x16, 0xf2, 0xff, 0x1a,
+ 0xf0, 0xf8, 0xe8, 0xc4, 0x52, 0x5c, 0x84, 0x27,
+ 0x33, 0xef, 0xe5, 0xba, 0xe7, 0x4f, 0xf9, 0xeb,
+ 0xfa, 0x37, 0x8f, 0xf5, 0x79, 0xd1, 0xbb, 0x3e,
+ 0x86, 0x89, 0xa7, 0xaf, 0x46, 0x6c, 0x74, 0xff,
+ 0x7b, 0x4e, 0xf1, 0x03, 0x3d, 0x53, 0xa1, 0xa3,
+ 0xe0, 0xdc, 0x23, 0x9c, 0x10, 0x84, 0xe9, 0xff,
+ 0xf6, 0x32, 0xff, 0x50, 0x66, 0xd5, 0xc6, 0x2a,
+ 0x14, 0xe2, 0xf2, 0x31, 0x32, 0xbf, 0x42, 0x1e,
+ 0xc8, 0x53, 0xf5, 0x97, 0x42, 0x7a, 0x83, 0xa7,
+ 0xe1, 0xe1, 0xfa, 0xbc, 0xe8, 0xd8, 0xf6, 0x44,
+ 0xbe, 0x67, 0xb9, 0xb8, 0xbd, 0x56, 0xa6, 0x2f,
+ 0x2e, 0xc8, 0x68, 0x69, 0x21, 0x43, 0x7a, 0x61,
+ 0x84, 0xd1, 0x17, 0x32, 0xfc, 0xf2, 0xb1, 0x96,
+ 0xde, 0x3c, 0x2d, 0xf0, 0x8e, 0x9f, 0x63, 0x07,
+ 0x37, 0x67, 0x4f, 0xfd, 0x96, 0xfa, 0xd1, 0xbe,
+ 0xd6, 0xed, 0xd9, 0xd3, 0xf7, 0x23, 0x82, 0x10,
+ 0x9d, 0x27, 0x23, 0x22, 0x70, 0x4c, 0xfa, 0x7b,
+ 0xa3, 0xf0, 0xe2, 0xa9, 0x4b, 0x64, 0xa8, 0x7b,
+ 0x3a, 0x07, 0x68, 0xf7, 0xa9, 0x86, 0x00, 0x93,
+ 0xb0, 0xec, 0x10, 0xb1, 0xac, 0x2c, 0xee, 0x69,
+ 0xad, 0x25, 0xf2, 0x7f, 0x3b, 0x05, 0x3b, 0x90,
+ 0xd1, 0x1a, 0xcf, 0x85, 0x3b, 0x90, 0xd1, 0x52,
+ 0xcd, 0xc8, 0x68, 0x86, 0xa4, 0xec, 0x3d, 0x1e,
+ 0x30, 0x9f, 0xf9, 0xdc, 0xf7, 0x60, 0xa7, 0x72,
+ 0x1a, 0x23, 0xe9, 0xfc, 0xec, 0x14, 0xee, 0x43,
+ 0x45, 0x8f, 0x3f, 0x6e, 0x9f, 0xcb, 0x75, 0xce,
+ 0x9f, 0xef, 0xf0, 0x2b, 0xd7, 0xbf, 0x1d, 0x3c,
+ 0x06, 0x78, 0x4e, 0x9f, 0xff, 0xe5, 0x1f, 0xe6,
+ 0xd9, 0x6b, 0x79, 0x2d, 0xeb, 0xd7, 0xa9, 0x3a,
+ 0x3c, 0x88, 0x7b, 0x10, 0xce, 0xee, 0x43, 0x45,
+ 0xa1, 0x3f, 0xee, 0x0b, 0x7a, 0x70, 0xd1, 0x81,
+ 0x3a, 0x42, 0x87, 0xca, 0x24, 0xd3, 0xf3, 0x6d,
+ 0xf7, 0xfa, 0x80, 0xe9, 0xf2, 0xdf, 0x2c, 0xa7,
+ 0x4f, 0xff, 0x65, 0xeb, 0x8d, 0x59, 0x5b, 0x65,
+ 0xac, 0xa7, 0x45, 0x07, 0xeb, 0xf2, 0x58, 0x54,
+ 0x64, 0xe4, 0x29, 0xa7, 0xfe, 0xca, 0xfb, 0x5f,
+ 0xbc, 0x57, 0x36, 0x3a, 0x7d, 0x7b, 0x77, 0xf4,
+ 0x9d, 0x3f, 0xdf, 0xd6, 0x8d, 0xad, 0x9f, 0x53,
+ 0xa6, 0xfe, 0x61, 0xf2, 0x21, 0x4c, 0xfe, 0xcb,
+ 0x35, 0xeb, 0x79, 0x87, 0x4f, 0xe7, 0xe0, 0xd7,
+ 0xeb, 0x41, 0xd3, 0xdb, 0x65, 0xb8, 0xe9, 0xfe,
+ 0xcc, 0x0e, 0x22, 0x60, 0x4e, 0x8c, 0x45, 0xdd,
+ 0x26, 0x9c, 0x65, 0x52, 0x19, 0xec, 0xb7, 0x5c,
+ 0xe9, 0xfd, 0xa7, 0xdf, 0xd5, 0xf9, 0x53, 0xa4,
+ 0xe6, 0xe2, 0xe5, 0x5a, 0x98, 0xed, 0x0b, 0xec,
+ 0x84, 0x45, 0xa1, 0xdd, 0xf2, 0x6a, 0xc2, 0xa2,
+ 0xf0, 0xe6, 0xdc, 0x3c, 0xde, 0x41, 0x3f, 0x37,
+ 0xfb, 0x6f, 0xab, 0x47, 0x4f, 0x65, 0xba, 0xe7,
+ 0x4b, 0x74, 0xc3, 0xd2, 0xf9, 0x94, 0xf8, 0x53,
+ 0xb9, 0x0d, 0x16, 0xb4, 0xff, 0xb9, 0xee, 0xc1,
+ 0x4e, 0xe4, 0x34, 0x50, 0x72, 0x73, 0x71, 0x14,
+ 0x58, 0x58, 0xc3, 0x09, 0xff, 0xce, 0x67, 0x3d,
+ 0xd8, 0x29, 0xdc, 0x86, 0x8a, 0x2e, 0x7f, 0x3b,
+ 0x05, 0x3b, 0x90, 0xd1, 0x75, 0x43, 0xd9, 0x0a,
+ 0x69, 0x08, 0xcf, 0x13, 0x31, 0x32, 0xd3, 0x9c,
+ 0xc0, 0x8e, 0xa6, 0xa7, 0x37, 0x52, 0x9f, 0x0a,
+ 0x77, 0x21, 0xa2, 0x21, 0x9d, 0x6c, 0xd8, 0xe9,
+ 0x3b, 0x0f, 0x32, 0x93, 0x09, 0xfc, 0xec, 0x14,
+ 0xee, 0x43, 0x44, 0x6d, 0x3f, 0x9d, 0x82, 0x9d,
+ 0xc8, 0x68, 0xa6, 0xe7, 0xf3, 0xb0, 0x53, 0xb9,
+ 0x0d, 0x15, 0x04, 0xfe, 0x76, 0x0a, 0x77, 0x21,
+ 0xa2, 0xa6, 0x9f, 0x0a, 0x77, 0x21, 0xa2, 0xb0,
+ 0x9f, 0x78, 0x3b, 0x6a, 0x27, 0x4f, 0xf3, 0xdd,
+ 0x82, 0x9d, 0xc8, 0x68, 0x8f, 0xe7, 0x62, 0xd0,
+ 0x74, 0x9d, 0x88, 0xb5, 0x43, 0x0e, 0x29, 0xfa,
+ 0x0c, 0xff, 0xe7, 0x33, 0x9e, 0xec, 0x14, 0xee,
+ 0x43, 0x44, 0xdf, 0x3f, 0xf3, 0x39, 0xee, 0xc1,
+ 0x4e, 0xe4, 0x34, 0x4f, 0xd3, 0xf3, 0x75, 0xdd,
+ 0x5b, 0xa6, 0xe6, 0x52, 0x74, 0xff, 0xf2, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xad, 0x35, 0x3a, 0x7c, 0x3e,
+ 0xa3, 0x98, 0x54, 0xc1, 0x09, 0x51, 0x86, 0xf4,
+ 0x24, 0xf2, 0xd4, 0xa7, 0x1a, 0x08, 0x54, 0x63,
+ 0xd6, 0x14, 0xd3, 0xf0, 0xf2, 0x5b, 0xc2, 0x74,
+ 0xf5, 0x0c, 0xf3, 0xce, 0x9f, 0x57, 0xfa, 0xf3,
+ 0xce, 0x9f, 0xd6, 0x56, 0x38, 0x00, 0x53, 0xa4,
+ 0x2a, 0x7f, 0xb8, 0x47, 0xe2, 0x89, 0xff, 0x2d,
+ 0x3b, 0x6f, 0x5d, 0xdd, 0xb5, 0xa9, 0xd3, 0x81,
+ 0x5c, 0x3a, 0x7f, 0xed, 0x96, 0xfd, 0x5c, 0xb5,
+ 0xbc, 0xc3, 0xa7, 0x5f, 0xcd, 0x1d, 0x0a, 0x7c,
+ 0x35, 0x44, 0x85, 0x4f, 0x93, 0xc4, 0xe3, 0x0a,
+ 0x76, 0x19, 0x7d, 0x1e, 0xef, 0x93, 0xdc, 0xd6,
+ 0xf6, 0x1d, 0x37, 0x7c, 0xe8, 0x13, 0x72, 0xc2,
+ 0x49, 0xc1, 0x08, 0x4e, 0x9e, 0xa3, 0xfe, 0x52,
+ 0x9c, 0x5e, 0x4f, 0x53, 0x7f, 0x21, 0xd0, 0xa8,
+ 0x8f, 0xb1, 0xe6, 0xa6, 0x33, 0xff, 0x51, 0xa8,
+ 0x33, 0xfa, 0xb4, 0xb7, 0xe3, 0xa7, 0x96, 0xf5,
+ 0x43, 0x44, 0x1d, 0x3f, 0x75, 0x97, 0x77, 0xab,
+ 0xce, 0x81, 0x45, 0x2d, 0xd1, 0xdb, 0x16, 0xcc,
+ 0x3b, 0x1d, 0x30, 0x42, 0x74, 0x3c, 0xd6, 0x04,
+ 0x5a, 0x7a, 0xab, 0xe6, 0xc5, 0x38, 0xd0, 0xcf,
+ 0xab, 0xbf, 0x60, 0x54, 0xe8, 0xf1, 0xef, 0x6f,
+ 0x33, 0x9c, 0x10, 0x84, 0xa8, 0x29, 0xc5, 0xe4,
+ 0xf7, 0x83, 0xe6, 0x8a, 0x84, 0x37, 0x9e, 0x19,
+ 0x8f, 0x26, 0xf1, 0x68, 0x6e, 0x7d, 0xf2, 0x77,
+ 0xfd, 0x53, 0xa7, 0xb6, 0xef, 0x80, 0xe9, 0xff,
+ 0x97, 0xe0, 0xfa, 0xd2, 0xd2, 0xfc, 0x07, 0x47,
+ 0x91, 0x06, 0x01, 0xca, 0x91, 0x4f, 0x97, 0x06,
+ 0xde, 0x3a, 0x7b, 0x6c, 0x66, 0xec, 0xe8, 0x68,
+ 0xf2, 0xdb, 0x12, 0xcf, 0xd7, 0xc6, 0xbe, 0xac,
+ 0x3c, 0x40, 0x53, 0xee, 0xfe, 0xd6, 0x53, 0x44,
+ 0x04, 0xe3, 0x75, 0x3f, 0xca, 0x34, 0x68, 0xc6,
+ 0xbc, 0xc3, 0xa7, 0xca, 0x0f, 0x53, 0x53, 0xa7,
+ 0xf0, 0xb5, 0x5f, 0x7e, 0xfe, 0x3a, 0x7a, 0x90,
+ 0x0a, 0x95, 0x30, 0x42, 0x54, 0x29, 0xb7, 0x09,
+ 0x0c, 0xfd, 0xc2, 0xf7, 0xff, 0xc5, 0x38, 0xd0,
+ 0x42, 0xaa, 0x48, 0xc7, 0xbf, 0x2f, 0xd9, 0x13,
+ 0xe7, 0x77, 0x28, 0xd6, 0x11, 0x73, 0xed, 0x6f,
+ 0xaf, 0x6f, 0x34, 0x40, 0xf3, 0xfe, 0xb6, 0xb4,
+ 0x2e, 0x85, 0xba, 0xec, 0x74, 0xee, 0x1a, 0x0e,
+ 0x98, 0x21, 0x3a, 0x7f, 0x0f, 0xb1, 0xb6, 0xf7,
+ 0xb9, 0x0d, 0x88, 0x46, 0xe3, 0x64, 0x5f, 0x8b,
+ 0x9c, 0xff, 0xdf, 0xcd, 0x36, 0xe7, 0xef, 0xea,
+ 0x54, 0xe8, 0x53, 0xea, 0xc2, 0x39, 0xff, 0xd8,
+ 0xc6, 0x73, 0xf0, 0x53, 0xb9, 0x0d, 0x10, 0xc4,
+ 0x58, 0xfc, 0x7e, 0x41, 0x3f, 0x60, 0xa7, 0x72,
+ 0x1a, 0x20, 0xa9, 0xeb, 0xd5, 0x40, 0x54, 0xee,
+ 0x1a, 0x0a, 0x9e, 0xd7, 0xfd, 0xa4, 0xa9, 0xfd,
+ 0xea, 0x32, 0xf5, 0x50, 0x15, 0x05, 0x4f, 0xd8,
+ 0x8b, 0x65, 0x61, 0x53, 0x04, 0x25, 0x4f, 0xdf,
+ 0x5f, 0xd1, 0xe1, 0x2a, 0x31, 0x30, 0xa4, 0x21,
+ 0x60, 0xdd, 0x89, 0x00, 0x67, 0xf0, 0xa0, 0x95,
+ 0x6f, 0x16, 0x9b, 0xc2, 0x53, 0x8f, 0xca, 0x5c,
+ 0xf4, 0xf5, 0xed, 0x1d, 0x8c, 0xff, 0x95, 0xfd,
+ 0xfc, 0xa8, 0xad, 0x4e, 0x9f, 0xeb, 0xd9, 0x5b,
+ 0x6c, 0xa0, 0x53, 0xa7, 0xf9, 0x69, 0x7e, 0xe2,
+ 0xa6, 0x30, 0xe8, 0x53, 0xf4, 0xb1, 0xd4, 0xff,
+ 0xfc, 0xd7, 0x73, 0xfa, 0xda, 0x32, 0x8d, 0x6f,
+ 0xaf, 0x6f, 0x34, 0x5f, 0x73, 0xef, 0x5f, 0xf8,
+ 0xf3, 0xa7, 0xfd, 0xff, 0x3e, 0xf6, 0xc1, 0xf5,
+ 0x4e, 0x9f, 0xd7, 0x06, 0xff, 0xbe, 0xd8, 0x78,
+ 0x80, 0x67, 0x70, 0xbc, 0xf1, 0x00, 0xc6, 0x1f,
+ 0x4e, 0xa8, 0x53, 0x73, 0xcf, 0x10, 0x0c, 0xf7,
+ 0x7e, 0x97, 0x9e, 0x20, 0x19, 0xfd, 0xe4, 0xb6,
+ 0x00, 0x0a, 0x78, 0x80, 0x67, 0x7b, 0xfb, 0x1e,
+ 0x20, 0x18, 0xd9, 0x17, 0x2c, 0x22, 0xb1, 0x7b,
+ 0x63, 0xe9, 0xc2, 0xb7, 0x3c, 0x40, 0x30, 0x78,
+ 0x80, 0x66, 0x56, 0x1e, 0x20, 0x18, 0xd8, 0xdc,
+ 0xf8, 0x5e, 0x7b, 0xcc, 0xd9, 0x4f, 0x10, 0x0c,
+ 0xeb, 0xf2, 0x1e, 0x20, 0x19, 0xff, 0x7f, 0x9e,
+ 0xeb, 0x79, 0x38, 0x4f, 0x10, 0x0c, 0xdd, 0xb1,
+ 0xe2, 0x01, 0x9f, 0xdf, 0xe0, 0xd6, 0xaa, 0x03,
+ 0xc4, 0x03, 0x3e, 0xf6, 0x9e, 0xf8, 0x0f, 0x10,
+ 0x0c, 0xde, 0xa9, 0xe2, 0x01, 0x81, 0x3d, 0x9b,
+ 0x9b, 0x4f, 0xaf, 0xf5, 0xa5, 0xe6, 0x88, 0x06,
+ 0x60, 0x29, 0xe2, 0x01, 0x71, 0xb5, 0x9f, 0x79,
+ 0x59, 0xdb, 0x1e, 0x20, 0x19, 0xed, 0x7b, 0xe8,
+ 0x78, 0x80, 0x67, 0x28, 0xa1, 0xe2, 0x01, 0x9f,
+ 0xf6, 0x53, 0x5d, 0x97, 0x3e, 0x0a, 0x9e, 0x20,
+ 0x19, 0xf6, 0xbc, 0xf7, 0xa9, 0xe2, 0x01, 0x8c,
+ 0x44, 0x05, 0x93, 0x26, 0x10, 0x1e, 0x20, 0x18,
+ 0x7a, 0xa8, 0xfd, 0x88, 0xf2, 0x13, 0x1e, 0x56,
+ 0xb1, 0x90, 0x0d, 0x2a, 0x5d, 0x78, 0x53, 0x6a,
+ 0x45, 0x3e, 0xcb, 0xd7, 0xa9, 0x3c, 0x40, 0x33,
+ 0xfb, 0x65, 0x46, 0x85, 0x6e, 0x78, 0x80, 0x76,
+ 0x36, 0x93, 0x85, 0x42, 0x78, 0x80, 0x61, 0x0f,
+ 0xdc, 0x54, 0x27, 0xbd, 0xf7, 0xd4, 0xf1, 0x00,
+ 0xcf, 0xdc, 0xd3, 0xf2, 0x97, 0x9e, 0x20, 0x18,
+ 0xc4, 0x45, 0x00, 0x83, 0x52, 0xf9, 0xfe, 0xb2,
+ 0xd5, 0xd5, 0xd4, 0x40, 0x78, 0x80, 0x65, 0xe3,
+ 0xc4, 0x03, 0x37, 0x51, 0xb1, 0xf1, 0xd9, 0x1a,
+ 0x61, 0x01, 0xe2, 0x01, 0x9f, 0x75, 0xeb, 0xea,
+ 0x4f, 0x10, 0x0c, 0xfd, 0xef, 0xea, 0xfc, 0xa9,
+ 0xe2, 0x01, 0x85, 0x44, 0x97, 0xc8, 0xae, 0x6b,
+ 0x1b, 0x32, 0x03, 0xb2, 0x1b, 0x6d, 0x20, 0x0b,
+ 0x05, 0x88, 0xb8, 0xbc, 0x04, 0xf5, 0x95, 0xb1,
+ 0x78, 0xf0, 0x37, 0x21, 0x27, 0xbe, 0x18, 0x33,
+ 0xbb, 0x90, 0xd1, 0x00, 0xb9, 0x17, 0x93, 0xda,
+ 0x77, 0x5b, 0x66, 0x1d, 0x30, 0x14, 0xa9, 0x69,
+ 0x2a, 0x75, 0x96, 0x83, 0xa6, 0x08, 0x4a, 0x8f,
+ 0x1e, 0xce, 0xec, 0x55, 0xa1, 0x20, 0x8e, 0x4e,
+ 0x67, 0xaa, 0x53, 0x8f, 0x06, 0x7a, 0xf5, 0x6f,
+ 0xd4, 0xe8, 0xa1, 0x95, 0xd2, 0xf2, 0x74, 0xa4,
+ 0xb8, 0xf8, 0xe0, 0x10, 0xc6, 0xde, 0x5b, 0x3f,
+ 0x0b, 0x4f, 0x51, 0xa0, 0xe9, 0xff, 0x3e, 0xba,
+ 0x3f, 0x8c, 0x51, 0xd2, 0x74, 0xff, 0xc3, 0x6e,
+ 0xc7, 0xa8, 0x83, 0x7b, 0x0e, 0x9f, 0xb7, 0x84,
+ 0x7d, 0x96, 0x2a, 0x79, 0xab, 0x73, 0x47, 0x4f,
+ 0xb1, 0xa7, 0xad, 0x27, 0x4f, 0x67, 0xd5, 0xe5,
+ 0x40, 0x9f, 0x5f, 0xc8, 0xdb, 0xca, 0x21, 0x53,
+ 0x7b, 0xc2, 0xdf, 0x20, 0xd9, 0x0f, 0xa1, 0x33,
+ 0x3d, 0xef, 0xde, 0xa7, 0x4e, 0xd5, 0xbb, 0xa9,
+ 0xd3, 0xff, 0x01, 0x98, 0x96, 0xf6, 0xd6, 0xd7,
+ 0x49, 0xd3, 0xff, 0x5e, 0xb9, 0xb2, 0xd3, 0x5c,
+ 0xa6, 0xe7, 0x4f, 0xe7, 0xe5, 0x77, 0xd6, 0xf8,
+ 0x74, 0x2a, 0x39, 0x3c, 0x45, 0xc9, 0x1a, 0xa3,
+ 0x4f, 0xb9, 0xb6, 0xdb, 0x29, 0xd3, 0x56, 0xa7,
+ 0x4e, 0x08, 0x42, 0x74, 0xc0, 0xe2, 0x9c, 0x5e,
+ 0x40, 0x9e, 0xb5, 0x4c, 0xa7, 0x70, 0x30, 0xa8,
+ 0x7a, 0x2e, 0xd9, 0x08, 0x0d, 0xc2, 0x19, 0xfd,
+ 0x7f, 0xe5, 0x20, 0xde, 0xf3, 0xa7, 0xfb, 0xf8,
+ 0xdb, 0x1c, 0x10, 0x84, 0xa9, 0xcc, 0xeb, 0x9d,
+ 0x16, 0x3d, 0x56, 0xc7, 0x50, 0xa8, 0xe7, 0xf1,
+ 0xc7, 0x42, 0x2e, 0x7f, 0xf6, 0x6d, 0xcc, 0xca,
+ 0x5f, 0x80, 0xcd, 0x8e, 0x9a, 0xdc, 0x74, 0xcd,
+ 0x54, 0xe9, 0xf6, 0x36, 0xf7, 0xf6, 0xc3, 0x59,
+ 0xbc, 0x56, 0x34, 0x22, 0xe1, 0xce, 0xd3, 0xdb,
+ 0x65, 0xb8, 0xe9, 0xff, 0x97, 0x3e, 0xfb, 0x67,
+ 0xfe, 0xa1, 0x3a, 0x5e, 0x14, 0x44, 0x7c, 0x96,
+ 0xe4, 0x31, 0x43, 0x6d, 0xc0, 0xf8, 0xf4, 0xb6,
+ 0x8f, 0xe7, 0x49, 0x7a, 0x42, 0xbf, 0xc4, 0x23,
+ 0x4b, 0x57, 0xb4, 0x7c, 0xc0, 0x4d, 0xfc, 0x60,
+ 0xd7, 0x8f, 0x79, 0xb4, 0x6e, 0x73, 0xfd, 0x83,
+ 0xf5, 0xbb, 0xf2, 0xc7, 0x4f, 0xdf, 0x06, 0x6d,
+ 0xcf, 0x3a, 0x7d, 0xbd, 0xa7, 0xae, 0xec, 0xa8,
+ 0x54, 0x48, 0xe1, 0xb6, 0xf2, 0xd9, 0xff, 0xc3,
+ 0xa7, 0xfa, 0xf6, 0xfc, 0xaf, 0x97, 0xe7, 0x4b,
+ 0x79, 0xa2, 0x05, 0x95, 0xcd, 0x40, 0xa4, 0xbd,
+ 0x73, 0x78, 0x11, 0xf9, 0xff, 0x7b, 0x72, 0xde,
+ 0xde, 0xe0, 0x01, 0x4a, 0x9f, 0xfd, 0x7a, 0xf5,
+ 0x3a, 0x18, 0xb9, 0xfb, 0xee, 0x1d, 0x0a, 0x89,
+ 0x3f, 0x22, 0x4e, 0xa3, 0xef, 0x3a, 0x15, 0x38,
+ 0x26, 0x42, 0x26, 0xd0, 0xba, 0xd4, 0x8a, 0x7f,
+ 0x3d, 0xac, 0xff, 0x5b, 0x0e, 0x9f, 0xfc, 0x29,
+ 0xfc, 0x6d, 0xfc, 0x51, 0x5a, 0x9d, 0x3f, 0xb9,
+ 0xab, 0x63, 0x32, 0xa7, 0x46, 0x1f, 0xcb, 0x64,
+ 0x79, 0xfb, 0xda, 0x6f, 0x98, 0xc3, 0xa7, 0xd9,
+ 0xb7, 0x86, 0xa7, 0x4f, 0xff, 0x56, 0xf4, 0xa7,
+ 0xad, 0xa1, 0xbf, 0x2d, 0xe6, 0x1d, 0x25, 0xa0,
+ 0xff, 0x42, 0x4f, 0x1e, 0x47, 0xb5, 0x88, 0xef,
+ 0x0a, 0xb9, 0xdb, 0x70, 0x9d, 0x3e, 0x07, 0x7f,
+ 0x1b, 0xce, 0x85, 0x3c, 0x4d, 0x46, 0xe7, 0x95,
+ 0x94, 0xb4, 0x74, 0x2a, 0xa5, 0xf7, 0xc7, 0x43,
+ 0x57, 0x9b, 0x91, 0x4f, 0x03, 0xa9, 0xa9, 0xd3,
+ 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,
};
-static const unsigned kPreloadedHSTSBits = 94538;
+static const unsigned kPreloadedHSTSBits = 97858;
-static const unsigned kHSTSRootPosition = 93961;
+static const unsigned kHSTSRootPosition = 97280;
#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 2517d20..39ca582 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -1395,7 +1395,7 @@
// 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" },
+ { "name": "facebook.com", "mode": "force-https", "pins": "facebook", "include_subdomains_for_pinning": true },
{ "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" },
@@ -1472,7 +1472,50 @@
{ "name": "www.etsy.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "etsysecure.com", "include_subdomains": true, "mode": "force-https" },
{ "name": "18f.gsa.gov", "include_subdomains": true, "mode": "force-https" },
- { "name": "my.usa.gov", "include_subdomains": true, "mode": "force-https" }
+ { "name": "my.usa.gov", "include_subdomains": true, "mode": "force-https" },
+ { "name": "alexyang.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "beamitapp.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "bonigo.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "certly.io", "include_subdomains": true, "mode": "force-https" },
+ { "name": "chontalpa.pw", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cktennis.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "clintwilson.technology", "include_subdomains": true, "mode": "force-https" },
+ { "name": "cspbuilder.info", "include_subdomains": true, "mode": "force-https" },
+ { "name": "depechemode-live.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "destinationbijoux.fr", "include_subdomains": true, "mode": "force-https" },
+ { "name": "dinamoelektrik.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "ethack.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fabianfischer.de", "include_subdomains": true, "mode": "force-https" },
+ { "name": "fastcomcorp.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "gizzo.sk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "inkbunny.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itsamurai.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "itshost.ru", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jmedved.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "jwilsson.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "keepclean.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "klausbrinch.dk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "leonardcamacho.me", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mdfnet.se", "include_subdomains": true, "mode": "force-https" },
+ { "name": "michalspacek.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mike-bland.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "mocloud.eu", "include_subdomains": true, "mode": "force-https" },
+ { "name": "oakslighting.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "onsitemassageco.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "propagandism.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "slevomat.cz", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sour.is", "include_subdomains": true, "mode": "force-https" },
+ { "name": "spongepowered.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "staticanime.net", "include_subdomains": true, "mode": "force-https" },
+ { "name": "sunjaydhama.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "swehack.org", "include_subdomains": true, "mode": "force-https" },
+ { "name": "thusoy.com", "include_subdomains": true, "mode": "force-https" },
+ { "name": "tls.li", "include_subdomains": true, "mode": "force-https" },
+ { "name": "vhost.co.id", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webandwords.com.au", "include_subdomains": true, "mode": "force-https" },
+ { "name": "webtiles.co.uk", "include_subdomains": true, "mode": "force-https" },
+ { "name": "yoursecondphone.co", "include_subdomains": true, "mode": "force-https" },
+ { "name": "zlavomat.sk", "include_subdomains": true, "mode": "force-https" }
],
// |ReportUMAOnPinFailure| uses these to report which domain was associated
diff --git a/net/http/transport_security_state_unittest.cc b/net/http/transport_security_state_unittest.cc
index eb72050..cf5f243 100644
--- a/net/http/transport_security_state_unittest.cc
+++ b/net/http/transport_security_state_unittest.cc
@@ -299,7 +299,6 @@
EXPECT_TRUE(HasStaticState("paypal.com"));
EXPECT_FALSE(HasStaticState("www2.paypal.com"));
- EXPECT_FALSE(HasStaticState("www2.paypal.com"));
// Google hosts:
@@ -535,6 +534,24 @@
EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
EXPECT_TRUE(HasStaticPublicKeyPins("www.twitter.com"));
+
+ // Check that Facebook subdomains have pinning but not HSTS.
+ EXPECT_TRUE(state.GetStaticDomainState("facebook.com", &domain_state));
+ 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_TRUE(state.GetStaticDomainState("www.facebook.com", &domain_state));
+ EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+ EXPECT_TRUE(StaticShouldRedirect("www.facebook.com"));
+
+ EXPECT_TRUE(
+ state.GetStaticDomainState("foo.www.facebook.com", &domain_state));
+ EXPECT_FALSE(domain_state.pkp.spki_hashes.empty());
+ EXPECT_TRUE(StaticShouldRedirect("foo.www.facebook.com"));
}
TEST_F(TransportSecurityStateTest, LongNames) {
diff --git a/net/http/url_security_manager_win.cc b/net/http/url_security_manager_win.cc
index db5620f..5576366 100644
--- a/net/http/url_security_manager_win.cc
+++ b/net/http/url_security_manager_win.cc
@@ -111,11 +111,11 @@
}
bool URLSecurityManagerWin::EnsureSystemSecurityManager() {
- if (!security_manager_) {
+ if (!security_manager_.get()) {
HRESULT hr = CoInternetCreateSecurityManager(NULL,
security_manager_.Receive(),
NULL);
- if (FAILED(hr) || !security_manager_) {
+ if (FAILED(hr) || !security_manager_.get()) {
LOG(ERROR) << "Unable to create the Windows Security Manager instance";
return false;
}
diff --git a/net/net.gyp b/net/net.gyp
index 7b4b5d6..e9379e0 100644
--- a/net/net.gyp
+++ b/net/net.gyp
@@ -376,13 +376,8 @@
}],
[ 'enable_websockets != 1', {
'sources/': [
- ['exclude', '^socket_stream/'],
['exclude', '^websockets/'],
],
- 'sources!': [
- 'spdy/spdy_websocket_stream.cc',
- 'spdy/spdy_websocket_stream.h',
- ],
}],
[ 'enable_mdns != 1', {
'sources!' : [
@@ -654,9 +649,7 @@
}],
[ 'enable_websockets != 1', {
'sources/': [
- ['exclude', '^socket_stream/'],
['exclude', '^websockets/'],
- ['exclude', '^spdy/spdy_websocket_stream_unittest\\.cc$'],
],
}],
['disable_file_support==1', {
@@ -1654,23 +1647,35 @@
'net_javatests',
'net_unittests',
],
+ 'conditions': [
+ ['v8_use_external_startup_data==1', {
+ 'dependencies': [
+ '../v8/tools/gyp/v8.gyp:v8_external_snapshot',
+ ],
+ 'copies': [
+ {
+ 'destination': '<(asset_location)',
+ 'files': [
+ '<(PRODUCT_DIR)/natives_blob.bin',
+ '<(PRODUCT_DIR)/snapshot_blob.bin',
+ ],
+ },
+ ],
+ }],
+ ],
'variables': {
'test_suite_name': 'net_unittests',
'conditions': [
['v8_use_external_startup_data==1', {
+ 'asset_location': '<(PRODUCT_DIR)/net_unittests_apk/assets',
'additional_input_paths': [
+ '<(PRODUCT_DIR)/net_unittests_apk/assets/natives_blob.bin',
+ '<(PRODUCT_DIR)/net_unittests_apk/assets/snapshot_blob.bin',
+ ],
+ 'inputs': [
'<(PRODUCT_DIR)/natives_blob.bin',
'<(PRODUCT_DIR)/snapshot_blob.bin',
],
- 'copies': [
- {
- 'destination': '<(PRODUCT_DIR)/net_unittests_apk/assets',
- 'files': [
- '<(PRODUCT_DIR)/natives_blob.bin',
- '<(PRODUCT_DIR)/snapshot_blob.bin',
- ],
- },
- ],
}],
],
},
diff --git a/net/net.gypi b/net/net.gypi
index f43c67f..fef6136 100644
--- a/net/net.gypi
+++ b/net/net.gypi
@@ -1016,14 +1016,6 @@
'socket/websocket_transport_client_socket_pool.h',
'socket/websocket_transport_connect_sub_job.cc',
'socket/websocket_transport_connect_sub_job.h',
- 'socket_stream/socket_stream.cc',
- 'socket_stream/socket_stream.h',
- 'socket_stream/socket_stream_job.cc',
- 'socket_stream/socket_stream_job.h',
- 'socket_stream/socket_stream_job_manager.cc',
- 'socket_stream/socket_stream_job_manager.h',
- 'socket_stream/socket_stream_metrics.cc',
- 'socket_stream/socket_stream_metrics.h',
'spdy/buffered_spdy_framer.cc',
'spdy/buffered_spdy_framer.h',
'spdy/fuzzing/hpack_fuzz_util.cc',
@@ -1089,8 +1081,6 @@
'spdy/spdy_session_pool.h',
'spdy/spdy_stream.cc',
'spdy/spdy_stream.h',
- 'spdy/spdy_websocket_stream.cc',
- 'spdy/spdy_websocket_stream.h',
'spdy/spdy_write_queue.cc',
'spdy/spdy_write_queue.h',
'spdy/write_blocked_list.h',
@@ -1249,15 +1239,9 @@
'websockets/websocket_handshake_stream_create_helper.h',
'websockets/websocket_inflater.cc',
'websockets/websocket_inflater.h',
- 'websockets/websocket_job.cc',
- 'websockets/websocket_job.h',
'websockets/websocket_mux.h',
- 'websockets/websocket_net_log_params.cc',
- 'websockets/websocket_net_log_params.h',
'websockets/websocket_stream.cc',
'websockets/websocket_stream.h',
- 'websockets/websocket_throttle.cc',
- 'websockets/websocket_throttle.h',
],
'net_extras_sources': [
'extras/sqlite/sqlite_channel_id_store.cc',
@@ -1613,8 +1597,6 @@
'socket/unix_domain_server_socket_posix_unittest.cc',
'socket/websocket_endpoint_lock_manager_unittest.cc',
'socket/websocket_transport_client_socket_pool_unittest.cc',
- 'socket_stream/socket_stream_metrics_unittest.cc',
- 'socket_stream/socket_stream_unittest.cc',
'spdy/buffered_spdy_framer_unittest.cc',
'spdy/fuzzing/hpack_fuzz_util_test.cc',
'spdy/hpack_decoder_test.cc',
@@ -1657,9 +1639,6 @@
'spdy/spdy_test_util_common.h',
'spdy/spdy_test_utils.cc',
'spdy/spdy_test_utils.h',
- 'spdy/spdy_websocket_stream_unittest.cc',
- 'spdy/spdy_websocket_test_util.cc',
- 'spdy/spdy_websocket_test_util.h',
'spdy/spdy_write_queue_unittest.cc',
'spdy/write_blocked_list_test.cc',
'ssl/channel_id_service_unittest.cc',
@@ -1722,16 +1701,12 @@
'websockets/websocket_extension_parser_test.cc',
'websockets/websocket_frame_parser_test.cc',
'websockets/websocket_frame_test.cc',
- 'websockets/websocket_handshake_handler_spdy_test.cc',
'websockets/websocket_handshake_handler_test.cc',
'websockets/websocket_handshake_stream_create_helper_test.cc',
'websockets/websocket_inflater_test.cc',
- 'websockets/websocket_job_test.cc',
- 'websockets/websocket_net_log_params_test.cc',
'websockets/websocket_stream_test.cc',
'websockets/websocket_test_util.cc',
'websockets/websocket_test_util.h',
- 'websockets/websocket_throttle_test.cc',
],
'net_linux_test_sources': [
'quic/quic_end_to_end_unittest.cc',
diff --git a/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc b/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
index 8e19001..dc0d1b4 100644
--- a/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
+++ b/net/proxy/dhcp_proxy_script_adapter_fetcher_win_unittest.cc
@@ -86,7 +86,7 @@
dhcp_query_ = new DelayingDhcpQuery();
dhcp_query_->dhcp_delay_ = dhcp_delay_;
dhcp_query_->configured_url_ = configured_url_;
- return dhcp_query_;
+ return dhcp_query_.get();
}
// Use a shorter timeout so tests can finish more quickly.
@@ -116,7 +116,7 @@
}
void FinishTest() {
- DCHECK(dhcp_query_);
+ DCHECK(dhcp_query_.get());
dhcp_query_->test_finished_event_.Signal();
}
diff --git a/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc b/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
index eb98330..c3368ac 100644
--- a/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
+++ b/net/proxy/dhcp_proxy_script_fetcher_win_unittest.cc
@@ -330,7 +330,7 @@
}
virtual AdapterQuery* ImplCreateAdapterQuery() override {
- DCHECK(adapter_query_);
+ DCHECK(adapter_query_.get());
return adapter_query_.get();
}
diff --git a/net/quic/crypto/quic_crypto_client_config.cc b/net/quic/crypto/quic_crypto_client_config.cc
index 8b6dfb7..4828c3a 100644
--- a/net/quic/crypto/quic_crypto_client_config.cc
+++ b/net/quic/crypto/quic_crypto_client_config.cc
@@ -32,25 +32,21 @@
namespace {
-enum ServerConfigState {
- // WARNING: Do not change the numerical values of any of server config state.
- // Do not remove deprecated server config states - just comment them as
- // deprecated.
- SERVER_CONFIG_EMPTY = 0,
- SERVER_CONFIG_INVALID = 1,
- SERVER_CONFIG_CORRUPTED = 2,
- SERVER_CONFIG_EXPIRED = 3,
- SERVER_CONFIG_INVALID_EXPIRY = 4,
+// Tracks the reason (the state of the server config) for sending inchoate
+// ClientHello to the server.
+void RecordInchoateClientHelloReason(
+ QuicCryptoClientConfig::CachedState::ServerConfigState state) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicInchoateClientHelloReason", state,
+ QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
+}
- // NOTE: Add new server config states only immediately above this line. Make
- // sure to update the QuicServerConfigState enum in
- // tools/metrics/histograms/histograms.xml accordingly.
- SERVER_CONFIG_COUNT
-};
-
-void RecordServerConfigState(ServerConfigState server_config_state) {
- UMA_HISTOGRAM_ENUMERATION("Net.QuicClientHelloServerConfigState",
- server_config_state, SERVER_CONFIG_COUNT);
+// Tracks the state of the QUIC server information loaded from the disk cache.
+void RecordDiskCacheServerConfigState(
+ QuicCryptoClientConfig::CachedState::ServerConfigState state) {
+ UMA_HISTOGRAM_ENUMERATION(
+ "Net.QuicServerInfo.DiskCacheState", state,
+ QuicCryptoClientConfig::CachedState::SERVER_CONFIG_COUNT);
}
} // namespace
@@ -72,12 +68,12 @@
bool QuicCryptoClientConfig::CachedState::IsComplete(QuicWallTime now) const {
if (server_config_.empty()) {
- RecordServerConfigState(SERVER_CONFIG_EMPTY);
+ RecordInchoateClientHelloReason(SERVER_CONFIG_EMPTY);
return false;
}
if (!server_config_valid_) {
- RecordServerConfigState(SERVER_CONFIG_INVALID);
+ RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID);
return false;
}
@@ -85,13 +81,13 @@
if (!scfg) {
// Should be impossible short of cache corruption.
DCHECK(false);
- RecordServerConfigState(SERVER_CONFIG_CORRUPTED);
+ RecordInchoateClientHelloReason(SERVER_CONFIG_CORRUPTED);
return false;
}
uint64 expiry_seconds;
if (scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
- RecordServerConfigState(SERVER_CONFIG_INVALID_EXPIRY);
+ RecordInchoateClientHelloReason(SERVER_CONFIG_INVALID_EXPIRY);
return false;
}
if (now.ToUNIXSeconds() >= expiry_seconds) {
@@ -99,7 +95,7 @@
"Net.QuicClientHelloServerConfig.InvalidDuration",
base::TimeDelta::FromSeconds(now.ToUNIXSeconds() - expiry_seconds),
base::TimeDelta::FromMinutes(1), base::TimeDelta::FromDays(20), 50);
- RecordServerConfigState(SERVER_CONFIG_EXPIRED);
+ RecordInchoateClientHelloReason(SERVER_CONFIG_EXPIRED);
return false;
}
@@ -123,7 +119,8 @@
return scfg_.get();
}
-QuicErrorCode QuicCryptoClientConfig::CachedState::SetServerConfig(
+QuicCryptoClientConfig::CachedState::ServerConfigState
+QuicCryptoClientConfig::CachedState::SetServerConfig(
StringPiece server_config, QuicWallTime now, string* error_details) {
const bool matches_existing = server_config == server_config_;
@@ -141,18 +138,18 @@
if (!new_scfg) {
*error_details = "SCFG invalid";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ return SERVER_CONFIG_INVALID;
}
uint64 expiry_seconds;
if (new_scfg->GetUint64(kEXPY, &expiry_seconds) != QUIC_NO_ERROR) {
*error_details = "SCFG missing EXPY";
- return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
+ return SERVER_CONFIG_INVALID_EXPIRY;
}
if (now.ToUNIXSeconds() >= expiry_seconds) {
*error_details = "SCFG has expired";
- return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
+ return SERVER_CONFIG_EXPIRED;
}
if (!matches_existing) {
@@ -160,7 +157,7 @@
SetProofInvalid();
scfg_.reset(new_scfg_storage.release());
}
- return QUIC_NO_ERROR;
+ return SERVER_CONFIG_VALID;
}
void QuicCryptoClientConfig::CachedState::InvalidateServerConfig() {
@@ -228,13 +225,15 @@
DCHECK(server_config_.empty());
if (server_config.empty()) {
+ RecordDiskCacheServerConfigState(SERVER_CONFIG_EMPTY);
return false;
}
string error_details;
- QuicErrorCode error = SetServerConfig(server_config, now,
- &error_details);
- if (error != QUIC_NO_ERROR) {
+ ServerConfigState state = SetServerConfig(server_config, now,
+ &error_details);
+ RecordDiskCacheServerConfigState(state);
+ if (state != SERVER_CONFIG_VALID) {
DVLOG(1) << "SetServerConfig failed with " << error_details;
return false;
}
@@ -325,7 +324,10 @@
CachedState* cached = new CachedState;
cached_states_.insert(make_pair(server_id, cached));
- PopulateFromCanonicalConfig(server_id, cached);
+ bool cache_populated = PopulateFromCanonicalConfig(server_id, cached);
+ UMA_HISTOGRAM_BOOLEAN(
+ "Net.QuicCryptoClientConfig.PopulatedFromCanonicalConfig",
+ cache_populated);
return cached;
}
@@ -591,9 +593,15 @@
return QUIC_CRYPTO_MESSAGE_PARAMETER_NOT_FOUND;
}
- QuicErrorCode error = cached->SetServerConfig(scfg, now, error_details);
- if (error != QUIC_NO_ERROR) {
- return error;
+ CachedState::ServerConfigState state = cached->SetServerConfig(
+ scfg, now, error_details);
+ if (state == CachedState::SERVER_CONFIG_EXPIRED) {
+ return QUIC_CRYPTO_SERVER_CONFIG_EXPIRED;
+ }
+ // TODO(rtenneti): Return more specific error code than returning
+ // QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER.
+ if (state != CachedState::SERVER_CONFIG_VALID) {
+ return QUIC_INVALID_CRYPTO_MESSAGE_PARAMETER;
}
StringPiece token;
@@ -829,7 +837,7 @@
disable_ecdsa_ = true;
}
-void QuicCryptoClientConfig::PopulateFromCanonicalConfig(
+bool QuicCryptoClientConfig::PopulateFromCanonicalConfig(
const QuicServerId& server_id,
CachedState* server_state) {
DCHECK(server_state->IsEmpty());
@@ -840,7 +848,7 @@
}
}
if (i == canonical_suffixes_.size())
- return;
+ return false;
QuicServerId suffix_server_id(canonical_suffixes_[i], server_id.port(),
server_id.is_https(),
@@ -849,20 +857,21 @@
// This is the first host we've seen which matches the suffix, so make it
// canonical.
canonical_server_map_[suffix_server_id] = server_id;
- return;
+ return false;
}
const QuicServerId& canonical_server_id =
canonical_server_map_[suffix_server_id];
CachedState* canonical_state = cached_states_[canonical_server_id];
if (!canonical_state->proof_valid()) {
- return;
+ return false;
}
// Update canonical version to point at the "most recent" entry.
canonical_server_map_[suffix_server_id] = server_id;
server_state->InitializeFrom(*canonical_state);
+ return true;
}
} // namespace net
diff --git a/net/quic/crypto/quic_crypto_client_config.h b/net/quic/crypto/quic_crypto_client_config.h
index 26fde24..4bfed1b 100644
--- a/net/quic/crypto/quic_crypto_client_config.h
+++ b/net/quic/crypto/quic_crypto_client_config.h
@@ -35,6 +35,24 @@
// over several connections to the same server.
class NET_EXPORT_PRIVATE CachedState {
public:
+ // Enum to track if the server config is valid or not. If it is not valid,
+ // it specifies why it is invalid.
+ enum ServerConfigState {
+ // WARNING: Do not change the numerical values of any of server config
+ // state. Do not remove deprecated server config states - just comment
+ // them as deprecated.
+ SERVER_CONFIG_EMPTY = 0,
+ SERVER_CONFIG_INVALID = 1,
+ SERVER_CONFIG_CORRUPTED = 2,
+ SERVER_CONFIG_EXPIRED = 3,
+ SERVER_CONFIG_INVALID_EXPIRY = 4,
+ SERVER_CONFIG_VALID = 5,
+ // NOTE: Add new server config states only immediately above this line.
+ // Make sure to update the QuicServerConfigState enum in
+ // tools/metrics/histograms/histograms.xml accordingly.
+ SERVER_CONFIG_COUNT
+ };
+
CachedState();
~CachedState();
@@ -54,9 +72,9 @@
// SetServerConfig checks that |server_config| parses correctly and stores
// it in |server_config_|. |now| is used to judge whether |server_config|
// has expired.
- QuicErrorCode SetServerConfig(base::StringPiece server_config,
- QuicWallTime now,
- std::string* error_details);
+ ServerConfigState SetServerConfig(base::StringPiece server_config,
+ QuicWallTime now,
+ std::string* error_details);
// InvalidateServerConfig clears the cached server config (if any).
void InvalidateServerConfig();
@@ -282,8 +300,9 @@
// If the suffix of the hostname in |server_id| is in |canonical_suffixes_|,
// then populate |cached| with the canonical cached state from
- // |canonical_server_map_| for that suffix.
- void PopulateFromCanonicalConfig(const QuicServerId& server_id,
+ // |canonical_server_map_| for that suffix. Returns true if |cached| is
+ // initialized with canonical cached state.
+ bool PopulateFromCanonicalConfig(const QuicServerId& server_id,
CachedState* cached);
// cached_states_ maps from the server_id to the cached information about
diff --git a/net/quic/crypto/quic_server_info.h b/net/quic/crypto/quic_server_info.h
index 2a5c6fc..c6525c8 100644
--- a/net/quic/crypto/quic_server_info.h
+++ b/net/quic/crypto/quic_server_info.h
@@ -64,6 +64,9 @@
// callback.
virtual void Persist() = 0;
+ // Called whenever an external cache reuses quic server config.
+ virtual void OnExternalCacheHit() = 0;
+
struct State {
State();
~State();
diff --git a/net/quic/quic_client_session.cc b/net/quic/quic_client_session.cc
index 7c220ad..73a5aec 100644
--- a/net/quic/quic_client_session.cc
+++ b/net/quic/quic_client_session.cc
@@ -590,6 +590,8 @@
++it;
observer->OnCryptoHandshakeConfirmed();
}
+ if (server_info_)
+ server_info_->OnExternalCacheHit();
}
QuicSession::OnCryptoHandshakeEvent(event);
}
@@ -682,7 +684,7 @@
const QuicCryptoClientConfig::CachedState& cached) {
DCHECK(cached.proof_valid());
- if (!server_info_ || !server_info_->IsReadyToPersist()) {
+ if (!server_info_) {
return;
}
diff --git a/net/quic/quic_headers_stream.cc b/net/quic/quic_headers_stream.cc
index b99e9d2..10a02a7 100644
--- a/net/quic/quic_headers_stream.cc
+++ b/net/quic/quic_headers_stream.cc
@@ -115,7 +115,11 @@
CloseConnection("SPDY GOAWAY frame received.");
}
- void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override {
+ void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
+ bool fin,
+ bool end) override {
CloseConnection("SPDY HEADERS frame received.");
}
diff --git a/net/quic/quic_headers_stream_test.cc b/net/quic/quic_headers_stream_test.cc
index 32d22fe..8649a3e 100644
--- a/net/quic/quic_headers_stream_test.cc
+++ b/net/quic/quic_headers_stream_test.cc
@@ -52,7 +52,8 @@
MOCK_METHOD2(OnPing, void(SpdyPingId unique_id, bool is_ack));
MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status));
- MOCK_METHOD3(OnHeaders, void(SpdyStreamId stream_id, bool fin, bool end));
+ MOCK_METHOD5(OnHeaders, void(SpdyStreamId stream_id, bool has_priority,
+ SpdyPriority priority, bool fin, bool end));
MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
uint32 delta_window_size));
MOCK_METHOD2(OnCredentialFrameData, bool(const char* credential_data,
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 62fe895..ab926d5 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -214,7 +214,7 @@
if (use_next_protos) {
params_.use_alternate_protocols = true;
- params_.next_protos = NextProtosSpdy3();
+ params_.next_protos = NextProtosWithSpdyAndQuic(true, true);
}
session_ = new HttpNetworkSession(params_);
diff --git a/net/quic/quic_protocol.h b/net/quic/quic_protocol.h
index afd5ed4..ad920d0 100644
--- a/net/quic/quic_protocol.h
+++ b/net/quic/quic_protocol.h
@@ -76,6 +76,9 @@
// Smaller values are ignored.
const QuicByteCount kMinSocketReceiveBuffer = 16 * 1024;
+// Don't allow a client to suggest an RTT shorter than 10ms.
+const uint32 kMinInitialRoundTripTimeUs = 10 * kNumMicrosPerMilli;
+
// Don't allow a client to suggest an RTT longer than 15 seconds.
const uint32 kMaxInitialRoundTripTimeUs = 15 * kNumMicrosPerSecond;
diff --git a/net/quic/quic_sent_packet_manager.cc b/net/quic/quic_sent_packet_manager.cc
index bdf8690..9e2d04f 100644
--- a/net/quic/quic_sent_packet_manager.cc
+++ b/net/quic/quic_sent_packet_manager.cc
@@ -97,12 +97,16 @@
void QuicSentPacketManager::SetFromConfig(const QuicConfig& config) {
if (config.HasReceivedInitialRoundTripTimeUs() &&
config.ReceivedInitialRoundTripTimeUs() > 0) {
- rtt_stats_.set_initial_rtt_us(min(kMaxInitialRoundTripTimeUs,
- config.ReceivedInitialRoundTripTimeUs()));
- } else if (config.HasInitialRoundTripTimeUsToSend()) {
rtt_stats_.set_initial_rtt_us(
- min(kMaxInitialRoundTripTimeUs,
- config.GetInitialRoundTripTimeUsToSend()));
+ max(kMinInitialRoundTripTimeUs,
+ min(kMaxInitialRoundTripTimeUs,
+ config.ReceivedInitialRoundTripTimeUs())));
+ } else if (config.HasInitialRoundTripTimeUsToSend() &&
+ config.GetInitialRoundTripTimeUsToSend() > 0) {
+ rtt_stats_.set_initial_rtt_us(
+ max(kMinInitialRoundTripTimeUs,
+ min(kMaxInitialRoundTripTimeUs,
+ config.GetInitialRoundTripTimeUsToSend())));
}
// TODO(ianswett): BBR is currently a server only feature.
if (FLAGS_quic_allow_bbr &&
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index cf70608..076797a 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -944,6 +944,14 @@
}
}
+ if (quic_server_info_factory_ && !server_info) {
+ // Start the disk cache loading so that we can persist the newer QUIC server
+ // information and/or inform the disk cache that we have reused
+ // |server_info|.
+ server_info.reset(quic_server_info_factory_->GetForServer(server_id));
+ server_info->Start();
+ }
+
*session = new QuicClientSession(
connection, socket.Pass(), this, transport_security_state_,
server_info.Pass(), config, server_id.is_https(),
@@ -985,6 +993,8 @@
void QuicStreamFactory::InitializeCachedStateInCryptoConfig(
const QuicServerId& server_id,
const scoped_ptr<QuicServerInfo>& server_info) {
+ // |server_info| will be NULL, if a non-empty server config already exists in
+ // the memory cache. This is a minor optimization to avoid LookupOrCreate.
if (!server_info)
return;
@@ -993,6 +1003,27 @@
if (!cached->IsEmpty())
return;
+ if (http_server_properties_) {
+ if (quic_supported_servers_at_startup_.empty()) {
+ for (const std::pair<net::HostPortPair, net::AlternateProtocolInfo>&
+ key_value : http_server_properties_->alternate_protocol_map()) {
+ if (key_value.second.protocol == QUIC) {
+ quic_supported_servers_at_startup_.insert(key_value.first);
+ }
+ }
+ }
+
+ // TODO(rtenneti): Delete the following histogram after collecting stats.
+ // If the AlternateProtocolMap contained an entry for this host, check if
+ // the disk cache contained an entry for it.
+ if (ContainsKey(quic_supported_servers_at_startup_,
+ server_id.host_port_pair())) {
+ UMA_HISTOGRAM_BOOLEAN(
+ "Net.QuicServerInfo.ExpectConfigMissingFromDiskCache",
+ server_info->state().server_config.empty());
+ }
+ }
+
if (!cached->Initialize(server_info->state().server_config,
server_info->state().source_address_token,
server_info->state().certs,
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h
index c892cb2..2fad1fc 100644
--- a/net/quic/quic_stream_factory.h
+++ b/net/quic/quic_stream_factory.h
@@ -299,6 +299,7 @@
// Local address of socket that was created in CreateSession.
IPEndPoint local_address_;
bool check_persisted_supports_quic_;
+ std::set<HostPortPair> quic_supported_servers_at_startup_;
base::TaskRunner* task_runner_;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc
index 1165b9c..05234c0 100644
--- a/net/quic/quic_stream_factory_test.cc
+++ b/net/quic/quic_stream_factory_test.cc
@@ -121,6 +121,8 @@
virtual bool IsReadyToPersist() override { return false; }
virtual void Persist() override {};
+
+ virtual void OnExternalCacheHit() override {};
};
class MockQuicServerInfoFactory : public QuicServerInfoFactory {
diff --git a/net/quic/quic_time.h b/net/quic/quic_time.h
index 5fbe30c..53e5ebe 100644
--- a/net/quic/quic_time.h
+++ b/net/quic/quic_time.h
@@ -18,6 +18,8 @@
namespace net {
static const uint64 kNumMicrosPerSecond = base::Time::kMicrosecondsPerSecond;
+static const uint64 kNumMicrosPerMilli =
+ base::Time::kMicrosecondsPerMillisecond;
// A QuicTime is a purely relative time. QuicTime values from different clocks
// cannot be compared to each other. If you need an absolute time, see
diff --git a/net/quic/quic_utils.cc b/net/quic/quic_utils.cc
index d786a95..f144651 100644
--- a/net/quic/quic_utils.cc
+++ b/net/quic/quic_utils.cc
@@ -7,12 +7,15 @@
#include <ctype.h>
#include <algorithm>
+#include <vector>
#include "base/basictypes.h"
+#include "base/containers/adapters.h"
#include "base/logging.h"
#include "base/port.h"
#include "base/strings/stringprintf.h"
#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
#include "net/quic/quic_write_blocked_list.h"
using base::StringPiece;
@@ -280,6 +283,25 @@
}
// static
+QuicTagVector QuicUtils::ParseQuicConnectionOptions(
+ const std::string& connection_options) {
+ QuicTagVector options;
+ std::vector<std::string> tokens;
+ base::SplitString(connection_options, ',', &tokens);
+ // Tokens are expected to be no more than 4 characters long, but we
+ // handle overflow gracefully.
+ for (const std::string& token : tokens) {
+ uint32 option = 0;
+ for (char token_char : base::Reversed(token)) {
+ option <<= 8;
+ option |= static_cast<unsigned char>(token_char);
+ }
+ options.push_back(option);
+ }
+ return options;
+}
+
+// static
string QuicUtils::StringToHexASCIIDump(StringPiece in_buffer) {
int offset = 0;
const int kBytesPerLine = 16; // Max bytes dumped per line
diff --git a/net/quic/quic_utils.h b/net/quic/quic_utils.h
index 1ecb37d..2c34ec4 100644
--- a/net/quic/quic_utils.h
+++ b/net/quic/quic_utils.h
@@ -7,6 +7,8 @@
#ifndef NET_QUIC_QUIC_UTILS_H_
#define NET_QUIC_QUIC_UTILS_H_
+#include <string>
+
#include "net/base/int128.h"
#include "net/base/net_export.h"
#include "net/quic/quic_protocol.h"
@@ -68,6 +70,11 @@
// if not.
static std::string TagToString(QuicTag tag);
+ // Returns the list of QUIC tags represented by the comma separated
+ // string in |connection_options|.
+ static QuicTagVector ParseQuicConnectionOptions(
+ const std::string& connection_options);
+
// Given a binary buffer, return a hex+ASCII dump in the style of
// tcpdump's -X and -XX options:
// "0x0000: 0090 69bd 5400 000d 610f 0189 0800 4500 ..i.T...a.....E.\n"
diff --git a/net/quic/quic_utils_test.cc b/net/quic/quic_utils_test.cc
index b7d23ed..d2f2631 100644
--- a/net/quic/quic_utils_test.cc
+++ b/net/quic/quic_utils_test.cc
@@ -84,6 +84,20 @@
QuicUtils::TagToString(MakeQuicTag('C', 'H', 'L', '\x1f')));
}
+TEST(QuicUtilsTest, ParseQuicConnectionOptions) {
+ QuicTagVector empty_options = QuicUtils::ParseQuicConnectionOptions("");
+ EXPECT_EQ(0ul, empty_options.size());
+
+ QuicTagVector parsed_options = QuicUtils::ParseQuicConnectionOptions(
+ "PACE,TIMER,TBBR,REJ");
+ QuicTagVector expected_options;
+ expected_options.push_back(net::kPACE);
+ expected_options.push_back(net::kTIME);
+ expected_options.push_back(net::kTBBR);
+ expected_options.push_back(net::kREJ);
+ EXPECT_EQ(expected_options, parsed_options);
+}
+
} // namespace
} // namespace test
} // namespace net
diff --git a/net/quic/test_tools/crypto_test_utils_openssl.cc b/net/quic/test_tools/crypto_test_utils_openssl.cc
index 39b48a5..5bcbccb 100644
--- a/net/quic/test_tools/crypto_test_utils_openssl.cc
+++ b/net/quic/test_tools/crypto_test_utils_openssl.cc
@@ -64,9 +64,10 @@
// The signature consists of a pair of 32-byte numbers.
static const size_t kSignatureLength = 32 * 2;
scoped_ptr<uint8[]> signature(new uint8[kSignatureLength]);
- memset(signature.get(), 0, kSignatureLength);
- BN_bn2bin(sig.get()->r, signature.get() + 32 - BN_num_bytes(sig.get()->r));
- BN_bn2bin(sig.get()->s, signature.get() + 64 - BN_num_bytes(sig.get()->s));
+ if (!BN_bn2bin_padded(&signature[0], 32, sig->r) ||
+ !BN_bn2bin_padded(&signature[32], 32, sig->s)) {
+ return false;
+ }
*out_signature = string(reinterpret_cast<char*>(signature.get()),
kSignatureLength);
diff --git a/net/socket/next_proto.cc b/net/socket/next_proto.cc
index 4ae4511..0e59ce7 100644
--- a/net/socket/next_proto.cc
+++ b/net/socket/next_proto.cc
@@ -31,13 +31,6 @@
return next_protos;
}
-NextProtoVector NextProtosSpdy3() {
- NextProtoVector next_protos;
- next_protos.push_back(kProtoHTTP11);
- next_protos.push_back(kProtoQUIC1SPDY3);
- return next_protos;
-}
-
NextProtoVector NextProtosSpdy31() {
NextProtoVector next_protos;
next_protos.push_back(kProtoHTTP11);
@@ -46,21 +39,13 @@
return next_protos;
}
-NextProtoVector NextProtosSpdy31WithSpdy2() {
- NextProtoVector next_protos;
- next_protos.push_back(kProtoHTTP11);
- next_protos.push_back(kProtoQUIC1SPDY3);
- next_protos.push_back(kProtoDeprecatedSPDY2);
- next_protos.push_back(kProtoSPDY31);
- return next_protos;
-}
-
NextProtoVector NextProtosSpdy4Http2() {
NextProtoVector next_protos;
next_protos.push_back(kProtoHTTP11);
next_protos.push_back(kProtoQUIC1SPDY3);
next_protos.push_back(kProtoSPDY31);
- next_protos.push_back(kProtoSPDY4);
+ next_protos.push_back(kProtoSPDY4_14);
+ next_protos.push_back(kProtoSPDY4_15);
return next_protos;
}
diff --git a/net/socket/next_proto.h b/net/socket/next_proto.h
index 465001d..c12a45b 100644
--- a/net/socket/next_proto.h
+++ b/net/socket/next_proto.h
@@ -25,11 +25,14 @@
kProtoDeprecatedSPDY2 = 100,
kProtoSPDYMinimumVersion = kProtoDeprecatedSPDY2,
+ kProtoSPDYHistogramOffset = kProtoDeprecatedSPDY2,
kProtoSPDY3 = 101,
kProtoSPDY31 = 102,
- // HTTP/2 draft-14 was 103,
- kProtoSPDY4 = 104, // SPDY4 is HTTP/2 draft-15.
- kProtoSPDYMaximumVersion = kProtoSPDY4,
+ kProtoSPDY4_14 = 103, // HTTP/2 draft-14
+ kProtoSPDY4MinimumVersion = kProtoSPDY4_14,
+ kProtoSPDY4_15 = 104, // HTTP/2 draft-15
+ kProtoSPDY4MaximumVersion = kProtoSPDY4_15,
+ kProtoSPDYMaximumVersion = kProtoSPDY4MaximumVersion,
kProtoQUIC1SPDY3 = 200,
@@ -51,9 +54,7 @@
bool quic_enabled);
// All of these also enable QUIC.
-NET_EXPORT NextProtoVector NextProtosSpdy3();
NET_EXPORT NextProtoVector NextProtosSpdy31();
-NET_EXPORT NextProtoVector NextProtosSpdy31WithSpdy2();
NET_EXPORT NextProtoVector NextProtosSpdy4Http2();
} // namespace net
diff --git a/net/socket/ssl_client_socket.cc b/net/socket/ssl_client_socket.cc
index 269ca7e..a52e6a3 100644
--- a/net/socket/ssl_client_socket.cc
+++ b/net/socket/ssl_client_socket.cc
@@ -37,10 +37,13 @@
return kProtoSPDY3;
} else if (proto_string == "spdy/3.1") {
return kProtoSPDY31;
+ } else if (proto_string == "h2-14") {
+ // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
+ // This is the HTTP/2 draft-14 identifier.
+ return kProtoSPDY4_14;
} else if (proto_string == "h2-15") {
- // This is the HTTP/2 draft-15 identifier. For internal
- // consistency, HTTP/2 is named SPDY4 within Chromium.
- return kProtoSPDY4;
+ // This is the HTTP/2 draft-15 identifier.
+ return kProtoSPDY4_15;
} else if (proto_string == "quic/1+spdy/3") {
return kProtoQUIC1SPDY3;
} else {
@@ -59,9 +62,12 @@
return "spdy/3";
case kProtoSPDY31:
return "spdy/3.1";
- case kProtoSPDY4:
- // This is the HTTP/2 draft-15 identifier. For internal
- // consistency, HTTP/2 is named SPDY4 within Chromium.
+ case kProtoSPDY4_14:
+ // For internal consistency, HTTP/2 is named SPDY4 within Chromium.
+ // This is the HTTP/2 draft-14 identifier.
+ return "h2-14";
+ case kProtoSPDY4_15:
+ // This is the HTTP/2 draft-15 identifier.
return "h2-15";
case kProtoQUIC1SPDY3:
return "quic/1+spdy/3";
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 31a9b8d..3e5bde0 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -218,8 +218,6 @@
return GetCacheOCSPResponseFromSideChannelFunction() != NULL;
}
#else
-// TODO(agl): Figure out if we can plumb the OCSP response into Mac's system
-// certificate validation functions.
bool IsOCSPStaplingSupported() {
return false;
}
@@ -1292,7 +1290,7 @@
core->client_auth_cert_needed_ = !core->ssl_config_.send_client_cert;
#if defined(OS_WIN)
if (core->ssl_config_.send_client_cert) {
- if (core->ssl_config_.client_cert) {
+ if (core->ssl_config_.client_cert.get()) {
PCCERT_CONTEXT cert_context =
core->ssl_config_.client_cert->os_cert_handle();
@@ -1630,8 +1628,8 @@
}
void SSLClientSocketNSS::Core::HandshakeSucceeded() {
- // TODO(vadimt): Remove ScopedProfile below once crbug.com/424386 is fixed.
- tracked_objects::ScopedProfile tracking_profile(
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"424386 SSLClientSocketNSS::Core::HandshakeSucceeded"));
@@ -1661,8 +1659,8 @@
}
int SSLClientSocketNSS::Core::HandleNSSError(PRErrorCode nss_error) {
- // TODO(vadimt): Remove ScopedProfile below once crbug.com/424386 is fixed.
- tracked_objects::ScopedProfile tracking_profile(
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"424386 SSLClientSocketNSS::Core::HandleNSSError"));
@@ -1687,7 +1685,7 @@
// re-insert the smart card if not.
if ((net_error == ERR_SSL_CLIENT_AUTH_CERT_NO_PRIVATE_KEY ||
net_error == ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED) &&
- ssl_config_.send_client_cert && ssl_config_.client_cert) {
+ ssl_config_.send_client_cert && ssl_config_.client_cert.get()) {
CertSetCertificateContextProperty(
ssl_config_.client_cert->os_cert_handle(),
CERT_KEY_PROV_HANDLE_PROP_ID, 0, NULL);
@@ -1813,8 +1811,8 @@
int net_error = OK;
SECStatus rv = SSL_ForceHandshake(nss_fd_);
- // TODO(vadimt): Remove ScopedProfile below once crbug.com/424386 is fixed.
- tracked_objects::ScopedProfile tracking_profile1(
+ // TODO(vadimt): Remove ScopedTracker below once crbug.com/424386 is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
FROM_HERE_WITH_EXPLICIT_FUNCTION(
"424386 SSLClientSocketNSS::Core::DoHandshake 1"));
@@ -2436,11 +2434,9 @@
reinterpret_cast<char*>(ocsp_responses->items[0].data),
ocsp_responses->items[0].len);
- // TODO(agl): figure out how to plumb an OCSP response into the Mac
- // system library and update IsOCSPStaplingSupported for Mac.
if (IsOCSPStaplingSupported()) {
#if defined(OS_WIN)
- if (nss_handshake_state_.server_cert) {
+ if (nss_handshake_state_.server_cert.get()) {
CRYPT_DATA_BLOB ocsp_response_blob;
ocsp_response_blob.cbData = ocsp_responses->items[0].len;
ocsp_response_blob.pbData = ocsp_responses->items[0].data;
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 9fdfe38..57aa619 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -140,6 +140,19 @@
return 1;
}
+bool IsOCSPStaplingSupported() {
+#if defined(OS_WIN)
+ // CERT_OCSP_RESPONSE_PROP_ID is only implemented on Vista+, but it can be
+ // set on Windows XP without error. There is some overhead from the server
+ // sending the OCSP response if it supports the extension, for the subset of
+ // XP clients who will request it but be unable to use it, but this is an
+ // acceptable trade-off for simplicity of implementation.
+ return true;
+#else
+ return false;
+#endif
+}
+
} // namespace
class SSLClientSocketOpenSSL::SSLContext {
@@ -829,8 +842,8 @@
SSL_enable_ocsp_stapling(ssl_);
}
- // TODO(davidben): Enable OCSP stapling on platforms which support it and pass
- // into the certificate verifier. https://crbug.com/398677
+ if (IsOCSPStaplingSupported())
+ SSL_enable_ocsp_stapling(ssl_);
return OK;
}
@@ -933,10 +946,16 @@
ssl_config_.channel_id_enabled,
crypto::ECPrivateKey::IsSupported());
- uint8_t* ocsp_response;
- size_t ocsp_response_len;
- SSL_get0_ocsp_response(ssl_, &ocsp_response, &ocsp_response_len);
- set_stapled_ocsp_response_received(ocsp_response_len != 0);
+ // Only record OCSP histograms if OCSP was requested.
+ if (ssl_config_.signed_cert_timestamps_enabled ||
+ IsOCSPStaplingSupported()) {
+ uint8_t* ocsp_response;
+ size_t ocsp_response_len;
+ SSL_get0_ocsp_response(ssl_, &ocsp_response, &ocsp_response_len);
+
+ set_stapled_ocsp_response_received(ocsp_response_len != 0);
+ UMA_HISTOGRAM_BOOLEAN("Net.OCSPResponseStapled", ocsp_response_len != 0);
+ }
uint8_t* sct_list;
size_t sct_list_len;
@@ -1166,6 +1185,31 @@
NetLog::TYPE_SSL_CERTIFICATES_RECEIVED,
base::Bind(&NetLogX509CertificateCallback,
base::Unretained(server_cert_.get())));
+
+ // TODO(rsleevi): Plumb an OCSP response into the Mac system library and
+ // update IsOCSPStaplingSupported for Mac. https://crbug.com/430714
+ if (IsOCSPStaplingSupported()) {
+#if defined(OS_WIN)
+ uint8_t* ocsp_response_raw;
+ size_t ocsp_response_len;
+ SSL_get0_ocsp_response(ssl_, &ocsp_response_raw, &ocsp_response_len);
+
+ CRYPT_DATA_BLOB ocsp_response_blob;
+ ocsp_response_blob.cbData = ocsp_response_len;
+ ocsp_response_blob.pbData = ocsp_response_raw;
+ BOOL ok = CertSetCertificateContextProperty(
+ server_cert_->os_cert_handle(),
+ CERT_OCSP_RESPONSE_PROP_ID,
+ CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG,
+ &ocsp_response_blob);
+ if (!ok) {
+ VLOG(1) << "Failed to set OCSP response property: "
+ << GetLastError();
+ }
+#else
+ NOTREACHED();
+#endif
+ }
}
}
@@ -1567,6 +1611,8 @@
DVLOG(3) << "OpenSSL ClientCertRequestCallback called";
DCHECK(ssl == ssl_);
+ net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_REQUESTED);
+
// Clear any currently configured certificates.
SSL_certs_clear(ssl_);
@@ -1644,11 +1690,17 @@
LOG(WARNING) << "Failed to set client certificate";
return -1;
}
+
+ int cert_count = 1 + sk_X509_num(chain.get());
+ net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_PROVIDED,
+ NetLog::IntegerCallback("cert_count", cert_count));
return 1;
}
#endif // defined(OS_IOS)
// Send no client certificate.
+ net_log_.AddEvent(NetLog::TYPE_SSL_CLIENT_CERT_PROVIDED,
+ NetLog::IntegerCallback("cert_count", 0));
return 1;
}
diff --git a/net/socket/ssl_client_socket_pool_unittest.cc b/net/socket/ssl_client_socket_pool_unittest.cc
index 202cd88..8ac29ef 100644
--- a/net/socket/ssl_client_socket_pool_unittest.cc
+++ b/net/socket/ssl_client_socket_pool_unittest.cc
@@ -240,7 +240,7 @@
NextProto,
SSLClientSocketPoolTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
// Tests that the final socket will connect even if all sockets
// prior to it fail.
diff --git a/net/socket/tcp_socket_win.cc b/net/socket/tcp_socket_win.cc
index d5565ad..fd3c8b7 100644
--- a/net/socket/tcp_socket_win.cc
+++ b/net/socket/tcp_socket_win.cc
@@ -324,7 +324,7 @@
const IPEndPoint& peer_address) {
DCHECK(CalledOnValidThread());
DCHECK_EQ(socket_, INVALID_SOCKET);
- DCHECK(!core_);
+ DCHECK(!core_.get());
socket_ = socket;
@@ -436,7 +436,7 @@
// again after a connection attempt failed on Windows, it results in
// unspecified behavior according to POSIX. Therefore, we make it behave in
// the same way as TCPSocketLibevent.
- DCHECK(!peer_address_ && !core_);
+ DCHECK(!peer_address_ && !core_.get());
if (!logging_multiple_connect_attempts_)
LogConnectBegin(AddressList(address));
@@ -504,7 +504,7 @@
DCHECK_NE(socket_, INVALID_SOCKET);
DCHECK(!waiting_read_);
CHECK(read_callback_.is_null());
- DCHECK(!core_->read_iobuffer_);
+ DCHECK(!core_->read_iobuffer_.get());
return DoRead(buf, buf_len, callback);
}
@@ -517,7 +517,7 @@
DCHECK(!waiting_write_);
CHECK(write_callback_.is_null());
DCHECK_GT(buf_len, 0);
- DCHECK(!core_->write_iobuffer_);
+ DCHECK(!core_->write_iobuffer_.get());
base::StatsCounter writes("tcp.writes");
writes.Increment();
@@ -689,7 +689,7 @@
accept_event_ = WSA_INVALID_EVENT;
}
- if (core_) {
+ if (core_.get()) {
if (waiting_connect_) {
// We closed the socket, so this notification will never come.
// From MSDN' WSAEventSelect documentation:
@@ -796,7 +796,7 @@
int TCPSocketWin::DoConnect() {
DCHECK_EQ(connect_os_error_, 0);
- DCHECK(!core_);
+ DCHECK(!core_.get());
net_log_.BeginEvent(NetLog::TYPE_TCP_CONNECT_ATTEMPT,
CreateNetLogIPEndPointCallback(peer_address_.get()));
@@ -1018,7 +1018,7 @@
// DoRead() because recv() reports a more accurate error code
// (WSAECONNRESET vs. WSAECONNABORTED) when the connection was
// reset.
- rv = DoRead(core_->read_iobuffer_, core_->read_buffer_length_,
+ rv = DoRead(core_->read_iobuffer_.get(), core_->read_buffer_length_,
read_callback_);
if (rv == ERR_IO_PENDING)
return;
diff --git a/net/socket_stream/OWNERS b/net/socket_stream/OWNERS
deleted file mode 100644
index a2bac60..0000000
--- a/net/socket_stream/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tyoshino@chromium.org
diff --git a/net/socket_stream/socket_stream.cc b/net/socket_stream/socket_stream.cc
deleted file mode 100644
index 422d61d..0000000
--- a/net/socket_stream/socket_stream.cc
+++ /dev/null
@@ -1,1353 +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.
-//
-// TODO(ukai): code is similar with http_network_transaction.cc. We should
-// think about ways to share code, if possible.
-
-#include "net/socket_stream/socket_stream.h"
-
-#include <set>
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/utf_string_conversions.h"
-#include "net/base/auth.h"
-#include "net/base/io_buffer.h"
-#include "net/base/load_flags.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_util.h"
-#include "net/dns/host_resolver.h"
-#include "net/http/http_auth_controller.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_stream_factory.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/http/http_util.h"
-#include "net/socket/client_socket_factory.h"
-#include "net/socket/client_socket_handle.h"
-#include "net/socket/socks5_client_socket.h"
-#include "net/socket/socks_client_socket.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/socket/tcp_client_socket.h"
-#include "net/socket_stream/socket_stream_metrics.h"
-#include "net/ssl/ssl_cert_request_info.h"
-#include "net/ssl/ssl_info.h"
-#include "net/url_request/url_request.h"
-#include "net/url_request/url_request_context.h"
-
-static const int kMaxPendingSendAllowed = 32768; // 32 kilobytes.
-static const int kReadBufferSize = 4096;
-
-namespace net {
-
-int SocketStream::Delegate::OnStartOpenConnection(
- SocketStream* socket, const CompletionCallback& callback) {
- return OK;
-}
-
-void SocketStream::Delegate::OnAuthRequired(SocketStream* socket,
- AuthChallengeInfo* auth_info) {
- // By default, no credential is available and close the connection.
- socket->Close();
-}
-
-void SocketStream::Delegate::OnSSLCertificateError(
- SocketStream* socket,
- const SSLInfo& ssl_info,
- bool fatal) {
- socket->CancelWithSSLError(ssl_info);
-}
-
-bool SocketStream::Delegate::CanGetCookies(SocketStream* socket,
- const GURL& url) {
- return true;
-}
-
-bool SocketStream::Delegate::CanSetCookie(SocketStream* request,
- const GURL& url,
- const std::string& cookie_line,
- CookieOptions* options) {
- return true;
-}
-
-SocketStream::ResponseHeaders::ResponseHeaders() : IOBuffer() {}
-
-void SocketStream::ResponseHeaders::Realloc(size_t new_size) {
- headers_.reset(static_cast<char*>(realloc(headers_.release(), new_size)));
-}
-
-SocketStream::ResponseHeaders::~ResponseHeaders() { data_ = NULL; }
-
-SocketStream::SocketStream(const GURL& url, Delegate* delegate,
- URLRequestContext* context,
- CookieStore* cookie_store)
- : delegate_(delegate),
- url_(url),
- max_pending_send_allowed_(kMaxPendingSendAllowed),
- context_(context),
- next_state_(STATE_NONE),
- factory_(ClientSocketFactory::GetDefaultFactory()),
- proxy_mode_(kDirectConnection),
- proxy_url_(url),
- pac_request_(NULL),
- connection_(new ClientSocketHandle),
- privacy_mode_(PRIVACY_MODE_DISABLED),
- // Unretained() is required; without it, Bind() creates a circular
- // dependency and the SocketStream object will not be freed.
- io_callback_(base::Bind(&SocketStream::OnIOCompleted,
- base::Unretained(this))),
- read_buf_(NULL),
- current_write_buf_(NULL),
- waiting_for_write_completion_(false),
- closing_(false),
- server_closed_(false),
- metrics_(new SocketStreamMetrics(url)),
- cookie_store_(cookie_store) {
- DCHECK(base::MessageLoop::current())
- << "The current base::MessageLoop must exist";
- DCHECK(base::MessageLoopForIO::IsCurrent())
- << "The current base::MessageLoop must be TYPE_IO";
- DCHECK(delegate_);
-
- if (context_) {
- if (!cookie_store_.get())
- cookie_store_ = context_->cookie_store();
-
- net_log_ = BoundNetLog::Make(
- context->net_log(),
- NetLog::SOURCE_SOCKET_STREAM);
-
- net_log_.BeginEvent(NetLog::TYPE_REQUEST_ALIVE);
- }
-}
-
-SocketStream::UserData* SocketStream::GetUserData(
- const void* key) const {
- UserDataMap::const_iterator found = user_data_.find(key);
- if (found != user_data_.end())
- return found->second.get();
- return NULL;
-}
-
-void SocketStream::SetUserData(const void* key, UserData* data) {
- user_data_[key] = linked_ptr<UserData>(data);
-}
-
-bool SocketStream::is_secure() const {
- return url_.SchemeIs("wss");
-}
-
-void SocketStream::DetachContext() {
- if (!context_)
- return;
-
- if (pac_request_) {
- context_->proxy_service()->CancelPacRequest(pac_request_);
- pac_request_ = NULL;
- }
-
- net_log_.EndEvent(NetLog::TYPE_REQUEST_ALIVE);
- net_log_ = BoundNetLog();
-
- context_ = NULL;
- cookie_store_ = NULL;
-}
-
-void SocketStream::CheckPrivacyMode() {
- if (context_ && context_->network_delegate()) {
- bool enable = context_->network_delegate()->CanEnablePrivacyMode(url_,
- url_);
- privacy_mode_ = enable ? PRIVACY_MODE_ENABLED : PRIVACY_MODE_DISABLED;
- // Disable Channel ID if privacy mode is enabled.
- if (enable)
- server_ssl_config_.channel_id_enabled = false;
- }
-}
-
-void SocketStream::Connect() {
- DCHECK(base::MessageLoop::current())
- << "The current base::MessageLoop must exist";
- DCHECK(base::MessageLoopForIO::IsCurrent())
- << "The current base::MessageLoop must be TYPE_IO";
- if (context_) {
- context_->ssl_config_service()->GetSSLConfig(&server_ssl_config_);
- proxy_ssl_config_ = server_ssl_config_;
- }
- CheckPrivacyMode();
-
- DCHECK_EQ(next_state_, STATE_NONE);
-
- AddRef(); // Released in Finish()
- // Open a connection asynchronously, so that delegate won't be called
- // back before returning Connect().
- next_state_ = STATE_BEFORE_CONNECT;
- net_log_.BeginEvent(
- NetLog::TYPE_SOCKET_STREAM_CONNECT,
- NetLog::StringCallback("url", &url_.possibly_invalid_spec()));
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK));
-}
-
-size_t SocketStream::GetTotalSizeOfPendingWriteBufs() const {
- size_t total_size = 0;
- for (PendingDataQueue::const_iterator iter = pending_write_bufs_.begin();
- iter != pending_write_bufs_.end();
- ++iter)
- total_size += (*iter)->size();
- return total_size;
-}
-
-bool SocketStream::SendData(const char* data, int len) {
- DCHECK(base::MessageLoop::current())
- << "The current base::MessageLoop must exist";
- DCHECK(base::MessageLoopForIO::IsCurrent())
- << "The current base::MessageLoop must be TYPE_IO";
- DCHECK_GT(len, 0);
-
- if (!connection_->socket() ||
- !connection_->socket()->IsConnected() || next_state_ == STATE_NONE) {
- return false;
- }
-
- int total_buffered_bytes = len;
- if (current_write_buf_.get()) {
- // Since
- // - the purpose of this check is to limit the amount of buffer used by
- // this instance.
- // - the DrainableIOBuffer doesn't release consumed memory.
- // we need to use not BytesRemaining() but size() here.
- total_buffered_bytes += current_write_buf_->size();
- }
- total_buffered_bytes += GetTotalSizeOfPendingWriteBufs();
- if (total_buffered_bytes > max_pending_send_allowed_)
- return false;
-
- // TODO(tyoshino): Split data into smaller chunks e.g. 8KiB to free consumed
- // buffer progressively
- pending_write_bufs_.push_back(make_scoped_refptr(
- new IOBufferWithSize(len)));
- memcpy(pending_write_bufs_.back()->data(), data, len);
-
- // If current_write_buf_ is not NULL, it means that a) there's ongoing write
- // operation or b) the connection is being closed. If a), the buffer we just
- // pushed will be automatically handled when the completion callback runs
- // the loop, and therefore we don't need to enqueue DoLoop(). If b), it's ok
- // to do nothing. If current_write_buf_ is NULL, to make sure DoLoop() is
- // ran soon, enequeue it.
- if (!current_write_buf_.get()) {
- // Send pending data asynchronously, so that delegate won't be called
- // back before returning from SendData().
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK));
- }
-
- return true;
-}
-
-void SocketStream::Close() {
- DCHECK(base::MessageLoop::current())
- << "The current base::MessageLoop must exist";
- DCHECK(base::MessageLoopForIO::IsCurrent())
- << "The current base::MessageLoop must be TYPE_IO";
- // If next_state_ is STATE_NONE, the socket was not opened, or already
- // closed. So, return immediately.
- // Otherwise, it might call Finish() more than once, so breaks balance
- // of AddRef() and Release() in Connect() and Finish(), respectively.
- if (next_state_ == STATE_NONE)
- return;
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoClose, this));
-}
-
-void SocketStream::RestartWithAuth(const AuthCredentials& credentials) {
- DCHECK(base::MessageLoop::current())
- << "The current base::MessageLoop must exist";
- DCHECK(base::MessageLoopForIO::IsCurrent())
- << "The current base::MessageLoop must be TYPE_IO";
- DCHECK(proxy_auth_controller_.get());
- if (!connection_->socket()) {
- DVLOG(1) << "Socket is closed before restarting with auth.";
- return;
- }
-
- proxy_auth_controller_->ResetAuth(credentials);
-
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this));
-}
-
-void SocketStream::DetachDelegate() {
- if (!delegate_)
- return;
- delegate_ = NULL;
- // Prevent the rest of the function from executing if we are being called from
- // within Finish().
- if (next_state_ == STATE_NONE)
- return;
- net_log_.AddEvent(NetLog::TYPE_CANCELLED);
- // We don't need to send pending data when client detach the delegate.
- pending_write_bufs_.clear();
- Close();
-}
-
-const ProxyServer& SocketStream::proxy_server() const {
- return proxy_info_.proxy_server();
-}
-
-void SocketStream::SetClientSocketFactory(
- ClientSocketFactory* factory) {
- DCHECK(factory);
- factory_ = factory;
-}
-
-void SocketStream::CancelWithError(int error) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, error));
-}
-
-void SocketStream::CancelWithSSLError(const SSLInfo& ssl_info) {
- CancelWithError(MapCertStatusToNetError(ssl_info.cert_status));
-}
-
-void SocketStream::ContinueDespiteError() {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoLoop, this, OK));
-}
-
-SocketStream::~SocketStream() {
- DetachContext();
- DCHECK(!delegate_);
- DCHECK(!pac_request_);
-}
-
-SocketStream::RequestHeaders::~RequestHeaders() { data_ = NULL; }
-
-void SocketStream::set_addresses(const AddressList& addresses) {
- addresses_ = addresses;
-}
-
-void SocketStream::DoClose() {
- closing_ = true;
- // If next_state_ is:
- // - STATE_TCP_CONNECT_COMPLETE, it's waiting other socket establishing
- // connection.
- // - STATE_AUTH_REQUIRED, it's waiting for restarting.
- // - STATE_RESOLVE_PROTOCOL_COMPLETE, it's waiting for delegate_ to finish
- // OnStartOpenConnection method call
- // In these states, we'll close the SocketStream now.
- if (next_state_ == STATE_TCP_CONNECT_COMPLETE ||
- next_state_ == STATE_AUTH_REQUIRED ||
- next_state_ == STATE_RESOLVE_PROTOCOL_COMPLETE) {
- DoLoop(ERR_ABORTED);
- return;
- }
- // If next_state_ is STATE_READ_WRITE, we'll run DoLoop and close
- // the SocketStream.
- // If it's writing now, we should defer the closing after the current
- // writing is completed.
- if (next_state_ == STATE_READ_WRITE && !current_write_buf_.get())
- DoLoop(ERR_ABORTED);
-
- // In other next_state_, we'll wait for callback of other APIs, such as
- // ResolveProxy().
-}
-
-void SocketStream::Finish(int result) {
- DCHECK(base::MessageLoop::current())
- << "The current base::MessageLoop must exist";
- DCHECK(base::MessageLoopForIO::IsCurrent())
- << "The current base::MessageLoop must be TYPE_IO";
- DCHECK_LE(result, OK);
- if (result == OK)
- result = ERR_CONNECTION_CLOSED;
- DCHECK_EQ(next_state_, STATE_NONE);
- DVLOG(1) << "Finish result=" << ErrorToString(result);
-
- metrics_->OnClose();
-
- if (result != ERR_CONNECTION_CLOSED && delegate_)
- delegate_->OnError(this, result);
- if (result != ERR_PROTOCOL_SWITCHED && delegate_)
- delegate_->OnClose(this);
- delegate_ = NULL;
-
- Release();
-}
-
-int SocketStream::DidEstablishConnection() {
- if (!connection_->socket() || !connection_->socket()->IsConnected()) {
- next_state_ = STATE_CLOSE;
- return ERR_CONNECTION_FAILED;
- }
- next_state_ = STATE_READ_WRITE;
- metrics_->OnConnected();
-
- net_log_.EndEvent(NetLog::TYPE_SOCKET_STREAM_CONNECT);
- if (delegate_)
- delegate_->OnConnected(this, max_pending_send_allowed_);
-
- return OK;
-}
-
-int SocketStream::DidReceiveData(int result) {
- DCHECK(read_buf_.get());
- DCHECK_GT(result, 0);
- net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_RECEIVED);
- int len = result;
- metrics_->OnRead(len);
- if (delegate_) {
- // Notify recevied data to delegate.
- delegate_->OnReceivedData(this, read_buf_->data(), len);
- }
- read_buf_ = NULL;
- return OK;
-}
-
-void SocketStream::DidSendData(int result) {
- DCHECK_GT(result, 0);
- DCHECK(current_write_buf_.get());
- net_log_.AddEvent(NetLog::TYPE_SOCKET_STREAM_SENT);
-
- int bytes_sent = result;
-
- metrics_->OnWrite(bytes_sent);
-
- current_write_buf_->DidConsume(result);
-
- if (current_write_buf_->BytesRemaining())
- return;
-
- size_t bytes_freed = current_write_buf_->size();
-
- current_write_buf_ = NULL;
-
- // We freed current_write_buf_ and this instance is now able to accept more
- // data via SendData() (note that DidConsume() doesn't free consumed memory).
- // We can tell that to delegate_ by calling OnSentData().
- if (delegate_)
- delegate_->OnSentData(this, bytes_freed);
-}
-
-void SocketStream::OnIOCompleted(int result) {
- DoLoop(result);
-}
-
-void SocketStream::OnReadCompleted(int result) {
- if (result == 0) {
- // 0 indicates end-of-file, so socket was closed.
- // Don't close the socket if it's still writing.
- server_closed_ = true;
- } else if (result > 0 && read_buf_.get()) {
- result = DidReceiveData(result);
- }
- DoLoop(result);
-}
-
-void SocketStream::OnWriteCompleted(int result) {
- waiting_for_write_completion_ = false;
- if (result > 0) {
- DidSendData(result);
- result = OK;
- }
- DoLoop(result);
-}
-
-void SocketStream::DoLoop(int result) {
- if (next_state_ == STATE_NONE)
- return;
-
- // If context was not set, close immediately.
- if (!context_)
- next_state_ = STATE_CLOSE;
-
- do {
- State state = next_state_;
- next_state_ = STATE_NONE;
- switch (state) {
- case STATE_BEFORE_CONNECT:
- DCHECK_EQ(OK, result);
- result = DoBeforeConnect();
- break;
- case STATE_BEFORE_CONNECT_COMPLETE:
- result = DoBeforeConnectComplete(result);
- break;
- case STATE_RESOLVE_PROXY:
- DCHECK_EQ(OK, result);
- result = DoResolveProxy();
- break;
- case STATE_RESOLVE_PROXY_COMPLETE:
- result = DoResolveProxyComplete(result);
- break;
- case STATE_RESOLVE_HOST:
- DCHECK_EQ(OK, result);
- result = DoResolveHost();
- break;
- case STATE_RESOLVE_HOST_COMPLETE:
- result = DoResolveHostComplete(result);
- break;
- case STATE_RESOLVE_PROTOCOL:
- result = DoResolveProtocol(result);
- break;
- case STATE_RESOLVE_PROTOCOL_COMPLETE:
- result = DoResolveProtocolComplete(result);
- break;
- case STATE_TCP_CONNECT:
- result = DoTcpConnect(result);
- break;
- case STATE_TCP_CONNECT_COMPLETE:
- result = DoTcpConnectComplete(result);
- break;
- case STATE_GENERATE_PROXY_AUTH_TOKEN:
- result = DoGenerateProxyAuthToken();
- break;
- case STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE:
- result = DoGenerateProxyAuthTokenComplete(result);
- break;
- case STATE_WRITE_TUNNEL_HEADERS:
- DCHECK_EQ(OK, result);
- result = DoWriteTunnelHeaders();
- break;
- case STATE_WRITE_TUNNEL_HEADERS_COMPLETE:
- result = DoWriteTunnelHeadersComplete(result);
- break;
- case STATE_READ_TUNNEL_HEADERS:
- DCHECK_EQ(OK, result);
- result = DoReadTunnelHeaders();
- break;
- case STATE_READ_TUNNEL_HEADERS_COMPLETE:
- result = DoReadTunnelHeadersComplete(result);
- break;
- case STATE_SOCKS_CONNECT:
- DCHECK_EQ(OK, result);
- result = DoSOCKSConnect();
- break;
- case STATE_SOCKS_CONNECT_COMPLETE:
- result = DoSOCKSConnectComplete(result);
- break;
- case STATE_SECURE_PROXY_CONNECT:
- DCHECK_EQ(OK, result);
- result = DoSecureProxyConnect();
- break;
- case STATE_SECURE_PROXY_CONNECT_COMPLETE:
- result = DoSecureProxyConnectComplete(result);
- break;
- case STATE_SECURE_PROXY_HANDLE_CERT_ERROR:
- result = DoSecureProxyHandleCertError(result);
- break;
- case STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE:
- result = DoSecureProxyHandleCertErrorComplete(result);
- break;
- case STATE_SSL_CONNECT:
- DCHECK_EQ(OK, result);
- result = DoSSLConnect();
- break;
- case STATE_SSL_CONNECT_COMPLETE:
- result = DoSSLConnectComplete(result);
- break;
- case STATE_SSL_HANDLE_CERT_ERROR:
- result = DoSSLHandleCertError(result);
- break;
- case STATE_SSL_HANDLE_CERT_ERROR_COMPLETE:
- result = DoSSLHandleCertErrorComplete(result);
- break;
- case STATE_READ_WRITE:
- result = DoReadWrite(result);
- break;
- case STATE_AUTH_REQUIRED:
- // It might be called when DoClose is called while waiting in
- // STATE_AUTH_REQUIRED.
- Finish(result);
- return;
- case STATE_CLOSE:
- DCHECK_LE(result, OK);
- Finish(result);
- return;
- default:
- NOTREACHED() << "bad state " << state;
- Finish(result);
- return;
- }
- if (state == STATE_RESOLVE_PROTOCOL && result == ERR_PROTOCOL_SWITCHED)
- continue;
- // If the connection is not established yet and had actual errors,
- // record the error. In next iteration, it will close the connection.
- if (state != STATE_READ_WRITE && result < ERR_IO_PENDING) {
- net_log_.EndEventWithNetErrorCode(
- NetLog::TYPE_SOCKET_STREAM_CONNECT, result);
- }
- } while (result != ERR_IO_PENDING);
-}
-
-int SocketStream::DoBeforeConnect() {
- next_state_ = STATE_BEFORE_CONNECT_COMPLETE;
- if (!context_ || !context_->network_delegate())
- return OK;
-
- int result = context_->network_delegate()->NotifyBeforeSocketStreamConnect(
- this, io_callback_);
- if (result != OK && result != ERR_IO_PENDING)
- next_state_ = STATE_CLOSE;
-
- return result;
-}
-
-int SocketStream::DoBeforeConnectComplete(int result) {
- DCHECK_NE(ERR_IO_PENDING, result);
-
- if (result == OK)
- next_state_ = STATE_RESOLVE_PROXY;
- else
- next_state_ = STATE_CLOSE;
-
- return result;
-}
-
-int SocketStream::DoResolveProxy() {
- DCHECK(context_);
- DCHECK(!pac_request_);
- next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
-
- if (!proxy_url_.is_valid()) {
- next_state_ = STATE_CLOSE;
- return ERR_INVALID_ARGUMENT;
- }
-
- // TODO(toyoshim): Check server advertisement of SPDY through the HTTP
- // Alternate-Protocol header, then switch to SPDY if SPDY is available.
- // Usually we already have a session to the SPDY server because JavaScript
- // running WebSocket itself would be served by SPDY. But, in some situation
- // (E.g. Used by Chrome Extensions or used for cross origin connection), this
- // connection might be the first one. At that time, we should check
- // Alternate-Protocol header here for ws:// or TLS NPN extension for wss:// .
-
- return context_->proxy_service()->ResolveProxy(
- proxy_url_, net::LOAD_NORMAL, &proxy_info_, io_callback_, &pac_request_,
- NULL, net_log_);
-}
-
-int SocketStream::DoResolveProxyComplete(int result) {
- pac_request_ = NULL;
- if (result != OK) {
- DVLOG(1) << "Failed to resolve proxy: " << result;
- if (delegate_)
- delegate_->OnError(this, result);
- proxy_info_.UseDirect();
- }
- if (proxy_info_.is_direct()) {
- // If proxy was not found for original URL (i.e. websocket URL),
- // try again with https URL, like Safari implementation.
- // Note that we don't want to use http proxy, because we'll use tunnel
- // proxy using CONNECT method, which is used by https proxy.
- if (!proxy_url_.SchemeIs("https")) {
- const std::string scheme = "https";
- GURL::Replacements repl;
- repl.SetSchemeStr(scheme);
- proxy_url_ = url_.ReplaceComponents(repl);
- DVLOG(1) << "Try https proxy: " << proxy_url_;
- next_state_ = STATE_RESOLVE_PROXY;
- return OK;
- }
- }
-
- if (proxy_info_.is_empty()) {
- // No proxies/direct to choose from. This happens when we don't support any
- // of the proxies in the returned list.
- return ERR_NO_SUPPORTED_PROXIES;
- }
-
- next_state_ = STATE_RESOLVE_HOST;
- return OK;
-}
-
-int SocketStream::DoResolveHost() {
- next_state_ = STATE_RESOLVE_HOST_COMPLETE;
-
- DCHECK(!proxy_info_.is_empty());
- if (proxy_info_.is_direct())
- proxy_mode_ = kDirectConnection;
- else if (proxy_info_.proxy_server().is_socks())
- proxy_mode_ = kSOCKSProxy;
- else
- proxy_mode_ = kTunnelProxy;
-
- // Determine the host and port to connect to.
- HostPortPair host_port_pair;
- if (proxy_mode_ != kDirectConnection) {
- host_port_pair = proxy_info_.proxy_server().host_port_pair();
- } else {
- host_port_pair = HostPortPair::FromURL(url_);
- }
-
- HostResolver::RequestInfo resolve_info(host_port_pair);
-
- DCHECK(context_->host_resolver());
- resolver_.reset(new SingleRequestHostResolver(context_->host_resolver()));
- return resolver_->Resolve(resolve_info,
- DEFAULT_PRIORITY,
- &addresses_,
- base::Bind(&SocketStream::OnIOCompleted, this),
- net_log_);
-}
-
-int SocketStream::DoResolveHostComplete(int result) {
- if (result == OK)
- next_state_ = STATE_RESOLVE_PROTOCOL;
- else
- next_state_ = STATE_CLOSE;
- // TODO(ukai): if error occured, reconsider proxy after error.
- return result;
-}
-
-int SocketStream::DoResolveProtocol(int result) {
- DCHECK_EQ(OK, result);
-
- if (!delegate_) {
- next_state_ = STATE_CLOSE;
- return result;
- }
-
- next_state_ = STATE_RESOLVE_PROTOCOL_COMPLETE;
- result = delegate_->OnStartOpenConnection(this, io_callback_);
- if (result == ERR_IO_PENDING)
- metrics_->OnWaitConnection();
- else if (result != OK && result != ERR_PROTOCOL_SWITCHED)
- next_state_ = STATE_CLOSE;
- return result;
-}
-
-int SocketStream::DoResolveProtocolComplete(int result) {
- DCHECK_NE(ERR_IO_PENDING, result);
-
- if (result == ERR_PROTOCOL_SWITCHED) {
- next_state_ = STATE_CLOSE;
- metrics_->OnCountWireProtocolType(
- SocketStreamMetrics::WIRE_PROTOCOL_SPDY);
- } else if (result == OK) {
- next_state_ = STATE_TCP_CONNECT;
- metrics_->OnCountWireProtocolType(
- SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET);
- } else {
- next_state_ = STATE_CLOSE;
- }
- return result;
-}
-
-int SocketStream::DoTcpConnect(int result) {
- if (result != OK) {
- next_state_ = STATE_CLOSE;
- return result;
- }
- next_state_ = STATE_TCP_CONNECT_COMPLETE;
- DCHECK(factory_);
- connection_->SetSocket(
- factory_->CreateTransportClientSocket(addresses_,
- net_log_.net_log(),
- net_log_.source()));
- metrics_->OnStartConnection();
- return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoTcpConnectComplete(int result) {
- // TODO(ukai): if error occured, reconsider proxy after error.
- if (result != OK) {
- next_state_ = STATE_CLOSE;
- return result;
- }
-
- if (proxy_mode_ == kTunnelProxy) {
- if (proxy_info_.is_https())
- next_state_ = STATE_SECURE_PROXY_CONNECT;
- else
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- } else if (proxy_mode_ == kSOCKSProxy) {
- next_state_ = STATE_SOCKS_CONNECT;
- } else if (is_secure()) {
- next_state_ = STATE_SSL_CONNECT;
- } else {
- result = DidEstablishConnection();
- }
- return result;
-}
-
-int SocketStream::DoGenerateProxyAuthToken() {
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE;
- if (!proxy_auth_controller_.get()) {
- DCHECK(context_);
- DCHECK(context_->http_transaction_factory());
- DCHECK(context_->http_transaction_factory()->GetSession());
- HttpNetworkSession* session =
- context_->http_transaction_factory()->GetSession();
- const char* scheme = proxy_info_.is_https() ? "https://" : "http://";
- GURL auth_url(scheme +
- proxy_info_.proxy_server().host_port_pair().ToString());
- proxy_auth_controller_ =
- new HttpAuthController(HttpAuth::AUTH_PROXY,
- auth_url,
- session->http_auth_cache(),
- session->http_auth_handler_factory());
- }
- HttpRequestInfo request_info;
- request_info.url = url_;
- request_info.method = "CONNECT";
- return proxy_auth_controller_->MaybeGenerateAuthToken(
- &request_info, io_callback_, net_log_);
-}
-
-int SocketStream::DoGenerateProxyAuthTokenComplete(int result) {
- if (result != OK) {
- next_state_ = STATE_CLOSE;
- return result;
- }
-
- next_state_ = STATE_WRITE_TUNNEL_HEADERS;
- return result;
-}
-
-int SocketStream::DoWriteTunnelHeaders() {
- DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
- next_state_ = STATE_WRITE_TUNNEL_HEADERS_COMPLETE;
-
- if (!tunnel_request_headers_.get()) {
- metrics_->OnCountConnectionType(SocketStreamMetrics::TUNNEL_CONNECTION);
- tunnel_request_headers_ = new RequestHeaders();
- tunnel_request_headers_bytes_sent_ = 0;
- }
- if (tunnel_request_headers_->headers_.empty()) {
- HttpRequestHeaders request_headers;
- request_headers.SetHeader("Host", GetHostAndOptionalPort(url_));
- request_headers.SetHeader("Proxy-Connection", "keep-alive");
- if (proxy_auth_controller_.get() && proxy_auth_controller_->HaveAuth())
- proxy_auth_controller_->AddAuthorizationHeader(&request_headers);
- tunnel_request_headers_->headers_ = base::StringPrintf(
- "CONNECT %s HTTP/1.1\r\n"
- "%s",
- GetHostAndPort(url_).c_str(),
- request_headers.ToString().c_str());
- }
- tunnel_request_headers_->SetDataOffset(tunnel_request_headers_bytes_sent_);
- int buf_len = static_cast<int>(tunnel_request_headers_->headers_.size() -
- tunnel_request_headers_bytes_sent_);
- DCHECK_GT(buf_len, 0);
- return connection_->socket()->Write(
- tunnel_request_headers_.get(), buf_len, io_callback_);
-}
-
-int SocketStream::DoWriteTunnelHeadersComplete(int result) {
- DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
- if (result < 0) {
- next_state_ = STATE_CLOSE;
- return result;
- }
-
- tunnel_request_headers_bytes_sent_ += result;
- if (tunnel_request_headers_bytes_sent_ <
- tunnel_request_headers_->headers_.size()) {
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- } else {
- // Handling a cert error or a client cert request requires reconnection.
- // DoWriteTunnelHeaders() will be called again.
- // Thus |tunnel_request_headers_bytes_sent_| should be reset to 0 for
- // sending |tunnel_request_headers_| correctly.
- tunnel_request_headers_bytes_sent_ = 0;
- next_state_ = STATE_READ_TUNNEL_HEADERS;
- }
- return OK;
-}
-
-int SocketStream::DoReadTunnelHeaders() {
- DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
- next_state_ = STATE_READ_TUNNEL_HEADERS_COMPLETE;
-
- if (!tunnel_response_headers_.get()) {
- tunnel_response_headers_ = new ResponseHeaders();
- tunnel_response_headers_capacity_ = kMaxTunnelResponseHeadersSize;
- tunnel_response_headers_->Realloc(tunnel_response_headers_capacity_);
- tunnel_response_headers_len_ = 0;
- }
-
- int buf_len = tunnel_response_headers_capacity_ -
- tunnel_response_headers_len_;
- tunnel_response_headers_->SetDataOffset(tunnel_response_headers_len_);
- CHECK(tunnel_response_headers_->data());
-
- return connection_->socket()->Read(
- tunnel_response_headers_.get(), buf_len, io_callback_);
-}
-
-int SocketStream::DoReadTunnelHeadersComplete(int result) {
- DCHECK_EQ(kTunnelProxy, proxy_mode_);
-
- if (result < 0) {
- next_state_ = STATE_CLOSE;
- return result;
- }
-
- if (result == 0) {
- // 0 indicates end-of-file, so socket was closed.
- next_state_ = STATE_CLOSE;
- return ERR_CONNECTION_CLOSED;
- }
-
- tunnel_response_headers_len_ += result;
- DCHECK(tunnel_response_headers_len_ <= tunnel_response_headers_capacity_);
-
- int eoh = HttpUtil::LocateEndOfHeaders(
- tunnel_response_headers_->headers(), tunnel_response_headers_len_, 0);
- if (eoh == -1) {
- if (tunnel_response_headers_len_ >= kMaxTunnelResponseHeadersSize) {
- next_state_ = STATE_CLOSE;
- return ERR_RESPONSE_HEADERS_TOO_BIG;
- }
-
- next_state_ = STATE_READ_TUNNEL_HEADERS;
- return OK;
- }
- // DidReadResponseHeaders
- scoped_refptr<HttpResponseHeaders> headers;
- headers = new HttpResponseHeaders(
- HttpUtil::AssembleRawHeaders(tunnel_response_headers_->headers(), eoh));
- if (headers->GetParsedHttpVersion() < HttpVersion(1, 0)) {
- // Require the "HTTP/1.x" status line.
- next_state_ = STATE_CLOSE;
- return ERR_TUNNEL_CONNECTION_FAILED;
- }
- switch (headers->response_code()) {
- case 200: // OK
- if (is_secure()) {
- DCHECK_EQ(eoh, tunnel_response_headers_len_);
- next_state_ = STATE_SSL_CONNECT;
- } else {
- result = DidEstablishConnection();
- if (result < 0) {
- next_state_ = STATE_CLOSE;
- return result;
- }
- if ((eoh < tunnel_response_headers_len_) && delegate_)
- delegate_->OnReceivedData(
- this, tunnel_response_headers_->headers() + eoh,
- tunnel_response_headers_len_ - eoh);
- }
- return OK;
- case 407: // Proxy Authentication Required.
- if (proxy_mode_ != kTunnelProxy)
- return ERR_UNEXPECTED_PROXY_AUTH;
-
- result = proxy_auth_controller_->HandleAuthChallenge(
- headers, false, true, net_log_);
- if (result != OK)
- return result;
- DCHECK(!proxy_info_.is_empty());
- next_state_ = STATE_AUTH_REQUIRED;
- if (proxy_auth_controller_->HaveAuth()) {
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoRestartWithAuth, this));
- return ERR_IO_PENDING;
- }
- if (delegate_) {
- // Wait until RestartWithAuth or Close is called.
- base::MessageLoop::current()->PostTask(
- FROM_HERE, base::Bind(&SocketStream::DoAuthRequired, this));
- return ERR_IO_PENDING;
- }
- break;
- default:
- break;
- }
- next_state_ = STATE_CLOSE;
- return ERR_TUNNEL_CONNECTION_FAILED;
-}
-
-int SocketStream::DoSOCKSConnect() {
- DCHECK_EQ(kSOCKSProxy, proxy_mode_);
-
- next_state_ = STATE_SOCKS_CONNECT_COMPLETE;
-
- HostResolver::RequestInfo req_info(HostPortPair::FromURL(url_));
-
- DCHECK(!proxy_info_.is_empty());
- scoped_ptr<StreamSocket> s;
- if (proxy_info_.proxy_server().scheme() == ProxyServer::SCHEME_SOCKS5) {
- s.reset(new SOCKS5ClientSocket(connection_.Pass(), req_info));
- } else {
- s.reset(new SOCKSClientSocket(connection_.Pass(),
- req_info,
- DEFAULT_PRIORITY,
- context_->host_resolver()));
- }
- connection_.reset(new ClientSocketHandle);
- connection_->SetSocket(s.Pass());
- metrics_->OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION);
- return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoSOCKSConnectComplete(int result) {
- DCHECK_EQ(kSOCKSProxy, proxy_mode_);
-
- if (result == OK) {
- if (is_secure())
- next_state_ = STATE_SSL_CONNECT;
- else
- result = DidEstablishConnection();
- } else {
- next_state_ = STATE_CLOSE;
- }
- return result;
-}
-
-int SocketStream::DoSecureProxyConnect() {
- DCHECK(factory_);
- SSLClientSocketContext ssl_context;
- ssl_context.cert_verifier = context_->cert_verifier();
- ssl_context.transport_security_state = context_->transport_security_state();
- ssl_context.channel_id_service = context_->channel_id_service();
- scoped_ptr<StreamSocket> socket(factory_->CreateSSLClientSocket(
- connection_.Pass(),
- proxy_info_.proxy_server().host_port_pair(),
- proxy_ssl_config_,
- ssl_context));
- connection_.reset(new ClientSocketHandle);
- connection_->SetSocket(socket.Pass());
- next_state_ = STATE_SECURE_PROXY_CONNECT_COMPLETE;
- metrics_->OnCountConnectionType(SocketStreamMetrics::SECURE_PROXY_CONNECTION);
- return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoSecureProxyConnectComplete(int result) {
- DCHECK_EQ(STATE_NONE, next_state_);
- // Reconnect with client authentication.
- if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
- return HandleCertificateRequest(result, &proxy_ssl_config_);
-
- if (IsCertificateError(result))
- next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR;
- else if (result == OK)
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- else
- next_state_ = STATE_CLOSE;
- return result;
-}
-
-int SocketStream::DoSecureProxyHandleCertError(int result) {
- DCHECK_EQ(STATE_NONE, next_state_);
- DCHECK(IsCertificateError(result));
- result = HandleCertificateError(result);
- if (result == ERR_IO_PENDING)
- next_state_ = STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE;
- else
- next_state_ = STATE_CLOSE;
- return result;
-}
-
-int SocketStream::DoSecureProxyHandleCertErrorComplete(int result) {
- DCHECK_EQ(STATE_NONE, next_state_);
- if (result == OK) {
- if (!connection_->socket()->IsConnectedAndIdle())
- return AllowCertErrorForReconnection(&proxy_ssl_config_);
- next_state_ = STATE_GENERATE_PROXY_AUTH_TOKEN;
- } else {
- next_state_ = STATE_CLOSE;
- }
- return result;
-}
-
-int SocketStream::DoSSLConnect() {
- DCHECK(factory_);
- SSLClientSocketContext ssl_context;
- ssl_context.cert_verifier = context_->cert_verifier();
- ssl_context.transport_security_state = context_->transport_security_state();
- ssl_context.channel_id_service = context_->channel_id_service();
- scoped_ptr<StreamSocket> socket(
- factory_->CreateSSLClientSocket(connection_.Pass(),
- HostPortPair::FromURL(url_),
- server_ssl_config_,
- ssl_context));
- connection_.reset(new ClientSocketHandle);
- connection_->SetSocket(socket.Pass());
- next_state_ = STATE_SSL_CONNECT_COMPLETE;
- metrics_->OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION);
- return connection_->socket()->Connect(io_callback_);
-}
-
-int SocketStream::DoSSLConnectComplete(int result) {
- DCHECK_EQ(STATE_NONE, next_state_);
- // Reconnect with client authentication.
- if (result == ERR_SSL_CLIENT_AUTH_CERT_NEEDED)
- return HandleCertificateRequest(result, &server_ssl_config_);
-
- if (IsCertificateError(result))
- next_state_ = STATE_SSL_HANDLE_CERT_ERROR;
- else if (result == OK)
- result = DidEstablishConnection();
- else
- next_state_ = STATE_CLOSE;
- return result;
-}
-
-int SocketStream::DoSSLHandleCertError(int result) {
- DCHECK_EQ(STATE_NONE, next_state_);
- DCHECK(IsCertificateError(result));
- result = HandleCertificateError(result);
- if (result == OK || result == ERR_IO_PENDING)
- next_state_ = STATE_SSL_HANDLE_CERT_ERROR_COMPLETE;
- else
- next_state_ = STATE_CLOSE;
- return result;
-}
-
-int SocketStream::DoSSLHandleCertErrorComplete(int result) {
- DCHECK_EQ(STATE_NONE, next_state_);
- // TODO(toyoshim): Upgrade to SPDY through TLS NPN extension if possible.
- // If we use HTTPS and this is the first connection to the SPDY server,
- // we should take care of TLS NPN extension here.
-
- if (result == OK) {
- if (!connection_->socket()->IsConnectedAndIdle())
- return AllowCertErrorForReconnection(&server_ssl_config_);
- result = DidEstablishConnection();
- } else {
- next_state_ = STATE_CLOSE;
- }
- return result;
-}
-
-int SocketStream::DoReadWrite(int result) {
- if (result < OK) {
- next_state_ = STATE_CLOSE;
- return result;
- }
- if (!connection_->socket() || !connection_->socket()->IsConnected()) {
- next_state_ = STATE_CLOSE;
- return ERR_CONNECTION_CLOSED;
- }
-
- // If client has requested close(), and there's nothing to write, then
- // let's close the socket.
- // We don't care about receiving data after the socket is closed.
- if (closing_ && !current_write_buf_.get() && pending_write_bufs_.empty()) {
- connection_->socket()->Disconnect();
- next_state_ = STATE_CLOSE;
- return OK;
- }
-
- next_state_ = STATE_READ_WRITE;
-
- // If server already closed the socket, we don't try to read.
- if (!server_closed_) {
- if (!read_buf_.get()) {
- // No read pending and server didn't close the socket.
- read_buf_ = new IOBuffer(kReadBufferSize);
- result = connection_->socket()->Read(
- read_buf_.get(),
- kReadBufferSize,
- base::Bind(&SocketStream::OnReadCompleted, base::Unretained(this)));
- if (result > 0) {
- return DidReceiveData(result);
- } else if (result == 0) {
- // 0 indicates end-of-file, so socket was closed.
- next_state_ = STATE_CLOSE;
- server_closed_ = true;
- return ERR_CONNECTION_CLOSED;
- }
- // If read is pending, try write as well.
- // Otherwise, return the result and do next loop (to close the
- // connection).
- if (result != ERR_IO_PENDING) {
- next_state_ = STATE_CLOSE;
- server_closed_ = true;
- return result;
- }
- }
- // Read is pending.
- DCHECK(read_buf_.get());
- }
-
- if (waiting_for_write_completion_)
- return ERR_IO_PENDING;
-
- if (!current_write_buf_.get()) {
- if (pending_write_bufs_.empty()) {
- // Nothing buffered for send.
- return ERR_IO_PENDING;
- }
-
- current_write_buf_ = new DrainableIOBuffer(
- pending_write_bufs_.front().get(), pending_write_bufs_.front()->size());
- pending_write_bufs_.pop_front();
- }
-
- result = connection_->socket()->Write(
- current_write_buf_.get(),
- current_write_buf_->BytesRemaining(),
- base::Bind(&SocketStream::OnWriteCompleted, base::Unretained(this)));
-
- if (result == ERR_IO_PENDING) {
- waiting_for_write_completion_ = true;
- } else if (result < 0) {
- // Shortcut. Enter STATE_CLOSE now by changing next_state_ here than by
- // calling DoReadWrite() again with the error code.
- next_state_ = STATE_CLOSE;
- } else if (result > 0) {
- // Write is not pending. Return OK and do next loop.
- DidSendData(result);
- result = OK;
- }
-
- return result;
-}
-
-GURL SocketStream::ProxyAuthOrigin() const {
- DCHECK(!proxy_info_.is_empty());
- return GURL("http://" +
- proxy_info_.proxy_server().host_port_pair().ToString());
-}
-
-int SocketStream::HandleCertificateRequest(int result, SSLConfig* ssl_config) {
- if (ssl_config->send_client_cert) {
- // We already have performed SSL client authentication once and failed.
- return result;
- }
-
- DCHECK(connection_->socket());
- scoped_refptr<SSLCertRequestInfo> cert_request_info = new SSLCertRequestInfo;
- SSLClientSocket* ssl_socket =
- static_cast<SSLClientSocket*>(connection_->socket());
- ssl_socket->GetSSLCertRequestInfo(cert_request_info.get());
-
- HttpTransactionFactory* factory = context_->http_transaction_factory();
- if (!factory)
- return result;
- scoped_refptr<HttpNetworkSession> session = factory->GetSession();
- if (!session.get())
- return result;
-
- // If the user selected one of the certificates in client_certs or declined
- // to provide one for this server before, use the past decision
- // automatically.
- scoped_refptr<X509Certificate> client_cert;
- if (!session->ssl_client_auth_cache()->Lookup(
- cert_request_info->host_and_port, &client_cert)) {
- return result;
- }
-
- // Note: |client_cert| may be NULL, indicating that the caller
- // wishes to proceed anonymously (eg: continue the handshake
- // without sending a client cert)
- //
- // Check that the certificate selected is still a certificate the server
- // is likely to accept, based on the criteria supplied in the
- // CertificateRequest message.
- const std::vector<std::string>& cert_authorities =
- cert_request_info->cert_authorities;
- if (client_cert.get() && !cert_authorities.empty() &&
- !client_cert->IsIssuedByEncoded(cert_authorities)) {
- return result;
- }
-
- ssl_config->send_client_cert = true;
- ssl_config->client_cert = client_cert;
- next_state_ = STATE_TCP_CONNECT;
- return OK;
-}
-
-int SocketStream::AllowCertErrorForReconnection(SSLConfig* ssl_config) {
- DCHECK(ssl_config);
- // The SSL handshake didn't finish, or the server closed the SSL connection.
- // So, we should restart establishing connection with the certificate in
- // allowed bad certificates in |ssl_config|.
- // See also net/http/http_network_transaction.cc HandleCertificateError() and
- // RestartIgnoringLastError().
- SSLClientSocket* ssl_socket =
- static_cast<SSLClientSocket*>(connection_->socket());
- SSLInfo ssl_info;
- ssl_socket->GetSSLInfo(&ssl_info);
- if (ssl_info.cert.get() == NULL ||
- ssl_config->IsAllowedBadCert(ssl_info.cert.get(), NULL)) {
- // If we already have the certificate in the set of allowed bad
- // certificates, we did try it and failed again, so we should not
- // retry again: the connection should fail at last.
- next_state_ = STATE_CLOSE;
- return ERR_UNEXPECTED;
- }
- // Add the bad certificate to the set of allowed certificates in the
- // SSL config object.
- SSLConfig::CertAndStatus bad_cert;
- if (!X509Certificate::GetDEREncoded(ssl_info.cert->os_cert_handle(),
- &bad_cert.der_cert)) {
- next_state_ = STATE_CLOSE;
- return ERR_UNEXPECTED;
- }
- bad_cert.cert_status = ssl_info.cert_status;
- ssl_config->allowed_bad_certs.push_back(bad_cert);
- // Restart connection ignoring the bad certificate.
- connection_->socket()->Disconnect();
- connection_->SetSocket(scoped_ptr<StreamSocket>());
- next_state_ = STATE_TCP_CONNECT;
- return OK;
-}
-
-void SocketStream::DoAuthRequired() {
- if (delegate_ && proxy_auth_controller_.get())
- delegate_->OnAuthRequired(this, proxy_auth_controller_->auth_info().get());
- else
- DoLoop(ERR_UNEXPECTED);
-}
-
-void SocketStream::DoRestartWithAuth() {
- DCHECK_EQ(next_state_, STATE_AUTH_REQUIRED);
- tunnel_request_headers_ = NULL;
- tunnel_request_headers_bytes_sent_ = 0;
- tunnel_response_headers_ = NULL;
- tunnel_response_headers_capacity_ = 0;
- tunnel_response_headers_len_ = 0;
-
- next_state_ = STATE_TCP_CONNECT;
- DoLoop(OK);
-}
-
-int SocketStream::HandleCertificateError(int result) {
- DCHECK(IsCertificateError(result));
- SSLClientSocket* ssl_socket =
- static_cast<SSLClientSocket*>(connection_->socket());
- DCHECK(ssl_socket);
-
- if (!context_)
- return result;
-
- if (SSLClientSocket::IgnoreCertError(result, LOAD_IGNORE_ALL_CERT_ERRORS)) {
- const HttpNetworkSession::Params* session_params =
- context_->GetNetworkSessionParams();
- if (session_params && session_params->ignore_certificate_errors)
- return OK;
- }
-
- if (!delegate_)
- return result;
-
- SSLInfo ssl_info;
- ssl_socket->GetSSLInfo(&ssl_info);
-
- TransportSecurityState* state = context_->transport_security_state();
- const bool fatal = state && state->ShouldSSLErrorsBeFatal(url_.host());
-
- delegate_->OnSSLCertificateError(this, ssl_info, fatal);
- return ERR_IO_PENDING;
-}
-
-CookieStore* SocketStream::cookie_store() const {
- return cookie_store_.get();
-}
-
-} // namespace net
diff --git a/net/socket_stream/socket_stream.h b/net/socket_stream/socket_stream.h
deleted file mode 100644
index 7387eb6..0000000
--- a/net/socket_stream/socket_stream.h
+++ /dev/null
@@ -1,404 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_H_
-
-#include <deque>
-#include <map>
-#include <string>
-
-#include "base/memory/linked_ptr.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_export.h"
-#include "net/base/net_log.h"
-#include "net/base/privacy_mode.h"
-#include "net/cookies/cookie_store.h"
-#include "net/proxy/proxy_service.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/url_request/url_request.h"
-
-namespace net {
-
-class AuthChallengeInfo;
-class CertVerifier;
-class ChannelIDService;
-class ClientSocketFactory;
-class ClientSocketHandle;
-class CookieOptions;
-class HostResolver;
-class HttpAuthController;
-class SSLInfo;
-class SingleRequestHostResolver;
-class SocketStreamMetrics;
-class TransportSecurityState;
-class URLRequestContext;
-
-// SocketStream is used to implement Web Sockets.
-// It provides plain full-duplex stream with proxy and SSL support.
-// For proxy authentication, only basic mechanisum is supported. It will try
-// authentication identity for proxy URL first. If server requires proxy
-// authentication, it will try authentication identity for realm that server
-// requests.
-class NET_EXPORT SocketStream
- : public base::RefCountedThreadSafe<SocketStream> {
- public:
- // Derive from this class and add your own data members to associate extra
- // information with a SocketStream. Use GetUserData(key) and
- // SetUserData(key, data).
- class UserData {
- public:
- UserData() {}
- virtual ~UserData() {}
- };
-
- class NET_EXPORT Delegate {
- public:
- virtual int OnStartOpenConnection(SocketStream* socket,
- const CompletionCallback& callback);
-
- // Called when a socket stream has been connected. The socket stream is
- // allowed to buffer pending send data at most |max_pending_send_allowed|
- // bytes. A client of the socket stream should keep track of how much
- // pending send data it has and must not call SendData() if the pending
- // data goes over |max_pending_send_allowed| bytes.
- virtual void OnConnected(SocketStream* socket,
- int max_pending_send_allowed) = 0;
-
- // Called when |amount_sent| bytes of data are sent.
- virtual void OnSentData(SocketStream* socket,
- int amount_sent) = 0;
-
- // Called when |len| bytes of |data| are received.
- virtual void OnReceivedData(SocketStream* socket,
- const char* data, int len) = 0;
-
- // Called when the socket stream has been closed.
- virtual void OnClose(SocketStream* socket) = 0;
-
- // Called when proxy authentication required.
- // The delegate should call RestartWithAuth() if credential for |auth_info|
- // is found in password database, or call Close() to close the connection.
- virtual void OnAuthRequired(SocketStream* socket,
- AuthChallengeInfo* auth_info);
-
- // Called when using SSL and the server responds with a certificate with an
- // error. The delegate should call CancelBecauseOfCertError() or
- // ContinueDespiteCertError() to resume connection handling.
- virtual void OnSSLCertificateError(SocketStream* socket,
- const SSLInfo& ssl_info,
- bool fatal);
-
- // Called when an error occured.
- // This is only for error reporting to the delegate.
- // |error| is net::Error.
- virtual void OnError(const SocketStream* socket, int error) {}
-
- // Called when reading cookies to allow the delegate to block access to the
- // cookie.
- virtual bool CanGetCookies(SocketStream* socket, const GURL& url);
-
- // Called when a cookie is set to allow the delegate to block access to the
- // cookie.
- virtual bool CanSetCookie(SocketStream* request,
- const GURL& url,
- const std::string& cookie_line,
- CookieOptions* options);
-
- protected:
- virtual ~Delegate() {}
- };
-
- SocketStream(const GURL& url, Delegate* delegate, URLRequestContext* context,
- CookieStore* cookie_store);
-
- // The user data allows the clients to associate data with this job.
- // Multiple user data values can be stored under different keys.
- // This job will TAKE OWNERSHIP of the given data pointer, and will
- // delete the object if it is changed or the job is destroyed.
- UserData* GetUserData(const void* key) const;
- void SetUserData(const void* key, UserData* data);
-
- const GURL& url() const { return url_; }
- bool is_secure() const;
- const AddressList& address_list() const { return addresses_; }
- Delegate* delegate() const { return delegate_; }
- int max_pending_send_allowed() const { return max_pending_send_allowed_; }
-
- URLRequestContext* context() { return context_; }
-
- const SSLConfig& server_ssl_config() const { return server_ssl_config_; }
- PrivacyMode privacy_mode() const { return privacy_mode_; }
- void CheckPrivacyMode();
-
- BoundNetLog* net_log() { return &net_log_; }
-
- // Opens the connection on the IO thread.
- // Once the connection is established, calls delegate's OnConnected.
- virtual void Connect();
-
- // Buffers |data| of |len| bytes for send and returns true if successful.
- // If size of buffered data exceeds |max_pending_send_allowed_|, sends no
- // data and returns false. |len| must be positive.
- virtual bool SendData(const char* data, int len);
-
- // Requests to close the connection.
- // Once the connection is closed, calls delegate's OnClose.
- virtual void Close();
-
- // Restarts with authentication info.
- // Should be used for response of OnAuthRequired.
- virtual void RestartWithAuth(const AuthCredentials& credentials);
-
- // Detach delegate. Call before delegate is deleted.
- // Once delegate is detached, close the socket stream and never call delegate
- // back.
- virtual void DetachDelegate();
-
- // Detach the context.
- virtual void DetachContext();
-
- const ProxyServer& proxy_server() const;
-
- // Sets an alternative ClientSocketFactory. Doesn't take ownership of
- // |factory|. For testing purposes only.
- void SetClientSocketFactory(ClientSocketFactory* factory);
-
- // Cancels the connection because of an error.
- // |error| is net::Error which represents the error.
- void CancelWithError(int error);
-
- // Cancels the connection because of receiving a certificate with an error.
- void CancelWithSSLError(const SSLInfo& ssl_info);
-
- // Continues to establish the connection in spite of an error. Usually this
- // case happens because users allow certificate with an error by manual
- // actions on alert dialog or browser cached such kinds of user actions.
- void ContinueDespiteError();
-
- CookieStore* cookie_store() const;
-
- protected:
- friend class base::RefCountedThreadSafe<SocketStream>;
- virtual ~SocketStream();
-
- Delegate* delegate_;
-
- private:
- FRIEND_TEST_ALL_PREFIXES(SocketStreamTest, IOPending);
- FRIEND_TEST_ALL_PREFIXES(SocketStreamTest, SwitchAfterPending);
- FRIEND_TEST_ALL_PREFIXES(SocketStreamTest,
- NullContextSocketStreamShouldNotCrash);
-
- friend class WebSocketThrottleTest;
-
- typedef std::map<const void*, linked_ptr<UserData> > UserDataMap;
- typedef std::deque< scoped_refptr<IOBufferWithSize> > PendingDataQueue;
-
- class RequestHeaders : public IOBuffer {
- public:
- RequestHeaders() : IOBuffer() {}
-
- void SetDataOffset(size_t offset) {
- data_ = const_cast<char*>(headers_.data()) + offset;
- }
-
- std::string headers_;
-
- private:
- ~RequestHeaders() override;
- };
-
- class ResponseHeaders : public IOBuffer {
- public:
- ResponseHeaders();
-
- void SetDataOffset(size_t offset) { data_ = headers_.get() + offset; }
- char* headers() const { return headers_.get(); }
- void Reset() { headers_.reset(); }
- void Realloc(size_t new_size);
-
- private:
- ~ResponseHeaders() override;
-
- scoped_ptr<char, base::FreeDeleter> headers_;
- };
-
- enum State {
- STATE_NONE,
- STATE_BEFORE_CONNECT,
- STATE_BEFORE_CONNECT_COMPLETE,
- STATE_RESOLVE_PROXY,
- STATE_RESOLVE_PROXY_COMPLETE,
- STATE_RESOLVE_HOST,
- STATE_RESOLVE_HOST_COMPLETE,
- STATE_RESOLVE_PROTOCOL,
- STATE_RESOLVE_PROTOCOL_COMPLETE,
- STATE_TCP_CONNECT,
- STATE_TCP_CONNECT_COMPLETE,
- STATE_GENERATE_PROXY_AUTH_TOKEN,
- STATE_GENERATE_PROXY_AUTH_TOKEN_COMPLETE,
- STATE_WRITE_TUNNEL_HEADERS,
- STATE_WRITE_TUNNEL_HEADERS_COMPLETE,
- STATE_READ_TUNNEL_HEADERS,
- STATE_READ_TUNNEL_HEADERS_COMPLETE,
- STATE_SOCKS_CONNECT,
- STATE_SOCKS_CONNECT_COMPLETE,
- STATE_SECURE_PROXY_CONNECT,
- STATE_SECURE_PROXY_CONNECT_COMPLETE,
- STATE_SECURE_PROXY_HANDLE_CERT_ERROR,
- STATE_SECURE_PROXY_HANDLE_CERT_ERROR_COMPLETE,
- STATE_SSL_CONNECT,
- STATE_SSL_CONNECT_COMPLETE,
- STATE_SSL_HANDLE_CERT_ERROR,
- STATE_SSL_HANDLE_CERT_ERROR_COMPLETE,
- STATE_READ_WRITE,
- STATE_AUTH_REQUIRED,
- STATE_CLOSE,
- };
-
- enum ProxyMode {
- kDirectConnection, // If using a direct connection
- kTunnelProxy, // If using a tunnel (CONNECT method as HTTPS)
- kSOCKSProxy, // If using a SOCKS proxy
- };
-
- // Use the same number as HttpNetworkTransaction::kMaxHeaderBufSize.
- enum { kMaxTunnelResponseHeadersSize = 32768 }; // 32 kilobytes.
-
- // Used for WebSocketThrottleTest.
- void set_addresses(const AddressList& addresses);
-
- void DoClose();
-
- // Finishes the job.
- // Calls OnError and OnClose of delegate, and no more
- // notifications will be sent to delegate.
- void Finish(int result);
-
- int DidEstablishConnection();
- int DidReceiveData(int result);
- // Given the number of bytes sent,
- // - notifies the |delegate_| and |metrics_| of this event.
- // - drains sent data from |current_write_buf_|.
- // - if |current_write_buf_| has been fully sent, sets NULL to
- // |current_write_buf_| to get ready for next write.
- // and then, returns OK.
- void DidSendData(int result);
-
- void OnIOCompleted(int result);
- void OnReadCompleted(int result);
- void OnWriteCompleted(int result);
-
- void DoLoop(int result);
-
- int DoBeforeConnect();
- int DoBeforeConnectComplete(int result);
- int DoResolveProxy();
- int DoResolveProxyComplete(int result);
- int DoResolveHost();
- int DoResolveHostComplete(int result);
- int DoResolveProtocol(int result);
- int DoResolveProtocolComplete(int result);
- int DoTcpConnect(int result);
- int DoTcpConnectComplete(int result);
- int DoGenerateProxyAuthToken();
- int DoGenerateProxyAuthTokenComplete(int result);
- int DoWriteTunnelHeaders();
- int DoWriteTunnelHeadersComplete(int result);
- int DoReadTunnelHeaders();
- int DoReadTunnelHeadersComplete(int result);
- int DoSOCKSConnect();
- int DoSOCKSConnectComplete(int result);
- int DoSecureProxyConnect();
- int DoSecureProxyConnectComplete(int result);
- int DoSecureProxyHandleCertError(int result);
- int DoSecureProxyHandleCertErrorComplete(int result);
- int DoSSLConnect();
- int DoSSLConnectComplete(int result);
- int DoSSLHandleCertError(int result);
- int DoSSLHandleCertErrorComplete(int result);
- int DoReadWrite(int result);
-
- GURL ProxyAuthOrigin() const;
- int HandleAuthChallenge(const HttpResponseHeaders* headers);
- int HandleCertificateRequest(int result, SSLConfig* ssl_config);
- void DoAuthRequired();
- void DoRestartWithAuth();
-
- int HandleCertificateError(int result);
- int AllowCertErrorForReconnection(SSLConfig* ssl_config);
-
- // Returns the sum of the size of buffers in |pending_write_bufs_|.
- size_t GetTotalSizeOfPendingWriteBufs() const;
-
- BoundNetLog net_log_;
-
- GURL url_;
- // The number of bytes allowed to be buffered in this object. If the size of
- // buffered data which is
- // current_write_buf_.BytesRemaining() +
- // sum of the size of buffers in |pending_write_bufs_|
- // exceeds this limit, SendData() fails.
- int max_pending_send_allowed_;
- URLRequestContext* context_;
-
- UserDataMap user_data_;
-
- State next_state_;
- ClientSocketFactory* factory_;
-
- ProxyMode proxy_mode_;
-
- GURL proxy_url_;
- ProxyService::PacRequest* pac_request_;
- ProxyInfo proxy_info_;
-
- scoped_refptr<HttpAuthController> proxy_auth_controller_;
-
- scoped_refptr<RequestHeaders> tunnel_request_headers_;
- size_t tunnel_request_headers_bytes_sent_;
- scoped_refptr<ResponseHeaders> tunnel_response_headers_;
- int tunnel_response_headers_capacity_;
- int tunnel_response_headers_len_;
-
- scoped_ptr<SingleRequestHostResolver> resolver_;
- AddressList addresses_;
- scoped_ptr<ClientSocketHandle> connection_;
-
- SSLConfig server_ssl_config_;
- SSLConfig proxy_ssl_config_;
- PrivacyMode privacy_mode_;
-
- CompletionCallback io_callback_;
-
- scoped_refptr<IOBuffer> read_buf_;
- int read_buf_size_;
-
- // Buffer to hold data to pass to socket_.
- scoped_refptr<DrainableIOBuffer> current_write_buf_;
- // True iff there's no error and this instance is waiting for completion of
- // Write operation by socket_.
- bool waiting_for_write_completion_;
- PendingDataQueue pending_write_bufs_;
-
- bool closing_;
- bool server_closed_;
-
- scoped_ptr<SocketStreamMetrics> metrics_;
-
- // Cookie store to use for this socket stream.
- scoped_refptr<CookieStore> cookie_store_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketStream);
-};
-
-} // namespace net
-
-#endif // NET_SOCKET_STREAM_SOCKET_STREAM_H_
diff --git a/net/socket_stream/socket_stream_job.cc b/net/socket_stream/socket_stream_job.cc
deleted file mode 100644
index 66da741..0000000
--- a/net/socket_stream/socket_stream_job.cc
+++ /dev/null
@@ -1,92 +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/socket_stream/socket_stream_job.h"
-
-#include "base/memory/singleton.h"
-#include "net/http/transport_security_state.h"
-#include "net/socket_stream/socket_stream_job_manager.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/url_request/url_request_context.h"
-
-namespace net {
-
-// static
-SocketStreamJob::ProtocolFactory* SocketStreamJob::RegisterProtocolFactory(
- const std::string& scheme, ProtocolFactory* factory) {
- return SocketStreamJobManager::GetInstance()->RegisterProtocolFactory(
- scheme, factory);
-}
-
-// static
-SocketStreamJob* SocketStreamJob::CreateSocketStreamJob(
- const GURL& url,
- SocketStream::Delegate* delegate,
- TransportSecurityState* sts,
- SSLConfigService* ssl,
- URLRequestContext* context,
- CookieStore* cookie_store) {
- GURL socket_url(url);
- if (url.scheme() == "ws" && sts &&
- sts->ShouldUpgradeToSSL(url.host())) {
- url::Replacements<char> replacements;
- static const char kNewScheme[] = "wss";
- replacements.SetScheme(kNewScheme, url::Component(0, strlen(kNewScheme)));
- socket_url = url.ReplaceComponents(replacements);
- }
- return SocketStreamJobManager::GetInstance()->CreateJob(
- socket_url, delegate, context, cookie_store);
-}
-
-SocketStreamJob::SocketStreamJob() {}
-
-SocketStream::UserData* SocketStreamJob::GetUserData(const void* key) const {
- return socket_->GetUserData(key);
-}
-
-void SocketStreamJob::SetUserData(const void* key,
- SocketStream::UserData* data) {
- socket_->SetUserData(key, data);
-}
-
-void SocketStreamJob::Connect() {
- socket_->Connect();
-}
-
-bool SocketStreamJob::SendData(const char* data, int len) {
- return socket_->SendData(data, len);
-}
-
-void SocketStreamJob::Close() {
- socket_->Close();
-}
-
-void SocketStreamJob::RestartWithAuth(const AuthCredentials& credentials) {
- socket_->RestartWithAuth(credentials);
-}
-
-void SocketStreamJob::CancelWithError(int error) {
- socket_->CancelWithError(error);
-}
-
-void SocketStreamJob::CancelWithSSLError(const net::SSLInfo& ssl_info) {
- socket_->CancelWithSSLError(ssl_info);
-}
-
-void SocketStreamJob::ContinueDespiteError() {
- socket_->ContinueDespiteError();
-}
-
-void SocketStreamJob::DetachDelegate() {
- socket_->DetachDelegate();
-}
-
-void SocketStreamJob::DetachContext() {
- if (socket_.get())
- socket_->DetachContext();
-}
-
-SocketStreamJob::~SocketStreamJob() {}
-
-} // namespace net
diff --git a/net/socket_stream/socket_stream_job.h b/net/socket_stream/socket_stream_job.h
deleted file mode 100644
index 9fc27d9..0000000
--- a/net/socket_stream/socket_stream_job.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
-
-#include <string>
-
-#include "base/memory/ref_counted.h"
-#include "net/base/net_export.h"
-#include "net/socket_stream/socket_stream.h"
-
-class GURL;
-
-namespace net {
-
-class CookieStore;
-class SSLConfigService;
-class SSLInfo;
-class TransportSecurityState;
-
-// SocketStreamJob represents full-duplex communication over SocketStream.
-// If a protocol (e.g. WebSocket protocol) needs to inspect/modify data
-// over SocketStream, you can implement protocol specific job (e.g.
-// WebSocketJob) to do some work on data over SocketStream.
-// Registers the protocol specific SocketStreamJob by RegisterProtocolFactory
-// and call CreateSocketStreamJob to create SocketStreamJob for the URL.
-class NET_EXPORT SocketStreamJob
- : public base::RefCountedThreadSafe<SocketStreamJob> {
- public:
- // Callback function implemented by protocol handlers to create new jobs.
- typedef SocketStreamJob* (ProtocolFactory)(const GURL& url,
- SocketStream::Delegate* delegate,
- URLRequestContext* context,
- CookieStore* cookie_store);
-
- static ProtocolFactory* RegisterProtocolFactory(const std::string& scheme,
- ProtocolFactory* factory);
-
- static SocketStreamJob* CreateSocketStreamJob(
- const GURL& url,
- SocketStream::Delegate* delegate,
- TransportSecurityState* sts,
- SSLConfigService* ssl,
- URLRequestContext* context,
- CookieStore* cookie_store);
-
- SocketStreamJob();
- void InitSocketStream(SocketStream* socket) {
- socket_ = socket;
- }
-
- virtual SocketStream::UserData* GetUserData(const void* key) const;
- virtual void SetUserData(const void* key, SocketStream::UserData* data);
-
- URLRequestContext* context() const {
- return socket_.get() ? socket_->context() : 0;
- }
- CookieStore* cookie_store() const {
- return socket_.get() ? socket_->cookie_store() : 0;
- }
-
- virtual void Connect();
-
- virtual bool SendData(const char* data, int len);
-
- virtual void Close();
-
- virtual void RestartWithAuth(const AuthCredentials& credentials);
-
- virtual void CancelWithError(int error);
-
- virtual void CancelWithSSLError(const net::SSLInfo& ssl_info);
-
- virtual void ContinueDespiteError();
-
- virtual void DetachDelegate();
-
- virtual void DetachContext();
-
- protected:
- friend class WebSocketJobTest;
- friend class base::RefCountedThreadSafe<SocketStreamJob>;
- virtual ~SocketStreamJob();
-
- scoped_refptr<SocketStream> socket_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketStreamJob);
-};
-
-} // namespace net
-
-#endif // NET_SOCKET_STREAM_SOCKET_STREAM_JOB_H_
diff --git a/net/socket_stream/socket_stream_job_manager.cc b/net/socket_stream/socket_stream_job_manager.cc
deleted file mode 100644
index 6418be4..0000000
--- a/net/socket_stream/socket_stream_job_manager.cc
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2011 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/socket_stream/socket_stream_job_manager.h"
-
-#include "base/memory/singleton.h"
-
-namespace net {
-
-SocketStreamJobManager::SocketStreamJobManager() {
-}
-
-SocketStreamJobManager::~SocketStreamJobManager() {
-}
-
-// static
-SocketStreamJobManager* SocketStreamJobManager::GetInstance() {
- return Singleton<SocketStreamJobManager>::get();
-}
-
-SocketStreamJob* SocketStreamJobManager::CreateJob(
- const GURL& url, SocketStream::Delegate* delegate,
- URLRequestContext* context, CookieStore* cookie_store) const {
- // If url is invalid, create plain SocketStreamJob, which will close
- // the socket immediately.
- if (!url.is_valid()) {
- SocketStreamJob* job = new SocketStreamJob();
- job->InitSocketStream(new SocketStream(url, delegate, context,
- cookie_store));
- return job;
- }
-
- const std::string& scheme = url.scheme(); // already lowercase
-
- base::AutoLock locked(lock_);
- FactoryMap::const_iterator found = factories_.find(scheme);
- if (found != factories_.end()) {
- SocketStreamJob* job = found->second(url, delegate, context, cookie_store);
- if (job)
- return job;
- }
- SocketStreamJob* job = new SocketStreamJob();
- job->InitSocketStream(new SocketStream(url, delegate, context, cookie_store));
- return job;
-}
-
-SocketStreamJob::ProtocolFactory*
-SocketStreamJobManager::RegisterProtocolFactory(
- const std::string& scheme, SocketStreamJob::ProtocolFactory* factory) {
- base::AutoLock locked(lock_);
-
- SocketStreamJob::ProtocolFactory* old_factory;
- FactoryMap::iterator found = factories_.find(scheme);
- if (found != factories_.end()) {
- old_factory = found->second;
- } else {
- old_factory = NULL;
- }
- if (factory) {
- factories_[scheme] = factory;
- } else if (found != factories_.end()) {
- factories_.erase(found);
- }
- return old_factory;
-}
-
-} // namespace net
diff --git a/net/socket_stream/socket_stream_job_manager.h b/net/socket_stream/socket_stream_job_manager.h
deleted file mode 100644
index 2363fb5..0000000
--- a/net/socket_stream/socket_stream_job_manager.h
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright (c) 2010 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_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
-
-#include <map>
-#include <string>
-
-#include "net/socket_stream/socket_stream.h"
-#include "net/socket_stream/socket_stream_job.h"
-
-template <typename T> struct DefaultSingletonTraits;
-class GURL;
-
-namespace net {
-
-class SocketStreamJobManager {
- public:
- // Returns the singleton instance.
- static SocketStreamJobManager* GetInstance();
-
- SocketStreamJob* CreateJob(
- const GURL& url, SocketStream::Delegate* delegate,
- URLRequestContext* context, CookieStore* cookie_store) const;
-
- SocketStreamJob::ProtocolFactory* RegisterProtocolFactory(
- const std::string& scheme, SocketStreamJob::ProtocolFactory* factory);
-
- private:
- friend struct DefaultSingletonTraits<SocketStreamJobManager>;
- typedef std::map<std::string, SocketStreamJob::ProtocolFactory*> FactoryMap;
-
- SocketStreamJobManager();
- ~SocketStreamJobManager();
-
- mutable base::Lock lock_;
- FactoryMap factories_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketStreamJobManager);
-};
-
-} // namespace net
-
-#endif // NET_SOCKET_STREAM_SOCKET_STREAM_JOB_MANAGER_H_
diff --git a/net/socket_stream/socket_stream_metrics.cc b/net/socket_stream/socket_stream_metrics.cc
deleted file mode 100644
index e026887..0000000
--- a/net/socket_stream/socket_stream_metrics.cc
+++ /dev/null
@@ -1,86 +0,0 @@
-// Copyright (c) 2011 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/socket_stream/socket_stream_metrics.h"
-
-#include <string.h>
-
-#include "base/metrics/histogram.h"
-#include "base/time/time.h"
-#include "url/gurl.h"
-
-namespace net {
-
-SocketStreamMetrics::SocketStreamMetrics(const GURL& url)
- : received_bytes_(0),
- received_counts_(0),
- sent_bytes_(0),
- sent_counts_(0) {
- ProtocolType protocol_type = PROTOCOL_UNKNOWN;
- if (url.SchemeIs("ws"))
- protocol_type = PROTOCOL_WEBSOCKET;
- else if (url.SchemeIs("wss"))
- protocol_type = PROTOCOL_WEBSOCKET_SECURE;
-
- UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.ProtocolType",
- protocol_type, NUM_PROTOCOL_TYPES);
-}
-
-SocketStreamMetrics::~SocketStreamMetrics() {}
-
-void SocketStreamMetrics::OnWaitConnection() {
- wait_start_time_ = base::TimeTicks::Now();
-}
-
-void SocketStreamMetrics::OnStartConnection() {
- connect_start_time_ = base::TimeTicks::Now();
- if (!wait_start_time_.is_null())
- UMA_HISTOGRAM_TIMES("Net.SocketStream.ConnectionLatency",
- connect_start_time_ - wait_start_time_);
- OnCountConnectionType(ALL_CONNECTIONS);
-}
-
-void SocketStreamMetrics::OnConnected() {
- connect_establish_time_ = base::TimeTicks::Now();
- UMA_HISTOGRAM_TIMES("Net.SocketStream.ConnectionEstablish",
- connect_establish_time_ - connect_start_time_);
-}
-
-void SocketStreamMetrics::OnRead(int len) {
- received_bytes_ += len;
- ++received_counts_;
-}
-
-void SocketStreamMetrics::OnWrite(int len) {
- sent_bytes_ += len;
- ++sent_counts_;
-}
-
-void SocketStreamMetrics::OnClose() {
- base::TimeTicks closed_time = base::TimeTicks::Now();
- if (!connect_establish_time_.is_null()) {
- UMA_HISTOGRAM_LONG_TIMES("Net.SocketStream.Duration",
- closed_time - connect_establish_time_);
- UMA_HISTOGRAM_COUNTS("Net.SocketStream.ReceivedBytes",
- received_bytes_);
- UMA_HISTOGRAM_COUNTS("Net.SocketStream.ReceivedCounts",
- received_counts_);
- UMA_HISTOGRAM_COUNTS("Net.SocketStream.SentBytes",
- sent_bytes_);
- UMA_HISTOGRAM_COUNTS("Net.SocketStream.SentCounts",
- sent_counts_);
- }
-}
-
-void SocketStreamMetrics::OnCountConnectionType(ConnectionType type) {
- UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.ConnectionType", type,
- NUM_CONNECTION_TYPES);
-}
-
-void SocketStreamMetrics::OnCountWireProtocolType(WireProtocolType type) {
- UMA_HISTOGRAM_ENUMERATION("Net.SocketStream.WireProtocolType", type,
- NUM_WIRE_PROTOCOL_TYPES);
-}
-
-} // namespace net
diff --git a/net/socket_stream/socket_stream_metrics.h b/net/socket_stream/socket_stream_metrics.h
deleted file mode 100644
index 0040a9a..0000000
--- a/net/socket_stream/socket_stream_metrics.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) 2011 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.
-//
-// Collect metrics of SocketStream usage.
-// TODO(ukai): collect WebSocket specific metrics (e.g. handshake time, etc).
-
-#ifndef NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
-#define NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
-
-#include "base/basictypes.h"
-#include "base/time/time.h"
-#include "net/base/net_export.h"
-
-class GURL;
-
-namespace net {
-
-class NET_EXPORT_PRIVATE SocketStreamMetrics {
- public:
- enum ProtocolType {
- PROTOCOL_UNKNOWN,
- PROTOCOL_WEBSOCKET,
- PROTOCOL_WEBSOCKET_SECURE,
- NUM_PROTOCOL_TYPES,
- };
-
- enum ConnectionType {
- CONNECTION_NONE,
- ALL_CONNECTIONS,
- TUNNEL_CONNECTION,
- SOCKS_CONNECTION,
- SSL_CONNECTION,
- SECURE_PROXY_CONNECTION,
- NUM_CONNECTION_TYPES,
- };
-
- enum WireProtocolType {
- WIRE_PROTOCOL_WEBSOCKET,
- WIRE_PROTOCOL_SPDY,
- NUM_WIRE_PROTOCOL_TYPES,
- };
-
- explicit SocketStreamMetrics(const GURL& url);
- ~SocketStreamMetrics();
-
- void OnWaitConnection();
- void OnStartConnection();
- void OnConnected();
- void OnRead(int len);
- void OnWrite(int len);
- void OnClose();
- void OnCountConnectionType(ConnectionType type);
- void OnCountWireProtocolType(WireProtocolType type);
-
- private:
- base::TimeTicks wait_start_time_;
- base::TimeTicks connect_start_time_;
- base::TimeTicks connect_establish_time_;
- int received_bytes_;
- int received_counts_;
- int sent_bytes_;
- int sent_counts_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketStreamMetrics);
-};
-
-} // namespace net
-
-#endif // NET_SOCKET_STREAM_SOCKET_STREAM_METRICS_H_
diff --git a/net/socket_stream/socket_stream_metrics_unittest.cc b/net/socket_stream/socket_stream_metrics_unittest.cc
deleted file mode 100644
index 219e692..0000000
--- a/net/socket_stream/socket_stream_metrics_unittest.cc
+++ /dev/null
@@ -1,221 +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/socket_stream/socket_stream_metrics.h"
-
-#include "base/basictypes.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/metrics/histogram.h"
-#include "base/metrics/histogram_samples.h"
-#include "base/metrics/statistics_recorder.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-using base::Histogram;
-using base::HistogramBase;
-using base::HistogramSamples;
-using base::StatisticsRecorder;
-
-namespace net {
-
-TEST(SocketStreamMetricsTest, ProtocolType) {
- // First we'll preserve the original values. We need to do this
- // as histograms can get affected by other tests. In particular,
- // SocketStreamTest and WebSocketTest can affect the histograms.
- scoped_ptr<HistogramSamples> original;
- HistogramBase* histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ProtocolType");
- if (histogram) {
- original = histogram->SnapshotSamples();
- }
-
- SocketStreamMetrics unknown(GURL("unknown://www.example.com/"));
- SocketStreamMetrics ws1(GURL("ws://www.example.com/"));
- SocketStreamMetrics ws2(GURL("ws://www.example.com/"));
- SocketStreamMetrics wss1(GURL("wss://www.example.com/"));
- SocketStreamMetrics wss2(GURL("wss://www.example.com/"));
- SocketStreamMetrics wss3(GURL("wss://www.example.com/"));
-
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ProtocolType");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-
- scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples());
- if (original.get()) {
- samples->Subtract(*original); // Cancel the original values.
- }
- EXPECT_EQ(1, samples->GetCount(SocketStreamMetrics::PROTOCOL_UNKNOWN));
- EXPECT_EQ(2, samples->GetCount(SocketStreamMetrics::PROTOCOL_WEBSOCKET));
- EXPECT_EQ(3,
- samples->GetCount(SocketStreamMetrics::PROTOCOL_WEBSOCKET_SECURE));
-}
-
-TEST(SocketStreamMetricsTest, ConnectionType) {
- // First we'll preserve the original values.
- scoped_ptr<HistogramSamples> original;
- HistogramBase* histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionType");
- if (histogram) {
- original = histogram->SnapshotSamples();
- }
-
- SocketStreamMetrics metrics(GURL("ws://www.example.com/"));
- for (int i = 0; i < 1; ++i)
- metrics.OnStartConnection();
- for (int i = 0; i < 2; ++i)
- metrics.OnCountConnectionType(SocketStreamMetrics::TUNNEL_CONNECTION);
- for (int i = 0; i < 3; ++i)
- metrics.OnCountConnectionType(SocketStreamMetrics::SOCKS_CONNECTION);
- for (int i = 0; i < 4; ++i)
- metrics.OnCountConnectionType(SocketStreamMetrics::SSL_CONNECTION);
-
-
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionType");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-
- scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples());
- if (original.get()) {
- samples->Subtract(*original); // Cancel the original values.
- }
- EXPECT_EQ(1, samples->GetCount(SocketStreamMetrics::ALL_CONNECTIONS));
- EXPECT_EQ(2, samples->GetCount(SocketStreamMetrics::TUNNEL_CONNECTION));
- EXPECT_EQ(3, samples->GetCount(SocketStreamMetrics::SOCKS_CONNECTION));
- EXPECT_EQ(4, samples->GetCount(SocketStreamMetrics::SSL_CONNECTION));
-}
-
-TEST(SocketStreamMetricsTest, WireProtocolType) {
- // First we'll preserve the original values.
- scoped_ptr<HistogramSamples> original;
- HistogramBase* histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.WireProtocolType");
- if (histogram) {
- original = histogram->SnapshotSamples();
- }
-
- SocketStreamMetrics metrics(GURL("ws://www.example.com/"));
- for (int i = 0; i < 3; ++i)
- metrics.OnCountWireProtocolType(
- SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET);
- for (int i = 0; i < 7; ++i)
- metrics.OnCountWireProtocolType(SocketStreamMetrics::WIRE_PROTOCOL_SPDY);
-
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.WireProtocolType");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
-
- scoped_ptr<HistogramSamples> samples(histogram->SnapshotSamples());
- if (original.get()) {
- samples->Subtract(*original); // Cancel the original values.
- }
- EXPECT_EQ(3, samples->GetCount(SocketStreamMetrics::WIRE_PROTOCOL_WEBSOCKET));
- EXPECT_EQ(7, samples->GetCount(SocketStreamMetrics::WIRE_PROTOCOL_SPDY));
-}
-
-TEST(SocketStreamMetricsTest, OtherNumbers) {
- // First we'll preserve the original values.
- int64 original_received_bytes = 0;
- int64 original_received_counts = 0;
- int64 original_sent_bytes = 0;
- int64 original_sent_counts = 0;
-
- scoped_ptr<HistogramSamples> original;
-
- HistogramBase* histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedBytes");
- if (histogram) {
- original = histogram->SnapshotSamples();
- original_received_bytes = original->sum();
- }
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedCounts");
- if (histogram) {
- original = histogram->SnapshotSamples();
- original_received_counts = original->sum();
- }
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.SentBytes");
- if (histogram) {
- original = histogram->SnapshotSamples();
- original_sent_bytes = original->sum();
- }
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.SentCounts");
- if (histogram) {
- original = histogram->SnapshotSamples();
- original_sent_counts = original->sum();
- }
-
- SocketStreamMetrics metrics(GURL("ws://www.example.com/"));
- metrics.OnWaitConnection();
- metrics.OnStartConnection();
- metrics.OnConnected();
- metrics.OnRead(1);
- metrics.OnRead(10);
- metrics.OnWrite(2);
- metrics.OnWrite(20);
- metrics.OnWrite(200);
- metrics.OnClose();
-
- scoped_ptr<HistogramSamples> samples;
-
- // ConnectionLatency.
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionLatency");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
- // We don't check the contents of the histogram as it's time sensitive.
-
- // ConnectionEstablish.
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ConnectionEstablish");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
- // We don't check the contents of the histogram as it's time sensitive.
-
- // Duration.
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.Duration");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
- // We don't check the contents of the histogram as it's time sensitive.
-
- // ReceivedBytes.
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedBytes");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
- samples = histogram->SnapshotSamples();
- EXPECT_EQ(11, samples->sum() - original_received_bytes); // 11 bytes read.
-
- // ReceivedCounts.
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.ReceivedCounts");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
- samples = histogram->SnapshotSamples();
- EXPECT_EQ(2, samples->sum() - original_received_counts); // 2 read requests.
-
- // SentBytes.
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.SentBytes");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
- samples = histogram->SnapshotSamples();
- EXPECT_EQ(222, samples->sum() - original_sent_bytes); // 222 bytes sent.
-
- // SentCounts.
- histogram =
- StatisticsRecorder::FindHistogram("Net.SocketStream.SentCounts");
- ASSERT_TRUE(histogram != NULL);
- EXPECT_EQ(HistogramBase::kUmaTargetedHistogramFlag, histogram->flags());
- samples = histogram->SnapshotSamples();
- EXPECT_EQ(3, samples->sum() - original_sent_counts); // 3 write requests.
-}
-
-} // namespace net
diff --git a/net/socket_stream/socket_stream_unittest.cc b/net/socket_stream/socket_stream_unittest.cc
deleted file mode 100644
index b5ee002..0000000
--- a/net/socket_stream/socket_stream_unittest.cc
+++ /dev/null
@@ -1,1041 +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/socket_stream/socket_stream.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/strings/utf_string_conversions.h"
-#include "net/base/auth.h"
-#include "net/base/net_log.h"
-#include "net/base/net_log_unittest.h"
-#include "net/base/test_completion_callback.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_network_session.h"
-#include "net/proxy/proxy_service.h"
-#include "net/socket/socket_test_util.h"
-#include "net/url_request/url_request_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-
-using base::ASCIIToUTF16;
-
-namespace net {
-
-namespace {
-
-struct SocketStreamEvent {
- enum EventType {
- EVENT_START_OPEN_CONNECTION, EVENT_CONNECTED, EVENT_SENT_DATA,
- EVENT_RECEIVED_DATA, EVENT_CLOSE, EVENT_AUTH_REQUIRED, EVENT_ERROR,
- };
-
- SocketStreamEvent(EventType type,
- SocketStream* socket_stream,
- int num,
- const std::string& str,
- AuthChallengeInfo* auth_challenge_info,
- int error)
- : event_type(type), socket(socket_stream), number(num), data(str),
- auth_info(auth_challenge_info), error_code(error) {}
-
- EventType event_type;
- SocketStream* socket;
- int number;
- std::string data;
- scoped_refptr<AuthChallengeInfo> auth_info;
- int error_code;
-};
-
-class SocketStreamEventRecorder : public SocketStream::Delegate {
- public:
- // |callback| will be run when the OnClose() or OnError() method is called.
- // For OnClose(), |callback| is called with OK. For OnError(), it's called
- // with the error code.
- explicit SocketStreamEventRecorder(const CompletionCallback& callback)
- : callback_(callback) {}
- ~SocketStreamEventRecorder() override {}
-
- void SetOnStartOpenConnection(
- const base::Callback<int(SocketStreamEvent*)>& callback) {
- on_start_open_connection_ = callback;
- }
- void SetOnConnected(
- const base::Callback<void(SocketStreamEvent*)>& callback) {
- on_connected_ = callback;
- }
- void SetOnSentData(
- const base::Callback<void(SocketStreamEvent*)>& callback) {
- on_sent_data_ = callback;
- }
- void SetOnReceivedData(
- const base::Callback<void(SocketStreamEvent*)>& callback) {
- on_received_data_ = callback;
- }
- void SetOnClose(const base::Callback<void(SocketStreamEvent*)>& callback) {
- on_close_ = callback;
- }
- void SetOnAuthRequired(
- const base::Callback<void(SocketStreamEvent*)>& callback) {
- on_auth_required_ = callback;
- }
- void SetOnError(const base::Callback<void(SocketStreamEvent*)>& callback) {
- on_error_ = callback;
- }
-
- int OnStartOpenConnection(SocketStream* socket,
- const CompletionCallback& callback) override {
- connection_callback_ = callback;
- events_.push_back(
- SocketStreamEvent(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- socket, 0, std::string(), NULL, OK));
- if (!on_start_open_connection_.is_null())
- return on_start_open_connection_.Run(&events_.back());
- return OK;
- }
- void OnConnected(SocketStream* socket,
- int num_pending_send_allowed) override {
- events_.push_back(
- SocketStreamEvent(SocketStreamEvent::EVENT_CONNECTED,
- socket, num_pending_send_allowed, std::string(),
- NULL, OK));
- if (!on_connected_.is_null())
- on_connected_.Run(&events_.back());
- }
- void OnSentData(SocketStream* socket, int amount_sent) override {
- events_.push_back(
- SocketStreamEvent(SocketStreamEvent::EVENT_SENT_DATA, socket,
- amount_sent, std::string(), NULL, OK));
- if (!on_sent_data_.is_null())
- on_sent_data_.Run(&events_.back());
- }
- void OnReceivedData(SocketStream* socket,
- const char* data,
- int len) override {
- events_.push_back(
- SocketStreamEvent(SocketStreamEvent::EVENT_RECEIVED_DATA, socket, len,
- std::string(data, len), NULL, OK));
- if (!on_received_data_.is_null())
- on_received_data_.Run(&events_.back());
- }
- void OnClose(SocketStream* socket) override {
- events_.push_back(
- SocketStreamEvent(SocketStreamEvent::EVENT_CLOSE, socket, 0,
- std::string(), NULL, OK));
- if (!on_close_.is_null())
- on_close_.Run(&events_.back());
- if (!callback_.is_null())
- callback_.Run(OK);
- }
- void OnAuthRequired(SocketStream* socket,
- AuthChallengeInfo* auth_info) override {
- events_.push_back(
- SocketStreamEvent(SocketStreamEvent::EVENT_AUTH_REQUIRED, socket, 0,
- std::string(), auth_info, OK));
- if (!on_auth_required_.is_null())
- on_auth_required_.Run(&events_.back());
- }
- void OnError(const SocketStream* socket, int error) override {
- events_.push_back(
- SocketStreamEvent(SocketStreamEvent::EVENT_ERROR, NULL, 0,
- std::string(), NULL, error));
- if (!on_error_.is_null())
- on_error_.Run(&events_.back());
- if (!callback_.is_null())
- callback_.Run(error);
- }
-
- void DoClose(SocketStreamEvent* event) {
- event->socket->Close();
- }
- void DoRestartWithAuth(SocketStreamEvent* event) {
- VLOG(1) << "RestartWithAuth username=" << credentials_.username()
- << " password=" << credentials_.password();
- event->socket->RestartWithAuth(credentials_);
- }
- void SetAuthInfo(const AuthCredentials& credentials) {
- credentials_ = credentials;
- }
- // Wakes up the SocketStream waiting for completion of OnStartOpenConnection()
- // of its delegate.
- void CompleteConnection(int result) {
- connection_callback_.Run(result);
- }
-
- const std::vector<SocketStreamEvent>& GetSeenEvents() const {
- return events_;
- }
-
- private:
- std::vector<SocketStreamEvent> events_;
- base::Callback<int(SocketStreamEvent*)> on_start_open_connection_;
- base::Callback<void(SocketStreamEvent*)> on_connected_;
- base::Callback<void(SocketStreamEvent*)> on_sent_data_;
- base::Callback<void(SocketStreamEvent*)> on_received_data_;
- base::Callback<void(SocketStreamEvent*)> on_close_;
- base::Callback<void(SocketStreamEvent*)> on_auth_required_;
- base::Callback<void(SocketStreamEvent*)> on_error_;
- const CompletionCallback callback_;
- CompletionCallback connection_callback_;
- AuthCredentials credentials_;
-
- DISALLOW_COPY_AND_ASSIGN(SocketStreamEventRecorder);
-};
-
-// This is used for the test OnErrorDetachDelegate.
-class SelfDeletingDelegate : public SocketStream::Delegate {
- public:
- // |callback| must cause the test message loop to exit when called.
- explicit SelfDeletingDelegate(const CompletionCallback& callback)
- : socket_stream_(), callback_(callback) {}
-
- ~SelfDeletingDelegate() override {}
-
- // Call DetachDelegate(), delete |this|, then run the callback.
- void OnError(const SocketStream* socket, int error) override {
- // callback_ will be deleted when we delete |this|, so copy it to call it
- // afterwards.
- CompletionCallback callback = callback_;
- socket_stream_->DetachDelegate();
- delete this;
- callback.Run(OK);
- }
-
- // This can't be passed in the constructor because this object needs to be
- // created before SocketStream.
- void set_socket_stream(const scoped_refptr<SocketStream>& socket_stream) {
- socket_stream_ = socket_stream;
- EXPECT_EQ(socket_stream_->delegate(), this);
- }
-
- void OnConnected(SocketStream* socket,
- int max_pending_send_allowed) override {
- ADD_FAILURE() << "OnConnected() should not be called";
- }
- void OnSentData(SocketStream* socket, int amount_sent) override {
- ADD_FAILURE() << "OnSentData() should not be called";
- }
- void OnReceivedData(SocketStream* socket,
- const char* data,
- int len) override {
- ADD_FAILURE() << "OnReceivedData() should not be called";
- }
- void OnClose(SocketStream* socket) override {
- ADD_FAILURE() << "OnClose() should not be called";
- }
-
- private:
- scoped_refptr<SocketStream> socket_stream_;
- const CompletionCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(SelfDeletingDelegate);
-};
-
-class TestURLRequestContextWithProxy : public TestURLRequestContext {
- public:
- explicit TestURLRequestContextWithProxy(const std::string& proxy)
- : TestURLRequestContext(true) {
- context_storage_.set_proxy_service(ProxyService::CreateFixed(proxy));
- Init();
- }
- ~TestURLRequestContextWithProxy() override {}
-};
-
-class TestSocketStreamNetworkDelegate : public TestNetworkDelegate {
- public:
- TestSocketStreamNetworkDelegate()
- : before_connect_result_(OK) {}
- ~TestSocketStreamNetworkDelegate() override {}
-
- int OnBeforeSocketStreamConnect(SocketStream* stream,
- const CompletionCallback& callback) override {
- return before_connect_result_;
- }
-
- void SetBeforeConnectResult(int result) {
- before_connect_result_ = result;
- }
-
- private:
- int before_connect_result_;
-};
-
-} // namespace
-
-class SocketStreamTest : public PlatformTest {
- public:
- ~SocketStreamTest() override {}
- void SetUp() override {
- mock_socket_factory_.reset();
- handshake_request_ = kWebSocketHandshakeRequest;
- handshake_response_ = kWebSocketHandshakeResponse;
- }
- void TearDown() override { mock_socket_factory_.reset(); }
-
- virtual void SetWebSocketHandshakeMessage(
- const char* request, const char* response) {
- handshake_request_ = request;
- handshake_response_ = response;
- }
- virtual void AddWebSocketMessage(const std::string& message) {
- messages_.push_back(message);
- }
-
- virtual MockClientSocketFactory* GetMockClientSocketFactory() {
- mock_socket_factory_.reset(new MockClientSocketFactory);
- return mock_socket_factory_.get();
- }
-
- // Functions for SocketStreamEventRecorder to handle calls to the
- // SocketStream::Delegate methods from the SocketStream.
-
- virtual void DoSendWebSocketHandshake(SocketStreamEvent* event) {
- event->socket->SendData(
- handshake_request_.data(), handshake_request_.size());
- }
-
- virtual void DoCloseFlushPendingWriteTest(SocketStreamEvent* event) {
- // handshake response received.
- for (size_t i = 0; i < messages_.size(); i++) {
- std::vector<char> frame;
- frame.push_back('\0');
- frame.insert(frame.end(), messages_[i].begin(), messages_[i].end());
- frame.push_back('\xff');
- EXPECT_TRUE(event->socket->SendData(&frame[0], frame.size()));
- }
- // Actual StreamSocket close must happen after all frames queued by
- // SendData above are sent out.
- event->socket->Close();
- }
-
- virtual void DoCloseFlushPendingWriteTestWithSetContextNull(
- SocketStreamEvent* event) {
- event->socket->DetachContext();
- // handshake response received.
- for (size_t i = 0; i < messages_.size(); i++) {
- std::vector<char> frame;
- frame.push_back('\0');
- frame.insert(frame.end(), messages_[i].begin(), messages_[i].end());
- frame.push_back('\xff');
- EXPECT_TRUE(event->socket->SendData(&frame[0], frame.size()));
- }
- // Actual StreamSocket close must happen after all frames queued by
- // SendData above are sent out.
- event->socket->Close();
- }
-
- virtual void DoFailByTooBigDataAndClose(SocketStreamEvent* event) {
- std::string frame(event->number + 1, 0x00);
- VLOG(1) << event->number;
- EXPECT_FALSE(event->socket->SendData(&frame[0], frame.size()));
- event->socket->Close();
- }
-
- virtual int DoSwitchToSpdyTest(SocketStreamEvent* event) {
- return ERR_PROTOCOL_SWITCHED;
- }
-
- // Notifies |io_test_callback_| of that this method is called, and keeps the
- // SocketStream waiting.
- virtual int DoIOPending(SocketStreamEvent* event) {
- io_test_callback_.callback().Run(OK);
- return ERR_IO_PENDING;
- }
-
- static const char kWebSocketHandshakeRequest[];
- static const char kWebSocketHandshakeResponse[];
-
- protected:
- TestCompletionCallback io_test_callback_;
-
- private:
- std::string handshake_request_;
- std::string handshake_response_;
- std::vector<std::string> messages_;
-
- scoped_ptr<MockClientSocketFactory> mock_socket_factory_;
-};
-
-const char SocketStreamTest::kWebSocketHandshakeRequest[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Upgrade: WebSocket\r\n"
- "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
- "Origin: http://example.com\r\n"
- "\r\n"
- "^n:ds[4U";
-
-const char SocketStreamTest::kWebSocketHandshakeResponse[] =
- "HTTP/1.1 101 WebSocket Protocol Handshake\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Origin: http://example.com\r\n"
- "Sec-WebSocket-Location: ws://example.com/demo\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "\r\n"
- "8jKS'y:G*Co,Wxa-";
-
-TEST_F(SocketStreamTest, CloseFlushPendingWrite) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnConnected(base::Bind(
- &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this)));
- delegate->SetOnReceivedData(base::Bind(
- &SocketStreamTest::DoCloseFlushPendingWriteTest,
- base::Unretained(this)));
-
- TestURLRequestContext context;
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- MockWrite data_writes[] = {
- MockWrite(SocketStreamTest::kWebSocketHandshakeRequest),
- MockWrite(ASYNC, "\0message1\xff", 10),
- MockWrite(ASYNC, "\0message2\xff", 10)
- };
- MockRead data_reads[] = {
- MockRead(SocketStreamTest::kWebSocketHandshakeResponse),
- // Server doesn't close the connection after handshake.
- MockRead(ASYNC, ERR_IO_PENDING)
- };
- AddWebSocketMessage("message1");
- AddWebSocketMessage("message2");
-
- DelayedSocketData data_provider(
- 1, data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
-
- MockClientSocketFactory* mock_socket_factory =
- GetMockClientSocketFactory();
- mock_socket_factory->AddSocketDataProvider(&data_provider);
-
- socket_stream->SetClientSocketFactory(mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- EXPECT_TRUE(data_provider.at_read_eof());
- EXPECT_TRUE(data_provider.at_write_eof());
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(7U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[4].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[5].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[6].event_type);
-}
-
-TEST_F(SocketStreamTest, ResolveFailure) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
-
- // Make resolver fail.
- TestURLRequestContext context;
- scoped_ptr<MockHostResolver> mock_host_resolver(
- new MockHostResolver());
- mock_host_resolver->rules()->AddSimulatedFailure("example.com");
- context.set_host_resolver(mock_host_resolver.get());
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- // No read/write on socket is expected.
- StaticSocketDataProvider data_provider(NULL, 0, NULL, 0);
- MockClientSocketFactory* mock_socket_factory =
- GetMockClientSocketFactory();
- mock_socket_factory->AddSocketDataProvider(&data_provider);
- socket_stream->SetClientSocketFactory(mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(2U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[1].event_type);
-}
-
-TEST_F(SocketStreamTest, ExceedMaxPendingSendAllowed) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnConnected(base::Bind(
- &SocketStreamTest::DoFailByTooBigDataAndClose, base::Unretained(this)));
-
- TestURLRequestContext context;
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- DelayedSocketData data_provider(1, NULL, 0, NULL, 0);
-
- MockClientSocketFactory* mock_socket_factory =
- GetMockClientSocketFactory();
- mock_socket_factory->AddSocketDataProvider(&data_provider);
-
- socket_stream->SetClientSocketFactory(mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(4U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[2].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, BasicAuthProxy) {
- MockClientSocketFactory mock_socket_factory;
- MockWrite data_writes1[] = {
- MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 407 Proxy Authentication Required\r\n"),
- MockRead("Proxy-Authenticate: Basic realm=\"MyRealm1\"\r\n"),
- MockRead("\r\n"),
- };
- StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
- data_writes1, arraysize(data_writes1));
- mock_socket_factory.AddSocketDataProvider(&data1);
-
- MockWrite data_writes2[] = {
- MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads2[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n"),
- MockRead("Proxy-agent: Apache/2.2.8\r\n"),
- MockRead("\r\n"),
- // SocketStream::DoClose is run asynchronously. Socket can be read after
- // "\r\n". We have to give ERR_IO_PENDING to SocketStream then to indicate
- // server doesn't close the connection.
- MockRead(ASYNC, ERR_IO_PENDING)
- };
- StaticSocketDataProvider data2(data_reads2, arraysize(data_reads2),
- data_writes2, arraysize(data_writes2));
- mock_socket_factory.AddSocketDataProvider(&data2);
-
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
- base::Unretained(delegate.get())));
- delegate->SetAuthInfo(AuthCredentials(ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar")));
- delegate->SetOnAuthRequired(base::Bind(
- &SocketStreamEventRecorder::DoRestartWithAuth,
- base::Unretained(delegate.get())));
-
- TestURLRequestContextWithProxy context("myproxy:70");
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(5U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_AUTH_REQUIRED, events[1].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[2].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[3].event_type);
- EXPECT_EQ(ERR_ABORTED, events[3].error_code);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[4].event_type);
-
- // TODO(eroman): Add back NetLogTest here...
-}
-
-TEST_F(SocketStreamTest, BasicAuthProxyWithAuthCache) {
- MockClientSocketFactory mock_socket_factory;
- MockWrite data_writes[] = {
- // WebSocket(SocketStream) always uses CONNECT when it is configured to use
- // proxy so the port may not be 443.
- MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n"),
- MockRead("Proxy-agent: Apache/2.2.8\r\n"),
- MockRead("\r\n"),
- MockRead(ASYNC, ERR_IO_PENDING)
- };
- StaticSocketDataProvider data(data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
- mock_socket_factory.AddSocketDataProvider(&data);
-
- TestCompletionCallback test_callback;
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
- base::Unretained(delegate.get())));
-
- TestURLRequestContextWithProxy context("myproxy:70");
- HttpAuthCache* auth_cache =
- context.http_transaction_factory()->GetSession()->http_auth_cache();
- auth_cache->Add(GURL("http://myproxy:70"),
- "MyRealm1",
- HttpAuth::AUTH_SCHEME_BASIC,
- "Basic realm=MyRealm1",
- AuthCredentials(ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar")),
- "/");
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(4U, events.size());
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
- EXPECT_EQ(ERR_ABORTED, events[2].error_code);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, WSSBasicAuthProxyWithAuthCache) {
- MockClientSocketFactory mock_socket_factory;
- MockWrite data_writes1[] = {
- MockWrite("CONNECT example.com:443 HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Proxy-Connection: keep-alive\r\n"
- "Proxy-Authorization: Basic Zm9vOmJhcg==\r\n\r\n"),
- };
- MockRead data_reads1[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n"),
- MockRead("Proxy-agent: Apache/2.2.8\r\n"),
- MockRead("\r\n"),
- MockRead(ASYNC, ERR_IO_PENDING)
- };
- StaticSocketDataProvider data1(data_reads1, arraysize(data_reads1),
- data_writes1, arraysize(data_writes1));
- mock_socket_factory.AddSocketDataProvider(&data1);
-
- SSLSocketDataProvider data2(ASYNC, OK);
- mock_socket_factory.AddSSLSocketDataProvider(&data2);
-
- TestCompletionCallback test_callback;
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
- base::Unretained(delegate.get())));
-
- TestURLRequestContextWithProxy context("myproxy:70");
- HttpAuthCache* auth_cache =
- context.http_transaction_factory()->GetSession()->http_auth_cache();
- auth_cache->Add(GURL("http://myproxy:70"),
- "MyRealm1",
- HttpAuth::AUTH_SCHEME_BASIC,
- "Basic realm=MyRealm1",
- AuthCredentials(ASCIIToUTF16("foo"),
- ASCIIToUTF16("bar")),
- "/");
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("wss://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(4U, events.size());
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
- EXPECT_EQ(ERR_ABORTED, events[2].error_code);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, IOPending) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnStartOpenConnection(base::Bind(
- &SocketStreamTest::DoIOPending, base::Unretained(this)));
- delegate->SetOnConnected(base::Bind(
- &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this)));
- delegate->SetOnReceivedData(base::Bind(
- &SocketStreamTest::DoCloseFlushPendingWriteTest,
- base::Unretained(this)));
-
- TestURLRequestContext context;
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- MockWrite data_writes[] = {
- MockWrite(SocketStreamTest::kWebSocketHandshakeRequest),
- MockWrite(ASYNC, "\0message1\xff", 10),
- MockWrite(ASYNC, "\0message2\xff", 10)
- };
- MockRead data_reads[] = {
- MockRead(SocketStreamTest::kWebSocketHandshakeResponse),
- // Server doesn't close the connection after handshake.
- MockRead(ASYNC, ERR_IO_PENDING)
- };
- AddWebSocketMessage("message1");
- AddWebSocketMessage("message2");
-
- DelayedSocketData data_provider(
- 1, data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
-
- MockClientSocketFactory* mock_socket_factory =
- GetMockClientSocketFactory();
- mock_socket_factory->AddSocketDataProvider(&data_provider);
-
- socket_stream->SetClientSocketFactory(mock_socket_factory);
-
- socket_stream->Connect();
- io_test_callback_.WaitForResult();
- EXPECT_EQ(SocketStream::STATE_RESOLVE_PROTOCOL_COMPLETE,
- socket_stream->next_state_);
- delegate->CompleteConnection(OK);
-
- EXPECT_EQ(OK, test_callback.WaitForResult());
-
- EXPECT_TRUE(data_provider.at_read_eof());
- EXPECT_TRUE(data_provider.at_write_eof());
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(7U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[4].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[5].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[6].event_type);
-}
-
-TEST_F(SocketStreamTest, SwitchToSpdy) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnStartOpenConnection(base::Bind(
- &SocketStreamTest::DoSwitchToSpdyTest, base::Unretained(this)));
-
- TestURLRequestContext context;
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->Connect();
-
- EXPECT_EQ(ERR_PROTOCOL_SWITCHED, test_callback.WaitForResult());
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(2U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type);
- EXPECT_EQ(ERR_PROTOCOL_SWITCHED, events[1].error_code);
-}
-
-TEST_F(SocketStreamTest, SwitchAfterPending) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnStartOpenConnection(base::Bind(
- &SocketStreamTest::DoIOPending, base::Unretained(this)));
-
- TestURLRequestContext context;
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->Connect();
- io_test_callback_.WaitForResult();
-
- EXPECT_EQ(SocketStream::STATE_RESOLVE_PROTOCOL_COMPLETE,
- socket_stream->next_state_);
- delegate->CompleteConnection(ERR_PROTOCOL_SWITCHED);
-
- EXPECT_EQ(ERR_PROTOCOL_SWITCHED, test_callback.WaitForResult());
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(2U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type);
- EXPECT_EQ(ERR_PROTOCOL_SWITCHED, events[1].error_code);
-}
-
-// Test a connection though a secure proxy.
-TEST_F(SocketStreamTest, SecureProxyConnectError) {
- MockClientSocketFactory mock_socket_factory;
- MockWrite data_writes[] = {
- MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n")
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n"),
- MockRead("Proxy-agent: Apache/2.2.8\r\n"),
- MockRead("\r\n"),
- // SocketStream::DoClose is run asynchronously. Socket can be read after
- // "\r\n". We have to give ERR_IO_PENDING to SocketStream then to indicate
- // server doesn't close the connection.
- MockRead(ASYNC, ERR_IO_PENDING)
- };
- StaticSocketDataProvider data(data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
- mock_socket_factory.AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, ERR_SSL_PROTOCOL_ERROR);
- mock_socket_factory.AddSSLSocketDataProvider(&ssl);
-
- TestCompletionCallback test_callback;
- TestURLRequestContextWithProxy context("https://myproxy:70");
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
- base::Unretained(delegate.get())));
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(3U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[1].event_type);
- EXPECT_EQ(ERR_SSL_PROTOCOL_ERROR, events[1].error_code);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[2].event_type);
-}
-
-// Test a connection though a secure proxy.
-TEST_F(SocketStreamTest, SecureProxyConnect) {
- MockClientSocketFactory mock_socket_factory;
- MockWrite data_writes[] = {
- MockWrite("CONNECT example.com:80 HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Proxy-Connection: keep-alive\r\n\r\n")
- };
- MockRead data_reads[] = {
- MockRead("HTTP/1.1 200 Connection Established\r\n"),
- MockRead("Proxy-agent: Apache/2.2.8\r\n"),
- MockRead("\r\n"),
- // SocketStream::DoClose is run asynchronously. Socket can be read after
- // "\r\n". We have to give ERR_IO_PENDING to SocketStream then to indicate
- // server doesn't close the connection.
- MockRead(ASYNC, ERR_IO_PENDING)
- };
- StaticSocketDataProvider data(data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
- mock_socket_factory.AddSocketDataProvider(&data);
- SSLSocketDataProvider ssl(SYNCHRONOUS, OK);
- mock_socket_factory.AddSSLSocketDataProvider(&ssl);
-
- TestCompletionCallback test_callback;
- TestURLRequestContextWithProxy context("https://myproxy:70");
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- delegate->SetOnConnected(base::Bind(&SocketStreamEventRecorder::DoClose,
- base::Unretained(delegate.get())));
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->SetClientSocketFactory(&mock_socket_factory);
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(4U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[2].event_type);
- EXPECT_EQ(ERR_ABORTED, events[2].error_code);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[3].event_type);
-}
-
-TEST_F(SocketStreamTest, BeforeConnectFailed) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
-
- TestURLRequestContext context;
- TestSocketStreamNetworkDelegate network_delegate;
- network_delegate.SetBeforeConnectResult(ERR_ACCESS_DENIED);
- context.set_network_delegate(&network_delegate);
-
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
-
- socket_stream->Connect();
-
- test_callback.WaitForResult();
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(2U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_ERROR, events[0].event_type);
- EXPECT_EQ(ERR_ACCESS_DENIED, events[0].error_code);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[1].event_type);
-}
-
-// Check that a connect failure, followed by the delegate calling DetachDelegate
-// and deleting itself in the OnError callback, is handled correctly.
-TEST_F(SocketStreamTest, OnErrorDetachDelegate) {
- MockClientSocketFactory mock_socket_factory;
- TestCompletionCallback test_callback;
-
- // SelfDeletingDelegate is self-owning; we just need a pointer to it to
- // connect it and the SocketStream.
- SelfDeletingDelegate* delegate =
- new SelfDeletingDelegate(test_callback.callback());
- MockConnect mock_connect(ASYNC, ERR_CONNECTION_REFUSED);
- StaticSocketDataProvider data;
- data.set_connect_data(mock_connect);
- mock_socket_factory.AddSocketDataProvider(&data);
-
- TestURLRequestContext context;
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://localhost:9998/echo"), delegate,
- &context, NULL));
- socket_stream->SetClientSocketFactory(&mock_socket_factory);
- delegate->set_socket_stream(socket_stream);
- // The delegate pointer will become invalid during the test. Set it to NULL to
- // avoid holding a dangling pointer.
- delegate = NULL;
-
- socket_stream->Connect();
-
- EXPECT_EQ(OK, test_callback.WaitForResult());
-}
-
-TEST_F(SocketStreamTest, NullContextSocketStreamShouldNotCrash) {
- TestCompletionCallback test_callback;
-
- scoped_ptr<SocketStreamEventRecorder> delegate(
- new SocketStreamEventRecorder(test_callback.callback()));
- TestURLRequestContext context;
- scoped_refptr<SocketStream> socket_stream(
- new SocketStream(GURL("ws://example.com/demo"), delegate.get(),
- &context, NULL));
- delegate->SetOnStartOpenConnection(base::Bind(
- &SocketStreamTest::DoIOPending, base::Unretained(this)));
- delegate->SetOnConnected(base::Bind(
- &SocketStreamTest::DoSendWebSocketHandshake, base::Unretained(this)));
- delegate->SetOnReceivedData(base::Bind(
- &SocketStreamTest::DoCloseFlushPendingWriteTestWithSetContextNull,
- base::Unretained(this)));
-
- MockWrite data_writes[] = {
- MockWrite(SocketStreamTest::kWebSocketHandshakeRequest),
- };
- MockRead data_reads[] = {
- MockRead(SocketStreamTest::kWebSocketHandshakeResponse),
- };
- AddWebSocketMessage("message1");
- AddWebSocketMessage("message2");
-
- DelayedSocketData data_provider(
- 1, data_reads, arraysize(data_reads),
- data_writes, arraysize(data_writes));
-
- MockClientSocketFactory* mock_socket_factory = GetMockClientSocketFactory();
- mock_socket_factory->AddSocketDataProvider(&data_provider);
- socket_stream->SetClientSocketFactory(mock_socket_factory);
-
- socket_stream->Connect();
- io_test_callback_.WaitForResult();
- delegate->CompleteConnection(OK);
- EXPECT_EQ(OK, test_callback.WaitForResult());
-
- EXPECT_TRUE(data_provider.at_read_eof());
- EXPECT_TRUE(data_provider.at_write_eof());
-
- const std::vector<SocketStreamEvent>& events = delegate->GetSeenEvents();
- ASSERT_EQ(5U, events.size());
-
- EXPECT_EQ(SocketStreamEvent::EVENT_START_OPEN_CONNECTION,
- events[0].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CONNECTED, events[1].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_SENT_DATA, events[2].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_RECEIVED_DATA, events[3].event_type);
- EXPECT_EQ(SocketStreamEvent::EVENT_CLOSE, events[4].event_type);
-}
-
-} // namespace net
diff --git a/net/spdy/buffered_spdy_framer.cc b/net/spdy/buffered_spdy_framer.cc
index fdc65a9..f3fc575 100644
--- a/net/spdy/buffered_spdy_framer.cc
+++ b/net/spdy/buffered_spdy_framer.cc
@@ -15,7 +15,8 @@
case kProtoSPDY3:
case kProtoSPDY31:
return SPDY3;
- case kProtoSPDY4:
+ case kProtoSPDY4_14:
+ case kProtoSPDY4_15:
return SPDY4;
case kProtoUnknown:
case kProtoHTTP11:
@@ -76,6 +77,8 @@
}
void BufferedSpdyFramer::OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
bool end) {
frames_received_++;
@@ -83,6 +86,10 @@
control_frame_fields_.reset(new ControlFrameFields());
control_frame_fields_->type = HEADERS;
control_frame_fields_->stream_id = stream_id;
+ control_frame_fields_->has_priority = has_priority;
+ if (control_frame_fields_->has_priority) {
+ control_frame_fields_->priority = priority;
+ }
control_frame_fields_->fin = fin;
InitHeaderStreaming(stream_id);
@@ -136,6 +143,8 @@
break;
case HEADERS:
visitor_->OnHeaders(control_frame_fields_->stream_id,
+ control_frame_fields_->has_priority,
+ control_frame_fields_->priority,
control_frame_fields_->fin,
headers);
break;
@@ -346,9 +355,14 @@
SpdyFrame* BufferedSpdyFramer::CreateHeaders(
SpdyStreamId stream_id,
SpdyControlFlags flags,
+ SpdyPriority priority,
const SpdyHeaderBlock* headers) {
SpdyHeadersIR headers_ir(stream_id);
headers_ir.set_fin((flags & CONTROL_FLAG_FIN) != 0);
+ if (flags & HEADERS_FLAG_PRIORITY) {
+ headers_ir.set_has_priority(true);
+ headers_ir.set_priority(priority);
+ }
headers_ir.set_name_value_block(*headers);
return spdy_framer_.SerializeHeaders(headers_ir);
}
diff --git a/net/spdy/buffered_spdy_framer.h b/net/spdy/buffered_spdy_framer.h
index 02fa583..1227a42 100644
--- a/net/spdy/buffered_spdy_framer.h
+++ b/net/spdy/buffered_spdy_framer.h
@@ -49,6 +49,8 @@
// Called after all the header data for HEADERS control frame is received.
virtual void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
const SpdyHeaderBlock& headers) = 0;
@@ -142,7 +144,11 @@
bool fin,
bool unidirectional) override;
void OnSynReply(SpdyStreamId stream_id, bool fin) override;
- void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override;
+ void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
+ bool fin,
+ bool end) override;
bool OnControlFrameHeaderData(SpdyStreamId stream_id,
const char* header_data,
size_t len) override;
@@ -194,6 +200,7 @@
SpdyGoAwayStatus status) const;
SpdyFrame* CreateHeaders(SpdyStreamId stream_id,
SpdyControlFlags flags,
+ SpdyPriority priority,
const SpdyHeaderBlock* headers);
SpdyFrame* CreateWindowUpdate(
SpdyStreamId stream_id,
@@ -262,6 +269,7 @@
SpdyStreamId stream_id;
SpdyStreamId associated_stream_id;
SpdyStreamId promised_stream_id;
+ bool has_priority;
SpdyPriority priority;
uint8 credential_slot;
bool fin;
diff --git a/net/spdy/buffered_spdy_framer_unittest.cc b/net/spdy/buffered_spdy_framer_unittest.cc
index 6be20dd..11f8d08 100644
--- a/net/spdy/buffered_spdy_framer_unittest.cc
+++ b/net/spdy/buffered_spdy_framer_unittest.cc
@@ -59,6 +59,8 @@
}
void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
const SpdyHeaderBlock& headers) override {
header_stream_id_ = stream_id;
@@ -207,7 +209,7 @@
NextProto,
BufferedSpdyFramerTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
TEST_P(BufferedSpdyFramerTest, OnSetting) {
SpdyFramer framer(spdy_version());
@@ -293,6 +295,7 @@
scoped_ptr<SpdyFrame> control_frame(
framer.CreateHeaders(1, // stream_id
CONTROL_FLAG_NONE,
+ 0, // priority
&headers));
EXPECT_TRUE(control_frame.get() != NULL);
diff --git a/net/spdy/mock_spdy_framer_visitor.h b/net/spdy/mock_spdy_framer_visitor.h
index b8467ba..480c367 100644
--- a/net/spdy/mock_spdy_framer_visitor.h
+++ b/net/spdy/mock_spdy_framer_visitor.h
@@ -42,7 +42,8 @@
MOCK_METHOD0(OnSettingsEnd, void());
MOCK_METHOD2(OnGoAway, void(SpdyStreamId last_accepted_stream_id,
SpdyGoAwayStatus status));
- MOCK_METHOD3(OnHeaders, void(SpdyStreamId stream_id, bool fin, bool end));
+ MOCK_METHOD5(OnHeaders, void(SpdyStreamId stream_id, bool has_priority,
+ SpdyPriority priority, bool fin, bool end));
MOCK_METHOD2(OnWindowUpdate, void(SpdyStreamId stream_id,
uint32 delta_window_size));
MOCK_METHOD1(OnBlocked, void(SpdyStreamId stream_id));
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index de7a7a3..c08b597 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -480,6 +480,10 @@
return "CONNECT_ERROR";
case RST_STREAM_ENHANCE_YOUR_CALM:
return "ENHANCE_YOUR_CALM";
+ case RST_STREAM_INADEQUATE_SECURITY:
+ return "INADEQUATE_SECURITY";
+ case RST_STREAM_HTTP_1_1_REQUIRED:
+ return "HTTP_1_1_REQUIRED";
}
return "UNKNOWN_STATUS";
}
@@ -1497,33 +1501,19 @@
}
DCHECK(reader.IsDoneReading());
if (debug_visitor_) {
- // SPDY 4 reports HEADERS with PRIORITY as SYN_STREAM.
- SpdyFrameType reported_type = current_frame_type_;
- if (protocol_version() > SPDY3 && has_priority) {
- reported_type = SYN_STREAM;
- }
debug_visitor_->OnReceiveCompressedFrame(
current_frame_stream_id_,
- reported_type,
+ current_frame_type_,
current_frame_length_);
}
if (current_frame_type_ == SYN_REPLY) {
visitor_->OnSynReply(
current_frame_stream_id_,
(current_frame_flags_ & CONTROL_FLAG_FIN) != 0);
- } else if (protocol_version() > SPDY3 &&
- current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
- // SPDY 4+ is missing SYN_STREAM. Simulate it so that API changes
- // can be made independent of wire changes.
- visitor_->OnSynStream(
- current_frame_stream_id_,
- 0, // associated_to_stream_id
- priority,
- current_frame_flags_ & CONTROL_FLAG_FIN,
- false); // unidirectional
} else {
visitor_->OnHeaders(
current_frame_stream_id_,
+ (current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0, priority,
(current_frame_flags_ & CONTROL_FLAG_FIN) != 0,
expect_continuation_ == 0);
}
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 29cab72..dcb2911 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -37,8 +37,6 @@
class SpdyProxyClientSocketTest;
class SpdySessionTest;
class SpdyStreamTest;
-class SpdyWebSocketStreamTest;
-class WebSocketJobTest;
class SpdyFramer;
class SpdyFrameBuilder;
@@ -237,7 +235,11 @@
// Called when a HEADERS frame is received.
// Note that header block data is not included. See
// OnControlFrameHeaderData().
- virtual void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) = 0;
+ virtual void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
+ bool fin,
+ bool end) = 0;
// Called when a WINDOW_UPDATE frame has been parsed.
virtual void OnWindowUpdate(SpdyStreamId stream_id,
@@ -612,16 +614,14 @@
TooLargeHeadersFrameUsesContinuation);
FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
TooLargePushPromiseFrameUsesContinuation);
- friend class net::HttpNetworkLayer; // This is temporary for the server.
- friend class net::HttpNetworkTransactionTest;
- friend class net::HttpProxyClientSocketPoolTest;
- friend class net::SpdyHttpStreamTest;
- friend class net::SpdyNetworkTransactionTest;
- friend class net::SpdyProxyClientSocketTest;
- friend class net::SpdySessionTest;
- friend class net::SpdyStreamTest;
- friend class net::SpdyWebSocketStreamTest;
- friend class net::WebSocketJobTest;
+ friend class HttpNetworkLayer; // This is temporary for the server.
+ friend class HttpNetworkTransactionTest;
+ friend class HttpProxyClientSocketPoolTest;
+ friend class SpdyHttpStreamTest;
+ friend class SpdyNetworkTransactionTest;
+ friend class SpdyProxyClientSocketTest;
+ friend class SpdySessionTest;
+ friend class SpdyStreamTest;
friend class test::TestSpdyVisitor;
private:
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 7a1c3df..2b7bc4b 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -154,10 +154,15 @@
LOG(FATAL);
}
- void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override {
+ void OnHeaders(SpdyStreamId stream_id, bool has_priority,
+ SpdyPriority priority, bool fin, bool end) override {
SpdyFramer framer(version_);
framer.set_enable_compression(false);
SpdyHeadersIR headers(stream_id);
+ headers.set_has_priority(has_priority);
+ if (headers.has_priority()) {
+ headers.set_priority(priority);
+ }
headers.set_fin(fin);
scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers));
ResetBuffer();
@@ -389,7 +394,8 @@
++goaway_count_;
}
- void OnHeaders(SpdyStreamId stream_id, bool fin, bool end) override {
+ void OnHeaders(SpdyStreamId stream_id, bool has_priority,
+ SpdyPriority priority, bool fin, bool end) override {
++headers_frame_count_;
InitHeaderStreaming(HEADERS, stream_id);
if (fin) {
@@ -1225,18 +1231,19 @@
visitor.SimulateInFramer(kV4Input, sizeof(kV4Input));
}
- EXPECT_EQ(2, visitor.syn_frame_count_);
EXPECT_EQ(0, visitor.syn_reply_frame_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
EXPECT_EQ(24, visitor.data_bytes_);
-
EXPECT_EQ(0, visitor.error_count_);
EXPECT_EQ(2, visitor.fin_frame_count_);
if (IsSpdy4()) {
+ EXPECT_EQ(3, visitor.headers_frame_count_);
+ EXPECT_EQ(0, visitor.syn_frame_count_);
base::StringPiece reset_stream = "RESETSTREAM";
EXPECT_EQ(reset_stream, visitor.fin_opaque_data_);
} else {
+ EXPECT_EQ(1, visitor.headers_frame_count_);
+ EXPECT_EQ(2, visitor.syn_frame_count_);
EXPECT_TRUE(visitor.fin_opaque_data_.empty());
}
@@ -1339,11 +1346,12 @@
}
EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.syn_frame_count_);
if (IsSpdy4()) {
+ EXPECT_EQ(0, visitor.syn_frame_count_);
EXPECT_EQ(0, visitor.syn_reply_frame_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
+ EXPECT_EQ(2, visitor.headers_frame_count_);
} else {
+ EXPECT_EQ(1, visitor.syn_frame_count_);
EXPECT_EQ(1, visitor.syn_reply_frame_count_);
EXPECT_EQ(0, visitor.headers_frame_count_);
}
@@ -1418,11 +1426,12 @@
}
EXPECT_EQ(0, visitor.error_count_);
- EXPECT_EQ(1, visitor.syn_frame_count_);
if (IsSpdy4()) {
+ EXPECT_EQ(0, visitor.syn_frame_count_);
EXPECT_EQ(0, visitor.syn_reply_frame_count_);
- EXPECT_EQ(1, visitor.headers_frame_count_);
+ EXPECT_EQ(2, visitor.headers_frame_count_);
} else {
+ EXPECT_EQ(1, visitor.syn_frame_count_);
EXPECT_EQ(1, visitor.syn_reply_frame_count_);
EXPECT_EQ(0, visitor.headers_frame_count_);
}
@@ -5210,13 +5219,14 @@
EXPECT_CALL(visitor, OnError(_));
} else {
if (spdy_version_ > SPDY3 && flags & HEADERS_FLAG_PRIORITY) {
- EXPECT_CALL(visitor, OnSynStream(57, // stream id
- 0, // associated stream id
- 3, // priority
- flags & CONTROL_FLAG_FIN,
- false)); // unidirectional
+ EXPECT_CALL(visitor, OnHeaders(57, // stream id
+ true, // has priority?
+ 3, // priority
+ flags & CONTROL_FLAG_FIN, // fin?
+ (flags & HEADERS_FLAG_END_HEADERS) ||
+ !IsSpdy4())); // end headers?
} else {
- EXPECT_CALL(visitor, OnHeaders(57,
+ EXPECT_CALL(visitor, OnHeaders(57, false, 0,
flags & CONTROL_FLAG_FIN,
(flags & HEADERS_FLAG_END_HEADERS) ||
!IsSpdy4()));
@@ -5391,7 +5401,7 @@
EXPECT_CALL(debug_visitor, OnSendCompressedFrame(42, HEADERS, _, _));
EXPECT_CALL(debug_visitor, OnReceiveCompressedFrame(42, HEADERS, _));
- EXPECT_CALL(visitor, OnHeaders(42, 0, false));
+ EXPECT_CALL(visitor, OnHeaders(42, false, 0, 0, false));
EXPECT_CALL(visitor, OnControlFrameHeaderData(42, _, _))
.WillRepeatedly(testing::Return(true));
diff --git a/net/spdy/spdy_headers_block_parser_test.cc b/net/spdy/spdy_headers_block_parser_test.cc
index d8cbe31..dc2cbb5 100644
--- a/net/spdy/spdy_headers_block_parser_test.cc
+++ b/net/spdy/spdy_headers_block_parser_test.cc
@@ -17,8 +17,6 @@
using base::IntToString;
using base::StringPiece;
using std::string;
-using testing::ElementsAre;
-using testing::ElementsAreArray;
// A mock the handler class to check that we parse out the correct headers
// and call the callback methods when we should.
diff --git a/net/spdy/spdy_http_stream_unittest.cc b/net/spdy/spdy_http_stream_unittest.cc
index 0e8fdb0..574b76a 100644
--- a/net/spdy/spdy_http_stream_unittest.cc
+++ b/net/spdy/spdy_http_stream_unittest.cc
@@ -131,7 +131,7 @@
NextProto,
SpdyHttpStreamTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
// SpdyHttpStream::GetUploadProgress() should still work even before the
// stream is initialized.
diff --git a/net/spdy/spdy_network_transaction_unittest.cc b/net/spdy/spdy_network_transaction_unittest.cc
index a68615f..edb39e9 100644
--- a/net/spdy/spdy_network_transaction_unittest.cc
+++ b/net/spdy/spdy_network_transaction_unittest.cc
@@ -726,9 +726,12 @@
SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNOSSL),
SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYSSL),
SpdyNetworkTransactionTestParams(kProtoSPDY31, SPDYNPN),
- SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNOSSL),
- SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYSSL),
- SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNOSSL),
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYSSL),
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNPN),
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNOSSL),
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYSSL),
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNPN)));
// Verify HttpNetworkTransaction constructor.
TEST_P(SpdyNetworkTransactionTest, Constructor) {
@@ -3576,7 +3579,7 @@
}
TEST_P(SpdyNetworkTransactionTest, GoAwayOnDecompressionFailure) {
- if (GetParam().protocol < kProtoSPDY4) {
+ if (GetParam().protocol < kProtoSPDY4MinimumVersion) {
// Decompression failures are a stream error in SPDY3 and above.
return;
}
@@ -4433,7 +4436,8 @@
spdy_util_.ConstructSpdyGet(NULL, 0, false, 1, LOWEST, true));
std::vector<MockWrite> writes;
- if (GetParam().protocol == kProtoSPDY4) {
+ if ((GetParam().protocol >= kProtoSPDY4MinimumVersion) &&
+ (GetParam().protocol <= kProtoSPDY4MaximumVersion)) {
writes.push_back(
MockWrite(ASYNC,
kHttp2ConnectionHeaderPrefix,
@@ -6599,7 +6603,9 @@
INSTANTIATE_TEST_CASE_P(
Spdy,
SpdyNetworkTransactionTLSUsageCheckTest,
- ::testing::Values(SpdyNetworkTransactionTestParams(kProtoSPDY4, SPDYNPN)));
+ ::testing::Values(
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_14, SPDYNPN),
+ SpdyNetworkTransactionTestParams(kProtoSPDY4_15, SPDYNPN)));
TEST_P(SpdyNetworkTransactionTLSUsageCheckTest, TLSVersionTooOld) {
scoped_ptr<SSLSocketDataProvider> ssl_provider(
diff --git a/net/spdy/spdy_protocol.cc b/net/spdy/spdy_protocol.cc
index d300a15..bf33d43 100644
--- a/net/spdy/spdy_protocol.cc
+++ b/net/spdy/spdy_protocol.cc
@@ -372,9 +372,9 @@
}
*/
- // ENHANCE_YOUR_CALM is the last valid status code.
+ // HTTP_1_1_REQUIRED is the last valid status code.
if (rst_stream_status_field >
- SerializeRstStreamStatus(version, RST_STREAM_ENHANCE_YOUR_CALM)) {
+ SerializeRstStreamStatus(version, RST_STREAM_HTTP_1_1_REQUIRED)) {
return false;
}
@@ -436,6 +436,10 @@
return RST_STREAM_CONNECT_ERROR;
case 11:
return RST_STREAM_ENHANCE_YOUR_CALM;
+ case 12:
+ return RST_STREAM_INADEQUATE_SECURITY;
+ case 13:
+ return RST_STREAM_HTTP_1_1_REQUIRED;
}
break;
}
@@ -499,6 +503,10 @@
return 10;
case RST_STREAM_ENHANCE_YOUR_CALM:
return 11;
+ case RST_STREAM_INADEQUATE_SECURITY:
+ return 12;
+ case RST_STREAM_HTTP_1_1_REQUIRED:
+ return 13;
default:
LOG(DFATAL) << "Unhandled RST_STREAM status "
<< rst_stream_status;
@@ -589,6 +597,8 @@
return GOAWAY_ENHANCE_YOUR_CALM;
case 12:
return GOAWAY_INADEQUATE_SECURITY;
+ case 13:
+ return GOAWAY_HTTP_1_1_REQUIRED;
}
break;
}
@@ -666,6 +676,7 @@
case GOAWAY_CONNECT_ERROR:
case GOAWAY_ENHANCE_YOUR_CALM:
case GOAWAY_INADEQUATE_SECURITY:
+ case GOAWAY_HTTP_1_1_REQUIRED:
return 1; // PROTOCOL_ERROR.
default:
LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
@@ -700,6 +711,8 @@
return 11;
case GOAWAY_INADEQUATE_SECURITY:
return 12;
+ case GOAWAY_HTTP_1_1_REQUIRED:
+ return 13;
default:
LOG(DFATAL) << "Serializing unhandled GOAWAY status " << status;
return -1;
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index b3f71d4..b02c44f 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -397,7 +397,9 @@
RST_STREAM_SETTINGS_TIMEOUT = 12,
RST_STREAM_CONNECT_ERROR = 13,
RST_STREAM_ENHANCE_YOUR_CALM = 14,
- RST_STREAM_NUM_STATUS_CODES = 15
+ RST_STREAM_INADEQUATE_SECURITY = 15,
+ RST_STREAM_HTTP_1_1_REQUIRED = 16,
+ RST_STREAM_NUM_STATUS_CODES = 17
};
// Status codes for GOAWAY frames.
@@ -415,7 +417,8 @@
GOAWAY_COMPRESSION_ERROR = 9,
GOAWAY_CONNECT_ERROR = 10,
GOAWAY_ENHANCE_YOUR_CALM = 11,
- GOAWAY_INADEQUATE_SECURITY = 12
+ GOAWAY_INADEQUATE_SECURITY = 12,
+ GOAWAY_HTTP_1_1_REQUIRED = 13
};
// A SPDY priority is a number between 0 and 7 (inclusive).
diff --git a/net/spdy/spdy_proxy_client_socket_unittest.cc b/net/spdy/spdy_proxy_client_socket_unittest.cc
index 92e446e..ba5d867 100644
--- a/net/spdy/spdy_proxy_client_socket_unittest.cc
+++ b/net/spdy/spdy_proxy_client_socket_unittest.cc
@@ -143,7 +143,7 @@
NextProto,
SpdyProxyClientSocketTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
SpdyProxyClientSocketTest::SpdyProxyClientSocketTest()
: spdy_util_(GetParam()),
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index d9a5108..08d838a 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -398,6 +398,10 @@
return STATUS_CODE_CONNECT_ERROR;
case RST_STREAM_ENHANCE_YOUR_CALM:
return STATUS_CODE_ENHANCE_YOUR_CALM;
+ case RST_STREAM_INADEQUATE_SECURITY:
+ return STATUS_CODE_INADEQUATE_SECURITY;
+ case RST_STREAM_HTTP_1_1_REQUIRED:
+ return STATUS_CODE_HTTP_1_1_REQUIRED;
default:
NOTREACHED();
return static_cast<SpdyProtocolErrorDetails>(-1);
@@ -721,7 +725,8 @@
DCHECK_GE(protocol_, kProtoSPDYMinimumVersion);
DCHECK_LE(protocol_, kProtoSPDYMaximumVersion);
- if (protocol_ == kProtoSPDY4)
+ if ((protocol_ >= kProtoSPDY4MinimumVersion) &&
+ (protocol_ <= kProtoSPDY4MaximumVersion))
send_connection_header_prefix_ = true;
if (protocol_ >= kProtoSPDY31) {
@@ -741,7 +746,7 @@
buffered_spdy_framer_->set_debug_visitor(this);
UMA_HISTOGRAM_ENUMERATION(
"Net.SpdyVersion2",
- protocol_ - kProtoSPDYMinimumVersion,
+ protocol_ - kProtoSPDYHistogramOffset,
kProtoSPDYMaximumVersion - kProtoSPDYMinimumVersion + 1);
net_log_.AddEvent(NetLog::TYPE_SPDY_SESSION_INITIALIZED,
@@ -2205,11 +2210,7 @@
const SpdyHeaderBlock& headers) {
CHECK(in_io_loop_);
- if (GetProtocolVersion() >= SPDY4) {
- DCHECK_EQ(0u, associated_stream_id);
- OnHeaders(stream_id, fin, headers);
- return;
- }
+ DCHECK_LE(GetProtocolVersion(), SPDY3);
base::Time response_time = base::Time::Now();
base::TimeTicks recv_first_byte_time = time_func_();
@@ -2332,6 +2333,8 @@
}
void SpdySession::OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
const SpdyHeaderBlock& headers) {
CHECK(in_io_loop_);
@@ -2459,8 +2462,8 @@
base::Bind(&NetLogSpdyPingCallback, unique_id, is_ack, "received"));
// Send response to a PING from server.
- if ((protocol_ >= kProtoSPDY4 && !is_ack) ||
- (protocol_ < kProtoSPDY4 && unique_id % 2 == 0)) {
+ if ((protocol_ >= kProtoSPDY4MinimumVersion && !is_ack) ||
+ (protocol_ < kProtoSPDY4MinimumVersion && unique_id % 2 == 0)) {
WritePingFrame(unique_id, true);
return;
}
@@ -2746,7 +2749,8 @@
DCHECK(enable_sending_initial_data_);
if (send_connection_header_prefix_) {
- DCHECK_EQ(protocol_, kProtoSPDY4);
+ DCHECK_GE(protocol_, kProtoSPDY4MinimumVersion);
+ DCHECK_LE(protocol_, kProtoSPDY4MaximumVersion);
scoped_ptr<SpdyFrame> connection_header_prefix_frame(
new SpdyFrame(const_cast<char*>(kHttp2ConnectionHeaderPrefix),
kHttp2ConnectionHeaderPrefixSize,
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index ef2d8fe..862918b 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -105,6 +105,8 @@
STATUS_CODE_SETTINGS_TIMEOUT = 32,
STATUS_CODE_CONNECT_ERROR = 33,
STATUS_CODE_ENHANCE_YOUR_CALM = 34,
+ STATUS_CODE_INADEQUATE_SECURITY = 35,
+ STATUS_CODE_HTTP_1_1_REQUIRED = 36,
// SpdySession errors
PROTOCOL_ERROR_UNEXPECTED_PING = 22,
@@ -116,7 +118,7 @@
PROTOCOL_ERROR_RECEIVE_WINDOW_VIOLATION = 28,
// Next free value.
- NUM_SPDY_PROTOCOL_ERROR_DETAILS = 35,
+ NUM_SPDY_PROTOCOL_ERROR_DETAILS = 37,
};
SpdyProtocolErrorDetails NET_EXPORT_PRIVATE
MapFramerErrorToProtocolError(SpdyFramer::SpdyError error);
@@ -129,7 +131,7 @@
// to be updated with new values, as do the mapping functions above.
COMPILE_ASSERT(12 == SpdyFramer::LAST_ERROR,
SpdyProtocolErrorDetails_SpdyErrors_mismatch);
-COMPILE_ASSERT(15 == RST_STREAM_NUM_STATUS_CODES,
+COMPILE_ASSERT(17 == RST_STREAM_NUM_STATUS_CODES,
SpdyProtocolErrorDetails_RstStreamStatus_mismatch);
// Splits pushed |headers| into request and response parts. Request headers are
@@ -844,6 +846,8 @@
bool fin,
const SpdyHeaderBlock& headers) override;
void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
const SpdyHeaderBlock& headers) override;
bool OnUnknownFrame(SpdyStreamId stream_id, int frame_type) override;
diff --git a/net/spdy/spdy_session_pool_unittest.cc b/net/spdy/spdy_session_pool_unittest.cc
index fef27bf..fc38cc2 100644
--- a/net/spdy/spdy_session_pool_unittest.cc
+++ b/net/spdy/spdy_session_pool_unittest.cc
@@ -52,7 +52,7 @@
NextProto,
SpdySessionPoolTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
// A delegate that opens a new session when it is closed.
class SessionOpeningDelegate : public SpdyStream::Delegate {
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index c6447bf..02e0c74 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -182,7 +182,7 @@
NextProto,
SpdySessionTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
// Try to create a SPDY session that will fail during
// initialization. Nothing should blow up.
@@ -1556,7 +1556,8 @@
kSessionFlowControlStreamId,
kDefaultInitialRecvWindowSize - kSpdySessionInitialWindowSize));
std::vector<MockWrite> writes;
- if (GetParam() == kProtoSPDY4) {
+ if ((GetParam() >= kProtoSPDY4MinimumVersion) &&
+ (GetParam() <= kProtoSPDY4MaximumVersion)) {
writes.push_back(
MockWrite(ASYNC,
kHttp2ConnectionHeaderPrefix,
@@ -5019,6 +5020,10 @@
MapRstStreamStatusToProtocolError(RST_STREAM_FRAME_SIZE_ERROR));
CHECK_EQ(STATUS_CODE_ENHANCE_YOUR_CALM,
MapRstStreamStatusToProtocolError(RST_STREAM_ENHANCE_YOUR_CALM));
+ CHECK_EQ(STATUS_CODE_INADEQUATE_SECURITY,
+ MapRstStreamStatusToProtocolError(RST_STREAM_INADEQUATE_SECURITY));
+ CHECK_EQ(STATUS_CODE_HTTP_1_1_REQUIRED,
+ MapRstStreamStatusToProtocolError(RST_STREAM_HTTP_1_1_REQUIRED));
}
TEST(MapNetErrorToGoAwayStatus, MapsValue) {
diff --git a/net/spdy/spdy_stream_unittest.cc b/net/spdy/spdy_stream_unittest.cc
index a6926ab..96153bf 100644
--- a/net/spdy/spdy_stream_unittest.cc
+++ b/net/spdy/spdy_stream_unittest.cc
@@ -111,7 +111,7 @@
NextProto,
SpdyStreamTest,
testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
+ kProtoSPDY3, kProtoSPDY31, kProtoSPDY4_14, kProtoSPDY4_15));
TEST_P(SpdyStreamTest, SendDataAfterOpen) {
GURL url(kStreamUrl);
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index baa3548..801d67d 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -57,7 +57,8 @@
next_protos.push_back(kProtoDeprecatedSPDY2);
next_protos.push_back(kProtoSPDY3);
next_protos.push_back(kProtoSPDY31);
- next_protos.push_back(kProtoSPDY4);
+ next_protos.push_back(kProtoSPDY4_14);
+ next_protos.push_back(kProtoSPDY4_15);
next_protos.push_back(kProtoQUIC1SPDY3);
return next_protos;
}
@@ -229,8 +230,14 @@
bool fin,
const SpdyHeaderBlock& headers) override {}
void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
- const SpdyHeaderBlock& headers) override {}
+ const SpdyHeaderBlock& headers) override {
+ if (has_priority) {
+ priority_ = priority;
+ }
+ }
void OnDataFrameHeader(SpdyStreamId stream_id,
size_t length,
bool fin) override {}
@@ -367,7 +374,6 @@
force_spdy_over_ssl(false),
force_spdy_always(false),
use_alternate_protocols(false),
- enable_websocket_over_spdy(false),
net_log(NULL) {
DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
@@ -401,7 +407,6 @@
force_spdy_over_ssl(false),
force_spdy_always(false),
use_alternate_protocols(false),
- enable_websocket_over_spdy(false),
net_log(NULL) {
DCHECK(next_proto_is_spdy(protocol)) << "Invalid protocol: " << protocol;
}
@@ -461,7 +466,6 @@
params.force_spdy_over_ssl = session_deps->force_spdy_over_ssl;
params.force_spdy_always = session_deps->force_spdy_always;
params.use_alternate_protocols = session_deps->use_alternate_protocols;
- params.enable_websocket_over_spdy = session_deps->enable_websocket_over_spdy;
params.net_log = session_deps->net_log;
return params;
}
@@ -786,6 +790,7 @@
break;
case HEADERS:
frame = framer.CreateHeaders(header_info.id, header_info.control_flags,
+ header_info.priority,
headers.get());
break;
default:
@@ -1103,7 +1108,7 @@
RequestPriority priority,
bool compressed,
bool fin) const {
- if (protocol_ < kProtoSPDY4) {
+ if (protocol_ < kProtoSPDY4MinimumVersion) {
SpdySynStreamIR syn_stream(stream_id);
syn_stream.set_name_value_block(block);
syn_stream.set_priority(
@@ -1123,7 +1128,7 @@
SpdyFrame* SpdyTestUtil::ConstructSpdyReply(int stream_id,
const SpdyHeaderBlock& headers) {
- if (protocol_ < kProtoSPDY4) {
+ if (protocol_ < kProtoSPDY4MinimumVersion) {
SpdySynReplyIR syn_reply(stream_id);
syn_reply.set_name_value_block(headers);
return CreateFramer(false)->SerializeFrame(syn_reply);
@@ -1264,7 +1269,7 @@
const char* SpdyTestUtil::GetHostKey() const {
if (protocol_ < kProtoSPDY3)
return "host";
- if (protocol_ < kProtoSPDY4)
+ if (protocol_ < kProtoSPDY4MinimumVersion)
return ":host";
else
return ":authority";
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index e91800d..b08657c 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -222,7 +222,6 @@
bool force_spdy_over_ssl;
bool force_spdy_always;
bool use_alternate_protocols;
- bool enable_websocket_over_spdy;
NetLog* net_log;
};
@@ -553,7 +552,9 @@
NextProto protocol() const { return protocol_; }
SpdyMajorVersion spdy_version() const { return spdy_version_; }
bool is_spdy2() const { return protocol_ < kProtoSPDY3; }
- bool include_version_header() const { return protocol_ < kProtoSPDY4; }
+ bool include_version_header() const {
+ return protocol_ < kProtoSPDY4MinimumVersion;
+ }
scoped_ptr<SpdyFramer> CreateFramer(bool compressed) const;
const char* GetMethodKey() const;
diff --git a/net/spdy/spdy_websocket_stream.cc b/net/spdy/spdy_websocket_stream.cc
deleted file mode 100644
index 54e668c..0000000
--- a/net/spdy/spdy_websocket_stream.cc
+++ /dev/null
@@ -1,130 +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/spdy/spdy_websocket_stream.h"
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/compiler_specific.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_stream.h"
-#include "url/gurl.h"
-
-namespace net {
-
-SpdyWebSocketStream::SpdyWebSocketStream(
- const base::WeakPtr<SpdySession>& spdy_session, Delegate* delegate)
- : spdy_session_(spdy_session),
- pending_send_data_length_(0),
- delegate_(delegate),
- weak_ptr_factory_(this) {
- DCHECK(spdy_session_.get());
- DCHECK(delegate_);
-}
-
-SpdyWebSocketStream::~SpdyWebSocketStream() {
- delegate_ = NULL;
- Close();
-}
-
-int SpdyWebSocketStream::InitializeStream(const GURL& url,
- RequestPriority request_priority,
- const BoundNetLog& net_log) {
- if (!spdy_session_)
- return ERR_SOCKET_NOT_CONNECTED;
-
- int rv = stream_request_.StartRequest(
- SPDY_BIDIRECTIONAL_STREAM, spdy_session_, url, request_priority, net_log,
- base::Bind(&SpdyWebSocketStream::OnSpdyStreamCreated,
- weak_ptr_factory_.GetWeakPtr()));
-
- if (rv == OK) {
- stream_ = stream_request_.ReleaseStream();
- DCHECK(stream_.get());
- stream_->SetDelegate(this);
- }
- return rv;
-}
-
-int SpdyWebSocketStream::SendRequest(scoped_ptr<SpdyHeaderBlock> headers) {
- if (!stream_.get()) {
- NOTREACHED();
- return ERR_UNEXPECTED;
- }
- int result = stream_->SendRequestHeaders(headers.Pass(), MORE_DATA_TO_SEND);
- if (result < OK && result != ERR_IO_PENDING)
- Close();
- return result;
-}
-
-int SpdyWebSocketStream::SendData(const char* data, int length) {
- if (!stream_.get()) {
- NOTREACHED();
- return ERR_UNEXPECTED;
- }
- DCHECK_GE(length, 0);
- pending_send_data_length_ = static_cast<size_t>(length);
- scoped_refptr<IOBuffer> buf(new IOBuffer(length));
- memcpy(buf->data(), data, length);
- stream_->SendData(buf.get(), length, MORE_DATA_TO_SEND);
- return ERR_IO_PENDING;
-}
-
-void SpdyWebSocketStream::Close() {
- if (stream_.get()) {
- stream_->Close();
- DCHECK(!stream_.get());
- }
-}
-
-void SpdyWebSocketStream::OnRequestHeadersSent() {
- DCHECK(delegate_);
- delegate_->OnSentSpdyHeaders();
-}
-
-SpdyResponseHeadersStatus SpdyWebSocketStream::OnResponseHeadersUpdated(
- const SpdyHeaderBlock& response_headers) {
- DCHECK(delegate_);
- delegate_->OnSpdyResponseHeadersUpdated(response_headers);
- return RESPONSE_HEADERS_ARE_COMPLETE;
-}
-
-void SpdyWebSocketStream::OnDataReceived(scoped_ptr<SpdyBuffer> buffer) {
- DCHECK(delegate_);
- delegate_->OnReceivedSpdyData(buffer.Pass());
-}
-
-void SpdyWebSocketStream::OnDataSent() {
- DCHECK(delegate_);
- delegate_->OnSentSpdyData(pending_send_data_length_);
- pending_send_data_length_ = 0;
-}
-
-void SpdyWebSocketStream::OnClose(int status) {
- stream_.reset();
-
- // Destruction without Close() call OnClose() with delegate_ being NULL.
- if (!delegate_)
- return;
- Delegate* delegate = delegate_;
- delegate_ = NULL;
- delegate->OnCloseSpdyStream();
-}
-
-void SpdyWebSocketStream::OnSpdyStreamCreated(int result) {
- DCHECK_NE(ERR_IO_PENDING, result);
- if (result == OK) {
- stream_ = stream_request_.ReleaseStream();
- DCHECK(stream_.get());
- stream_->SetDelegate(this);
- }
- DCHECK(delegate_);
- delegate_->OnCreatedSpdyStream(result);
-}
-
-} // namespace net
diff --git a/net/spdy/spdy_websocket_stream.h b/net/spdy/spdy_websocket_stream.h
deleted file mode 100644
index 854afbf..0000000
--- a/net/spdy/spdy_websocket_stream.h
+++ /dev/null
@@ -1,104 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_SPDY_SPDY_WEBSOCKET_STREAM_H_
-#define NET_SPDY_SPDY_WEBSOCKET_STREAM_H_
-
-#include "base/basictypes.h"
-#include "base/gtest_prod_util.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/memory/weak_ptr.h"
-#include "base/time/time.h"
-#include "net/base/completion_callback.h"
-#include "net/base/request_priority.h"
-#include "net/spdy/spdy_framer.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_stream.h"
-
-namespace net {
-
-// The SpdyWebSocketStream is a WebSocket-specific type of stream known to a
-// SpdySession. WebSocket's opening handshake is converted to SPDY's
-// SYN_STREAM/SYN_REPLY. WebSocket frames are encapsulated as SPDY data frames.
-class NET_EXPORT_PRIVATE SpdyWebSocketStream
- : public SpdyStream::Delegate {
- public:
- // Delegate handles asynchronous events.
- class NET_EXPORT_PRIVATE Delegate {
- public:
- // Called when InitializeStream() finishes asynchronously. This delegate is
- // called if InitializeStream() returns ERR_IO_PENDING. |status| indicates
- // network error.
- virtual void OnCreatedSpdyStream(int status) = 0;
-
- // Called on corresponding to OnSendHeadersComplete() or SPDY's SYN frame
- // has been sent.
- virtual void OnSentSpdyHeaders() = 0;
-
- // Called on corresponding to OnResponseHeadersUpdated() or
- // SPDY's SYN_STREAM, SYN_REPLY, or HEADERS frames are
- // received. This callback may be called multiple times as SPDY's
- // delegate does.
- virtual void OnSpdyResponseHeadersUpdated(
- const SpdyHeaderBlock& response_headers) = 0;
-
- // Called when data is sent.
- virtual void OnSentSpdyData(size_t bytes_sent) = 0;
-
- // Called when data is received.
- virtual void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) = 0;
-
- // Called when SpdyStream is closed.
- virtual void OnCloseSpdyStream() = 0;
-
- protected:
- virtual ~Delegate() {}
- };
-
- SpdyWebSocketStream(const base::WeakPtr<SpdySession>& spdy_session,
- Delegate* delegate);
- ~SpdyWebSocketStream() override;
-
- // Initializes SPDY stream for the WebSocket.
- // It might create SPDY stream asynchronously. In this case, this method
- // returns ERR_IO_PENDING and call OnCreatedSpdyStream delegate with result
- // after completion. In other cases, delegate does not be called.
- int InitializeStream(const GURL& url,
- RequestPriority request_priority,
- const BoundNetLog& stream_net_log);
-
- int SendRequest(scoped_ptr<SpdyHeaderBlock> headers);
- int SendData(const char* data, int length);
- void Close();
-
- // SpdyStream::Delegate
- void OnRequestHeadersSent() override;
- SpdyResponseHeadersStatus OnResponseHeadersUpdated(
- const SpdyHeaderBlock& response_headers) override;
- void OnDataReceived(scoped_ptr<SpdyBuffer> buffer) override;
- void OnDataSent() override;
- void OnClose(int status) override;
-
- private:
- friend class SpdyWebSocketStreamTest;
- FRIEND_TEST_ALL_PREFIXES(SpdyWebSocketStreamTest, Basic);
-
- void OnSpdyStreamCreated(int status);
-
- SpdyStreamRequest stream_request_;
- base::WeakPtr<SpdyStream> stream_;
- const base::WeakPtr<SpdySession> spdy_session_;
- size_t pending_send_data_length_;
- Delegate* delegate_;
-
- base::WeakPtrFactory<SpdyWebSocketStream> weak_ptr_factory_;
-
- DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStream);
-};
-
-} // namespace net
-
-#endif // NET_SPDY_SPDY_WEBSOCKET_STREAM_H_
diff --git a/net/spdy/spdy_websocket_stream_unittest.cc b/net/spdy/spdy_websocket_stream_unittest.cc
deleted file mode 100644
index fc54884..0000000
--- a/net/spdy/spdy_websocket_stream_unittest.cc
+++ /dev/null
@@ -1,669 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/spdy/spdy_websocket_stream.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "net/base/completion_callback.h"
-#include "net/proxy/proxy_server.h"
-#include "net/socket/next_proto.h"
-#include "net/socket/ssl_client_socket.h"
-#include "net/spdy/spdy_http_utils.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_websocket_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-struct SpdyWebSocketStreamEvent {
- enum EventType {
- EVENT_CREATED,
- EVENT_SENT_HEADERS,
- EVENT_RECEIVED_HEADER,
- EVENT_SENT_DATA,
- EVENT_RECEIVED_DATA,
- EVENT_CLOSE,
- };
- SpdyWebSocketStreamEvent(EventType type,
- const SpdyHeaderBlock& headers,
- int result,
- const std::string& data)
- : event_type(type),
- headers(headers),
- result(result),
- data(data) {}
-
- EventType event_type;
- SpdyHeaderBlock headers;
- int result;
- std::string data;
-};
-
-class SpdyWebSocketStreamEventRecorder : public SpdyWebSocketStream::Delegate {
- public:
- explicit SpdyWebSocketStreamEventRecorder(const CompletionCallback& callback)
- : callback_(callback) {}
- ~SpdyWebSocketStreamEventRecorder() override {}
-
- typedef base::Callback<void(SpdyWebSocketStreamEvent*)> StreamEventCallback;
-
- void SetOnCreated(const StreamEventCallback& callback) {
- on_created_ = callback;
- }
- void SetOnSentHeaders(const StreamEventCallback& callback) {
- on_sent_headers_ = callback;
- }
- void SetOnReceivedHeader(const StreamEventCallback& callback) {
- on_received_header_ = callback;
- }
- void SetOnSentData(const StreamEventCallback& callback) {
- on_sent_data_ = callback;
- }
- void SetOnReceivedData(const StreamEventCallback& callback) {
- on_received_data_ = callback;
- }
- void SetOnClose(const StreamEventCallback& callback) {
- on_close_ = callback;
- }
-
- void OnCreatedSpdyStream(int result) override {
- events_.push_back(
- SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_CREATED,
- SpdyHeaderBlock(),
- result,
- std::string()));
- if (!on_created_.is_null())
- on_created_.Run(&events_.back());
- }
- void OnSentSpdyHeaders() override {
- events_.push_back(
- SpdyWebSocketStreamEvent(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
- SpdyHeaderBlock(),
- OK,
- std::string()));
- if (!on_sent_data_.is_null())
- on_sent_data_.Run(&events_.back());
- }
- void OnSpdyResponseHeadersUpdated(
- const SpdyHeaderBlock& response_headers) override {
- events_.push_back(
- SpdyWebSocketStreamEvent(
- SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
- response_headers,
- OK,
- std::string()));
- if (!on_received_header_.is_null())
- on_received_header_.Run(&events_.back());
- }
- void OnSentSpdyData(size_t bytes_sent) override {
- events_.push_back(
- SpdyWebSocketStreamEvent(
- SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- SpdyHeaderBlock(),
- static_cast<int>(bytes_sent),
- std::string()));
- if (!on_sent_data_.is_null())
- on_sent_data_.Run(&events_.back());
- }
- void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) override {
- std::string buffer_data;
- size_t buffer_len = 0;
- if (buffer) {
- buffer_len = buffer->GetRemainingSize();
- buffer_data.append(buffer->GetRemainingData(), buffer_len);
- }
- events_.push_back(
- SpdyWebSocketStreamEvent(
- SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- SpdyHeaderBlock(),
- buffer_len,
- buffer_data));
- if (!on_received_data_.is_null())
- on_received_data_.Run(&events_.back());
- }
- void OnCloseSpdyStream() override {
- events_.push_back(
- SpdyWebSocketStreamEvent(
- SpdyWebSocketStreamEvent::EVENT_CLOSE,
- SpdyHeaderBlock(),
- OK,
- std::string()));
- if (!on_close_.is_null())
- on_close_.Run(&events_.back());
- if (!callback_.is_null())
- callback_.Run(OK);
- }
-
- const std::vector<SpdyWebSocketStreamEvent>& GetSeenEvents() const {
- return events_;
- }
-
- private:
- std::vector<SpdyWebSocketStreamEvent> events_;
- StreamEventCallback on_created_;
- StreamEventCallback on_sent_headers_;
- StreamEventCallback on_received_header_;
- StreamEventCallback on_sent_data_;
- StreamEventCallback on_received_data_;
- StreamEventCallback on_close_;
- CompletionCallback callback_;
-
- DISALLOW_COPY_AND_ASSIGN(SpdyWebSocketStreamEventRecorder);
-};
-
-} // namespace
-
-class SpdyWebSocketStreamTest
- : public ::testing::Test,
- public ::testing::WithParamInterface<NextProto> {
- public:
- OrderedSocketData* data() { return data_.get(); }
-
- void DoSendHelloFrame(SpdyWebSocketStreamEvent* event) {
- // Record the actual stream_id.
- created_stream_id_ = websocket_stream_->stream_->stream_id();
- websocket_stream_->SendData(kMessageFrame, kMessageFrameLength);
- }
-
- void DoSendClosingFrame(SpdyWebSocketStreamEvent* event) {
- websocket_stream_->SendData(kClosingFrame, kClosingFrameLength);
- }
-
- void DoClose(SpdyWebSocketStreamEvent* event) {
- websocket_stream_->Close();
- }
-
- void DoSync(SpdyWebSocketStreamEvent* event) {
- sync_callback_.callback().Run(OK);
- }
-
- protected:
- SpdyWebSocketStreamTest()
- : spdy_util_(GetParam()),
- spdy_settings_id_to_set_(SETTINGS_MAX_CONCURRENT_STREAMS),
- spdy_settings_flags_to_set_(SETTINGS_FLAG_PLEASE_PERSIST),
- spdy_settings_value_to_set_(1),
- session_deps_(GetParam()),
- stream_id_(0),
- created_stream_id_(0) {}
- virtual ~SpdyWebSocketStreamTest() {}
-
- void SetUp() override {
- host_port_pair_.set_host("example.com");
- host_port_pair_.set_port(80);
- spdy_session_key_ = SpdySessionKey(host_port_pair_,
- ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED);
-
- spdy_settings_to_send_[spdy_settings_id_to_set_] =
- SettingsFlagsAndValue(
- SETTINGS_FLAG_PERSISTED, spdy_settings_value_to_set_);
- }
-
- void TearDown() override { base::MessageLoop::current()->RunUntilIdle(); }
-
- void Prepare(SpdyStreamId stream_id) {
- stream_id_ = stream_id;
-
- request_frame_.reset(spdy_util_.ConstructSpdyWebSocketSynStream(
- stream_id_,
- "/echo",
- "example.com",
- "http://example.com/wsdemo"));
-
- response_frame_.reset(
- spdy_util_.ConstructSpdyWebSocketSynReply(stream_id_));
-
- message_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
- kMessageFrame,
- kMessageFrameLength,
- stream_id_,
- false));
-
- closing_frame_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
- kClosingFrame,
- kClosingFrameLength,
- stream_id_,
- false));
-
- closing_frame_fin_.reset(spdy_util_.ConstructSpdyWebSocketDataFrame(
- kClosingFrame,
- kClosingFrameLength,
- stream_id_,
- true));
- }
-
- void InitSession(MockRead* reads, size_t reads_count,
- MockWrite* writes, size_t writes_count) {
- data_.reset(new OrderedSocketData(reads, reads_count,
- writes, writes_count));
- session_deps_.socket_factory->AddSocketDataProvider(data_.get());
- http_session_ = SpdySessionDependencies::SpdyCreateSession(&session_deps_);
- session_ = CreateInsecureSpdySession(
- http_session_, spdy_session_key_, BoundNetLog());
- }
-
- void SendRequest() {
- scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
- spdy_util_.SetHeader("path", "/echo", headers.get());
- spdy_util_.SetHeader("host", "example.com", headers.get());
- spdy_util_.SetHeader("version", "WebSocket/13", headers.get());
- spdy_util_.SetHeader("scheme", "ws", headers.get());
- spdy_util_.SetHeader("origin", "http://example.com/wsdemo", headers.get());
- websocket_stream_->SendRequest(headers.Pass());
- }
-
- SpdyWebSocketTestUtil spdy_util_;
- SpdySettingsIds spdy_settings_id_to_set_;
- SpdySettingsFlags spdy_settings_flags_to_set_;
- uint32 spdy_settings_value_to_set_;
- SettingsMap spdy_settings_to_send_;
- SpdySessionDependencies session_deps_;
- scoped_ptr<OrderedSocketData> data_;
- scoped_refptr<HttpNetworkSession> http_session_;
- base::WeakPtr<SpdySession> session_;
- scoped_ptr<SpdyWebSocketStream> websocket_stream_;
- SpdyStreamId stream_id_;
- SpdyStreamId created_stream_id_;
- scoped_ptr<SpdyFrame> request_frame_;
- scoped_ptr<SpdyFrame> response_frame_;
- scoped_ptr<SpdyFrame> message_frame_;
- scoped_ptr<SpdyFrame> closing_frame_;
- scoped_ptr<SpdyFrame> closing_frame_fin_;
- HostPortPair host_port_pair_;
- SpdySessionKey spdy_session_key_;
- TestCompletionCallback completion_callback_;
- TestCompletionCallback sync_callback_;
-
- static const char kMessageFrame[];
- static const char kClosingFrame[];
- static const size_t kMessageFrameLength;
- static const size_t kClosingFrameLength;
-};
-
-INSTANTIATE_TEST_CASE_P(
- NextProto,
- SpdyWebSocketStreamTest,
- testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
-
-// TODO(toyoshim): Replace old framing data to new one, then use HEADERS and
-// data frames.
-const char SpdyWebSocketStreamTest::kMessageFrame[] = "\x81\x05hello";
-const char SpdyWebSocketStreamTest::kClosingFrame[] = "\x88\0";
-const size_t SpdyWebSocketStreamTest::kMessageFrameLength =
- arraysize(SpdyWebSocketStreamTest::kMessageFrame) - 1;
-const size_t SpdyWebSocketStreamTest::kClosingFrameLength =
- arraysize(SpdyWebSocketStreamTest::kClosingFrame) - 1;
-
-TEST_P(SpdyWebSocketStreamTest, Basic) {
- Prepare(1);
- MockWrite writes[] = {
- CreateMockWrite(*request_frame_.get(), 1),
- CreateMockWrite(*message_frame_.get(), 3),
- CreateMockWrite(*closing_frame_.get(), 5)
- };
-
- MockRead reads[] = {
- CreateMockRead(*response_frame_.get(), 2),
- CreateMockRead(*message_frame_.get(), 4),
- // Skip sequence 6 to notify closing has been sent.
- CreateMockRead(*closing_frame_.get(), 7),
- MockRead(SYNCHRONOUS, 0, 8) // EOF cause OnCloseSpdyStream event.
- };
-
- InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
- SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
- delegate.SetOnReceivedHeader(
- base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
- base::Unretained(this)));
- delegate.SetOnReceivedData(
- base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
- base::Unretained(this)));
-
- websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-
- BoundNetLog net_log;
- GURL url("ws://example.com/echo");
- ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
- ASSERT_TRUE(websocket_stream_->stream_.get());
-
- SendRequest();
-
- completion_callback_.WaitForResult();
-
- EXPECT_EQ(stream_id_, created_stream_id_);
-
- websocket_stream_.reset();
-
- const std::vector<SpdyWebSocketStreamEvent>& events =
- delegate.GetSeenEvents();
- ASSERT_EQ(7U, events.size());
-
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
- events[0].event_type);
- EXPECT_EQ(OK, events[0].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
- events[1].event_type);
- EXPECT_EQ(OK, events[1].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- events[2].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- events[3].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- events[4].event_type);
- EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[4].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- events[5].event_type);
- EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
- events[6].event_type);
- EXPECT_EQ(OK, events[6].result);
-
- // EOF close SPDY session.
- EXPECT_FALSE(
- HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
- EXPECT_TRUE(data()->at_read_eof());
- EXPECT_TRUE(data()->at_write_eof());
-}
-
-// A SPDY websocket may still send it's close frame after
-// recieving a close with SPDY stream FIN.
-TEST_P(SpdyWebSocketStreamTest, RemoteCloseWithFin) {
- Prepare(1);
- MockWrite writes[] = {
- CreateMockWrite(*request_frame_.get(), 1),
- CreateMockWrite(*closing_frame_.get(), 4),
- };
- MockRead reads[] = {
- CreateMockRead(*response_frame_.get(), 2),
- CreateMockRead(*closing_frame_fin_.get(), 3),
- MockRead(SYNCHRONOUS, 0, 5) // EOF cause OnCloseSpdyStream event.
- };
- InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
- SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
- delegate.SetOnReceivedData(
- base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
- base::Unretained(this)));
-
- websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
- BoundNetLog net_log;
- GURL url("ws://example.com/echo");
- ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
- SendRequest();
- completion_callback_.WaitForResult();
- websocket_stream_.reset();
-
- const std::vector<SpdyWebSocketStreamEvent>& events =
- delegate.GetSeenEvents();
- EXPECT_EQ(5U, events.size());
-
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
- events[0].event_type);
- EXPECT_EQ(OK, events[0].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
- events[1].event_type);
- EXPECT_EQ(OK, events[1].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- events[2].event_type);
- EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[2].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- events[3].event_type);
- EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[3].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
- events[4].event_type);
- EXPECT_EQ(OK, events[4].result);
-
- // EOF closes SPDY session.
- EXPECT_FALSE(
- HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
- EXPECT_TRUE(data()->at_read_eof());
- EXPECT_TRUE(data()->at_write_eof());
-}
-
-TEST_P(SpdyWebSocketStreamTest, DestructionBeforeClose) {
- Prepare(1);
- MockWrite writes[] = {
- CreateMockWrite(*request_frame_.get(), 1),
- CreateMockWrite(*message_frame_.get(), 3)
- };
-
- MockRead reads[] = {
- CreateMockRead(*response_frame_.get(), 2),
- CreateMockRead(*message_frame_.get(), 4),
- MockRead(ASYNC, ERR_IO_PENDING, 5)
- };
-
- InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
- SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
- delegate.SetOnReceivedHeader(
- base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
- base::Unretained(this)));
- delegate.SetOnReceivedData(
- base::Bind(&SpdyWebSocketStreamTest::DoSync,
- base::Unretained(this)));
-
- websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-
- BoundNetLog net_log;
- GURL url("ws://example.com/echo");
- ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
- SendRequest();
-
- sync_callback_.WaitForResult();
-
- // WebSocketStream destruction remove its SPDY stream from the session.
- EXPECT_TRUE(session_->IsStreamActive(stream_id_));
- websocket_stream_.reset();
- EXPECT_FALSE(session_->IsStreamActive(stream_id_));
-
- const std::vector<SpdyWebSocketStreamEvent>& events =
- delegate.GetSeenEvents();
- ASSERT_GE(4U, events.size());
-
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
- events[0].event_type);
- EXPECT_EQ(OK, events[0].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
- events[1].event_type);
- EXPECT_EQ(OK, events[1].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- events[2].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- events[3].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
-
- EXPECT_TRUE(
- HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
- EXPECT_TRUE(data()->at_read_eof());
- EXPECT_TRUE(data()->at_write_eof());
-}
-
-TEST_P(SpdyWebSocketStreamTest, DestructionAfterExplicitClose) {
- Prepare(1);
- MockWrite writes[] = {
- CreateMockWrite(*request_frame_.get(), 1),
- CreateMockWrite(*message_frame_.get(), 3),
- CreateMockWrite(*closing_frame_.get(), 5)
- };
-
- MockRead reads[] = {
- CreateMockRead(*response_frame_.get(), 2),
- CreateMockRead(*message_frame_.get(), 4),
- MockRead(ASYNC, ERR_IO_PENDING, 6)
- };
-
- InitSession(reads, arraysize(reads), writes, arraysize(writes));
-
- SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
- delegate.SetOnReceivedHeader(
- base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
- base::Unretained(this)));
- delegate.SetOnReceivedData(
- base::Bind(&SpdyWebSocketStreamTest::DoClose,
- base::Unretained(this)));
-
- websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
-
- BoundNetLog net_log;
- GURL url("ws://example.com/echo");
- ASSERT_EQ(OK, websocket_stream_->InitializeStream(url, HIGHEST, net_log));
-
- SendRequest();
-
- completion_callback_.WaitForResult();
-
- // SPDY stream has already been removed from the session by Close().
- EXPECT_FALSE(session_->IsStreamActive(stream_id_));
- websocket_stream_.reset();
-
- const std::vector<SpdyWebSocketStreamEvent>& events =
- delegate.GetSeenEvents();
- ASSERT_EQ(5U, events.size());
-
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
- events[0].event_type);
- EXPECT_EQ(OK, events[0].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
- events[1].event_type);
- EXPECT_EQ(OK, events[1].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- events[2].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[2].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- events[3].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE, events[4].event_type);
-
- EXPECT_TRUE(
- HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
-}
-
-TEST_P(SpdyWebSocketStreamTest, IOPending) {
- Prepare(1);
- scoped_ptr<SpdyFrame> settings_frame(
- spdy_util_.ConstructSpdySettings(spdy_settings_to_send_));
- scoped_ptr<SpdyFrame> settings_ack(spdy_util_.ConstructSpdySettingsAck());
- MockWrite writes[] = {
- CreateMockWrite(*settings_ack, 1),
- CreateMockWrite(*request_frame_.get(), 2),
- CreateMockWrite(*message_frame_.get(), 4),
- CreateMockWrite(*closing_frame_.get(), 6)
- };
-
- MockRead reads[] = {
- CreateMockRead(*settings_frame.get(), 0),
- CreateMockRead(*response_frame_.get(), 3),
- CreateMockRead(*message_frame_.get(), 5),
- CreateMockRead(*closing_frame_.get(), 7),
- MockRead(SYNCHRONOUS, 0, 8) // EOF cause OnCloseSpdyStream event.
- };
-
- DeterministicSocketData data(reads, arraysize(reads),
- writes, arraysize(writes));
- session_deps_.deterministic_socket_factory->AddSocketDataProvider(&data);
- http_session_ =
- SpdySessionDependencies::SpdyCreateSessionDeterministic(&session_deps_);
-
- session_ = CreateInsecureSpdySession(
- http_session_, spdy_session_key_, BoundNetLog());
-
- // Create a dummy WebSocketStream which cause ERR_IO_PENDING to another
- // WebSocketStream under test.
- SpdyWebSocketStreamEventRecorder block_delegate((CompletionCallback()));
-
- scoped_ptr<SpdyWebSocketStream> block_stream(
- new SpdyWebSocketStream(session_, &block_delegate));
- BoundNetLog block_net_log;
- GURL block_url("ws://example.com/block");
- ASSERT_EQ(OK,
- block_stream->InitializeStream(block_url, HIGHEST, block_net_log));
-
- data.RunFor(1);
-
- // Create a WebSocketStream under test.
- SpdyWebSocketStreamEventRecorder delegate(completion_callback_.callback());
- delegate.SetOnCreated(
- base::Bind(&SpdyWebSocketStreamTest::DoSync,
- base::Unretained(this)));
- delegate.SetOnReceivedHeader(
- base::Bind(&SpdyWebSocketStreamTest::DoSendHelloFrame,
- base::Unretained(this)));
- delegate.SetOnReceivedData(
- base::Bind(&SpdyWebSocketStreamTest::DoSendClosingFrame,
- base::Unretained(this)));
-
- websocket_stream_.reset(new SpdyWebSocketStream(session_, &delegate));
- BoundNetLog net_log;
- GURL url("ws://example.com/echo");
- ASSERT_EQ(ERR_IO_PENDING, websocket_stream_->InitializeStream(
- url, HIGHEST, net_log));
-
- // Delete the fist stream to allow create the second stream.
- block_stream.reset();
- ASSERT_EQ(OK, sync_callback_.WaitForResult());
-
- SendRequest();
-
- data.RunFor(8);
- completion_callback_.WaitForResult();
-
- websocket_stream_.reset();
-
- const std::vector<SpdyWebSocketStreamEvent>& block_events =
- block_delegate.GetSeenEvents();
- ASSERT_EQ(0U, block_events.size());
-
- const std::vector<SpdyWebSocketStreamEvent>& events =
- delegate.GetSeenEvents();
- ASSERT_EQ(8U, events.size());
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CREATED,
- events[0].event_type);
- EXPECT_EQ(0, events[0].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_HEADERS,
- events[1].event_type);
- EXPECT_EQ(OK, events[1].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_HEADER,
- events[2].event_type);
- EXPECT_EQ(OK, events[2].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- events[3].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[3].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- events[4].event_type);
- EXPECT_EQ(static_cast<int>(kMessageFrameLength), events[4].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_SENT_DATA,
- events[5].event_type);
- EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[5].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_RECEIVED_DATA,
- events[6].event_type);
- EXPECT_EQ(static_cast<int>(kClosingFrameLength), events[6].result);
- EXPECT_EQ(SpdyWebSocketStreamEvent::EVENT_CLOSE,
- events[7].event_type);
- EXPECT_EQ(OK, events[7].result);
-
- // EOF close SPDY session.
- EXPECT_FALSE(
- HasSpdySession(http_session_->spdy_session_pool(), spdy_session_key_));
- EXPECT_TRUE(data.at_read_eof());
- EXPECT_TRUE(data.at_write_eof());
-}
-
-} // namespace net
diff --git a/net/spdy/spdy_websocket_test_util.cc b/net/spdy/spdy_websocket_test_util.cc
deleted file mode 100644
index b1ef81b..0000000
--- a/net/spdy/spdy_websocket_test_util.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/spdy/spdy_websocket_test_util.h"
-
-#include "net/spdy/buffered_spdy_framer.h"
-#include "net/spdy/spdy_http_utils.h"
-
-namespace net {
-
-const bool kDefaultCompressed = false;
-
-SpdyWebSocketTestUtil::SpdyWebSocketTestUtil(
- NextProto protocol) : spdy_util_(protocol) {}
-
-std::string SpdyWebSocketTestUtil::GetHeader(const SpdyHeaderBlock& headers,
- const std::string& key) const {
- SpdyHeaderBlock::const_iterator it = headers.find(GetHeaderKey(key));
- return (it == headers.end()) ? "" : it->second;
-}
-
-void SpdyWebSocketTestUtil::SetHeader(
- const std::string& key,
- const std::string& value,
- SpdyHeaderBlock* headers) const {
- (*headers)[GetHeaderKey(key)] = value;
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketSynStream(
- int stream_id,
- const char* path,
- const char* host,
- const char* origin) {
- scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
- SetHeader("path", path, headers.get());
- SetHeader("host", host, headers.get());
- SetHeader("version", "WebSocket/13", headers.get());
- SetHeader("scheme", "ws", headers.get());
- SetHeader("origin", origin, headers.get());
- return spdy_util_.ConstructSpdySyn(
- stream_id, *headers, HIGHEST, false, false);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketSynReply(
- int stream_id) {
- SpdyHeaderBlock block;
- SetHeader("status", "101", &block);
- return spdy_util_.ConstructSpdyReply(stream_id, block);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHandshakeRequestFrame(
- scoped_ptr<SpdyHeaderBlock> headers,
- SpdyStreamId stream_id,
- RequestPriority request_priority) {
- return spdy_util_.ConstructSpdySyn(
- stream_id, *headers, request_priority, kDefaultCompressed, false);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHandshakeResponseFrame(
- scoped_ptr<SpdyHeaderBlock> headers,
- SpdyStreamId stream_id,
- RequestPriority request_priority) {
- return spdy_util_.ConstructSpdyReply(stream_id, *headers);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketHeadersFrame(
- int stream_id,
- const char* length,
- bool fin) {
- scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock());
- SetHeader("opcode", "1", headers.get()); // text frame
- SetHeader("length", length, headers.get());
- SetHeader("fin", fin ? "1" : "0", headers.get());
- return spdy_util_.ConstructSpdySyn(stream_id, *headers, LOWEST, false, false);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdyWebSocketDataFrame(
- const char* data,
- int len,
- SpdyStreamId stream_id,
- bool fin) {
-
- // Construct SPDY data frame.
- BufferedSpdyFramer framer(spdy_util_.spdy_version(), false);
- return framer.CreateDataFrame(
- stream_id,
- data,
- len,
- fin ? DATA_FLAG_FIN : DATA_FLAG_NONE);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdySettings(
- const SettingsMap& settings) const {
- return spdy_util_.ConstructSpdySettings(settings);
-}
-
-SpdyFrame* SpdyWebSocketTestUtil::ConstructSpdySettingsAck() const {
- return spdy_util_.ConstructSpdySettingsAck();
-}
-
-SpdyMajorVersion SpdyWebSocketTestUtil::spdy_version() const {
- return spdy_util_.spdy_version();
-}
-
-std::string SpdyWebSocketTestUtil::GetHeaderKey(
- const std::string& key) const {
- return (spdy_util_.is_spdy2() ? "" : ":") + key;
-}
-
-} // namespace net
diff --git a/net/spdy/spdy_websocket_test_util.h b/net/spdy/spdy_websocket_test_util.h
deleted file mode 100644
index 14c8c02..0000000
--- a/net/spdy/spdy_websocket_test_util.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_
-#define NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_
-
-#include "net/base/request_priority.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_protocol.h"
-#include "net/spdy/spdy_test_util_common.h"
-
-namespace net {
-
-class SpdyWebSocketTestUtil {
- public:
- explicit SpdyWebSocketTestUtil(NextProto protocol);
-
- // Returns the value corresponding to the given key (passed through
- // GetHeaderKey()), or the empty string if none exists.
- std::string GetHeader(const SpdyHeaderBlock& headers,
- const std::string& key) const;
-
- // Adds the given key/value pair to |headers|, passing the key
- // through GetHeaderKey().
- void SetHeader(const std::string& key,
- const std::string& value,
- SpdyHeaderBlock* headers) const;
-
- // Constructs a standard SPDY SYN_STREAM frame for WebSocket over
- // SPDY opening handshake.
- SpdyFrame* ConstructSpdyWebSocketSynStream(int stream_id,
- const char* path,
- const char* host,
- const char* origin);
-
- // Constructs a standard SPDY SYN_REPLY packet to match the
- // WebSocket over SPDY opening handshake.
- SpdyFrame* ConstructSpdyWebSocketSynReply(int stream_id);
-
- // Constructs a WebSocket over SPDY handshake request packet.
- SpdyFrame* ConstructSpdyWebSocketHandshakeRequestFrame(
- scoped_ptr<SpdyHeaderBlock> headers,
- SpdyStreamId stream_id,
- RequestPriority request_priority);
-
- // Constructs a WebSocket over SPDY handshake response packet.
- SpdyFrame* ConstructSpdyWebSocketHandshakeResponseFrame(
- scoped_ptr<SpdyHeaderBlock> headers,
- SpdyStreamId stream_id,
- RequestPriority request_priority);
-
- // Constructs a SPDY HEADERS frame for a WebSocket frame over SPDY.
- SpdyFrame* ConstructSpdyWebSocketHeadersFrame(int stream_id,
- const char* length,
- bool fin);
-
- // Constructs a WebSocket over SPDY data packet.
- SpdyFrame* ConstructSpdyWebSocketDataFrame(const char* data,
- int len,
- SpdyStreamId stream_id,
- bool fin);
-
- // Forwards to |spdy_util_|.
- SpdyFrame* ConstructSpdySettings(const SettingsMap& settings) const;
- SpdyFrame* ConstructSpdySettingsAck() const;
- SpdyMajorVersion spdy_version() const;
-
- private:
- // Modify the header key based on the SPDY version and return it.
- std::string GetHeaderKey(const std::string& key) const;
-
- SpdyTestUtil spdy_util_;
-};
-
-} // namespace net
-
-#endif // NET_SPDY_SPDY_WEBSOCKET_TEST_UTIL_H_
diff --git a/net/ssl/ssl_cipher_suite_names.h b/net/ssl/ssl_cipher_suite_names.h
index 29c03a1..4e02fc6 100644
--- a/net/ssl/ssl_cipher_suite_names.h
+++ b/net/ssl/ssl_cipher_suite_names.h
@@ -55,7 +55,7 @@
// Currently, this function follows these criteria:
// 1) Only uses forward secure key exchanges
// 2) Only uses AEADs
-NET_EXPORT_PRIVATE bool IsSecureTLSCipherSuite(uint16 cipher_suite);
+NET_EXPORT bool IsSecureTLSCipherSuite(uint16 cipher_suite);
} // namespace net
diff --git a/net/test/embedded_test_server/http_request.cc b/net/test/embedded_test_server/http_request.cc
index 3acb550..3156e51 100644
--- a/net/test/embedded_test_server/http_request.cc
+++ b/net/test/embedded_test_server/http_request.cc
@@ -83,8 +83,10 @@
// Parse request's the first header line.
// Request main main header, eg. GET /foobar.html HTTP/1.1
+ std::string request_headers;
{
const std::string header_line = ShiftLine();
+ http_request_->all_headers += header_line + "\r\n";
std::vector<std::string> header_line_tokens;
base::SplitString(header_line, ' ', &header_line_tokens);
DCHECK_EQ(3u, header_line_tokens.size());
@@ -111,6 +113,7 @@
if (header_line.empty())
break;
+ http_request_->all_headers += header_line + "\r\n";
if (header_line[0] == ' ' || header_line[0] == '\t') {
// Continuation of the previous multi-line header.
std::string header_value =
diff --git a/net/test/embedded_test_server/http_request.h b/net/test/embedded_test_server/http_request.h
index cb9144b..fcbf54c 100644
--- a/net/test/embedded_test_server/http_request.h
+++ b/net/test/embedded_test_server/http_request.h
@@ -36,6 +36,7 @@
std::string relative_url; // Starts with '/'. Example: "/test?query=foo"
HttpMethod method;
std::string method_string;
+ std::string all_headers;
std::map<std::string, std::string> headers;
std::string content;
bool has_content;
diff --git a/net/test/embedded_test_server/http_request_unittest.cc b/net/test/embedded_test_server/http_request_unittest.cc
index 1006e4e..56121bb 100644
--- a/net/test/embedded_test_server/http_request_unittest.cc
+++ b/net/test/embedded_test_server/http_request_unittest.cc
@@ -44,6 +44,14 @@
EXPECT_EQ(1u, request->headers.count("Multi-line-header"));
EXPECT_EQ(1u, request->headers.count("Content-Length"));
+ const char kExpectedAllHeaders[] =
+ "POST /foobar.html HTTP/1.1\r\n"
+ "Host: localhost:1234\r\n"
+ "Multi-line-header: abcd\r\n"
+ " efgh\r\n"
+ " ijkl\r\n"
+ "Content-Length: 10\r\n";
+ EXPECT_EQ(kExpectedAllHeaders, request->all_headers);
EXPECT_EQ("localhost:1234", request->headers["Host"]);
EXPECT_EQ("abcd efgh ijkl", request->headers["Multi-line-header"]);
EXPECT_EQ("10", request->headers["Content-Length"]);
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index 0e23c7a..0c586f2 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -101,6 +101,7 @@
tls_intolerance_type(TLS_INTOLERANCE_ALERT),
fallback_scsv_enabled(false),
staple_ocsp_response(false),
+ ocsp_server_unavailable(false),
enable_npn(false),
disable_session_cache(false) {
}
@@ -118,6 +119,7 @@
tls_intolerance_type(TLS_INTOLERANCE_ALERT),
fallback_scsv_enabled(false),
staple_ocsp_response(false),
+ ocsp_server_unavailable(false),
enable_npn(false),
disable_session_cache(false) {
}
@@ -476,6 +478,10 @@
}
if (ssl_options_.staple_ocsp_response)
arguments->Set("staple-ocsp-response", base::Value::CreateNullValue());
+ if (ssl_options_.ocsp_server_unavailable) {
+ arguments->Set("ocsp-server-unavailable",
+ base::Value::CreateNullValue());
+ }
if (ssl_options_.enable_npn)
arguments->Set("enable-npn", base::Value::CreateNullValue());
if (ssl_options_.disable_session_cache)
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
index 45ea1ce..73ac855 100644
--- a/net/test/spawned_test_server/base_test_server.h
+++ b/net/test/spawned_test_server/base_test_server.h
@@ -201,6 +201,10 @@
// Whether to staple the OCSP response.
bool staple_ocsp_response;
+ // Whether to make the OCSP server unavailable. This does not affect the
+ // stapled OCSP response.
+ bool ocsp_server_unavailable;
+
// Whether to enable NPN support.
bool enable_npn;
diff --git a/net/test/url_request/url_request_mock_http_job.cc b/net/test/url_request/url_request_mock_http_job.cc
index 5542ac7..ede87cf 100644
--- a/net/test/url_request/url_request_mock_http_job.cc
+++ b/net/test/url_request/url_request_mock_http_job.cc
@@ -5,24 +5,35 @@
#include "net/test/url_request/url_request_mock_http_job.h"
#include "base/files/file_util.h"
+#include "base/macros.h"
#include "base/message_loop/message_loop.h"
+#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/utf_string_conversions.h"
#include "base/task_runner_util.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/thread_restrictions.h"
#include "net/base/filename_util.h"
+#include "net/base/net_errors.h"
+#include "net/base/url_util.h"
#include "net/http/http_response_headers.h"
#include "net/url_request/url_request_filter.h"
#include "net/url_request/url_request_interceptor.h"
+namespace net {
+
+namespace {
+
const char kMockHostname[] = "mock.http";
const base::FilePath::CharType kMockHeaderFileSuffix[] =
FILE_PATH_LITERAL(".mock-http-headers");
-namespace net {
-
-namespace {
+// String names of failure phases matching FailurePhase enum.
+const char* kFailurePhase[] {
+ "start", // START
+ "readasync", // READ_ASYNC
+ "readsync", // READ_SYNC
+};
class MockJobInterceptor : public net::URLRequestInterceptor {
public:
@@ -119,6 +130,22 @@
}
// static
+GURL URLRequestMockHTTPJob::GetMockUrlWithFailure(const base::FilePath& path,
+ FailurePhase phase,
+ int net_error) {
+ COMPILE_ASSERT(arraysize(kFailurePhase) == MAX_FAILURE_PHASE,
+ kFailurePhase_must_match_FailurePhase_enum);
+ DCHECK_GE(phase, START);
+ DCHECK_LE(phase, READ_SYNC);
+ std::string url(GetMockUrl(path).spec());
+ url.append("?");
+ url.append(kFailurePhase[phase]);
+ url.append("=");
+ url.append(base::IntToString(net_error));
+ return GURL(url);
+}
+
+// static
scoped_ptr<net::URLRequestInterceptor> URLRequestMockHTTPJob::CreateInterceptor(
const base::FilePath& base_path,
const scoped_refptr<base::SequencedWorkerPool>& worker_pool) {
@@ -163,23 +190,72 @@
// Public virtual version.
void URLRequestMockHTTPJob::Start() {
+ if (MaybeReportErrorOnPhase(START))
+ return;
base::PostTaskAndReplyWithResult(
task_runner_.get(),
FROM_HERE,
base::Bind(&DoFileIO, file_path_),
- base::Bind(&URLRequestMockHTTPJob::GetRawHeaders,
+ base::Bind(&URLRequestMockHTTPJob::SetHeadersAndStart,
weak_ptr_factory_.GetWeakPtr()));
}
-void URLRequestMockHTTPJob::GetRawHeaders(std::string raw_headers) {
- // Handle CRLF line-endings.
- ReplaceSubstringsAfterOffset(&raw_headers, 0, "\r\n", "\n");
- // ParseRawHeaders expects \0 to end each header line.
- ReplaceSubstringsAfterOffset(&raw_headers, 0, "\n", std::string("\0", 1));
+// Public virtual version.
+bool URLRequestMockHTTPJob::ReadRawData(IOBuffer* buf,
+ int buf_size,
+ int* bytes_read) {
+ if (MaybeReportErrorOnPhase(READ_SYNC))
+ return false;
+ if (MaybeReportErrorOnPhase(READ_ASYNC))
+ return false;
+ return URLRequestFileJob::ReadRawData(buf, buf_size, bytes_read);
+}
+
+void URLRequestMockHTTPJob::SetHeadersAndStart(const std::string& raw_headers) {
+ if (MaybeReportErrorOnPhase(START))
+ return;
raw_headers_ = raw_headers;
+ // Handle CRLF line-endings.
+ ReplaceSubstringsAfterOffset(&raw_headers_, 0, "\r\n", "\n");
+ // ParseRawHeaders expects \0 to end each header line.
+ ReplaceSubstringsAfterOffset(&raw_headers_, 0, "\n", std::string("\0", 1));
URLRequestFileJob::Start();
}
+bool URLRequestMockHTTPJob::MaybeReportErrorOnPhase(
+ FailurePhase current_phase) {
+ DCHECK_GE(current_phase, START);
+ DCHECK_LE(current_phase, READ_SYNC);
+ std::string phase_key(kFailurePhase[current_phase]);
+ std::string phase_error_string;
+ if (!GetValueForKeyInQuery(request_->url(), phase_key, &phase_error_string))
+ return false;
+
+ int net_error;
+ if (!base::StringToInt(phase_error_string, &net_error))
+ return false;
+
+ if (net_error != net::ERR_IO_PENDING &&
+ (current_phase == START || current_phase == READ_SYNC)) {
+ NotifyDone(net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error));
+ return true;
+ }
+
+ SetStatus(net::URLRequestStatus(net::URLRequestStatus::IO_PENDING, 0));
+
+ if (current_phase != READ_ASYNC)
+ return true;
+
+ base::MessageLoopProxy::current()->PostTask(
+ FROM_HERE,
+ base::Bind(
+ &URLRequestMockHTTPJob::NotifyDone,
+ weak_ptr_factory_.GetWeakPtr(),
+ net::URLRequestStatus(net::URLRequestStatus::FAILED, net_error)));
+
+ return true;
+}
+
// Private const version.
void URLRequestMockHTTPJob::GetResponseInfoConst(
net::HttpResponseInfo* info) const {
diff --git a/net/test/url_request/url_request_mock_http_job.h b/net/test/url_request/url_request_mock_http_job.h
index 1a01a30..6eb3c72 100644
--- a/net/test/url_request/url_request_mock_http_job.h
+++ b/net/test/url_request/url_request_mock_http_job.h
@@ -28,6 +28,13 @@
class URLRequestMockHTTPJob : public URLRequestFileJob {
public:
+ enum FailurePhase {
+ START = 0,
+ READ_ASYNC = 1,
+ READ_SYNC = 2,
+ MAX_FAILURE_PHASE = 3,
+ };
+
// Note that all file IO is done using |worker_pool|.
URLRequestMockHTTPJob(URLRequest* request,
NetworkDelegate* network_delegate,
@@ -35,6 +42,7 @@
const scoped_refptr<base::TaskRunner>& task_runner);
void Start() override;
+ bool ReadRawData(IOBuffer* buf, int buf_size, int* bytes_read) override;
bool GetMimeType(std::string* mime_type) const override;
int GetResponseCode() const override;
bool GetCharset(std::string* charset) override;
@@ -57,6 +65,13 @@
// construct a mock URL.
static GURL GetMockUrl(const base::FilePath& path);
+ // Given the path to a file relative to the path passed to AddUrlHandler(),
+ // construct a mock URL that reports |net_error| at given |phase| of the
+ // request. Reporting |net_error| ERR_IO_PENDING results in a hung request.
+ static GURL GetMockUrlWithFailure(const base::FilePath& path,
+ FailurePhase phase,
+ int net_error);
+
// Returns a URLRequestJobFactory::ProtocolHandler that serves
// URLRequestMockHTTPJob's responding like an HTTP server. |base_path| is the
// file path leading to the root of the directory to use as the root of the
@@ -77,7 +92,13 @@
private:
void GetResponseInfoConst(HttpResponseInfo* info) const;
- void GetRawHeaders(std::string raw_headers);
+ void SetHeadersAndStart(const std::string& raw_headers);
+ // Checks query part of request url, and reports an error if it matches.
+ // Error is parsed out from the query and is reported synchronously.
+ // Reporting ERR_IO_PENDING results in a hung request.
+ // The "readasync" error is posted asynchronously.
+ bool MaybeReportErrorOnPhase(FailurePhase phase);
+
std::string raw_headers_;
const scoped_refptr<base::TaskRunner> task_runner_;
diff --git a/net/tools/flip_server/spdy_interface.cc b/net/tools/flip_server/spdy_interface.cc
index 297045d..22da7db 100644
--- a/net/tools/flip_server/spdy_interface.cc
+++ b/net/tools/flip_server/spdy_interface.cc
@@ -285,6 +285,8 @@
}
void SpdySM::OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
const SpdyHeaderBlock& headers) {
VLOG(2) << ACCEPTOR_CLIENT_IDENT << "SpdySM: OnHeaders(" << stream_id << ")";
diff --git a/net/tools/flip_server/spdy_interface.h b/net/tools/flip_server/spdy_interface.h
index de53e87..15cf0e9 100644
--- a/net/tools/flip_server/spdy_interface.h
+++ b/net/tools/flip_server/spdy_interface.h
@@ -81,6 +81,8 @@
// Called after all the header data for HEADERS control frame is received.
void OnHeaders(SpdyStreamId stream_id,
+ bool has_priority,
+ SpdyPriority priority,
bool fin,
const SpdyHeaderBlock& headers) override;
diff --git a/net/tools/flip_server/spdy_interface_test.cc b/net/tools/flip_server/spdy_interface_test.cc
index 9e66d0c..09909e2 100644
--- a/net/tools/flip_server/spdy_interface_test.cc
+++ b/net/tools/flip_server/spdy_interface_test.cc
@@ -52,7 +52,12 @@
bool,
const SpdyHeaderBlock&));
MOCK_METHOD3(OnSynReply, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
- MOCK_METHOD3(OnHeaders, void(SpdyStreamId, bool, const SpdyHeaderBlock&));
+ MOCK_METHOD5(OnHeaders,
+ void(SpdyStreamId,
+ bool,
+ SpdyPriority,
+ bool,
+ const SpdyHeaderBlock&));
MOCK_METHOD3(OnDataFrameHeader, void(SpdyStreamId, size_t, bool));
MOCK_METHOD4(OnStreamFrameData, void(SpdyStreamId,
const char*,
@@ -471,8 +476,9 @@
EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
.WillOnce(SaveArg<2>(&actual_header_block));
} else {
- EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ EXPECT_CALL(*spdy_framer_visitor_,
+ OnHeaders(stream_id, false, 0, false, _))
+ .WillOnce(SaveArg<4>(&actual_header_block));
}
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(*spdy_framer_visitor_,
@@ -522,8 +528,8 @@
.WillOnce(SaveArg<2>(&actual_header_block));
} else {
EXPECT_CALL(*spdy_framer_visitor_,
- OnHeaders(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ OnHeaders(stream_id, false, 0, false, _))
+ .WillOnce(SaveArg<4>(&actual_header_block));
}
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(*spdy_framer_visitor_,
@@ -641,8 +647,9 @@
EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
.WillOnce(SaveArg<2>(&actual_header_block));
} else {
- EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ EXPECT_CALL(*spdy_framer_visitor_,
+ OnHeaders(stream_id, false, 0, false, _))
+ .WillOnce(SaveArg<4>(&actual_header_block));
}
}
@@ -677,8 +684,9 @@
EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
.WillOnce(SaveArg<2>(&actual_header_block));
} else {
- EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ EXPECT_CALL(*spdy_framer_visitor_,
+ OnHeaders(stream_id, false, 0, false, _))
+ .WillOnce(SaveArg<4>(&actual_header_block));
}
}
@@ -854,8 +862,9 @@
EXPECT_CALL(*spdy_framer_visitor_, OnSynReply(stream_id, false, _))
.WillOnce(SaveArg<2>(&actual_header_block));
} else {
- EXPECT_CALL(*spdy_framer_visitor_, OnHeaders(stream_id, false, _))
- .WillOnce(SaveArg<2>(&actual_header_block));
+ EXPECT_CALL(*spdy_framer_visitor_,
+ OnHeaders(stream_id, false, 0, false, _))
+ .WillOnce(SaveArg<4>(&actual_header_block));
}
EXPECT_CALL(checkpoint, Call(0));
EXPECT_CALL(*spdy_framer_visitor_,
diff --git a/net/tools/quic/end_to_end_test.cc b/net/tools/quic/end_to_end_test.cc
index 55e2d88..1fb3e79 100644
--- a/net/tools/quic/end_to_end_test.cc
+++ b/net/tools/quic/end_to_end_test.cc
@@ -924,7 +924,7 @@
// 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(1000);
+ client_config_.SetInitialRoundTripTimeUsToSend(20000);
ASSERT_TRUE(Initialize());
client_->client()->WaitForCryptoHandshakeConfirmed();
@@ -949,9 +949,9 @@
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.
- EXPECT_EQ(1000u, client_sent_packet_manager.GetRttStats()->initial_rtt_us());
- EXPECT_EQ(1000u, server_sent_packet_manager.GetRttStats()->initial_rtt_us());
+ // 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);
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 0dcbd25..93de5ca 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -1976,6 +1976,7 @@
if self.options.server_type == SERVER_HTTP:
if self.options.https:
pem_cert_and_key = None
+ ocsp_der = None
if self.options.cert_and_key_file:
if not os.path.isfile(self.options.cert_and_key_file):
raise testserver_base.OptionError(
@@ -1988,7 +1989,6 @@
print ('OCSP server started on %s:%d...' %
(host, self.__ocsp_server.server_port))
- ocsp_der = None
ocsp_state = None
if self.options.ocsp == 'ok':
@@ -2012,7 +2012,11 @@
ocsp_state = ocsp_state,
serial = self.options.cert_serial)
- self.__ocsp_server.ocsp_response = ocsp_der
+ if self.options.ocsp_server_unavailable:
+ # SEQUENCE containing ENUMERATED with value 3 (tryLater).
+ self.__ocsp_server.ocsp_response = '30030a0103'.decode('hex')
+ else:
+ self.__ocsp_server.ocsp_response = ocsp_der
for ca_cert in self.options.ssl_client_ca:
if not os.path.isfile(ca_cert):
@@ -2021,8 +2025,8 @@
' exiting...')
stapled_ocsp_response = None
- if self.__ocsp_server and self.options.staple_ocsp_response:
- stapled_ocsp_response = self.__ocsp_server.ocsp_response
+ if self.options.staple_ocsp_response:
+ stapled_ocsp_response = ocsp_der
server = HTTPSServer((host, port), TestPageHandler, pem_cert_and_key,
self.options.ssl_client_auth,
@@ -2269,6 +2273,12 @@
self.option_parser.add_option('--ws-basic-auth', action='store_true',
dest='ws_basic_auth',
help='Enable basic-auth for WebSocket')
+ self.option_parser.add_option('--ocsp-server-unavailable',
+ dest='ocsp_server_unavailable',
+ default=False, action='store_true',
+ help='If set, the OCSP server will return '
+ 'a tryLater status rather than the actual '
+ 'OCSP response.')
if __name__ == '__main__':
diff --git a/net/udp/udp_socket_win.cc b/net/udp/udp_socket_win.cc
index b18aa0a..4c307fd 100644
--- a/net/udp/udp_socket_win.cc
+++ b/net/udp/udp_socket_win.cc
@@ -630,7 +630,7 @@
int UDPSocketWin::InternalRecvFrom(IOBuffer* buf, int buf_len,
IPEndPoint* address) {
- DCHECK(!core_->read_iobuffer_);
+ DCHECK(!core_->read_iobuffer_.get());
SockaddrStorage& storage = core_->recv_addr_storage_;
storage.addr_len = sizeof(storage.addr_storage);
@@ -670,7 +670,7 @@
int UDPSocketWin::InternalSendTo(IOBuffer* buf, int buf_len,
const IPEndPoint* address) {
- DCHECK(!core_->write_iobuffer_);
+ DCHECK(!core_->write_iobuffer_.get());
SockaddrStorage storage;
struct sockaddr* addr = storage.addr;
// Convert address.
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 666bd03..04c190c 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -351,6 +351,8 @@
http_network_session_params_.trusted_spdy_proxy;
network_session_params.next_protos = http_network_session_params_.next_protos;
network_session_params.enable_quic = http_network_session_params_.enable_quic;
+ network_session_params.quic_connection_options =
+ http_network_session_params_.quic_connection_options;
HttpTransactionFactory* http_transaction_factory = NULL;
if (http_cache_enabled_) {
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h
index 9053372..a7d9d7b 100644
--- a/net/url_request/url_request_context_builder.h
+++ b/net/url_request/url_request_context_builder.h
@@ -27,6 +27,7 @@
#include "net/dns/host_resolver.h"
#include "net/proxy/proxy_config_service.h"
#include "net/proxy/proxy_service.h"
+#include "net/quic/quic_protocol.h"
#include "net/socket/next_proto.h"
namespace net {
@@ -72,6 +73,7 @@
std::string trusted_spdy_proxy;
bool use_alternate_protocols;
bool enable_quic;
+ QuicTagVector quic_connection_options;
};
URLRequestContextBuilder();
@@ -162,6 +164,12 @@
void SetSpdyAndQuicEnabled(bool spdy_enabled,
bool quic_enabled);
+ void set_quic_connection_options(
+ const QuicTagVector& quic_connection_options) {
+ http_network_session_params_.quic_connection_options =
+ quic_connection_options;
+ }
+
void set_throttling_enabled(bool throttling_enabled) {
throttling_enabled_ = throttling_enabled;
}
diff --git a/net/url_request/url_request_file_job_unittest.cc b/net/url_request/url_request_file_job_unittest.cc
index f4d7f7a..23ded74 100644
--- a/net/url_request/url_request_file_job_unittest.cc
+++ b/net/url_request/url_request_file_job_unittest.cc
@@ -82,6 +82,19 @@
return job;
}
+ net::URLRequestJob* MaybeInterceptRedirect(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate,
+ const GURL& location) const override {
+ return nullptr;
+ }
+
+ net::URLRequestJob* MaybeInterceptResponse(
+ net::URLRequest* request,
+ net::NetworkDelegate* network_delegate) const override {
+ return nullptr;
+ }
+
bool IsHandledProtocol(const std::string& scheme) const override {
return scheme == "file";
}
diff --git a/net/url_request/url_request_intercepting_job_factory.cc b/net/url_request/url_request_intercepting_job_factory.cc
index 43789e1..ea2d1f2 100644
--- a/net/url_request/url_request_intercepting_job_factory.cc
+++ b/net/url_request/url_request_intercepting_job_factory.cc
@@ -32,6 +32,33 @@
scheme, request, network_delegate);
}
+URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptRedirect(
+ URLRequest* request,
+ NetworkDelegate* network_delegate,
+ const GURL& location) const {
+ DCHECK(CalledOnValidThread());
+ URLRequestJob* job = interceptor_->MaybeInterceptRedirect(request,
+ network_delegate,
+ location);
+ if (job)
+ return job;
+ return job_factory_->MaybeInterceptRedirect(request,
+ network_delegate,
+ location);
+}
+
+URLRequestJob* URLRequestInterceptingJobFactory::MaybeInterceptResponse(
+ URLRequest* request,
+ NetworkDelegate* network_delegate) const {
+ DCHECK(CalledOnValidThread());
+ URLRequestJob* job = interceptor_->MaybeInterceptResponse(request,
+ network_delegate);
+ if (job)
+ return job;
+ return job_factory_->MaybeInterceptResponse(request,
+ network_delegate);
+}
+
bool URLRequestInterceptingJobFactory::IsHandledProtocol(
const std::string& scheme) const {
return job_factory_->IsHandledProtocol(scheme);
diff --git a/net/url_request/url_request_intercepting_job_factory.h b/net/url_request/url_request_intercepting_job_factory.h
index 857dbf4..056b385 100644
--- a/net/url_request/url_request_intercepting_job_factory.h
+++ b/net/url_request/url_request_intercepting_job_factory.h
@@ -42,6 +42,16 @@
const std::string& scheme,
URLRequest* request,
NetworkDelegate* network_delegate) const override;
+
+ URLRequestJob* MaybeInterceptRedirect(
+ URLRequest* request,
+ NetworkDelegate* network_delegate,
+ const GURL& location) const override;
+
+ URLRequestJob* MaybeInterceptResponse(
+ URLRequest* request,
+ NetworkDelegate* network_delegate) const override;
+
bool IsHandledProtocol(const std::string& scheme) const override;
bool IsHandledURL(const GURL& url) const override;
bool IsSafeRedirectTarget(const GURL& location) const override;
diff --git a/net/url_request/url_request_interceptor.cc b/net/url_request/url_request_interceptor.cc
index bcd0fd5..b93611b 100644
--- a/net/url_request/url_request_interceptor.cc
+++ b/net/url_request/url_request_interceptor.cc
@@ -12,4 +12,16 @@
URLRequestInterceptor::~URLRequestInterceptor() {
}
+URLRequestJob* URLRequestInterceptor::MaybeInterceptRedirect(
+ URLRequest* request,
+ NetworkDelegate* network_delegate,
+ const GURL& location) const {
+ return nullptr;
+}
+
+URLRequestJob* URLRequestInterceptor::MaybeInterceptResponse(
+ URLRequest* request, NetworkDelegate* network_delegate) const {
+ return nullptr;
+}
+
} // namespace net
diff --git a/net/url_request/url_request_interceptor.h b/net/url_request/url_request_interceptor.h
index 682368d..f7d5275 100644
--- a/net/url_request/url_request_interceptor.h
+++ b/net/url_request/url_request_interceptor.h
@@ -8,6 +8,8 @@
#include "base/macros.h"
#include "net/base/net_export.h"
+class GURL;
+
namespace net {
class URLRequest;
@@ -28,6 +30,20 @@
virtual URLRequestJob* MaybeInterceptRequest(
URLRequest* request, NetworkDelegate* network_delegate) const = 0;
+ // Returns a URLRequestJob to handle |request|, if the interceptor wants to
+ // take over the handling of the request after a redirect is received,
+ // instead of using the default ProtocolHandler. Otherwise, returns NULL.
+ virtual URLRequestJob* MaybeInterceptRedirect(
+ URLRequest* request,
+ NetworkDelegate* network_delegate,
+ const GURL& location) const;
+
+ // Returns a URLRequestJob to handle |request, if the interceptor wants to
+ // take over the handling of the request after a response has started,
+ // instead of using the default ProtocolHandler. Otherwise, returns NULL.
+ virtual URLRequestJob* MaybeInterceptResponse(
+ URLRequest* request, NetworkDelegate* network_delegate) const;
+
private:
DISALLOW_COPY_AND_ASSIGN(URLRequestInterceptor);
};
diff --git a/net/url_request/url_request_job_factory.h b/net/url_request/url_request_job_factory.h
index d4cc49e..96f218a 100644
--- a/net/url_request/url_request_job_factory.h
+++ b/net/url_request/url_request_job_factory.h
@@ -47,6 +47,15 @@
URLRequest* request,
NetworkDelegate* network_delegate) const = 0;
+ virtual URLRequestJob* MaybeInterceptRedirect(
+ URLRequest* request,
+ NetworkDelegate* network_delegate,
+ const GURL& location) const = 0;
+
+ virtual URLRequestJob* MaybeInterceptResponse(
+ URLRequest* request,
+ NetworkDelegate* network_delegate) const = 0;
+
virtual bool IsHandledProtocol(const std::string& scheme) const = 0;
virtual bool IsHandledURL(const GURL& url) const = 0;
diff --git a/net/url_request/url_request_job_factory_impl.cc b/net/url_request/url_request_job_factory_impl.cc
index 57e775b..264a7a1 100644
--- a/net/url_request/url_request_job_factory_impl.cc
+++ b/net/url_request/url_request_job_factory_impl.cc
@@ -63,6 +63,19 @@
return it->second->MaybeCreateJob(request, network_delegate);
}
+URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptRedirect(
+ URLRequest* request,
+ NetworkDelegate* network_delegate,
+ const GURL& location) const {
+ return nullptr;
+}
+
+URLRequestJob* URLRequestJobFactoryImpl::MaybeInterceptResponse(
+ URLRequest* request,
+ NetworkDelegate* network_delegate) const {
+ return nullptr;
+}
+
bool URLRequestJobFactoryImpl::IsHandledProtocol(
const std::string& scheme) const {
DCHECK(CalledOnValidThread());
diff --git a/net/url_request/url_request_job_factory_impl.h b/net/url_request/url_request_job_factory_impl.h
index 695661e..8d1d8d9 100644
--- a/net/url_request/url_request_job_factory_impl.h
+++ b/net/url_request/url_request_job_factory_impl.h
@@ -33,6 +33,16 @@
const std::string& scheme,
URLRequest* request,
NetworkDelegate* network_delegate) const override;
+
+ URLRequestJob* MaybeInterceptRedirect(
+ URLRequest* request,
+ NetworkDelegate* network_delegate,
+ const GURL& location) const override;
+
+ URLRequestJob* MaybeInterceptResponse(
+ URLRequest* request,
+ NetworkDelegate* network_delegate) const override;
+
bool IsHandledProtocol(const std::string& scheme) const override;
bool IsHandledURL(const GURL& url) const override;
bool IsSafeRedirectTarget(const GURL& location) const override;
diff --git a/net/url_request/url_request_job_manager.cc b/net/url_request/url_request_job_manager.cc
index 0fe557b..6fcff22 100644
--- a/net/url_request/url_request_job_manager.cc
+++ b/net/url_request/url_request_job_manager.cc
@@ -128,6 +128,13 @@
if (job)
return job;
}
+
+ URLRequestJob* job =
+ request->context()->job_factory()->MaybeInterceptRedirect(
+ request, network_delegate, location);
+ if (job)
+ return job;
+
return NULL;
}
@@ -154,6 +161,13 @@
if (job)
return job;
}
+
+ URLRequestJob* job =
+ request->context()->job_factory()->MaybeInterceptResponse(
+ request, network_delegate);
+ if (job)
+ return job;
+
return NULL;
}
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc
index 82d8579..8f70ee7 100644
--- a/net/url_request/url_request_test_util.cc
+++ b/net/url_request/url_request_test_util.cc
@@ -317,11 +317,14 @@
blocked_set_cookie_count_(0),
set_cookie_count_(0),
observed_before_proxy_headers_sent_callbacks_(0),
+ before_send_headers_count_(0),
+ headers_received_count_(0),
has_load_timing_info_before_redirect_(false),
has_load_timing_info_before_auth_(false),
can_access_files_(true),
can_throttle_requests_(true),
- cancel_request_with_policy_violating_referrer_(false) {
+ cancel_request_with_policy_violating_referrer_(false),
+ will_be_intercepted_on_next_error_(false) {
}
TestNetworkDelegate::~TestNetworkDelegate() {
@@ -386,7 +389,7 @@
next_states_[req_id] =
kStageSendHeaders |
kStageCompletedError; // request canceled by delegate
-
+ before_send_headers_count_++;
return OK;
}
@@ -406,9 +409,11 @@
event_order_[req_id] += "OnSendHeaders\n";
EXPECT_TRUE(next_states_[req_id] & kStageSendHeaders) <<
event_order_[req_id];
- next_states_[req_id] =
- kStageHeadersReceived |
- kStageCompletedError;
+ if (!will_be_intercepted_on_next_error_)
+ next_states_[req_id] = kStageHeadersReceived | kStageCompletedError;
+ else
+ next_states_[req_id] = kStageResponseStarted;
+ will_be_intercepted_on_next_error_ = false;
}
int TestNetworkDelegate::OnHeadersReceived(
@@ -445,7 +450,7 @@
if (!allowed_unsafe_redirect_url_.is_empty())
*allowed_unsafe_redirect_url = allowed_unsafe_redirect_url_;
}
-
+ headers_received_count_++;
return OK;
}
diff --git a/net/url_request/url_request_test_util.h b/net/url_request/url_request_test_util.h
index 5784931..1289db7 100644
--- a/net/url_request/url_request_test_util.h
+++ b/net/url_request/url_request_test_util.h
@@ -275,12 +275,18 @@
int observed_before_proxy_headers_sent_callbacks() const {
return observed_before_proxy_headers_sent_callbacks_;
}
+ int before_send_headers_count() const { return before_send_headers_count_; }
+ int headers_received_count() const { return headers_received_count_; }
// Last observed proxy in proxy header sent callback.
HostPortPair last_observed_proxy() {
return last_observed_proxy_;
}
+ void set_can_be_intercepted_on_error(bool can_be_intercepted_on_error) {
+ will_be_intercepted_on_next_error_ = can_be_intercepted_on_error;
+ }
+
protected:
// NetworkDelegate:
int OnBeforeURLRequest(URLRequest* request,
@@ -343,6 +349,8 @@
int blocked_set_cookie_count_;
int set_cookie_count_;
int observed_before_proxy_headers_sent_callbacks_;
+ int before_send_headers_count_;
+ int headers_received_count_;
// Last observed proxy in before proxy header sent callback.
HostPortPair last_observed_proxy_;
@@ -365,6 +373,7 @@
bool can_access_files_; // true by default
bool can_throttle_requests_; // true by default
bool cancel_request_with_policy_violating_referrer_; // false by default
+ bool will_be_intercepted_on_next_error_;
};
// Overrides the host used by the LocalHttpTestServer in
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index 139b6f3..2aeecc6 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -72,6 +72,8 @@
#include "net/url_request/static_http_user_agent_settings.h"
#include "net/url_request/url_request.h"
#include "net/url_request/url_request_http_job.h"
+#include "net/url_request/url_request_intercepting_job_factory.h"
+#include "net/url_request/url_request_interceptor.h"
#include "net/url_request/url_request_job_factory_impl.h"
#include "net/url_request/url_request_redirect_job.h"
#include "net/url_request/url_request_test_job.h"
@@ -607,31 +609,52 @@
URLRequestTest() : default_context_(true) {
default_context_.set_network_delegate(&default_network_delegate_);
default_context_.set_net_log(&net_log_);
- job_factory_.SetProtocolHandler("data", new DataProtocolHandler);
-#if !defined(DISABLE_FILE_SUPPORT)
- job_factory_.SetProtocolHandler(
- "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
-#endif
- default_context_.set_job_factory(&job_factory_);
- default_context_.Init();
+ job_factory_impl_ = new URLRequestJobFactoryImpl();
+ job_factory_.reset(job_factory_impl_);
}
+
~URLRequestTest() override {
// URLRequestJobs may post clean-up tasks on destruction.
base::RunLoop().RunUntilIdle();
}
+ virtual void SetUp() {
+ SetUpFactory();
+ default_context_.set_job_factory(job_factory_.get());
+ default_context_.Init();
+ PlatformTest::SetUp();
+ }
+
+ virtual void SetUpFactory() {
+ job_factory_impl_->SetProtocolHandler("data", new DataProtocolHandler);
+#if !defined(DISABLE_FILE_SUPPORT)
+ job_factory_impl_->SetProtocolHandler(
+ "file", new FileProtocolHandler(base::MessageLoopProxy::current()));
+#endif
+ }
+
+ TestNetworkDelegate* default_network_delegate() {
+ return &default_network_delegate_;
+ }
+
+ const TestURLRequestContext& default_context() const {
+ return default_context_;
+ }
+
+
// Adds the TestJobInterceptor to the default context.
TestJobInterceptor* AddTestInterceptor() {
TestJobInterceptor* protocol_handler_ = new TestJobInterceptor();
- job_factory_.SetProtocolHandler("http", NULL);
- job_factory_.SetProtocolHandler("http", protocol_handler_);
+ job_factory_impl_->SetProtocolHandler("http", NULL);
+ job_factory_impl_->SetProtocolHandler("http", protocol_handler_);
return protocol_handler_;
}
protected:
CapturingNetLog net_log_;
TestNetworkDelegate default_network_delegate_; // Must outlive URLRequest.
- URLRequestJobFactoryImpl job_factory_;
+ URLRequestJobFactoryImpl* job_factory_impl_;
+ scoped_ptr<URLRequestJobFactory> job_factory_;
TestURLRequestContext default_context_;
};
@@ -1574,29 +1597,570 @@
EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
}
-LoadTimingInfo RunLoadTimingTest(const LoadTimingInfo& job_load_timing,
- URLRequestContext* context) {
- TestInterceptor interceptor;
- interceptor.intercept_main_request_ = true;
- interceptor.main_request_load_timing_info_ = job_load_timing;
+// An Interceptor for use with interceptor tests.
+class MockURLRequestInterceptor : public URLRequestInterceptor {
+ public:
+ // 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();
+ }
+
+ MockURLRequestInterceptor()
+ : 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),
+ use_url_request_http_job_(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) {
+ }
+
+ ~MockURLRequestInterceptor() override {
+ }
+
+ // URLRequestInterceptor implementation:
+ URLRequestJob* MaybeInterceptRequest(
+ URLRequest* request,
+ NetworkDelegate* network_delegate) const 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;
+ if (use_url_request_http_job_) {
+ return URLRequestHttpJob::Factory(request, network_delegate, "http");
+ }
+ // This job will result in error since the requested URL is not one of the
+ // URLs supported by these tests.
+ return new URLRequestTestJob(request, network_delegate, true);
+ }
+ if (!intercept_main_request_)
+ return nullptr;
+ 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) const override {
+ if (cancel_redirect_request_) {
+ cancel_redirect_request_ = false;
+ did_cancel_redirect_ = true;
+ return new CancelTestJob(request, network_delegate);
+ }
+ if (!intercept_redirect_)
+ return nullptr;
+ intercept_redirect_ = false;
+ did_intercept_redirect_ = true;
+ if (use_url_request_http_job_) {
+ return URLRequestHttpJob::Factory(request, network_delegate, "http");
+ }
+ return new URLRequestTestJob(request,
+ network_delegate,
+ redirect_headers_,
+ redirect_data_,
+ true);
+ }
+
+ URLRequestJob* MaybeInterceptResponse(
+ URLRequest* request,
+ NetworkDelegate* network_delegate) const override {
+ if (cancel_final_request_) {
+ cancel_final_request_ = false;
+ did_cancel_final_ = true;
+ return new CancelTestJob(request, network_delegate);
+ }
+ if (!intercept_final_response_)
+ return nullptr;
+ intercept_final_response_ = false;
+ did_intercept_final_ = true;
+ if (use_url_request_http_job_) {
+ return URLRequestHttpJob::Factory(request, network_delegate, "http");
+ }
+ return new URLRequestTestJob(request,
+ network_delegate,
+ final_headers_,
+ final_data_,
+ true);
+ }
+
+ void set_intercept_main_request(bool intercept_main_request) {
+ intercept_main_request_ = intercept_main_request;
+ }
+
+ void set_main_headers(const std::string& main_headers) {
+ main_headers_ = main_headers;
+ }
+
+ void set_main_data(const std::string& main_data) {
+ main_data_ = main_data;
+ }
+
+ void set_main_request_load_timing_info(
+ const LoadTimingInfo& main_request_load_timing_info) {
+ main_request_load_timing_info_ = main_request_load_timing_info;
+ }
+
+ void set_restart_main_request(bool restart_main_request) {
+ restart_main_request_ = restart_main_request;
+ }
+
+ void set_cancel_main_request(bool cancel_main_request) {
+ cancel_main_request_ = cancel_main_request;
+ }
+
+ void set_cancel_then_restart_main_request(
+ bool cancel_then_restart_main_request) {
+ cancel_then_restart_main_request_ = cancel_then_restart_main_request;
+ }
+
+ void set_simulate_main_network_error(bool simulate_main_network_error) {
+ simulate_main_network_error_ = simulate_main_network_error;
+ }
+
+ void set_intercept_redirect(bool intercept_redirect) {
+ intercept_redirect_ = intercept_redirect;
+ }
+
+ void set_redirect_headers(const std::string& redirect_headers) {
+ redirect_headers_ = redirect_headers;
+ }
+
+ void set_redirect_data(const std::string& redirect_data) {
+ redirect_data_ = redirect_data;
+ }
+
+ void set_cancel_redirect_request(bool cancel_redirect_request) {
+ cancel_redirect_request_ = cancel_redirect_request;
+ }
+
+ void set_intercept_final_response(bool intercept_final_response) {
+ intercept_final_response_ = intercept_final_response;
+ }
+
+ void set_final_headers(const std::string& final_headers) {
+ final_headers_ = final_headers;
+ }
+
+ void set_final_data(const std::string& final_data) {
+ final_data_ = final_data;
+ }
+
+ void set_cancel_final_request(bool cancel_final_request) {
+ cancel_final_request_ = cancel_final_request;
+ }
+
+ void set_use_url_request_http_job(bool use_url_request_http_job) {
+ use_url_request_http_job_ = use_url_request_http_job;
+ }
+
+ bool did_intercept_main() const {
+ return did_intercept_main_;
+ }
+
+ bool did_restart_main() const {
+ return did_restart_main_;
+ }
+
+ bool did_cancel_main() const {
+ return did_cancel_main_;
+ }
+
+ bool did_cancel_then_restart_main() const {
+ return did_cancel_then_restart_main_;
+ }
+
+ bool did_simulate_error_main() const {
+ return did_simulate_error_main_;
+ }
+
+ bool did_intercept_redirect() const {
+ return did_intercept_redirect_;
+ }
+
+ bool did_cancel_redirect() const {
+ return did_cancel_redirect_;
+ }
+
+ bool did_intercept_final() const {
+ return did_intercept_final_;
+ }
+
+ bool did_cancel_final() const {
+ return did_cancel_final_;
+ }
+
+ private:
+ // Indicate whether to intercept the main request, and if so specify the
+ // response to return and the LoadTimingInfo to use.
+ mutable bool intercept_main_request_;
+ mutable std::string main_headers_;
+ mutable std::string main_data_;
+ mutable LoadTimingInfo main_request_load_timing_info_;
+
+ // These indicate actions that can be taken within MaybeInterceptRequest.
+ mutable bool restart_main_request_;
+ mutable bool cancel_main_request_;
+ mutable bool cancel_then_restart_main_request_;
+ mutable bool simulate_main_network_error_;
+
+ // Indicate whether to intercept redirects, and if so specify the response to
+ // return.
+ mutable bool intercept_redirect_;
+ mutable std::string redirect_headers_;
+ mutable std::string redirect_data_;
+
+ // Cancel the request within MaybeInterceptRedirect.
+ mutable bool cancel_redirect_request_;
+
+ // Indicate whether to intercept the final response, and if so specify the
+ // response to return.
+ mutable bool intercept_final_response_;
+ mutable std::string final_headers_;
+ mutable std::string final_data_;
+
+ // Cancel the final request within MaybeInterceptResponse.
+ mutable bool cancel_final_request_;
+
+ // Instruct the interceptor to use a real URLRequestHTTPJob.
+ mutable bool use_url_request_http_job_;
+
+ // These indicate if the interceptor did something or not.
+ mutable bool did_intercept_main_;
+ mutable bool did_restart_main_;
+ mutable bool did_cancel_main_;
+ mutable bool did_cancel_then_restart_main_;
+ mutable bool did_simulate_error_main_;
+ mutable bool did_intercept_redirect_;
+ mutable bool did_cancel_redirect_;
+ mutable bool did_intercept_final_;
+ mutable bool did_cancel_final_;
+};
+
+// Inherit PlatformTest since we require the autorelease pool on Mac OS X.
+class URLRequestInterceptorTest : public URLRequestTest {
+ public:
+ URLRequestInterceptorTest() : URLRequestTest(), interceptor_(NULL) {
+ }
+
+ ~URLRequestInterceptorTest() override {
+ // URLRequestJobs may post clean-up tasks on destruction.
+ base::RunLoop().RunUntilIdle();
+ }
+
+ void SetUpFactory() override {
+ interceptor_ = new MockURLRequestInterceptor();
+ job_factory_.reset(new URLRequestInterceptingJobFactory(
+ job_factory_.Pass(), make_scoped_ptr(interceptor_)));
+ }
+
+ MockURLRequestInterceptor* interceptor() const {
+ return interceptor_;
+ }
+
+ private:
+ MockURLRequestInterceptor* interceptor_;
+};
+
+TEST_F(URLRequestInterceptorTest, Intercept) {
+ // Intercept the main request and respond with a simple response.
+ interceptor()->set_intercept_main_request(true);
+ interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_main_data(MockURLRequestInterceptor::ok_data());
TestDelegate d;
- scoped_ptr<URLRequest> req(context->CreateRequest(
- GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, NULL));
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ 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(nullptr, user_data0);
+ req->SetUserData(&user_data1, user_data1);
+ req->SetUserData(&user_data2, user_data2);
+ req->set_method("GET");
req->Start();
base::RunLoop().Run();
- LoadTimingInfo resulting_load_timing;
- req->GetLoadTimingInfo(&resulting_load_timing);
+ // Make sure we can retrieve our specific user data.
+ EXPECT_EQ(user_data0, req->GetUserData(nullptr));
+ EXPECT_EQ(user_data1, req->GetUserData(&user_data1));
+ EXPECT_EQ(user_data2, req->GetUserData(&user_data2));
- // None of these should be modified by the URLRequest.
- EXPECT_EQ(job_load_timing.socket_reused, resulting_load_timing.socket_reused);
- EXPECT_EQ(job_load_timing.socket_log_id, resulting_load_timing.socket_log_id);
- EXPECT_EQ(job_load_timing.send_start, resulting_load_timing.send_start);
- EXPECT_EQ(job_load_timing.send_end, resulting_load_timing.send_end);
- EXPECT_EQ(job_load_timing.receive_headers_end,
- resulting_load_timing.receive_headers_end);
+ // Check that we got one good response.
+ EXPECT_TRUE(req->status().is_success());
+ EXPECT_EQ(200, req->response_headers()->response_code());
+ EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+}
- return resulting_load_timing;
+TEST_F(URLRequestInterceptorTest, InterceptRedirect) {
+ // Intercept the main request and respond with a redirect.
+ interceptor()->set_intercept_main_request(true);
+ interceptor()->set_main_headers(
+ MockURLRequestInterceptor::redirect_headers());
+ interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data());
+
+ // Intercept that redirect and respond with a final OK response.
+ interceptor()->set_intercept_redirect(true);
+ interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that the interceptor got called as expected.
+ EXPECT_TRUE(interceptor()->did_intercept_main());
+ EXPECT_TRUE(interceptor()->did_intercept_redirect());
+
+ // Check that 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(MockURLRequestInterceptor::ok_data(), d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptServerError) {
+ // Intercept the main request to generate a server error response.
+ interceptor()->set_intercept_main_request(true);
+ interceptor()->set_main_headers(MockURLRequestInterceptor::error_headers());
+ interceptor()->set_main_data(MockURLRequestInterceptor::error_data());
+
+ // Intercept that error and respond with an OK response.
+ interceptor()->set_intercept_final_response(true);
+ interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that the interceptor got called as expected.
+ EXPECT_TRUE(interceptor()->did_intercept_main());
+ EXPECT_TRUE(interceptor()->did_intercept_final());
+
+ // Check that we got one good response.
+ EXPECT_TRUE(req->status().is_success());
+ EXPECT_EQ(200, req->response_headers()->response_code());
+ EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptNetworkError) {
+ // Intercept the main request to simulate a network error.
+ interceptor()->set_simulate_main_network_error(true);
+
+ // Intercept that error and respond with an OK response.
+ interceptor()->set_intercept_final_response(true);
+ interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that the interceptor got called as expected.
+ EXPECT_TRUE(interceptor()->did_simulate_error_main());
+ EXPECT_TRUE(interceptor()->did_intercept_final());
+
+ // Check that we received one good response.
+ EXPECT_TRUE(req->status().is_success());
+ EXPECT_EQ(200, req->response_headers()->response_code());
+ EXPECT_EQ(MockURLRequestInterceptor::ok_data(), d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRestartRequired) {
+ // Restart the main request.
+ interceptor()->set_restart_main_request(true);
+
+ // then intercept the new main request and respond with an OK response
+ interceptor()->set_intercept_main_request(true);
+ interceptor()->set_main_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_main_data(MockURLRequestInterceptor::ok_data());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that the interceptor got called as expected.
+ EXPECT_TRUE(interceptor()->did_restart_main());
+ EXPECT_TRUE(interceptor()->did_intercept_main());
+
+ // Check that 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(MockURLRequestInterceptor::ok_data(), d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelMain) {
+ // Intercept the main request and cancel from within the restarted job.
+ interceptor()->set_cancel_main_request(true);
+
+ // Set up to intercept the final response and override it with an OK response.
+ interceptor()->set_intercept_final_response(true);
+ interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that the interceptor got called as expected.
+ EXPECT_TRUE(interceptor()->did_cancel_main());
+ EXPECT_FALSE(interceptor()->did_intercept_final());
+
+ // Check that we see a canceled request.
+ EXPECT_FALSE(req->status().is_success());
+ EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelRedirect) {
+ // Intercept the main request and respond with a redirect.
+ interceptor()->set_intercept_main_request(true);
+ interceptor()->set_main_headers(
+ MockURLRequestInterceptor::redirect_headers());
+ interceptor()->set_main_data(MockURLRequestInterceptor::redirect_data());
+
+ // Intercept the redirect and cancel from within that job.
+ interceptor()->set_cancel_redirect_request(true);
+
+ // Set up to intercept the final response and override it with an OK response.
+ interceptor()->set_intercept_final_response(true);
+ interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that 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 that we see a canceled request.
+ EXPECT_FALSE(req->status().is_success());
+ EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelFinal) {
+ // Intercept the main request to simulate a network error.
+ interceptor()->set_simulate_main_network_error(true);
+
+ // Set up to intercept final the response and cancel from within that job.
+ interceptor()->set_cancel_final_request(true);
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that the interceptor got called as expected.
+ EXPECT_TRUE(interceptor()->did_simulate_error_main());
+ EXPECT_TRUE(interceptor()->did_cancel_final());
+
+ // Check that we see a canceled request.
+ EXPECT_FALSE(req->status().is_success());
+ EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
+}
+
+TEST_F(URLRequestInterceptorTest, InterceptRespectsCancelInRestart) {
+ // Intercept the main request and cancel then restart from within that job.
+ interceptor()->set_cancel_then_restart_main_request(true);
+
+ // 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());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ // Check that the interceptor got called as expected.
+ EXPECT_TRUE(interceptor()->did_cancel_then_restart_main());
+ EXPECT_FALSE(interceptor()->did_intercept_final());
+
+ // Check that we see a canceled request.
+ EXPECT_FALSE(req->status().is_success());
+ EXPECT_EQ(URLRequestStatus::CANCELED, req->status().status());
}
// "Normal" LoadTimingInfo as returned by a job. Everything is in order, not
@@ -1649,14 +2213,41 @@
return load_timing;
}
+LoadTimingInfo RunURLRequestInterceptorLoadTimingTest(
+ const LoadTimingInfo& job_load_timing,
+ const URLRequestContext& context,
+ MockURLRequestInterceptor* interceptor) {
+ interceptor->set_intercept_main_request(true);
+ interceptor->set_main_request_load_timing_info(job_load_timing);
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(context.CreateRequest(
+ GURL("http://test_intercept/foo"), DEFAULT_PRIORITY, &d, nullptr));
+ req->Start();
+ base::RunLoop().Run();
+
+ LoadTimingInfo resulting_load_timing;
+ req->GetLoadTimingInfo(&resulting_load_timing);
+
+ // None of these should be modified by the URLRequest.
+ EXPECT_EQ(job_load_timing.socket_reused, resulting_load_timing.socket_reused);
+ EXPECT_EQ(job_load_timing.socket_log_id, resulting_load_timing.socket_log_id);
+ EXPECT_EQ(job_load_timing.send_start, resulting_load_timing.send_start);
+ EXPECT_EQ(job_load_timing.send_end, resulting_load_timing.send_end);
+ EXPECT_EQ(job_load_timing.receive_headers_end,
+ resulting_load_timing.receive_headers_end);
+
+ return resulting_load_timing;
+}
+
// Basic test that the intercept + load timing tests work.
-TEST_F(URLRequestTest, InterceptLoadTiming) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTiming) {
base::TimeTicks now = base::TimeTicks::Now();
LoadTimingInfo job_load_timing =
NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, false);
LoadTimingInfo load_timing_result =
- RunLoadTimingTest(job_load_timing, &default_context_);
+ RunURLRequestInterceptorLoadTimingTest(
+ job_load_timing, default_context(), interceptor());
// Nothing should have been changed by the URLRequest.
EXPECT_EQ(job_load_timing.proxy_resolve_start,
@@ -1681,13 +2272,14 @@
}
// Another basic test, with proxy and SSL times, but no DNS times.
-TEST_F(URLRequestTest, InterceptLoadTimingProxy) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingProxy) {
base::TimeTicks now = base::TimeTicks::Now();
LoadTimingInfo job_load_timing =
NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, true);
LoadTimingInfo load_timing_result =
- RunLoadTimingTest(job_load_timing, &default_context_);
+ RunURLRequestInterceptorLoadTimingTest(
+ job_load_timing, default_context(), interceptor());
// Nothing should have been changed by the URLRequest.
EXPECT_EQ(job_load_timing.proxy_resolve_start,
@@ -1718,7 +2310,7 @@
// reused in this test (May be a preconnect).
//
// To mix things up from the test above, assumes DNS times but no SSL times.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolution) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyProxyResolution) {
base::TimeTicks now = base::TimeTicks::Now();
LoadTimingInfo job_load_timing =
NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_DNS_TIMES, true);
@@ -1732,7 +2324,8 @@
now - base::TimeDelta::FromDays(1);
LoadTimingInfo load_timing_result =
- RunLoadTimingTest(job_load_timing, &default_context_);
+ RunURLRequestInterceptorLoadTimingTest(
+ job_load_timing, default_context(), interceptor());
// Proxy times, connect times, and DNS times should all be replaced with
// request_start.
@@ -1755,14 +2348,16 @@
}
// Same as above, but in the reused case.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyProxyResolutionReused) {
+TEST_F(URLRequestInterceptorTest,
+ InterceptLoadTimingEarlyProxyResolutionReused) {
base::TimeTicks now = base::TimeTicks::Now();
LoadTimingInfo job_load_timing = NormalLoadTimingInfoReused(now, true);
job_load_timing.proxy_resolve_start = now - base::TimeDelta::FromDays(4);
job_load_timing.proxy_resolve_end = now - base::TimeDelta::FromDays(3);
LoadTimingInfo load_timing_result =
- RunLoadTimingTest(job_load_timing, &default_context_);
+ RunURLRequestInterceptorLoadTimingTest(
+ job_load_timing, default_context(), interceptor());
// Proxy times and connect times should all be replaced with request_start.
EXPECT_EQ(load_timing_result.request_start,
@@ -1779,7 +2374,7 @@
// not considered reused in this test (May be a preconnect).
//
// To mix things up, the request has SSL times, but no DNS times.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnect) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnect) {
base::TimeTicks now = base::TimeTicks::Now();
LoadTimingInfo job_load_timing =
NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_SSL_TIMES, false);
@@ -1791,7 +2386,8 @@
now - base::TimeDelta::FromDays(4);
LoadTimingInfo load_timing_result =
- RunLoadTimingTest(job_load_timing, &default_context_);
+ RunURLRequestInterceptorLoadTimingTest(
+ job_load_timing, default_context(), interceptor());
// Connect times, and SSL times should be replaced with request_start.
EXPECT_EQ(load_timing_result.request_start,
@@ -1813,7 +2409,7 @@
// test (May be a preconnect).
//
// In this test, there are no SSL or DNS times.
-TEST_F(URLRequestTest, InterceptLoadTimingEarlyConnectWithProxy) {
+TEST_F(URLRequestInterceptorTest, InterceptLoadTimingEarlyConnectWithProxy) {
base::TimeTicks now = base::TimeTicks::Now();
LoadTimingInfo job_load_timing =
NormalLoadTimingInfo(now, CONNECT_TIMING_HAS_CONNECT_TIMES_ONLY, true);
@@ -1823,7 +2419,8 @@
now - base::TimeDelta::FromDays(2);
LoadTimingInfo load_timing_result =
- RunLoadTimingTest(job_load_timing, &default_context_);
+ RunURLRequestInterceptorLoadTimingTest(
+ job_load_timing, default_context(), interceptor());
// Connect times should be replaced with proxy_resolve_end.
EXPECT_EQ(load_timing_result.proxy_resolve_end,
@@ -2665,6 +3262,11 @@
return is_success;
}
+ LocalHttpTestServer* test_server() {
+ return &test_server_;
+ }
+
+ protected:
LocalHttpTestServer test_server_;
};
@@ -5166,7 +5768,7 @@
EXPECT_FALSE(data_protocol_handler.IsSafeRedirectTarget(data_url));
// Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
- EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(data_url));
+ EXPECT_FALSE(job_factory_->IsSafeRedirectTarget(data_url));
}
#if !defined(DISABLE_FILE_SUPPORT)
@@ -5177,7 +5779,7 @@
EXPECT_FALSE(file_protocol_handler.IsSafeRedirectTarget(file_url));
// Test URLRequestJobFactoryImpl::IsSafeRedirectTarget().
- EXPECT_FALSE(job_factory_.IsSafeRedirectTarget(file_url));
+ EXPECT_FALSE(job_factory_->IsSafeRedirectTarget(file_url));
}
TEST_F(URLRequestTestHTTP, RestrictFileRedirects) {
@@ -6446,6 +7048,124 @@
EXPECT_EQ(ERR_NETWORK_IO_SUSPENDED, req->status().error());
}
+class URLRequestInterceptorTestHTTP : public URLRequestTestHTTP {
+ public:
+ // TODO(bengr): Merge this with the URLRequestInterceptorHTTPTest fixture,
+ // ideally remove the dependency on URLRequestTestJob, and maybe move these
+ // tests into the factory tests.
+ URLRequestInterceptorTestHTTP() : URLRequestTestHTTP(), interceptor_(NULL) {
+ }
+
+ void SetUpFactory() override {
+ interceptor_ = new MockURLRequestInterceptor();
+ job_factory_.reset(new URLRequestInterceptingJobFactory(
+ job_factory_.Pass(), make_scoped_ptr(interceptor_)));
+ }
+
+ MockURLRequestInterceptor* interceptor() const {
+ return interceptor_;
+ }
+
+ private:
+ MockURLRequestInterceptor* interceptor_;
+};
+
+TEST_F(URLRequestInterceptorTestHTTP,
+ NetworkDelegateNotificationOnRedirectIntercept) {
+ interceptor()->set_intercept_redirect(true);
+ interceptor()->set_redirect_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_redirect_data(MockURLRequestInterceptor::ok_data());
+
+ ASSERT_TRUE(test_server()->Start());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ test_server()->GetURL("files/redirect-test.html"), DEFAULT_PRIORITY,
+ &d, nullptr));
+ req->Start();
+ base::RunLoop().Run();
+
+ 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(MockURLRequestInterceptor::ok_data(), d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+
+ EXPECT_EQ(1, default_network_delegate()->created_requests());
+ EXPECT_EQ(1, default_network_delegate()->before_send_headers_count());
+ EXPECT_EQ(1, default_network_delegate()->headers_received_count());
+}
+
+TEST_F(URLRequestInterceptorTestHTTP,
+ NetworkDelegateNotificationOnErrorIntercept) {
+ // Intercept that error and respond with an OK response.
+ interceptor()->set_intercept_final_response(true);
+ interceptor()->set_final_headers(MockURLRequestInterceptor::ok_headers());
+ interceptor()->set_final_data(MockURLRequestInterceptor::ok_data());
+ default_network_delegate()->set_can_be_intercepted_on_error(true);
+
+ ASSERT_TRUE(test_server()->Start());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ test_server()->GetURL("files/two-content-lengths.html"), DEFAULT_PRIORITY,
+ &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ EXPECT_TRUE(interceptor()->did_intercept_final());
+
+ // 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(MockURLRequestInterceptor::ok_data(), d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+
+ EXPECT_EQ(1, default_network_delegate()->created_requests());
+ EXPECT_EQ(1, default_network_delegate()->before_send_headers_count());
+ EXPECT_EQ(0, default_network_delegate()->headers_received_count());
+}
+
+TEST_F(URLRequestInterceptorTestHTTP,
+ NetworkDelegateNotificationOnResponseIntercept) {
+ // Intercept that error and respond with an OK response.
+ interceptor()->set_intercept_final_response(true);
+
+ // Intercept with a real URLRequestHttpJob.
+ interceptor()->set_use_url_request_http_job(true);
+
+ ASSERT_TRUE(test_server()->Start());
+
+ TestDelegate d;
+ scoped_ptr<URLRequest> req(default_context().CreateRequest(
+ test_server()->GetURL("files/simple.html"), DEFAULT_PRIORITY,
+ &d, nullptr));
+ req->set_method("GET");
+ req->Start();
+ base::RunLoop().Run();
+
+ EXPECT_TRUE(interceptor()->did_intercept_final());
+
+ // 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("hello", d.data_received());
+ EXPECT_EQ(1, d.response_started_count());
+ EXPECT_EQ(0, d.received_redirect_count());
+
+ EXPECT_EQ(1, default_network_delegate()->created_requests());
+ EXPECT_EQ(2, default_network_delegate()->before_send_headers_count());
+ EXPECT_EQ(2, default_network_delegate()->headers_received_count());
+}
+
class HTTPSRequestTest : public testing::Test {
public:
HTTPSRequestTest() : default_context_(true) {
@@ -7590,7 +8310,7 @@
}
static bool SystemSupportsOCSP() {
-#if defined(USE_OPENSSL)
+#if defined(USE_OPENSSL_CERTS)
// http://crbug.com/117478 - OpenSSL does not support OCSP.
return false;
#elif defined(OS_WIN)
@@ -7603,6 +8323,16 @@
#endif
}
+static bool SystemSupportsOCSPStapling() {
+#if defined(USE_NSS)
+ return true;
+#elif defined(OS_WIN)
+ return base::win::GetVersion() >= base::win::VERSION_VISTA;
+#else
+ return false;
+#endif
+}
+
TEST_F(HTTPSOCSPTest, Valid) {
if (!SystemSupportsOCSP()) {
LOG(WARNING) << "Skipping test because system doesn't support OCSP";
@@ -7666,6 +8396,51 @@
EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
}
+TEST_F(HTTPSOCSPTest, ValidStapled) {
+ if (!SystemSupportsOCSPStapling()) {
+ LOG(WARNING)
+ << "Skipping test because system doesn't support OCSP stapling";
+ return;
+ }
+
+ SpawnedTestServer::SSLOptions ssl_options(
+ SpawnedTestServer::SSLOptions::CERT_AUTO);
+ ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_OK;
+ ssl_options.staple_ocsp_response = true;
+ ssl_options.ocsp_server_unavailable = true;
+
+ CertStatus cert_status;
+ DoConnection(ssl_options, &cert_status);
+
+ EXPECT_EQ(0u, cert_status & CERT_STATUS_ALL_ERRORS);
+
+ EXPECT_EQ(SystemUsesChromiumEVMetadata(),
+ static_cast<bool>(cert_status & CERT_STATUS_IS_EV));
+
+ EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
+}
+
+TEST_F(HTTPSOCSPTest, RevokedStapled) {
+ if (!SystemSupportsOCSPStapling()) {
+ LOG(WARNING)
+ << "Skipping test because system doesn't support OCSP stapling";
+ return;
+ }
+
+ SpawnedTestServer::SSLOptions ssl_options(
+ SpawnedTestServer::SSLOptions::CERT_AUTO);
+ ssl_options.ocsp_status = SpawnedTestServer::SSLOptions::OCSP_REVOKED;
+ ssl_options.staple_ocsp_response = true;
+ ssl_options.ocsp_server_unavailable = true;
+
+ CertStatus cert_status;
+ DoConnection(ssl_options, &cert_status);
+
+ EXPECT_EQ(CERT_STATUS_REVOKED, cert_status & CERT_STATUS_ALL_ERRORS);
+ EXPECT_FALSE(cert_status & CERT_STATUS_IS_EV);
+ EXPECT_TRUE(cert_status & CERT_STATUS_REV_CHECKING_ENABLED);
+}
+
class HTTPSHardFailTest : public HTTPSOCSPTest {
protected:
void SetupContext(URLRequestContext* context) override {
@@ -7677,7 +8452,6 @@
}
};
-
TEST_F(HTTPSHardFailTest, FailsOnOCSPInvalid) {
if (!SystemSupportsOCSP()) {
LOG(WARNING) << "Skipping test because system doesn't support OCSP";
diff --git a/net/websockets/PRESUBMIT.py b/net/websockets/PRESUBMIT.py
deleted file mode 100644
index 1da441c..0000000
--- a/net/websockets/PRESUBMIT.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright 2013 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Chromium presubmit script for src/net/websockets.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details on the presubmit API built into gcl.
-"""
-
-
-# TODO(ricea): Remove this once the old implementation has been removed and the
-# list of files in the README file is no longer needed.
-def _CheckReadMeComplete(input_api, output_api):
- """Verifies that any new files have been added to the README file.
-
- Checks that if any source files were added in this CL, that they were
- also added to the README file. We do not warn about pre-existing
- errors, as that would be annoying.
-
- Args:
- input_api: The InputApi object provided by the presubmit framework.
- output_api: The OutputApi object provided by the framework.
-
- Returns:
- A list of zero or more PresubmitPromptWarning objects.
- """
- # None passed to AffectedSourceFiles means "use the default filter", which
- # does what we want, ie. returns files in the CL with filenames that look like
- # source code.
- added_source_filenames = set(input_api.basename(af.LocalPath())
- for af in input_api.AffectedSourceFiles(None)
- if af.Action().startswith('A'))
- if not added_source_filenames:
- return []
- readme = input_api.AffectedSourceFiles(
- lambda af: af.LocalPath().endswith('/README'))
- if not readme:
- return [output_api.PresubmitPromptWarning(
- 'One or more files were added to net/websockets without being added\n'
- 'to net/websockets/README.\n', added_source_filenames)]
- readme_added_filenames = set(line.strip() for line in readme[0].NewContents()
- if line.strip() in added_source_filenames)
- if readme_added_filenames < added_source_filenames:
- return [output_api.PresubmitPromptWarning(
- 'One or more files added to net/websockets but not found in the README '
- 'file.\n', added_source_filenames - readme_added_filenames)]
- else:
- return []
-
-
-def CheckChangeOnUpload(input_api, output_api):
- return _CheckReadMeComplete(input_api, output_api)
-
-
-def CheckChangeOnCommit(input_api, output_api):
- return _CheckReadMeComplete(input_api, output_api)
diff --git a/net/websockets/README b/net/websockets/README
deleted file mode 100644
index efe7a59..0000000
--- a/net/websockets/README
+++ /dev/null
@@ -1,91 +0,0 @@
-This directory contains files related to Chromium's WebSocket
-implementation. See http://www.websocket.org/ for an explanation of WebSockets.
-
-As of April 2013, the contents of this directory are in a transitional state,
-and contain parts of two different WebSocket implementations.
-
-The following files are part of the legacy implementation. The legacy
-implementation performs WebSocket framing within Blink and presents a
-low-level socket-like interface to the renderer process. It is described in the
-design doc at
-https://docs.google.com/a/google.com/document/d/1_R6YjCIrm4kikJ3YeapcOU2Keqr3lVUPd-OeaIJ93qQ/preview
-
-websocket_handshake_handler_test.cc
-websocket_handshake_handler_spdy_test.cc
-websocket_job.cc
-websocket_job.h
-websocket_job_test.cc
-websocket_net_log_params.cc
-websocket_net_log_params.h
-websocket_net_log_params_test.cc
-websocket_throttle.cc
-websocket_throttle.h
-websocket_throttle_test.cc
-
-The following files are part of the new implementation. The new implementation
-performs framing and implements protocol semantics in the browser process, and
-presents a high-level interface to the renderer process similar to a
-multiplexing proxy. This is the default implementation from M38.
-
-websocket_basic_handshake_stream.cc
-websocket_basic_handshake_stream.h
-websocket_basic_stream.cc
-websocket_basic_stream.h
-websocket_basic_stream_test.cc
-websocket_channel.cc
-websocket_channel.h
-websocket_channel_test.cc
-websocket_deflate_predictor.h
-websocket_deflate_predictor_impl.cc
-websocket_deflate_predictor_impl.h
-websocket_deflate_predictor_impl_test.cc
-websocket_deflate_stream.cc
-websocket_deflate_stream.h
-websocket_deflate_stream_test.cc
-websocket_deflater.cc
-websocket_deflater.h
-websocket_deflater_test.cc
-websocket_errors.cc
-websocket_errors.h
-websocket_errors_test.cc
-websocket_event_interface.h
-websocket_extension.cc
-websocket_extension.h
-websocket_extension_parser.cc
-websocket_extension_parser.h
-websocket_extension_parser_test.cc
-websocket_frame.cc
-websocket_frame.h
-websocket_frame_parser.cc
-websocket_frame_parser.h
-websocket_frame_parser_test.cc
-websocket_frame_test.cc
-websocket_frame_perftest.cc
-websocket_handshake_stream_base.h
-websocket_handshake_stream_create_helper.cc
-websocket_handshake_stream_create_helper.h
-websocket_handshake_stream_create_helper_test.cc
-websocket_handshake_request_info.cc
-websocket_handshake_request_info.h
-websocket_handshake_response_info.cc
-websocket_handshake_response_info.h
-websocket_inflater.cc
-websocket_inflater.h
-websocket_inflater_test.cc
-websocket_mux.h
-websocket_stream.cc
-websocket_stream.h
-websocket_stream_test.cc
-websocket_test_util.cc
-websocket_test_util.h
-
-These files are shared between the old and new implementations.
-
-websocket_handshake_constants.cc
-websocket_handshake_constants.h
-websocket_handshake_handler.cc
-websocket_handshake_handler.h
-
-A pre-submit check helps us keep this README file up-to-date:
-
-PRESUBMIT.py
diff --git a/net/websockets/websocket_channel.cc b/net/websockets/websocket_channel.cc
index 598b5e6..30abb2db 100644
--- a/net/websockets/websocket_channel.cc
+++ b/net/websockets/websocket_channel.cc
@@ -44,9 +44,16 @@
const int kDefaultSendQuotaLowWaterMark = 1 << 16;
const int kDefaultSendQuotaHighWaterMark = 1 << 17;
const size_t kWebSocketCloseCodeLength = 2;
-// This timeout is based on TCPMaximumSegmentLifetime * 2 from
-// MainThreadWebSocketChannel.cpp in Blink.
-const int kClosingHandshakeTimeoutSeconds = 2 * 2 * 60;
+// Timeout for waiting for the server to acknowledge a closing handshake.
+const int kClosingHandshakeTimeoutSeconds = 60;
+// We wait for the server to close the underlying connection as recommended in
+// https://tools.ietf.org/html/rfc6455#section-7.1.1
+// We don't use 2MSL since there're server implementations that don't follow
+// the recommendation and wait for the client to close the underlying
+// connection. It leads to unnecessarily long time before CloseEvent
+// invocation. We want to avoid this rather than strictly following the spec
+// recommendation.
+const int kUnderlyingConnectionCloseTimeoutSeconds = 2;
typedef WebSocketEventInterface::ChannelState ChannelState;
const ChannelState CHANNEL_ALIVE = WebSocketEventInterface::CHANNEL_ALIVE;
@@ -296,7 +303,10 @@
send_quota_high_water_mark_(kDefaultSendQuotaHighWaterMark),
current_send_quota_(0),
current_receive_quota_(0),
- timeout_(base::TimeDelta::FromSeconds(kClosingHandshakeTimeoutSeconds)),
+ closing_handshake_timeout_(base::TimeDelta::FromSeconds(
+ kClosingHandshakeTimeoutSeconds)),
+ underlying_connection_close_timeout_(base::TimeDelta::FromSeconds(
+ kUnderlyingConnectionCloseTimeoutSeconds)),
has_received_close_frame_(false),
received_close_code_(0),
state_(FRESHLY_CONSTRUCTED),
@@ -312,7 +322,7 @@
stream_.reset();
// The timer may have a callback pointing back to us, so stop it just in case
// someone decides to run the event loop from their destructor.
- timer_.Stop();
+ close_timer_.Stop();
}
void WebSocketChannel::SendAddChannelRequest(
@@ -478,6 +488,15 @@
NOTREACHED() << "StartClosingHandshake() called in state " << state_;
return;
}
+
+ DCHECK(!close_timer_.IsRunning());
+ // This use of base::Unretained() is safe because we stop the timer in the
+ // destructor.
+ close_timer_.Start(
+ FROM_HERE,
+ closing_handshake_timeout_,
+ base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
+
// Javascript actually only permits 1000 and 3000-4999, but the implementation
// itself may produce different codes. The length of |reason| is also checked
// by Javascript.
@@ -513,7 +532,12 @@
void WebSocketChannel::SetClosingHandshakeTimeoutForTesting(
base::TimeDelta delay) {
- timeout_ = delay;
+ closing_handshake_timeout_ = delay;
+}
+
+void WebSocketChannel::SetUnderlyingConnectionCloseTimeoutForTesting(
+ base::TimeDelta delay) {
+ underlying_connection_close_timeout_ = delay;
}
void WebSocketChannel::SendAddChannelRequestWithSuppliedCreator(
@@ -839,10 +863,20 @@
switch (state_) {
case CONNECTED:
SetState(RECV_CLOSED);
+
if (SendClose(code, reason) == CHANNEL_DELETED)
return CHANNEL_DELETED;
DCHECK_EQ(RECV_CLOSED, state_);
+
SetState(CLOSE_WAIT);
+ DCHECK(!close_timer_.IsRunning());
+ // This use of base::Unretained() is safe because we stop the timer
+ // in the destructor.
+ close_timer_.Start(
+ FROM_HERE,
+ underlying_connection_close_timeout_,
+ base::Bind(
+ &WebSocketChannel::CloseTimeout, base::Unretained(this)));
if (event_interface_->OnClosingHandshake() == CHANNEL_DELETED)
return CHANNEL_DELETED;
@@ -853,6 +887,16 @@
case SEND_CLOSED:
SetState(CLOSE_WAIT);
+ DCHECK(close_timer_.IsRunning());
+ close_timer_.Stop();
+ // This use of base::Unretained() is safe because we stop the timer
+ // in the destructor.
+ close_timer_.Start(
+ FROM_HERE,
+ underlying_connection_close_timeout_,
+ base::Bind(
+ &WebSocketChannel::CloseTimeout, base::Unretained(this)));
+
// From RFC6455 section 7.1.5: "Each endpoint
// will see the status code sent by the other end as _The WebSocket
// Connection Close Code_."
@@ -1027,12 +1071,6 @@
std::copy(
reason.begin(), reason.end(), body->data() + kWebSocketCloseCodeLength);
}
- // This use of base::Unretained() is safe because we stop the timer in the
- // destructor.
- timer_.Start(
- FROM_HERE,
- timeout_,
- base::Bind(&WebSocketChannel::CloseTimeout, base::Unretained(this)));
if (SendFrameFromIOBuffer(
true, WebSocketFrameHeader::kOpCodeClose, body, size) ==
CHANNEL_DELETED)
diff --git a/net/websockets/websocket_channel.h b/net/websockets/websocket_channel.h
index 59e50a1..4df6a62 100644
--- a/net/websockets/websocket_channel.h
+++ b/net/websockets/websocket_channel.h
@@ -110,6 +110,11 @@
// set it to a very small value for testing purposes.
void SetClosingHandshakeTimeoutForTesting(base::TimeDelta delay);
+ // The default timout for the underlying connection close is a sensible value
+ // (see kUnderlyingConnectionCloseTimeoutSeconds in websocket_channel.cc).
+ // However, we can set it to a very small value for testing purposes.
+ void SetUnderlyingConnectionCloseTimeoutForTesting(base::TimeDelta delay);
+
// Called when the stream starts the WebSocket Opening Handshake.
// This method is public for testing.
void OnStartOpeningHandshake(
@@ -371,10 +376,14 @@
uint64 current_receive_quota_;
// Timer for the closing handshake.
- base::OneShotTimer<WebSocketChannel> timer_;
+ base::OneShotTimer<WebSocketChannel> close_timer_;
// Timeout for the closing handshake.
- base::TimeDelta timeout_;
+ base::TimeDelta closing_handshake_timeout_;
+
+ // Timeout for the underlying connection close after completion of closing
+ // handshake.
+ base::TimeDelta underlying_connection_close_timeout_;
// Storage for the status code and reason from the time the Close frame
// arrives until the connection is closed and they are passed to
diff --git a/net/websockets/websocket_channel_test.cc b/net/websockets/websocket_channel_test.cc
index f814f10..d5ec3da 100644
--- a/net/websockets/websocket_channel_test.cc
+++ b/net/websockets/websocket_channel_test.cc
@@ -127,6 +127,8 @@
// kDefaultSendQuotaLowWaterMark change.
const size_t kDefaultQuotaRefreshTrigger = (1 << 16) + 1;
+const int kVeryBigTimeoutMillis = 60 * 60 * 24 * 1000;
+
// TestTimeouts::tiny_timeout() is 100ms! I could run halfway around the world
// in that time! I would like my tests to run a bit quicker.
const int kVeryTinyTimeoutMillis = 1;
@@ -2145,6 +2147,8 @@
// was fired by the behaviour of the WebSocketChannel object.
channel_->SetClosingHandshakeTimeoutForTesting(
TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
+ channel_->SetUnderlyingConnectionCloseTimeoutForTesting(
+ TimeDelta::FromMilliseconds(kVeryBigTimeoutMillis));
channel_->StartClosingHandshake(kWebSocketNormalClosure, "");
checkpoint.Call(1);
completion.WaitForResult();
@@ -2175,6 +2179,8 @@
}
CreateChannelAndConnectSuccessfully();
channel_->SetClosingHandshakeTimeoutForTesting(
+ TimeDelta::FromMilliseconds(kVeryBigTimeoutMillis));
+ channel_->SetUnderlyingConnectionCloseTimeoutForTesting(
TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
checkpoint.Call(1);
completion.WaitForResult();
@@ -3304,6 +3310,8 @@
channel_->SendFlowControl(kPlentyOfQuota);
channel_->SetClosingHandshakeTimeoutForTesting(
TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
+ channel_->SetUnderlyingConnectionCloseTimeoutForTesting(
+ TimeDelta::FromMilliseconds(kVeryTinyTimeoutMillis));
connect_data_.creator.connect_delegate->OnSuccess(stream_.Pass());
}
};
diff --git a/net/websockets/websocket_handshake_handler.cc b/net/websockets/websocket_handshake_handler.cc
index 6324710..6bcc230 100644
--- a/net/websockets/websocket_handshake_handler.cc
+++ b/net/websockets/websocket_handshake_handler.cc
@@ -4,346 +4,12 @@
#include "net/websockets/websocket_handshake_handler.h"
-#include <limits>
-
#include "base/base64.h"
+#include "base/logging.h"
#include "base/sha1.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_piece.h"
-#include "base/strings/string_tokenizer.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/http/http_request_headers.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
#include "net/websockets/websocket_handshake_constants.h"
-#include "url/gurl.h"
namespace net {
-namespace {
-
-const int kVersionHeaderValueForRFC6455 = 13;
-
-// Splits |handshake_message| into Status-Line or Request-Line (including CRLF)
-// and headers (excluding 2nd CRLF of double CRLFs at the end of a handshake
-// response).
-void ParseHandshakeHeader(
- const char* handshake_message, int len,
- std::string* request_line,
- std::string* headers) {
- size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n");
- if (i == base::StringPiece::npos) {
- *request_line = std::string(handshake_message, len);
- *headers = "";
- return;
- }
- // |request_line| includes \r\n.
- *request_line = std::string(handshake_message, i + 2);
-
- int header_len = len - (i + 2) - 2;
- if (header_len > 0) {
- // |handshake_message| includes trailing \r\n\r\n.
- // |headers| doesn't include 2nd \r\n.
- *headers = std::string(handshake_message + i + 2, header_len);
- } else {
- *headers = "";
- }
-}
-
-void FetchHeaders(const std::string& headers,
- const char* const headers_to_get[],
- size_t headers_to_get_len,
- std::vector<std::string>* values) {
- net::HttpUtil::HeadersIterator iter(headers.begin(), headers.end(), "\r\n");
- while (iter.GetNext()) {
- for (size_t i = 0; i < headers_to_get_len; i++) {
- if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(),
- headers_to_get[i])) {
- values->push_back(iter.values());
- }
- }
- }
-}
-
-bool GetHeaderName(std::string::const_iterator line_begin,
- std::string::const_iterator line_end,
- std::string::const_iterator* name_begin,
- std::string::const_iterator* name_end) {
- std::string::const_iterator colon = std::find(line_begin, line_end, ':');
- if (colon == line_end) {
- return false;
- }
- *name_begin = line_begin;
- *name_end = colon;
- if (*name_begin == *name_end || net::HttpUtil::IsLWS(**name_begin))
- return false;
- net::HttpUtil::TrimLWS(name_begin, name_end);
- return true;
-}
-
-// Similar to HttpUtil::StripHeaders, but it preserves malformed headers, that
-// is, lines that are not formatted as "<name>: <value>\r\n".
-std::string FilterHeaders(
- const std::string& headers,
- const char* const headers_to_remove[],
- size_t headers_to_remove_len) {
- std::string filtered_headers;
-
- base::StringTokenizer lines(headers.begin(), headers.end(), "\r\n");
- while (lines.GetNext()) {
- std::string::const_iterator line_begin = lines.token_begin();
- std::string::const_iterator line_end = lines.token_end();
- std::string::const_iterator name_begin;
- std::string::const_iterator name_end;
- bool should_remove = false;
- if (GetHeaderName(line_begin, line_end, &name_begin, &name_end)) {
- for (size_t i = 0; i < headers_to_remove_len; ++i) {
- if (LowerCaseEqualsASCII(name_begin, name_end, headers_to_remove[i])) {
- should_remove = true;
- break;
- }
- }
- }
- if (!should_remove) {
- filtered_headers.append(line_begin, line_end);
- filtered_headers.append("\r\n");
- }
- }
- return filtered_headers;
-}
-
-bool CheckVersionInRequest(const std::string& request_headers) {
- std::vector<std::string> values;
- const char* const headers_to_get[1] = {
- websockets::kSecWebSocketVersionLowercase};
- FetchHeaders(request_headers, headers_to_get, 1, &values);
- DCHECK_LE(values.size(), 1U);
- if (values.empty())
- return false;
-
- int version;
- bool conversion_success = base::StringToInt(values[0], &version);
- if (!conversion_success)
- return false;
-
- return version == kVersionHeaderValueForRFC6455;
-}
-
-// Append a header to a string. Equivalent to
-// response_message += header + ": " + value + "\r\n"
-// but avoids unnecessary allocations and copies.
-void AppendHeader(const base::StringPiece& header,
- const base::StringPiece& value,
- std::string* response_message) {
- static const char kColonSpace[] = ": ";
- const size_t kColonSpaceSize = sizeof(kColonSpace) - 1;
- static const char kCrNl[] = "\r\n";
- const size_t kCrNlSize = sizeof(kCrNl) - 1;
-
- size_t extra_size =
- header.size() + kColonSpaceSize + value.size() + kCrNlSize;
- response_message->reserve(response_message->size() + extra_size);
- response_message->append(header.begin(), header.end());
- response_message->append(kColonSpace, kColonSpace + kColonSpaceSize);
- response_message->append(value.begin(), value.end());
- response_message->append(kCrNl, kCrNl + kCrNlSize);
-}
-
-} // namespace
-
-WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler()
- : original_length_(0),
- raw_length_(0) {}
-
-bool WebSocketHandshakeRequestHandler::ParseRequest(
- const char* data, int length) {
- DCHECK_GT(length, 0);
- std::string input(data, length);
- int input_header_length =
- HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0);
- if (input_header_length <= 0)
- return false;
-
- ParseHandshakeHeader(input.data(),
- input_header_length,
- &request_line_,
- &headers_);
-
- if (!CheckVersionInRequest(headers_)) {
- NOTREACHED();
- return false;
- }
-
- original_length_ = input_header_length;
- return true;
-}
-
-size_t WebSocketHandshakeRequestHandler::original_length() const {
- return original_length_;
-}
-
-void WebSocketHandshakeRequestHandler::AppendHeaderIfMissing(
- const std::string& name, const std::string& value) {
- DCHECK(!headers_.empty());
- HttpUtil::AppendHeaderIfMissing(name.c_str(), value, &headers_);
-}
-
-void WebSocketHandshakeRequestHandler::RemoveHeaders(
- const char* const headers_to_remove[],
- size_t headers_to_remove_len) {
- DCHECK(!headers_.empty());
- headers_ = FilterHeaders(
- headers_, headers_to_remove, headers_to_remove_len);
-}
-
-HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo(
- const GURL& url, std::string* challenge) {
- HttpRequestInfo request_info;
- request_info.url = url;
- size_t method_end = base::StringPiece(request_line_).find_first_of(" ");
- if (method_end != base::StringPiece::npos)
- request_info.method = std::string(request_line_.data(), method_end);
-
- request_info.extra_headers.Clear();
- request_info.extra_headers.AddHeadersFromString(headers_);
-
- request_info.extra_headers.RemoveHeader(websockets::kUpgrade);
- request_info.extra_headers.RemoveHeader(HttpRequestHeaders::kConnection);
-
- std::string key;
- bool header_present = request_info.extra_headers.GetHeader(
- websockets::kSecWebSocketKey, &key);
- DCHECK(header_present);
- request_info.extra_headers.RemoveHeader(websockets::kSecWebSocketKey);
- *challenge = key;
- return request_info;
-}
-
-bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock(
- const GURL& url,
- SpdyHeaderBlock* headers,
- std::string* challenge,
- int spdy_protocol_version) {
- // Construct opening handshake request headers as a SPDY header block.
- // For details, see WebSocket Layering over SPDY/3 Draft 8.
- if (spdy_protocol_version <= 2) {
- (*headers)["path"] = url.path();
- (*headers)["version"] = "WebSocket/13";
- (*headers)["scheme"] = url.scheme();
- } else {
- (*headers)[":path"] = url.path();
- (*headers)[":version"] = "WebSocket/13";
- (*headers)[":scheme"] = url.scheme();
- }
-
- HttpUtil::HeadersIterator iter(headers_.begin(), headers_.end(), "\r\n");
- while (iter.GetNext()) {
- if (LowerCaseEqualsASCII(iter.name_begin(),
- iter.name_end(),
- websockets::kUpgradeLowercase) ||
- LowerCaseEqualsASCII(
- iter.name_begin(), iter.name_end(), "connection") ||
- LowerCaseEqualsASCII(iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketVersionLowercase)) {
- // These headers must be ignored.
- continue;
- } else if (LowerCaseEqualsASCII(iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketKeyLowercase)) {
- *challenge = iter.values();
- // Sec-WebSocket-Key is not sent to the server.
- continue;
- } else if (LowerCaseEqualsASCII(
- iter.name_begin(), iter.name_end(), "host") ||
- LowerCaseEqualsASCII(
- iter.name_begin(), iter.name_end(), "origin") ||
- LowerCaseEqualsASCII(
- iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketProtocolLowercase) ||
- LowerCaseEqualsASCII(
- iter.name_begin(),
- iter.name_end(),
- websockets::kSecWebSocketExtensionsLowercase)) {
- // TODO(toyoshim): Some WebSocket extensions may not be compatible with
- // SPDY. We should omit them from a Sec-WebSocket-Extension header.
- std::string name;
- if (spdy_protocol_version <= 2)
- name = base::StringToLowerASCII(iter.name());
- else
- name = ":" + base::StringToLowerASCII(iter.name());
- (*headers)[name] = iter.values();
- continue;
- }
- // Others should be sent out to |headers|.
- std::string name = base::StringToLowerASCII(iter.name());
- SpdyHeaderBlock::iterator found = headers->find(name);
- if (found == headers->end()) {
- (*headers)[name] = iter.values();
- } else {
- // For now, websocket doesn't use multiple headers, but follows to http.
- found->second.append(1, '\0'); // +=() doesn't append 0's
- found->second.append(iter.values());
- }
- }
-
- return true;
-}
-
-std::string WebSocketHandshakeRequestHandler::GetRawRequest() {
- DCHECK(!request_line_.empty());
- DCHECK(!headers_.empty());
-
- std::string raw_request = request_line_ + headers_ + "\r\n";
- raw_length_ = raw_request.size();
- return raw_request;
-}
-
-size_t WebSocketHandshakeRequestHandler::raw_length() const {
- DCHECK_GT(raw_length_, 0);
- return raw_length_;
-}
-
-WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler()
- : original_header_length_(0) {}
-
-WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {}
-
-size_t WebSocketHandshakeResponseHandler::ParseRawResponse(
- const char* data, int length) {
- DCHECK_GT(length, 0);
- if (HasResponse()) {
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
-
- return 0;
- }
-
- size_t old_original_length = original_.size();
-
- original_.append(data, length);
- // TODO(ukai): fail fast when response gives wrong status code.
- original_header_length_ = HttpUtil::LocateEndOfHeaders(
- original_.data(), original_.size(), 0);
- if (!HasResponse())
- return length;
-
- ParseHandshakeHeader(original_.data(),
- original_header_length_,
- &status_line_,
- &headers_);
- int header_size = status_line_.size() + headers_.size();
- DCHECK_GE(original_header_length_, header_size);
- header_separator_ = std::string(original_.data() + header_size,
- original_header_length_ - header_size);
- return original_header_length_ - old_original_length;
-}
-
-bool WebSocketHandshakeResponseHandler::HasResponse() const {
- return original_header_length_ > 0 &&
- static_cast<size_t>(original_header_length_) <= original_.size();
-}
void ComputeSecWebSocketAccept(const std::string& key,
std::string* accept) {
@@ -354,145 +20,4 @@
base::Base64Encode(hash, accept);
}
-bool WebSocketHandshakeResponseHandler::ParseResponseInfo(
- const HttpResponseInfo& response_info,
- const std::string& challenge) {
- if (!response_info.headers.get())
- return false;
-
- // TODO(ricea): Eliminate all the reallocations and string copies.
- std::string response_message;
- response_message = response_info.headers->GetStatusLine();
- response_message += "\r\n";
-
- AppendHeader(websockets::kUpgrade,
- websockets::kWebSocketLowercase,
- &response_message);
-
- AppendHeader(
- HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
-
- std::string websocket_accept;
- ComputeSecWebSocketAccept(challenge, &websocket_accept);
- AppendHeader(
- websockets::kSecWebSocketAccept, websocket_accept, &response_message);
-
- void* iter = NULL;
- std::string name;
- std::string value;
- while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
- AppendHeader(name, value, &response_message);
- }
- response_message += "\r\n";
-
- return ParseRawResponse(response_message.data(),
- response_message.size()) == response_message.size();
-}
-
-bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock(
- const SpdyHeaderBlock& headers,
- const std::string& challenge,
- int spdy_protocol_version) {
- SpdyHeaderBlock::const_iterator status;
- if (spdy_protocol_version <= 2)
- status = headers.find("status");
- else
- status = headers.find(":status");
- if (status == headers.end())
- return false;
-
- std::string hash =
- base::SHA1HashString(challenge + websockets::kWebSocketGuid);
- std::string websocket_accept;
- base::Base64Encode(hash, &websocket_accept);
-
- std::string response_message = base::StringPrintf(
- "%s %s\r\n", websockets::kHttpProtocolVersion, status->second.c_str());
-
- AppendHeader(
- websockets::kUpgrade, websockets::kWebSocketLowercase, &response_message);
- AppendHeader(
- HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
- AppendHeader(
- websockets::kSecWebSocketAccept, websocket_accept, &response_message);
-
- for (SpdyHeaderBlock::const_iterator iter = headers.begin();
- iter != headers.end();
- ++iter) {
- // For each value, if the server sends a NUL-separated list of values,
- // we separate that back out into individual headers for each value
- // in the list.
- if ((spdy_protocol_version <= 2 &&
- LowerCaseEqualsASCII(iter->first, "status")) ||
- (spdy_protocol_version >= 3 &&
- LowerCaseEqualsASCII(iter->first, ":status"))) {
- // The status value is already handled as the first line of
- // |response_message|. Just skip here.
- continue;
- }
- const std::string& value = iter->second;
- size_t start = 0;
- size_t end = 0;
- do {
- end = value.find('\0', start);
- std::string tval;
- if (end != std::string::npos)
- tval = value.substr(start, (end - start));
- else
- tval = value.substr(start);
- if (spdy_protocol_version >= 3 &&
- (LowerCaseEqualsASCII(iter->first,
- websockets::kSecWebSocketProtocolSpdy3) ||
- LowerCaseEqualsASCII(iter->first,
- websockets::kSecWebSocketExtensionsSpdy3)))
- AppendHeader(iter->first.substr(1), tval, &response_message);
- else
- AppendHeader(iter->first, tval, &response_message);
- start = end + 1;
- } while (end != std::string::npos);
- }
- response_message += "\r\n";
-
- return ParseRawResponse(response_message.data(),
- response_message.size()) == response_message.size();
-}
-
-void WebSocketHandshakeResponseHandler::GetHeaders(
- const char* const headers_to_get[],
- size_t headers_to_get_len,
- std::vector<std::string>* values) {
- DCHECK(HasResponse());
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
- if (headers_.empty())
- return;
-
- FetchHeaders(headers_, headers_to_get, headers_to_get_len, values);
-}
-
-void WebSocketHandshakeResponseHandler::RemoveHeaders(
- const char* const headers_to_remove[],
- size_t headers_to_remove_len) {
- DCHECK(HasResponse());
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
- if (headers_.empty())
- return;
-
- headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len);
-}
-
-std::string WebSocketHandshakeResponseHandler::GetRawResponse() const {
- DCHECK(HasResponse());
- return original_.substr(0, original_header_length_);
-}
-
-std::string WebSocketHandshakeResponseHandler::GetResponse() {
- DCHECK(HasResponse());
- DCHECK(!status_line_.empty());
- // headers_ might be empty for wrong response from server.
-
- return status_line_ + headers_ + header_separator_;
-}
-
} // namespace net
diff --git a/net/websockets/websocket_handshake_handler.h b/net/websockets/websocket_handshake_handler.h
index 73af66d..c65e6d9 100644
--- a/net/websockets/websocket_handshake_handler.h
+++ b/net/websockets/websocket_handshake_handler.h
@@ -1,124 +1,19 @@
// 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.
-//
-// WebSocketHandshake*Handler handles WebSocket handshake request message
-// from WebKit renderer process, and WebSocket handshake response message
-// from WebSocket server.
-// It modifies messages for the following reason:
-// - We don't trust WebKit renderer process, so we'll not expose HttpOnly
-// cookies to the renderer process, so handles HttpOnly cookies in
-// browser process.
-//
+
#ifndef NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
#define NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
#include <string>
-#include <vector>
-
-#include "net/base/net_export.h"
-#include "net/http/http_request_info.h"
-#include "net/http/http_response_info.h"
-#include "net/spdy/spdy_header_block.h"
namespace net {
+// Given a WebSocket handshake challenge, compute the correct response.
+// TODO(ricea): There should probably be a test for this.
void ComputeSecWebSocketAccept(const std::string& key,
std::string* accept);
-class NET_EXPORT_PRIVATE WebSocketHandshakeRequestHandler {
- public:
- WebSocketHandshakeRequestHandler();
- ~WebSocketHandshakeRequestHandler() {}
-
- // Parses WebSocket handshake request from renderer process.
- // It assumes a WebSocket handshake request message is given at once, and
- // no other data is added to the request message.
- bool ParseRequest(const char* data, int length);
-
- size_t original_length() const;
-
- // Appends the header value pair for |name| and |value|, if |name| doesn't
- // exist.
- void AppendHeaderIfMissing(const std::string& name,
- const std::string& value);
- // Removes the headers that matches (case insensitive).
- void RemoveHeaders(const char* const headers_to_remove[],
- size_t headers_to_remove_len);
-
- // Gets request info to open WebSocket connection and fills challenge data in
- // |challenge|.
- HttpRequestInfo GetRequestInfo(const GURL& url, std::string* challenge);
- // Gets request as SpdyHeaderBlock.
- // Also, fills challenge data in |challenge|.
- bool GetRequestHeaderBlock(const GURL& url,
- SpdyHeaderBlock* headers,
- std::string* challenge,
- int spdy_protocol_version);
- // Gets WebSocket handshake raw request message to open WebSocket
- // connection.
- std::string GetRawRequest();
- // Calling raw_length is valid only after GetRawRequest() call.
- size_t raw_length() const;
-
- private:
- std::string request_line_;
- std::string headers_;
- int original_length_;
- int raw_length_;
-
- DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeRequestHandler);
-};
-
-class NET_EXPORT_PRIVATE WebSocketHandshakeResponseHandler {
- public:
- WebSocketHandshakeResponseHandler();
- ~WebSocketHandshakeResponseHandler();
-
- // Parses WebSocket handshake response from WebSocket server.
- // Returns number of bytes in |data| used for WebSocket handshake response
- // message. If it already got whole WebSocket handshake response message,
- // returns zero. In other words, [data + returned value, data + length) will
- // be WebSocket frame data after handshake response message.
- // TODO(ukai): fail fast when response gives wrong status code.
- size_t ParseRawResponse(const char* data, int length);
- // Returns true if it already parses full handshake response message.
- bool HasResponse() const;
- // Parses WebSocket handshake response info given as HttpResponseInfo.
- bool ParseResponseInfo(const HttpResponseInfo& response_info,
- const std::string& challenge);
- // Parses WebSocket handshake response as SpdyHeaderBlock.
- bool ParseResponseHeaderBlock(const SpdyHeaderBlock& headers,
- const std::string& challenge,
- int spdy_protocol_version);
-
- // Gets the headers value.
- void GetHeaders(const char* const headers_to_get[],
- size_t headers_to_get_len,
- std::vector<std::string>* values);
- // Removes the headers that matches (case insensitive).
- void RemoveHeaders(const char* const headers_to_remove[],
- size_t headers_to_remove_len);
-
- // Gets raw WebSocket handshake response received from WebSocket server.
- std::string GetRawResponse() const;
-
- // Gets WebSocket handshake response message sent to renderer process.
- std::string GetResponse();
-
- private:
- // Original bytes input by using ParseRawResponse().
- std::string original_;
- // Number of bytes actually used for the handshake response in |original_|.
- int original_header_length_;
-
- std::string status_line_;
- std::string headers_;
- std::string header_separator_;
-
- DISALLOW_COPY_AND_ASSIGN(WebSocketHandshakeResponseHandler);
-};
-
} // namespace net
#endif // NET_WEBSOCKETS_WEBSOCKET_HANDSHAKE_HANDLER_H_
diff --git a/net/websockets/websocket_handshake_handler_spdy_test.cc b/net/websockets/websocket_handshake_handler_spdy_test.cc
deleted file mode 100644
index 064bdcf..0000000
--- a/net/websockets/websocket_handshake_handler_spdy_test.cc
+++ /dev/null
@@ -1,187 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_handshake_handler.h"
-
-#include <string>
-
-#include "net/socket/next_proto.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_websocket_test_util.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "url/gurl.h"
-
-namespace net {
-
-namespace {
-
-class WebSocketHandshakeHandlerSpdyTest
- : public ::testing::Test,
- public ::testing::WithParamInterface<NextProto> {
- protected:
- WebSocketHandshakeHandlerSpdyTest() : spdy_util_(GetParam()) {}
-
- SpdyWebSocketTestUtil spdy_util_;
-};
-
-INSTANTIATE_TEST_CASE_P(
- NextProto,
- WebSocketHandshakeHandlerSpdyTest,
- testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
-
-TEST_P(WebSocketHandshakeHandlerSpdyTest, RequestResponse) {
- WebSocketHandshakeRequestHandler request_handler;
-
- static const char kHandshakeRequestMessage[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Extensions: foo\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n";
-
- EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
- strlen(kHandshakeRequestMessage)));
-
- GURL url("ws://example.com/demo");
- std::string challenge;
- SpdyHeaderBlock headers;
- ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url,
- &headers,
- &challenge,
- spdy_util_.spdy_version()));
-
- EXPECT_EQ(url.path(), spdy_util_.GetHeader(headers, "path"));
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "upgrade").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Upgrade").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "connection").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Connection").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Key").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-websocket-key").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Version").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-webSocket-version").empty());
- EXPECT_EQ("example.com", spdy_util_.GetHeader(headers, "host"));
- EXPECT_EQ("http://example.com", spdy_util_.GetHeader(headers, "origin"));
- EXPECT_EQ("sample", spdy_util_.GetHeader(headers, "sec-websocket-protocol"));
- EXPECT_EQ("foo", spdy_util_.GetHeader(headers, "sec-websocket-extensions"));
- EXPECT_EQ("ws", spdy_util_.GetHeader(headers, "scheme"));
- EXPECT_EQ("WebSocket/13", spdy_util_.GetHeader(headers, "version"));
-
- static const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ==";
-
- EXPECT_EQ(expected_challenge, challenge);
-
- headers.clear();
-
- spdy_util_.SetHeader("status", "101 Switching Protocols", &headers);
- spdy_util_.SetHeader("sec-websocket-protocol", "sample", &headers);
- spdy_util_.SetHeader("sec-websocket-extensions", "foo", &headers);
-
- WebSocketHandshakeResponseHandler response_handler;
- EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(
- headers, challenge, spdy_util_.spdy_version()));
- EXPECT_TRUE(response_handler.HasResponse());
-
- // Note that order of sec-websocket-* is sensitive with hash_map order.
- static const char kHandshakeResponseExpectedMessage[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "sec-websocket-extensions: foo\r\n"
- "sec-websocket-protocol: sample\r\n"
- "\r\n";
-
- EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
-}
-
-TEST_P(WebSocketHandshakeHandlerSpdyTest, RequestResponseWithCookies) {
- WebSocketHandshakeRequestHandler request_handler;
-
- // Note that websocket won't use multiple headers in request now.
- static const char kHandshakeRequestMessage[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Extensions: foo\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n"
- "\r\n";
-
- EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
- strlen(kHandshakeRequestMessage)));
-
- GURL url("ws://example.com/demo");
- std::string challenge;
- SpdyHeaderBlock headers;
- ASSERT_TRUE(request_handler.GetRequestHeaderBlock(url,
- &headers,
- &challenge,
- spdy_util_.spdy_version()));
-
- EXPECT_EQ(url.path(), spdy_util_.GetHeader(headers, "path"));
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "upgrade").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Upgrade").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "connection").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Connection").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Key").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-websocket-key").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "Sec-WebSocket-Version").empty());
- EXPECT_TRUE(spdy_util_.GetHeader(headers, "sec-webSocket-version").empty());
- EXPECT_EQ("example.com", spdy_util_.GetHeader(headers, "host"));
- EXPECT_EQ("http://example.com", spdy_util_.GetHeader(headers, "origin"));
- EXPECT_EQ("sample", spdy_util_.GetHeader(headers, "sec-websocket-protocol"));
- EXPECT_EQ("foo", spdy_util_.GetHeader(headers, "sec-websocket-extensions"));
- EXPECT_EQ("ws", spdy_util_.GetHeader(headers, "scheme"));
- EXPECT_EQ("WebSocket/13", spdy_util_.GetHeader(headers, "version"));
- EXPECT_EQ("WK-websocket-test=1; WK-websocket-test-httponly=1",
- headers["cookie"]);
-
- const char expected_challenge[] = "dGhlIHNhbXBsZSBub25jZQ==";
-
- EXPECT_EQ(expected_challenge, challenge);
-
- headers.clear();
-
- spdy_util_.SetHeader("status", "101 Switching Protocols", &headers);
- spdy_util_.SetHeader("sec-websocket-protocol", "sample", &headers);
- spdy_util_.SetHeader("sec-websocket-extensions", "foo", &headers);
- std::string cookie = "WK-websocket-test=1";
- cookie.append(1, '\0');
- cookie += "WK-websocket-test-httponly=1; HttpOnly";
- headers["set-cookie"] = cookie;
-
-
- WebSocketHandshakeResponseHandler response_handler;
- EXPECT_TRUE(response_handler.ParseResponseHeaderBlock(
- headers, challenge, spdy_util_.spdy_version()));
- EXPECT_TRUE(response_handler.HasResponse());
-
- // Note that order of sec-websocket-* is sensitive with hash_map order.
- static const char kHandshakeResponseExpectedMessage[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "sec-websocket-extensions: foo\r\n"
- "sec-websocket-protocol: sample\r\n"
- "set-cookie: WK-websocket-test=1\r\n"
- "set-cookie: WK-websocket-test-httponly=1; HttpOnly\r\n"
- "\r\n";
-
- EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
-}
-
-} // namespace
-
-} // namespace net
diff --git a/net/websockets/websocket_handshake_handler_test.cc b/net/websockets/websocket_handshake_handler_test.cc
index e59a982..8eff571 100644
--- a/net/websockets/websocket_handshake_handler_test.cc
+++ b/net/websockets/websocket_handshake_handler_test.cc
@@ -4,238 +4,14 @@
#include "net/websockets/websocket_handshake_handler.h"
-#include <string>
-#include <vector>
-
-#include "base/basictypes.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/http/http_response_headers.h"
-#include "net/http/http_util.h"
-#include "url/gurl.h"
-
#include "testing/gtest/include/gtest/gtest.h"
-namespace {
-
-const char* const kCookieHeaders[] = {
- "cookie", "cookie2"
-};
-
-const char* const kSetCookieHeaders[] = {
- "set-cookie", "set-cookie2"
-};
-
-} // namespace
-
namespace net {
-TEST(WebSocketHandshakeRequestHandlerTest, SimpleRequest) {
- WebSocketHandshakeRequestHandler handler;
+namespace {
- static const char kHandshakeRequestMessage[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n";
+// TODO(ricea): Put a test for ComputeSecWebSocketAccept() here.
- EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
- strlen(kHandshakeRequestMessage)));
-
- handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
-
- EXPECT_EQ(kHandshakeRequestMessage, handler.GetRawRequest());
-}
-
-TEST(WebSocketHandshakeRequestHandlerTest, ReplaceRequestCookies) {
- WebSocketHandshakeRequestHandler handler;
-
- static const char kHandshakeRequestMessage[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Cookie: WK-websocket-test=1\r\n"
- "\r\n";
-
- EXPECT_TRUE(handler.ParseRequest(kHandshakeRequestMessage,
- strlen(kHandshakeRequestMessage)));
-
- handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
-
- handler.AppendHeaderIfMissing("Cookie",
- "WK-websocket-test=1; "
- "WK-websocket-test-httponly=1");
-
- static const char kHandshakeRequestExpectedMessage[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Cookie: WK-websocket-test=1; WK-websocket-test-httponly=1\r\n"
- "\r\n";
-
- EXPECT_EQ(kHandshakeRequestExpectedMessage, handler.GetRawRequest());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, SimpleResponse) {
- WebSocketHandshakeResponseHandler handler;
-
- static const char kHandshakeResponseMessage[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "\r\n";
-
- EXPECT_EQ(strlen(kHandshakeResponseMessage),
- handler.ParseRawResponse(kHandshakeResponseMessage,
- strlen(kHandshakeResponseMessage)));
- EXPECT_TRUE(handler.HasResponse());
-
- handler.RemoveHeaders(kCookieHeaders, arraysize(kCookieHeaders));
-
- EXPECT_EQ(kHandshakeResponseMessage, handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, ReplaceResponseCookies) {
- WebSocketHandshakeResponseHandler handler;
-
- static const char kHandshakeResponseMessage[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Set-Cookie: WK-websocket-test-1\r\n"
- "Set-Cookie: WK-websocket-test-httponly=1; HttpOnly\r\n"
- "\r\n";
-
- EXPECT_EQ(strlen(kHandshakeResponseMessage),
- handler.ParseRawResponse(kHandshakeResponseMessage,
- strlen(kHandshakeResponseMessage)));
- EXPECT_TRUE(handler.HasResponse());
- std::vector<std::string> cookies;
- handler.GetHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders), &cookies);
- ASSERT_EQ(2U, cookies.size());
- EXPECT_EQ("WK-websocket-test-1", cookies[0]);
- EXPECT_EQ("WK-websocket-test-httponly=1; HttpOnly", cookies[1]);
- handler.RemoveHeaders(kSetCookieHeaders, arraysize(kSetCookieHeaders));
-
- static const char kHandshakeResponseExpectedMessage[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "\r\n";
-
- EXPECT_EQ(kHandshakeResponseExpectedMessage, handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, BadResponse) {
- WebSocketHandshakeResponseHandler handler;
-
- static const char kBadMessage[] = "\n\n\r\net-Location: w";
- EXPECT_EQ(2U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
- EXPECT_TRUE(handler.HasResponse());
- EXPECT_EQ("\n\n", handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeResponseHandlerTest, BadResponse2) {
- WebSocketHandshakeResponseHandler handler;
-
- static const char kBadMessage[] = "\n\r\n\r\net-Location: w";
- EXPECT_EQ(3U, handler.ParseRawResponse(kBadMessage, strlen(kBadMessage)));
- EXPECT_TRUE(handler.HasResponse());
- EXPECT_EQ("\n\r\n", handler.GetResponse());
-}
-
-TEST(WebSocketHandshakeHandlerTest, HttpRequestResponse) {
- WebSocketHandshakeRequestHandler request_handler;
-
- static const char kHandshakeRequestMessage[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Sec-WebSocket-Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n";
-
- EXPECT_TRUE(request_handler.ParseRequest(kHandshakeRequestMessage,
- strlen(kHandshakeRequestMessage)));
-
- GURL url("ws://example.com/demo");
- std::string challenge;
- const HttpRequestInfo& request_info =
- request_handler.GetRequestInfo(url, &challenge);
-
- EXPECT_EQ(url, request_info.url);
- EXPECT_EQ("GET", request_info.method);
- EXPECT_FALSE(request_info.extra_headers.HasHeader("Upgrade"));
- EXPECT_FALSE(request_info.extra_headers.HasHeader("Connection"));
- EXPECT_FALSE(request_info.extra_headers.HasHeader("Sec-WebSocket-Key"));
- std::string value;
- EXPECT_TRUE(request_info.extra_headers.GetHeader("Host", &value));
- EXPECT_EQ("example.com", value);
- EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Origin",
- &value));
- EXPECT_EQ("http://example.com", value);
- EXPECT_TRUE(request_info.extra_headers.GetHeader("Sec-WebSocket-Protocol",
- &value));
- EXPECT_EQ("sample", value);
-
- EXPECT_EQ("dGhlIHNhbXBsZSBub25jZQ==", challenge);
-
- static const char kHandshakeResponseHeader[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Sec-WebSocket-Protocol: sample\r\n";
-
- std::string raw_headers =
- HttpUtil::AssembleRawHeaders(kHandshakeResponseHeader,
- strlen(kHandshakeResponseHeader));
- HttpResponseInfo response_info;
- response_info.headers = new HttpResponseHeaders(raw_headers);
-
- EXPECT_TRUE(StartsWithASCII(response_info.headers->GetStatusLine(),
- "HTTP/1.1 101 ", false));
- EXPECT_FALSE(response_info.headers->HasHeader("Upgrade"));
- EXPECT_FALSE(response_info.headers->HasHeader("Connection"));
- EXPECT_FALSE(response_info.headers->HasHeader("Sec-WebSocket-Accept"));
- EXPECT_TRUE(response_info.headers->HasHeaderValue("Sec-WebSocket-Protocol",
- "sample"));
-
- WebSocketHandshakeResponseHandler response_handler;
-
- EXPECT_TRUE(response_handler.ParseResponseInfo(response_info, challenge));
- EXPECT_TRUE(response_handler.HasResponse());
-
- static const char kHandshakeResponseExpectedMessage[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "\r\n";
-
- EXPECT_EQ(kHandshakeResponseExpectedMessage, response_handler.GetResponse());
-}
+} // namespace
} // namespace net
diff --git a/net/websockets/websocket_job.cc b/net/websockets/websocket_job.cc
deleted file mode 100644
index eb653fa..0000000
--- a/net/websockets/websocket_job.cc
+++ /dev/null
@@ -1,693 +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/websockets/websocket_job.h"
-
-#include <algorithm>
-
-#include "base/bind.h"
-#include "base/lazy_instance.h"
-#include "net/base/io_buffer.h"
-#include "net/base/net_errors.h"
-#include "net/base/net_log.h"
-#include "net/cookies/cookie_store.h"
-#include "net/http/http_network_session.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/http/http_util.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_session_pool.h"
-#include "net/url_request/url_request_context.h"
-#include "net/websockets/websocket_handshake_handler.h"
-#include "net/websockets/websocket_net_log_params.h"
-#include "net/websockets/websocket_throttle.h"
-#include "url/gurl.h"
-
-static const int kMaxPendingSendAllowed = 32768; // 32 kilobytes.
-
-namespace {
-
-// lower-case header names.
-const char* const kCookieHeaders[] = {
- "cookie", "cookie2"
-};
-const char* const kSetCookieHeaders[] = {
- "set-cookie", "set-cookie2"
-};
-
-net::SocketStreamJob* WebSocketJobFactory(
- const GURL& url, net::SocketStream::Delegate* delegate,
- net::URLRequestContext* context, net::CookieStore* cookie_store) {
- net::WebSocketJob* job = new net::WebSocketJob(delegate);
- job->InitSocketStream(new net::SocketStream(url, job, context, cookie_store));
- return job;
-}
-
-class WebSocketJobInitSingleton {
- private:
- friend struct base::DefaultLazyInstanceTraits<WebSocketJobInitSingleton>;
- WebSocketJobInitSingleton() {
- net::SocketStreamJob::RegisterProtocolFactory("ws", WebSocketJobFactory);
- net::SocketStreamJob::RegisterProtocolFactory("wss", WebSocketJobFactory);
- }
-};
-
-static base::LazyInstance<WebSocketJobInitSingleton> g_websocket_job_init =
- LAZY_INSTANCE_INITIALIZER;
-
-} // anonymous namespace
-
-namespace net {
-
-// static
-void WebSocketJob::EnsureInit() {
- g_websocket_job_init.Get();
-}
-
-WebSocketJob::WebSocketJob(SocketStream::Delegate* delegate)
- : delegate_(delegate),
- state_(INITIALIZED),
- waiting_(false),
- handshake_request_(new WebSocketHandshakeRequestHandler),
- handshake_response_(new WebSocketHandshakeResponseHandler),
- started_to_send_handshake_request_(false),
- handshake_request_sent_(0),
- response_cookies_save_index_(0),
- spdy_protocol_version_(0),
- save_next_cookie_running_(false),
- callback_pending_(false),
- weak_ptr_factory_(this),
- weak_ptr_factory_for_send_pending_(this) {
-}
-
-WebSocketJob::~WebSocketJob() {
- DCHECK_EQ(CLOSED, state_);
- DCHECK(!delegate_);
- DCHECK(!socket_.get());
-}
-
-void WebSocketJob::Connect() {
- DCHECK(socket_.get());
- DCHECK_EQ(state_, INITIALIZED);
- state_ = CONNECTING;
- socket_->Connect();
-}
-
-bool WebSocketJob::SendData(const char* data, int len) {
- switch (state_) {
- case INITIALIZED:
- return false;
-
- case CONNECTING:
- return SendHandshakeRequest(data, len);
-
- case OPEN:
- {
- scoped_refptr<IOBufferWithSize> buffer = new IOBufferWithSize(len);
- memcpy(buffer->data(), data, len);
- if (current_send_buffer_.get() || !send_buffer_queue_.empty()) {
- send_buffer_queue_.push_back(buffer);
- return true;
- }
- current_send_buffer_ = new DrainableIOBuffer(buffer.get(), len);
- return SendDataInternal(current_send_buffer_->data(),
- current_send_buffer_->BytesRemaining());
- }
-
- case CLOSING:
- case CLOSED:
- return false;
- }
- return false;
-}
-
-void WebSocketJob::Close() {
- if (state_ == CLOSED)
- return;
-
- state_ = CLOSING;
- if (current_send_buffer_.get()) {
- // Will close in SendPending.
- return;
- }
- state_ = CLOSED;
- CloseInternal();
-}
-
-void WebSocketJob::RestartWithAuth(const AuthCredentials& credentials) {
- state_ = CONNECTING;
- socket_->RestartWithAuth(credentials);
-}
-
-void WebSocketJob::DetachDelegate() {
- state_ = CLOSED;
- WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
-
- scoped_refptr<WebSocketJob> protect(this);
- weak_ptr_factory_.InvalidateWeakPtrs();
- weak_ptr_factory_for_send_pending_.InvalidateWeakPtrs();
-
- delegate_ = NULL;
- if (socket_.get())
- socket_->DetachDelegate();
- socket_ = NULL;
- if (!callback_.is_null()) {
- waiting_ = false;
- callback_.Reset();
- Release(); // Balanced with OnStartOpenConnection().
- }
-}
-
-int WebSocketJob::OnStartOpenConnection(
- SocketStream* socket, const CompletionCallback& callback) {
- DCHECK(callback_.is_null());
- state_ = CONNECTING;
-
- addresses_ = socket->address_list();
- if (!WebSocketThrottle::GetInstance()->PutInQueue(this)) {
- return ERR_WS_THROTTLE_QUEUE_TOO_LARGE;
- }
-
- if (delegate_) {
- int result = delegate_->OnStartOpenConnection(socket, callback);
- DCHECK_EQ(OK, result);
- }
- if (waiting_) {
- // PutInQueue() may set |waiting_| true for throttling. In this case,
- // Wakeup() will be called later.
- callback_ = callback;
- AddRef(); // Balanced when callback_ is cleared.
- return ERR_IO_PENDING;
- }
- return TrySpdyStream();
-}
-
-void WebSocketJob::OnConnected(
- SocketStream* socket, int max_pending_send_allowed) {
- if (state_ == CLOSED)
- return;
- DCHECK_EQ(CONNECTING, state_);
- if (delegate_)
- delegate_->OnConnected(socket, max_pending_send_allowed);
-}
-
-void WebSocketJob::OnSentData(SocketStream* socket, int amount_sent) {
- DCHECK_NE(INITIALIZED, state_);
- DCHECK_GT(amount_sent, 0);
- if (state_ == CLOSED)
- return;
- if (state_ == CONNECTING) {
- OnSentHandshakeRequest(socket, amount_sent);
- return;
- }
- if (delegate_) {
- DCHECK(state_ == OPEN || state_ == CLOSING);
- if (!current_send_buffer_.get()) {
- VLOG(1)
- << "OnSentData current_send_buffer=NULL amount_sent=" << amount_sent;
- return;
- }
- current_send_buffer_->DidConsume(amount_sent);
- if (current_send_buffer_->BytesRemaining() > 0)
- return;
-
- // We need to report amount_sent of original buffer size, instead of
- // amount sent to |socket|.
- amount_sent = current_send_buffer_->size();
- DCHECK_GT(amount_sent, 0);
- current_send_buffer_ = NULL;
- if (!weak_ptr_factory_for_send_pending_.HasWeakPtrs()) {
- base::MessageLoopForIO::current()->PostTask(
- FROM_HERE,
- base::Bind(&WebSocketJob::SendPending,
- weak_ptr_factory_for_send_pending_.GetWeakPtr()));
- }
- delegate_->OnSentData(socket, amount_sent);
- }
-}
-
-void WebSocketJob::OnReceivedData(
- SocketStream* socket, const char* data, int len) {
- DCHECK_NE(INITIALIZED, state_);
- if (state_ == CLOSED)
- return;
- if (state_ == CONNECTING) {
- OnReceivedHandshakeResponse(socket, data, len);
- return;
- }
- DCHECK(state_ == OPEN || state_ == CLOSING);
- if (delegate_ && len > 0)
- delegate_->OnReceivedData(socket, data, len);
-}
-
-void WebSocketJob::OnClose(SocketStream* socket) {
- state_ = CLOSED;
- WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
-
- scoped_refptr<WebSocketJob> protect(this);
- weak_ptr_factory_.InvalidateWeakPtrs();
-
- SocketStream::Delegate* delegate = delegate_;
- delegate_ = NULL;
- socket_ = NULL;
- if (!callback_.is_null()) {
- waiting_ = false;
- callback_.Reset();
- Release(); // Balanced with OnStartOpenConnection().
- }
- if (delegate)
- delegate->OnClose(socket);
-}
-
-void WebSocketJob::OnAuthRequired(
- SocketStream* socket, AuthChallengeInfo* auth_info) {
- if (delegate_)
- delegate_->OnAuthRequired(socket, auth_info);
-}
-
-void WebSocketJob::OnSSLCertificateError(
- SocketStream* socket, const SSLInfo& ssl_info, bool fatal) {
- if (delegate_)
- delegate_->OnSSLCertificateError(socket, ssl_info, fatal);
-}
-
-void WebSocketJob::OnError(const SocketStream* socket, int error) {
- if (delegate_ && error != ERR_PROTOCOL_SWITCHED)
- delegate_->OnError(socket, error);
-}
-
-void WebSocketJob::OnCreatedSpdyStream(int result) {
- DCHECK(spdy_websocket_stream_.get());
- DCHECK(socket_.get());
- DCHECK_NE(ERR_IO_PENDING, result);
-
- if (state_ == CLOSED) {
- result = ERR_ABORTED;
- } else if (result == OK) {
- state_ = CONNECTING;
- result = ERR_PROTOCOL_SWITCHED;
- } else {
- spdy_websocket_stream_.reset();
- }
-
- CompleteIO(result);
-}
-
-void WebSocketJob::OnSentSpdyHeaders() {
- DCHECK_NE(INITIALIZED, state_);
- if (state_ != CONNECTING)
- return;
- size_t original_length = handshake_request_->original_length();
- handshake_request_.reset();
- if (delegate_)
- delegate_->OnSentData(socket_.get(), original_length);
-}
-
-void WebSocketJob::OnSpdyResponseHeadersUpdated(
- const SpdyHeaderBlock& response_headers) {
- DCHECK_NE(INITIALIZED, state_);
- if (state_ != CONNECTING)
- return;
- // TODO(toyoshim): Fallback to non-spdy connection?
- handshake_response_->ParseResponseHeaderBlock(response_headers,
- challenge_,
- spdy_protocol_version_);
-
- SaveCookiesAndNotifyHeadersComplete();
-}
-
-void WebSocketJob::OnSentSpdyData(size_t bytes_sent) {
- DCHECK_NE(INITIALIZED, state_);
- DCHECK_NE(CONNECTING, state_);
- if (state_ == CLOSED)
- return;
- if (!spdy_websocket_stream_.get())
- return;
- OnSentData(socket_.get(), static_cast<int>(bytes_sent));
-}
-
-void WebSocketJob::OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) {
- DCHECK_NE(INITIALIZED, state_);
- DCHECK_NE(CONNECTING, state_);
- if (state_ == CLOSED)
- return;
- if (!spdy_websocket_stream_.get())
- return;
- if (buffer) {
- OnReceivedData(
- socket_.get(), buffer->GetRemainingData(), buffer->GetRemainingSize());
- } else {
- OnReceivedData(socket_.get(), NULL, 0);
- }
-}
-
-void WebSocketJob::OnCloseSpdyStream() {
- spdy_websocket_stream_.reset();
- OnClose(socket_.get());
-}
-
-bool WebSocketJob::SendHandshakeRequest(const char* data, int len) {
- DCHECK_EQ(state_, CONNECTING);
- if (started_to_send_handshake_request_)
- return false;
- if (!handshake_request_->ParseRequest(data, len))
- return false;
-
- AddCookieHeaderAndSend();
- return true;
-}
-
-void WebSocketJob::AddCookieHeaderAndSend() {
- bool allow = true;
- if (delegate_ && !delegate_->CanGetCookies(socket_.get(), GetURLForCookies()))
- allow = false;
-
- if (socket_.get() && delegate_ && state_ == CONNECTING) {
- handshake_request_->RemoveHeaders(kCookieHeaders,
- arraysize(kCookieHeaders));
- if (allow && socket_->cookie_store()) {
- // Add cookies, including HttpOnly cookies.
- CookieOptions cookie_options;
- cookie_options.set_include_httponly();
- socket_->cookie_store()->GetCookiesWithOptionsAsync(
- GetURLForCookies(), cookie_options,
- base::Bind(&WebSocketJob::LoadCookieCallback,
- weak_ptr_factory_.GetWeakPtr()));
- } else {
- DoSendData();
- }
- }
-}
-
-void WebSocketJob::LoadCookieCallback(const std::string& cookie) {
- if (!cookie.empty())
- // TODO(tyoshino): Sending cookie means that connection doesn't need
- // PRIVACY_MODE_ENABLED as cookies may be server-bound and channel id
- // wouldn't negatively affect privacy anyway. Need to restart connection
- // or refactor to determine cookie status prior to connecting.
- handshake_request_->AppendHeaderIfMissing("Cookie", cookie);
- DoSendData();
-}
-
-void WebSocketJob::DoSendData() {
- if (spdy_websocket_stream_.get()) {
- scoped_ptr<SpdyHeaderBlock> headers(new SpdyHeaderBlock);
- handshake_request_->GetRequestHeaderBlock(
- socket_->url(), headers.get(), &challenge_, spdy_protocol_version_);
- spdy_websocket_stream_->SendRequest(headers.Pass());
- } else {
- const std::string& handshake_request =
- handshake_request_->GetRawRequest();
- handshake_request_sent_ = 0;
- socket_->net_log()->AddEvent(
- NetLog::TYPE_WEB_SOCKET_SEND_REQUEST_HEADERS,
- base::Bind(&NetLogWebSocketHandshakeCallback, &handshake_request));
- socket_->SendData(handshake_request.data(),
- handshake_request.size());
- }
- // Just buffered in |handshake_request_|.
- started_to_send_handshake_request_ = true;
-}
-
-void WebSocketJob::OnSentHandshakeRequest(
- SocketStream* socket, int amount_sent) {
- DCHECK_EQ(state_, CONNECTING);
- handshake_request_sent_ += amount_sent;
- DCHECK_LE(handshake_request_sent_, handshake_request_->raw_length());
- if (handshake_request_sent_ >= handshake_request_->raw_length()) {
- // handshake request has been sent.
- // notify original size of handshake request to delegate.
- // Reset the handshake_request_ first in case this object is deleted by the
- // delegate.
- size_t original_length = handshake_request_->original_length();
- handshake_request_.reset();
- if (delegate_)
- delegate_->OnSentData(socket, original_length);
- }
-}
-
-void WebSocketJob::OnReceivedHandshakeResponse(
- SocketStream* socket, const char* data, int len) {
- DCHECK_EQ(state_, CONNECTING);
- if (handshake_response_->HasResponse()) {
- // If we already has handshake response, received data should be frame
- // data, not handshake message.
- received_data_after_handshake_.insert(
- received_data_after_handshake_.end(), data, data + len);
- return;
- }
-
- size_t response_length = handshake_response_->ParseRawResponse(data, len);
- if (!handshake_response_->HasResponse()) {
- // not yet. we need more data.
- return;
- }
- // handshake message is completed.
- std::string raw_response = handshake_response_->GetRawResponse();
- socket_->net_log()->AddEvent(
- NetLog::TYPE_WEB_SOCKET_READ_RESPONSE_HEADERS,
- base::Bind(&NetLogWebSocketHandshakeCallback, &raw_response));
- if (len - response_length > 0) {
- // If we received extra data, it should be frame data.
- DCHECK(received_data_after_handshake_.empty());
- received_data_after_handshake_.assign(data + response_length, data + len);
- }
- SaveCookiesAndNotifyHeadersComplete();
-}
-
-void WebSocketJob::SaveCookiesAndNotifyHeadersComplete() {
- // handshake message is completed.
- DCHECK(handshake_response_->HasResponse());
-
- // Extract cookies from the handshake response into a temporary vector.
- response_cookies_.clear();
- response_cookies_save_index_ = 0;
-
- handshake_response_->GetHeaders(
- kSetCookieHeaders, arraysize(kSetCookieHeaders), &response_cookies_);
-
- // Now, loop over the response cookies, and attempt to persist each.
- SaveNextCookie();
-}
-
-void WebSocketJob::NotifyHeadersComplete() {
- // Remove cookie headers, with malformed headers preserved.
- // Actual handshake should be done in Blink.
- handshake_response_->RemoveHeaders(
- kSetCookieHeaders, arraysize(kSetCookieHeaders));
- std::string handshake_response = handshake_response_->GetResponse();
- handshake_response_.reset();
- std::vector<char> received_data(handshake_response.begin(),
- handshake_response.end());
- received_data.insert(received_data.end(),
- received_data_after_handshake_.begin(),
- received_data_after_handshake_.end());
- received_data_after_handshake_.clear();
-
- state_ = OPEN;
-
- DCHECK(!received_data.empty());
- if (delegate_)
- delegate_->OnReceivedData(
- socket_.get(), &received_data.front(), received_data.size());
-
- WebSocketThrottle::GetInstance()->RemoveFromQueue(this);
-}
-
-void WebSocketJob::SaveNextCookie() {
- if (!socket_.get() || !delegate_ || state_ != CONNECTING)
- return;
-
- callback_pending_ = false;
- save_next_cookie_running_ = true;
-
- if (socket_->cookie_store()) {
- GURL url_for_cookies = GetURLForCookies();
-
- CookieOptions options;
- options.set_include_httponly();
-
- // Loop as long as SetCookieWithOptionsAsync completes synchronously. Since
- // CookieMonster's asynchronous operation APIs queue the callback to run it
- // on the thread where the API was called, there won't be race. I.e. unless
- // the callback is run synchronously, it won't be run in parallel with this
- // method.
- while (!callback_pending_ &&
- response_cookies_save_index_ < response_cookies_.size()) {
- std::string cookie = response_cookies_[response_cookies_save_index_];
- response_cookies_save_index_++;
-
- if (!delegate_->CanSetCookie(
- socket_.get(), url_for_cookies, cookie, &options))
- continue;
-
- callback_pending_ = true;
- socket_->cookie_store()->SetCookieWithOptionsAsync(
- url_for_cookies, cookie, options,
- base::Bind(&WebSocketJob::OnCookieSaved,
- weak_ptr_factory_.GetWeakPtr()));
- }
- }
-
- save_next_cookie_running_ = false;
-
- if (callback_pending_)
- return;
-
- response_cookies_.clear();
- response_cookies_save_index_ = 0;
-
- NotifyHeadersComplete();
-}
-
-void WebSocketJob::OnCookieSaved(bool cookie_status) {
- // Tell the caller of SetCookieWithOptionsAsync() that this completion
- // callback is invoked.
- // - If the caller checks callback_pending earlier than this callback, the
- // caller exits to let this method continue iteration.
- // - Otherwise, the caller continues iteration.
- callback_pending_ = false;
-
- // Resume SaveNextCookie if the caller of SetCookieWithOptionsAsync() exited
- // the loop. Otherwise, return.
- if (save_next_cookie_running_)
- return;
-
- SaveNextCookie();
-}
-
-GURL WebSocketJob::GetURLForCookies() const {
- GURL url = socket_->url();
- std::string scheme = socket_->is_secure() ? "https" : "http";
- url::Replacements<char> replacements;
- replacements.SetScheme(scheme.c_str(), url::Component(0, scheme.length()));
- return url.ReplaceComponents(replacements);
-}
-
-const AddressList& WebSocketJob::address_list() const {
- return addresses_;
-}
-
-int WebSocketJob::TrySpdyStream() {
- if (!socket_.get())
- return ERR_FAILED;
-
- // Check if we have a SPDY session available.
- HttpTransactionFactory* factory =
- socket_->context()->http_transaction_factory();
- if (!factory)
- return OK;
- scoped_refptr<HttpNetworkSession> session = factory->GetSession();
- if (!session.get() || !session->params().enable_websocket_over_spdy)
- return OK;
- SpdySessionPool* spdy_pool = session->spdy_session_pool();
- PrivacyMode privacy_mode = socket_->privacy_mode();
- const SpdySessionKey key(HostPortPair::FromURL(socket_->url()),
- socket_->proxy_server(), privacy_mode);
- // Forbid wss downgrade to SPDY without SSL.
- // TODO(toyoshim): Does it realize the same policy with HTTP?
- base::WeakPtr<SpdySession> spdy_session =
- spdy_pool->FindAvailableSession(key, *socket_->net_log());
- if (!spdy_session)
- return OK;
-
- SSLInfo ssl_info;
- bool was_npn_negotiated;
- NextProto protocol_negotiated = kProtoUnknown;
- bool use_ssl = spdy_session->GetSSLInfo(
- &ssl_info, &was_npn_negotiated, &protocol_negotiated);
- if (socket_->is_secure() && !use_ssl)
- return OK;
-
- // Create SpdyWebSocketStream.
- spdy_protocol_version_ = spdy_session->GetProtocolVersion();
- spdy_websocket_stream_.reset(new SpdyWebSocketStream(spdy_session, this));
-
- int result = spdy_websocket_stream_->InitializeStream(
- socket_->url(), MEDIUM, *socket_->net_log());
- if (result == OK) {
- OnConnected(socket_.get(), kMaxPendingSendAllowed);
- return ERR_PROTOCOL_SWITCHED;
- }
- if (result != ERR_IO_PENDING) {
- spdy_websocket_stream_.reset();
- return OK;
- }
-
- return ERR_IO_PENDING;
-}
-
-void WebSocketJob::SetWaiting() {
- waiting_ = true;
-}
-
-bool WebSocketJob::IsWaiting() const {
- return waiting_;
-}
-
-void WebSocketJob::Wakeup() {
- if (!waiting_)
- return;
- waiting_ = false;
- DCHECK(!callback_.is_null());
- base::MessageLoopForIO::current()->PostTask(
- FROM_HERE,
- base::Bind(&WebSocketJob::RetryPendingIO,
- weak_ptr_factory_.GetWeakPtr()));
-}
-
-void WebSocketJob::RetryPendingIO() {
- int result = TrySpdyStream();
-
- // In the case of ERR_IO_PENDING, CompleteIO() will be called from
- // OnCreatedSpdyStream().
- if (result != ERR_IO_PENDING)
- CompleteIO(result);
-}
-
-void WebSocketJob::CompleteIO(int result) {
- // |callback_| may be null if OnClose() or DetachDelegate() was called.
- if (!callback_.is_null()) {
- CompletionCallback callback = callback_;
- callback_.Reset();
- callback.Run(result);
- Release(); // Balanced with OnStartOpenConnection().
- }
-}
-
-bool WebSocketJob::SendDataInternal(const char* data, int length) {
- if (spdy_websocket_stream_.get())
- return ERR_IO_PENDING == spdy_websocket_stream_->SendData(data, length);
- if (socket_.get())
- return socket_->SendData(data, length);
- return false;
-}
-
-void WebSocketJob::CloseInternal() {
- if (spdy_websocket_stream_.get())
- spdy_websocket_stream_->Close();
- if (socket_.get())
- socket_->Close();
-}
-
-void WebSocketJob::SendPending() {
- if (current_send_buffer_.get())
- return;
-
- // Current buffer has been sent. Try next if any.
- if (send_buffer_queue_.empty()) {
- // No more data to send.
- if (state_ == CLOSING)
- CloseInternal();
- return;
- }
-
- scoped_refptr<IOBufferWithSize> next_buffer = send_buffer_queue_.front();
- send_buffer_queue_.pop_front();
- current_send_buffer_ =
- new DrainableIOBuffer(next_buffer.get(), next_buffer->size());
- SendDataInternal(current_send_buffer_->data(),
- current_send_buffer_->BytesRemaining());
-}
-
-} // namespace net
diff --git a/net/websockets/websocket_job.h b/net/websockets/websocket_job.h
deleted file mode 100644
index bad06cf..0000000
--- a/net/websockets/websocket_job.h
+++ /dev/null
@@ -1,154 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_WEBSOCKETS_WEBSOCKET_JOB_H_
-#define NET_WEBSOCKETS_WEBSOCKET_JOB_H_
-
-#include <deque>
-#include <string>
-#include <vector>
-
-#include "base/memory/weak_ptr.h"
-#include "net/base/address_list.h"
-#include "net/base/completion_callback.h"
-#include "net/socket_stream/socket_stream_job.h"
-#include "net/spdy/spdy_header_block.h"
-#include "net/spdy/spdy_websocket_stream.h"
-
-class GURL;
-
-namespace net {
-
-class DrainableIOBuffer;
-class SSLInfo;
-class WebSocketHandshakeRequestHandler;
-class WebSocketHandshakeResponseHandler;
-
-// WebSocket protocol specific job on SocketStream.
-// It captures WebSocket handshake message and handles cookie operations.
-// Chrome security policy doesn't allow renderer process (except dev tools)
-// see HttpOnly cookies, so it injects cookie header in handshake request and
-// strips set-cookie headers in handshake response.
-// TODO(ukai): refactor websocket.cc to use this.
-class NET_EXPORT WebSocketJob
- : public SocketStreamJob,
- public SocketStream::Delegate,
- public SpdyWebSocketStream::Delegate {
- public:
- // This is state of WebSocket, not SocketStream.
- enum State {
- INITIALIZED = -1,
- CONNECTING = 0,
- OPEN = 1,
- CLOSING = 2,
- CLOSED = 3,
- };
-
- explicit WebSocketJob(SocketStream::Delegate* delegate);
-
- static void EnsureInit();
-
- State state() const { return state_; }
- void Connect() override;
- bool SendData(const char* data, int len) override;
- void Close() override;
- void RestartWithAuth(const AuthCredentials& credentials) override;
- void DetachDelegate() override;
-
- // SocketStream::Delegate methods.
- int OnStartOpenConnection(SocketStream* socket,
- const CompletionCallback& callback) override;
- void OnConnected(SocketStream* socket, int max_pending_send_allowed) override;
- void OnSentData(SocketStream* socket, int amount_sent) override;
- void OnReceivedData(SocketStream* socket, const char* data, int len) override;
- void OnClose(SocketStream* socket) override;
- void OnAuthRequired(SocketStream* socket,
- AuthChallengeInfo* auth_info) override;
- void OnSSLCertificateError(SocketStream* socket,
- const SSLInfo& ssl_info,
- bool fatal) override;
- void OnError(const SocketStream* socket, int error) override;
-
- // SpdyWebSocketStream::Delegate methods.
- void OnCreatedSpdyStream(int status) override;
- void OnSentSpdyHeaders() override;
- void OnSpdyResponseHeadersUpdated(
- const SpdyHeaderBlock& response_headers) override;
- void OnSentSpdyData(size_t bytes_sent) override;
- void OnReceivedSpdyData(scoped_ptr<SpdyBuffer> buffer) override;
- void OnCloseSpdyStream() override;
-
- private:
- friend class WebSocketThrottle;
- friend class WebSocketJobTest;
- ~WebSocketJob() override;
-
- bool SendHandshakeRequest(const char* data, int len);
- void AddCookieHeaderAndSend();
- void LoadCookieCallback(const std::string& cookie);
-
- void OnSentHandshakeRequest(SocketStream* socket, int amount_sent);
- // Parses received data into handshake_response_. When finished receiving the
- // response, calls SaveCookiesAndNotifyHeadersComplete().
- void OnReceivedHandshakeResponse(
- SocketStream* socket, const char* data, int len);
- // Saves received cookies to the cookie store, and then notifies the
- // delegate_ of completion of handshake.
- void SaveCookiesAndNotifyHeadersComplete();
- void SaveNextCookie();
- void OnCookieSaved(bool cookie_status);
- // Clears variables for handling cookies, rebuilds handshake string excluding
- // cookies, and then pass the handshake string to delegate_.
- void NotifyHeadersComplete();
- void DoSendData();
-
- GURL GetURLForCookies() const;
-
- const AddressList& address_list() const;
- int TrySpdyStream();
- void SetWaiting();
- bool IsWaiting() const;
- void Wakeup();
- void RetryPendingIO();
- void CompleteIO(int result);
-
- bool SendDataInternal(const char* data, int length);
- void CloseInternal();
- void SendPending();
-
- SocketStream::Delegate* delegate_;
- State state_;
- bool waiting_;
- AddressList addresses_;
- CompletionCallback callback_; // for throttling.
-
- scoped_ptr<WebSocketHandshakeRequestHandler> handshake_request_;
- scoped_ptr<WebSocketHandshakeResponseHandler> handshake_response_;
-
- bool started_to_send_handshake_request_;
- size_t handshake_request_sent_;
-
- std::vector<std::string> response_cookies_;
- size_t response_cookies_save_index_;
-
- std::deque<scoped_refptr<IOBufferWithSize> > send_buffer_queue_;
- scoped_refptr<DrainableIOBuffer> current_send_buffer_;
- std::vector<char> received_data_after_handshake_;
-
- int spdy_protocol_version_;
- scoped_ptr<SpdyWebSocketStream> spdy_websocket_stream_;
- std::string challenge_;
-
- bool save_next_cookie_running_;
- bool callback_pending_;
-
- base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_;
- base::WeakPtrFactory<WebSocketJob> weak_ptr_factory_for_send_pending_;
-
- DISALLOW_COPY_AND_ASSIGN(WebSocketJob);
-};
-
-} // namespace
-
-#endif // NET_WEBSOCKETS_WEBSOCKET_JOB_H_
diff --git a/net/websockets/websocket_job_test.cc b/net/websockets/websocket_job_test.cc
deleted file mode 100644
index c84af8f..0000000
--- a/net/websockets/websocket_job_test.cc
+++ /dev/null
@@ -1,1287 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_job.h"
-
-#include <string>
-#include <vector>
-
-#include "base/bind.h"
-#include "base/bind_helpers.h"
-#include "base/callback.h"
-#include "base/memory/ref_counted.h"
-#include "base/strings/string_split.h"
-#include "base/strings/string_util.h"
-#include "net/base/completion_callback.h"
-#include "net/base/net_errors.h"
-#include "net/base/test_completion_callback.h"
-#include "net/cookies/cookie_store.h"
-#include "net/cookies/cookie_store_test_helpers.h"
-#include "net/dns/mock_host_resolver.h"
-#include "net/http/http_transaction_factory.h"
-#include "net/http/transport_security_state.h"
-#include "net/proxy/proxy_service.h"
-#include "net/socket/next_proto.h"
-#include "net/socket/socket_test_util.h"
-#include "net/socket_stream/socket_stream.h"
-#include "net/spdy/spdy_session.h"
-#include "net/spdy/spdy_websocket_test_util.h"
-#include "net/ssl/ssl_config_service.h"
-#include "net/url_request/url_request_context.h"
-#include "net/websockets/websocket_throttle.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-namespace net {
-
-namespace {
-
-class MockSocketStream : public SocketStream {
- public:
- MockSocketStream(const GURL& url, SocketStream::Delegate* delegate,
- URLRequestContext* context, CookieStore* cookie_store)
- : SocketStream(url, delegate, context, cookie_store) {}
-
- void Connect() override {}
- bool SendData(const char* data, int len) override {
- sent_data_ += std::string(data, len);
- return true;
- }
-
- void Close() override {}
- void RestartWithAuth(const AuthCredentials& credentials) override {}
-
- void DetachDelegate() override { delegate_ = NULL; }
-
- const std::string& sent_data() const {
- return sent_data_;
- }
-
- protected:
- ~MockSocketStream() override {}
-
- private:
- std::string sent_data_;
-};
-
-class MockSocketStreamDelegate : public SocketStream::Delegate {
- public:
- MockSocketStreamDelegate()
- : amount_sent_(0), allow_all_cookies_(true) {}
- void set_allow_all_cookies(bool allow_all_cookies) {
- allow_all_cookies_ = allow_all_cookies;
- }
- ~MockSocketStreamDelegate() override {}
-
- void SetOnStartOpenConnection(const base::Closure& callback) {
- on_start_open_connection_ = callback;
- }
- void SetOnConnected(const base::Closure& callback) {
- on_connected_ = callback;
- }
- void SetOnSentData(const base::Closure& callback) {
- on_sent_data_ = callback;
- }
- void SetOnReceivedData(const base::Closure& callback) {
- on_received_data_ = callback;
- }
- void SetOnClose(const base::Closure& callback) {
- on_close_ = callback;
- }
-
- int OnStartOpenConnection(SocketStream* socket,
- const CompletionCallback& callback) override {
- if (!on_start_open_connection_.is_null())
- on_start_open_connection_.Run();
- return OK;
- }
- void OnConnected(SocketStream* socket,
- int max_pending_send_allowed) override {
- if (!on_connected_.is_null())
- on_connected_.Run();
- }
- void OnSentData(SocketStream* socket, int amount_sent) override {
- amount_sent_ += amount_sent;
- if (!on_sent_data_.is_null())
- on_sent_data_.Run();
- }
- void OnReceivedData(SocketStream* socket,
- const char* data,
- int len) override {
- received_data_ += std::string(data, len);
- if (!on_received_data_.is_null())
- on_received_data_.Run();
- }
- void OnClose(SocketStream* socket) override {
- if (!on_close_.is_null())
- on_close_.Run();
- }
- bool CanGetCookies(SocketStream* socket, const GURL& url) override {
- return allow_all_cookies_;
- }
- bool CanSetCookie(SocketStream* request,
- const GURL& url,
- const std::string& cookie_line,
- CookieOptions* options) override {
- return allow_all_cookies_;
- }
-
- size_t amount_sent() const { return amount_sent_; }
- const std::string& received_data() const { return received_data_; }
-
- private:
- int amount_sent_;
- bool allow_all_cookies_;
- std::string received_data_;
- base::Closure on_start_open_connection_;
- base::Closure on_connected_;
- base::Closure on_sent_data_;
- base::Closure on_received_data_;
- base::Closure on_close_;
-};
-
-class MockCookieStore : public CookieStore {
- public:
- struct Entry {
- GURL url;
- std::string cookie_line;
- CookieOptions options;
- };
-
- MockCookieStore() {}
-
- bool SetCookieWithOptions(const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options) {
- Entry entry;
- entry.url = url;
- entry.cookie_line = cookie_line;
- entry.options = options;
- entries_.push_back(entry);
- return true;
- }
-
- std::string GetCookiesWithOptions(const GURL& url,
- const CookieOptions& options) {
- std::string result;
- for (size_t i = 0; i < entries_.size(); i++) {
- Entry& entry = entries_[i];
- if (url == entry.url) {
- if (!result.empty()) {
- result += "; ";
- }
- result += entry.cookie_line;
- }
- }
- return result;
- }
-
- // CookieStore:
- void SetCookieWithOptionsAsync(const GURL& url,
- const std::string& cookie_line,
- const CookieOptions& options,
- const SetCookiesCallback& callback) override {
- bool result = SetCookieWithOptions(url, cookie_line, options);
- if (!callback.is_null())
- callback.Run(result);
- }
-
- void GetCookiesWithOptionsAsync(const GURL& url,
- const CookieOptions& options,
- const GetCookiesCallback& callback) override {
- if (!callback.is_null())
- callback.Run(GetCookiesWithOptions(url, options));
- }
-
- void GetAllCookiesForURLAsync(
- const GURL& url,
- const GetCookieListCallback& callback) override {
- ADD_FAILURE();
- }
-
- void DeleteCookieAsync(const GURL& url,
- const std::string& cookie_name,
- const base::Closure& callback) override {
- ADD_FAILURE();
- }
-
- void DeleteAllCreatedBetweenAsync(const base::Time& delete_begin,
- const base::Time& delete_end,
- const DeleteCallback& callback) override {
- ADD_FAILURE();
- }
-
- void DeleteAllCreatedBetweenForHostAsync(
- const base::Time delete_begin,
- const base::Time delete_end,
- const GURL& url,
- const DeleteCallback& callback) override {
- ADD_FAILURE();
- }
-
- void DeleteSessionCookiesAsync(const DeleteCallback&) override {
- ADD_FAILURE();
- }
-
- CookieMonster* GetCookieMonster() override { return NULL; }
-
- scoped_ptr<CookieStore::CookieChangedSubscription>
- AddCallbackForCookie(const GURL& url, const std::string& name,
- const CookieChangedCallback& callback) override {
- ADD_FAILURE();
- return scoped_ptr<CookieChangedSubscription>();
- }
-
- const std::vector<Entry>& entries() const { return entries_; }
-
- private:
- friend class base::RefCountedThreadSafe<MockCookieStore>;
- ~MockCookieStore() override {}
-
- std::vector<Entry> entries_;
-};
-
-class MockSSLConfigService : public SSLConfigService {
- public:
- void GetSSLConfig(SSLConfig* config) override {}
-
- protected:
- ~MockSSLConfigService() override {}
-};
-
-class MockURLRequestContext : public URLRequestContext {
- public:
- explicit MockURLRequestContext(CookieStore* cookie_store)
- : transport_security_state_() {
- set_cookie_store(cookie_store);
- set_transport_security_state(&transport_security_state_);
- base::Time expiry = base::Time::Now() + base::TimeDelta::FromDays(1000);
- bool include_subdomains = false;
- transport_security_state_.AddHSTS("upgrademe.com", expiry,
- include_subdomains);
- }
-
- ~MockURLRequestContext() override { AssertNoURLRequests(); }
-
- private:
- TransportSecurityState transport_security_state_;
-};
-
-class MockHttpTransactionFactory : public HttpTransactionFactory {
- public:
- MockHttpTransactionFactory(NextProto next_proto,
- OrderedSocketData* data,
- bool enable_websocket_over_spdy) {
- data_ = data;
- MockConnect connect_data(SYNCHRONOUS, OK);
- data_->set_connect_data(connect_data);
- session_deps_.reset(new SpdySessionDependencies(next_proto));
- session_deps_->enable_websocket_over_spdy = enable_websocket_over_spdy;
- session_deps_->socket_factory->AddSocketDataProvider(data_);
- http_session_ =
- SpdySessionDependencies::SpdyCreateSession(session_deps_.get());
- host_port_pair_.set_host("example.com");
- host_port_pair_.set_port(80);
- spdy_session_key_ = SpdySessionKey(host_port_pair_,
- ProxyServer::Direct(),
- PRIVACY_MODE_DISABLED);
- session_ = CreateInsecureSpdySession(
- http_session_, spdy_session_key_, BoundNetLog());
- }
-
- int CreateTransaction(RequestPriority priority,
- scoped_ptr<HttpTransaction>* trans) override {
- NOTREACHED();
- return ERR_UNEXPECTED;
- }
-
- HttpCache* GetCache() override {
- NOTREACHED();
- return NULL;
- }
-
- HttpNetworkSession* GetSession() override { return http_session_.get(); }
-
- private:
- OrderedSocketData* data_;
- scoped_ptr<SpdySessionDependencies> session_deps_;
- scoped_refptr<HttpNetworkSession> http_session_;
- base::WeakPtr<SpdySession> session_;
- HostPortPair host_port_pair_;
- SpdySessionKey spdy_session_key_;
-};
-
-class DeletingSocketStreamDelegate : public SocketStream::Delegate {
- public:
- DeletingSocketStreamDelegate()
- : delete_next_(false) {}
-
- // Since this class needs to be able to delete |job_|, it must be the only
- // reference holder (except for temporary references). Provide access to the
- // pointer for tests to use.
- WebSocketJob* job() { return job_.get(); }
-
- void set_job(WebSocketJob* job) { job_ = job; }
-
- // After calling this, the next call to a method on this delegate will delete
- // the WebSocketJob object.
- void set_delete_next(bool delete_next) { delete_next_ = delete_next; }
-
- void DeleteJobMaybe() {
- if (delete_next_) {
- job_->DetachContext();
- job_->DetachDelegate();
- job_ = NULL;
- }
- }
-
- // SocketStream::Delegate implementation
-
- // OnStartOpenConnection() is not implemented by SocketStreamDispatcherHost
-
- void OnConnected(SocketStream* socket,
- int max_pending_send_allowed) override {
- DeleteJobMaybe();
- }
-
- void OnSentData(SocketStream* socket, int amount_sent) override {
- DeleteJobMaybe();
- }
-
- void OnReceivedData(SocketStream* socket,
- const char* data,
- int len) override {
- DeleteJobMaybe();
- }
-
- void OnClose(SocketStream* socket) override { DeleteJobMaybe(); }
-
- void OnAuthRequired(SocketStream* socket,
- AuthChallengeInfo* auth_info) override {
- DeleteJobMaybe();
- }
-
- void OnSSLCertificateError(SocketStream* socket,
- const SSLInfo& ssl_info,
- bool fatal) override {
- DeleteJobMaybe();
- }
-
- void OnError(const SocketStream* socket, int error) override {
- DeleteJobMaybe();
- }
-
- // CanGetCookies() and CanSetCookies() do not appear to be able to delete the
- // WebSocketJob object.
-
- private:
- scoped_refptr<WebSocketJob> job_;
- bool delete_next_;
-};
-
-} // namespace
-
-class WebSocketJobTest : public PlatformTest,
- public ::testing::WithParamInterface<NextProto> {
- public:
- WebSocketJobTest()
- : spdy_util_(GetParam()),
- enable_websocket_over_spdy_(false) {}
-
- void SetUp() override {
- stream_type_ = STREAM_INVALID;
- cookie_store_ = new MockCookieStore;
- context_.reset(new MockURLRequestContext(cookie_store_.get()));
- }
- void TearDown() override {
- cookie_store_ = NULL;
- context_.reset();
- websocket_ = NULL;
- socket_ = NULL;
- }
- void DoSendRequest() {
- EXPECT_TRUE(websocket_->SendData(kHandshakeRequestWithoutCookie,
- kHandshakeRequestWithoutCookieLength));
- }
- void DoSendData() {
- if (received_data().size() == kHandshakeResponseWithoutCookieLength)
- websocket_->SendData(kDataHello, kDataHelloLength);
- }
- void DoSync() {
- sync_test_callback_.callback().Run(OK);
- }
- int WaitForResult() {
- return sync_test_callback_.WaitForResult();
- }
-
- protected:
- enum StreamType {
- STREAM_INVALID,
- STREAM_MOCK_SOCKET,
- STREAM_SOCKET,
- STREAM_SPDY_WEBSOCKET,
- };
- enum ThrottlingOption {
- THROTTLING_OFF,
- THROTTLING_ON,
- };
- enum SpdyOption {
- SPDY_OFF,
- SPDY_ON,
- };
- void InitWebSocketJob(const GURL& url,
- MockSocketStreamDelegate* delegate,
- StreamType stream_type) {
- DCHECK_NE(STREAM_INVALID, stream_type);
- stream_type_ = stream_type;
- websocket_ = new WebSocketJob(delegate);
-
- if (stream_type == STREAM_MOCK_SOCKET)
- socket_ = new MockSocketStream(url, websocket_.get(), context_.get(),
- NULL);
-
- if (stream_type == STREAM_SOCKET || stream_type == STREAM_SPDY_WEBSOCKET) {
- if (stream_type == STREAM_SPDY_WEBSOCKET) {
- http_factory_.reset(new MockHttpTransactionFactory(
- GetParam(), data_.get(), enable_websocket_over_spdy_));
- context_->set_http_transaction_factory(http_factory_.get());
- }
-
- ssl_config_service_ = new MockSSLConfigService();
- context_->set_ssl_config_service(ssl_config_service_.get());
- proxy_service_.reset(ProxyService::CreateDirect());
- context_->set_proxy_service(proxy_service_.get());
- host_resolver_.reset(new MockHostResolver);
- context_->set_host_resolver(host_resolver_.get());
-
- socket_ = new SocketStream(url, websocket_.get(), context_.get(), NULL);
- socket_factory_.reset(new MockClientSocketFactory);
- DCHECK(data_.get());
- socket_factory_->AddSocketDataProvider(data_.get());
- socket_->SetClientSocketFactory(socket_factory_.get());
- }
-
- websocket_->InitSocketStream(socket_.get());
- // MockHostResolver resolves all hosts to 127.0.0.1; however, when we create
- // a WebSocketJob purely to block another one in a throttling test, we don't
- // perform a real connect. In that case, the following address is used
- // instead.
- IPAddressNumber ip;
- ParseIPLiteralToNumber("127.0.0.1", &ip);
- websocket_->addresses_ = AddressList::CreateFromIPAddress(ip, 80);
- }
- void SkipToConnecting() {
- websocket_->state_ = WebSocketJob::CONNECTING;
- ASSERT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(websocket_.get()));
- }
- WebSocketJob::State GetWebSocketJobState() {
- return websocket_->state_;
- }
- void CloseWebSocketJob() {
- if (websocket_->socket_.get()) {
- websocket_->socket_->DetachDelegate();
- WebSocketThrottle::GetInstance()->RemoveFromQueue(websocket_.get());
- }
- websocket_->state_ = WebSocketJob::CLOSED;
- websocket_->delegate_ = NULL;
- websocket_->socket_ = NULL;
- }
- SocketStream* GetSocket(SocketStreamJob* job) {
- return job->socket_.get();
- }
- const std::string& sent_data() const {
- DCHECK_EQ(STREAM_MOCK_SOCKET, stream_type_);
- MockSocketStream* socket =
- static_cast<MockSocketStream*>(socket_.get());
- DCHECK(socket);
- return socket->sent_data();
- }
- const std::string& received_data() const {
- DCHECK_NE(STREAM_INVALID, stream_type_);
- MockSocketStreamDelegate* delegate =
- static_cast<MockSocketStreamDelegate*>(websocket_->delegate_);
- DCHECK(delegate);
- return delegate->received_data();
- }
-
- void TestSimpleHandshake();
- void TestSlowHandshake();
- void TestHandshakeWithCookie();
- void TestHandshakeWithCookieButNotAllowed();
- void TestHSTSUpgrade();
- void TestInvalidSendData();
- void TestConnectByWebSocket(ThrottlingOption throttling);
- void TestConnectBySpdy(SpdyOption spdy, ThrottlingOption throttling);
- void TestThrottlingLimit();
-
- SpdyWebSocketTestUtil spdy_util_;
- StreamType stream_type_;
- scoped_refptr<MockCookieStore> cookie_store_;
- scoped_ptr<MockURLRequestContext> context_;
- scoped_refptr<WebSocketJob> websocket_;
- scoped_refptr<SocketStream> socket_;
- scoped_ptr<MockClientSocketFactory> socket_factory_;
- scoped_ptr<OrderedSocketData> data_;
- TestCompletionCallback sync_test_callback_;
- scoped_refptr<MockSSLConfigService> ssl_config_service_;
- scoped_ptr<ProxyService> proxy_service_;
- scoped_ptr<MockHostResolver> host_resolver_;
- scoped_ptr<MockHttpTransactionFactory> http_factory_;
-
- // Must be set before call to enable_websocket_over_spdy, defaults to false.
- bool enable_websocket_over_spdy_;
-
- static const char kHandshakeRequestWithoutCookie[];
- static const char kHandshakeRequestWithCookie[];
- static const char kHandshakeRequestWithFilteredCookie[];
- static const char kHandshakeResponseWithoutCookie[];
- static const char kHandshakeResponseWithCookie[];
- static const char kDataHello[];
- static const char kDataWorld[];
- static const char* const kHandshakeRequestForSpdy[];
- static const char* const kHandshakeResponseForSpdy[];
- static const size_t kHandshakeRequestWithoutCookieLength;
- static const size_t kHandshakeRequestWithCookieLength;
- static const size_t kHandshakeRequestWithFilteredCookieLength;
- static const size_t kHandshakeResponseWithoutCookieLength;
- static const size_t kHandshakeResponseWithCookieLength;
- static const size_t kDataHelloLength;
- static const size_t kDataWorldLength;
-};
-
-// Tests using this fixture verify that the WebSocketJob can handle being
-// deleted while calling back to the delegate correctly. These tests need to be
-// run under AddressSanitizer or other systems for detecting use-after-free
-// errors in order to find problems.
-class WebSocketJobDeleteTest : public ::testing::Test {
- protected:
- WebSocketJobDeleteTest()
- : delegate_(new DeletingSocketStreamDelegate),
- cookie_store_(new MockCookieStore),
- context_(new MockURLRequestContext(cookie_store_.get())) {
- WebSocketJob* websocket = new WebSocketJob(delegate_.get());
- delegate_->set_job(websocket);
-
- socket_ = new MockSocketStream(
- GURL("ws://127.0.0.1/"), websocket, context_.get(), NULL);
-
- websocket->InitSocketStream(socket_.get());
- }
-
- void SetDeleteNext() { return delegate_->set_delete_next(true); }
- WebSocketJob* job() { return delegate_->job(); }
-
- scoped_ptr<DeletingSocketStreamDelegate> delegate_;
- scoped_refptr<MockCookieStore> cookie_store_;
- scoped_ptr<MockURLRequestContext> context_;
- scoped_refptr<SocketStream> socket_;
-};
-
-const char WebSocketJobTest::kHandshakeRequestWithoutCookie[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n";
-
-const char WebSocketJobTest::kHandshakeRequestWithCookie[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Cookie: WK-test=1\r\n"
- "\r\n";
-
-const char WebSocketJobTest::kHandshakeRequestWithFilteredCookie[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Origin: http://example.com\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Cookie: CR-test=1; CR-test-httponly=1\r\n"
- "\r\n";
-
-const char WebSocketJobTest::kHandshakeResponseWithoutCookie[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "\r\n";
-
-const char WebSocketJobTest::kHandshakeResponseWithCookie[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Set-Cookie: CR-set-test=1\r\n"
- "\r\n";
-
-const char WebSocketJobTest::kDataHello[] = "Hello, ";
-
-const char WebSocketJobTest::kDataWorld[] = "World!\n";
-
-const size_t WebSocketJobTest::kHandshakeRequestWithoutCookieLength =
- arraysize(kHandshakeRequestWithoutCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeRequestWithCookieLength =
- arraysize(kHandshakeRequestWithCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeRequestWithFilteredCookieLength =
- arraysize(kHandshakeRequestWithFilteredCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeResponseWithoutCookieLength =
- arraysize(kHandshakeResponseWithoutCookie) - 1;
-const size_t WebSocketJobTest::kHandshakeResponseWithCookieLength =
- arraysize(kHandshakeResponseWithCookie) - 1;
-const size_t WebSocketJobTest::kDataHelloLength =
- arraysize(kDataHello) - 1;
-const size_t WebSocketJobTest::kDataWorldLength =
- arraysize(kDataWorld) - 1;
-
-void WebSocketJobTest::TestSimpleHandshake() {
- GURL url("ws://example.com/demo");
- MockSocketStreamDelegate delegate;
- InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
- SkipToConnecting();
-
- DoSendRequest();
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- websocket_->OnSentData(socket_.get(),
- kHandshakeRequestWithoutCookieLength);
- EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
-
- websocket_->OnReceivedData(socket_.get(),
- kHandshakeResponseWithoutCookie,
- kHandshakeResponseWithoutCookieLength);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
- EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
- CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestSlowHandshake() {
- GURL url("ws://example.com/demo");
- MockSocketStreamDelegate delegate;
- InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
- SkipToConnecting();
-
- DoSendRequest();
- // We assume request is sent in one data chunk (from WebKit)
- // We don't support streaming request.
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- websocket_->OnSentData(socket_.get(),
- kHandshakeRequestWithoutCookieLength);
- EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
-
- std::vector<std::string> lines;
- base::SplitString(kHandshakeResponseWithoutCookie, '\n', &lines);
- for (size_t i = 0; i < lines.size() - 2; i++) {
- std::string line = lines[i] + "\r\n";
- SCOPED_TRACE("Line: " + line);
- websocket_->OnReceivedData(socket_.get(), line.c_str(), line.size());
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_TRUE(delegate.received_data().empty());
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- }
- websocket_->OnReceivedData(socket_.get(), "\r\n", 2);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_FALSE(delegate.received_data().empty());
- EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
- EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
- CloseWebSocketJob();
-}
-
-INSTANTIATE_TEST_CASE_P(
- NextProto,
- WebSocketJobTest,
- testing::Values(kProtoDeprecatedSPDY2,
- kProtoSPDY3, kProtoSPDY31, kProtoSPDY4));
-
-TEST_P(WebSocketJobTest, DelayedCookies) {
- enable_websocket_over_spdy_ = true;
- GURL url("ws://example.com/demo");
- GURL cookieUrl("http://example.com/demo");
- CookieOptions cookie_options;
- scoped_refptr<DelayedCookieMonster> cookie_store = new DelayedCookieMonster();
- context_->set_cookie_store(cookie_store.get());
- cookie_store->SetCookieWithOptionsAsync(cookieUrl,
- "CR-test=1",
- cookie_options,
- CookieMonster::SetCookiesCallback());
- cookie_options.set_include_httponly();
- cookie_store->SetCookieWithOptionsAsync(
- cookieUrl, "CR-test-httponly=1", cookie_options,
- CookieMonster::SetCookiesCallback());
-
- MockSocketStreamDelegate delegate;
- InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
- SkipToConnecting();
-
- bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
- kHandshakeRequestWithCookieLength);
- EXPECT_TRUE(sent);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- websocket_->OnSentData(socket_.get(),
- kHandshakeRequestWithFilteredCookieLength);
- EXPECT_EQ(kHandshakeRequestWithCookieLength,
- delegate.amount_sent());
-
- websocket_->OnReceivedData(socket_.get(),
- kHandshakeResponseWithCookie,
- kHandshakeResponseWithCookieLength);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
- EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-
- CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestHandshakeWithCookie() {
- GURL url("ws://example.com/demo");
- GURL cookieUrl("http://example.com/demo");
- CookieOptions cookie_options;
- cookie_store_->SetCookieWithOptions(
- cookieUrl, "CR-test=1", cookie_options);
- cookie_options.set_include_httponly();
- cookie_store_->SetCookieWithOptions(
- cookieUrl, "CR-test-httponly=1", cookie_options);
-
- MockSocketStreamDelegate delegate;
- InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
- SkipToConnecting();
-
- bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
- kHandshakeRequestWithCookieLength);
- EXPECT_TRUE(sent);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeRequestWithFilteredCookie, sent_data());
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- websocket_->OnSentData(socket_.get(),
- kHandshakeRequestWithFilteredCookieLength);
- EXPECT_EQ(kHandshakeRequestWithCookieLength,
- delegate.amount_sent());
-
- websocket_->OnReceivedData(socket_.get(),
- kHandshakeResponseWithCookie,
- kHandshakeResponseWithCookieLength);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
- EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-
- EXPECT_EQ(3U, cookie_store_->entries().size());
- EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
- EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
- EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
- EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
- EXPECT_EQ(cookieUrl, cookie_store_->entries()[2].url);
- EXPECT_EQ("CR-set-test=1", cookie_store_->entries()[2].cookie_line);
-
- CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestHandshakeWithCookieButNotAllowed() {
- GURL url("ws://example.com/demo");
- GURL cookieUrl("http://example.com/demo");
- CookieOptions cookie_options;
- cookie_store_->SetCookieWithOptions(
- cookieUrl, "CR-test=1", cookie_options);
- cookie_options.set_include_httponly();
- cookie_store_->SetCookieWithOptions(
- cookieUrl, "CR-test-httponly=1", cookie_options);
-
- MockSocketStreamDelegate delegate;
- delegate.set_allow_all_cookies(false);
- InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
- SkipToConnecting();
-
- bool sent = websocket_->SendData(kHandshakeRequestWithCookie,
- kHandshakeRequestWithCookieLength);
- EXPECT_TRUE(sent);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- websocket_->OnSentData(socket_.get(), kHandshakeRequestWithoutCookieLength);
- EXPECT_EQ(kHandshakeRequestWithCookieLength, delegate.amount_sent());
-
- websocket_->OnReceivedData(socket_.get(),
- kHandshakeResponseWithCookie,
- kHandshakeResponseWithCookieLength);
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeResponseWithoutCookie, delegate.received_data());
- EXPECT_EQ(WebSocketJob::OPEN, GetWebSocketJobState());
-
- EXPECT_EQ(2U, cookie_store_->entries().size());
- EXPECT_EQ(cookieUrl, cookie_store_->entries()[0].url);
- EXPECT_EQ("CR-test=1", cookie_store_->entries()[0].cookie_line);
- EXPECT_EQ(cookieUrl, cookie_store_->entries()[1].url);
- EXPECT_EQ("CR-test-httponly=1", cookie_store_->entries()[1].cookie_line);
-
- CloseWebSocketJob();
-}
-
-void WebSocketJobTest::TestHSTSUpgrade() {
- GURL url("ws://upgrademe.com/");
- MockSocketStreamDelegate delegate;
- scoped_refptr<SocketStreamJob> job =
- SocketStreamJob::CreateSocketStreamJob(
- url, &delegate, context_->transport_security_state(),
- context_->ssl_config_service(), NULL, NULL);
- EXPECT_TRUE(GetSocket(job.get())->is_secure());
- job->DetachDelegate();
-
- url = GURL("ws://donotupgrademe.com/");
- job = SocketStreamJob::CreateSocketStreamJob(
- url, &delegate, context_->transport_security_state(),
- context_->ssl_config_service(), NULL, NULL);
- EXPECT_FALSE(GetSocket(job.get())->is_secure());
- job->DetachDelegate();
-}
-
-void WebSocketJobTest::TestInvalidSendData() {
- GURL url("ws://example.com/demo");
- MockSocketStreamDelegate delegate;
- InitWebSocketJob(url, &delegate, STREAM_MOCK_SOCKET);
- SkipToConnecting();
-
- DoSendRequest();
- // We assume request is sent in one data chunk (from WebKit)
- // We don't support streaming request.
- base::MessageLoop::current()->RunUntilIdle();
- EXPECT_EQ(kHandshakeRequestWithoutCookie, sent_data());
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- websocket_->OnSentData(socket_.get(),
- kHandshakeRequestWithoutCookieLength);
- EXPECT_EQ(kHandshakeRequestWithoutCookieLength, delegate.amount_sent());
-
- // We could not send any data until connection is established.
- bool sent = websocket_->SendData(kHandshakeRequestWithoutCookie,
- kHandshakeRequestWithoutCookieLength);
- EXPECT_FALSE(sent);
- EXPECT_EQ(WebSocketJob::CONNECTING, GetWebSocketJobState());
- CloseWebSocketJob();
-}
-
-// Following tests verify cooperation between WebSocketJob and SocketStream.
-// Other former tests use MockSocketStream as SocketStream, so we could not
-// check SocketStream behavior.
-// OrderedSocketData provide socket level verifiation by checking out-going
-// packets in comparison with the MockWrite array and emulating in-coming
-// packets with MockRead array.
-
-void WebSocketJobTest::TestConnectByWebSocket(
- ThrottlingOption throttling) {
- // This is a test for verifying cooperation between WebSocketJob and
- // SocketStream. If |throttling| was |THROTTLING_OFF|, it test basic
- // situation. If |throttling| was |THROTTLING_ON|, throttling limits the
- // latter connection.
- MockWrite writes[] = {
- MockWrite(ASYNC,
- kHandshakeRequestWithoutCookie,
- kHandshakeRequestWithoutCookieLength,
- 1),
- MockWrite(ASYNC,
- kDataHello,
- kDataHelloLength,
- 3)
- };
- MockRead reads[] = {
- MockRead(ASYNC,
- kHandshakeResponseWithoutCookie,
- kHandshakeResponseWithoutCookieLength,
- 2),
- MockRead(ASYNC,
- kDataWorld,
- kDataWorldLength,
- 4),
- MockRead(SYNCHRONOUS, 0, 5) // EOF
- };
- data_.reset(new OrderedSocketData(
- reads, arraysize(reads), writes, arraysize(writes)));
-
- GURL url("ws://example.com/demo");
- MockSocketStreamDelegate delegate;
- WebSocketJobTest* test = this;
- if (throttling == THROTTLING_ON)
- delegate.SetOnStartOpenConnection(
- base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
- delegate.SetOnConnected(
- base::Bind(&WebSocketJobTest::DoSendRequest,
- base::Unretained(test)));
- delegate.SetOnReceivedData(
- base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
- delegate.SetOnClose(
- base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
- InitWebSocketJob(url, &delegate, STREAM_SOCKET);
-
- scoped_refptr<WebSocketJob> block_websocket;
- if (throttling == THROTTLING_ON) {
- // Create former WebSocket object which obstructs the latter one.
- block_websocket = new WebSocketJob(NULL);
- block_websocket->addresses_ = AddressList(websocket_->address_list());
- ASSERT_TRUE(
- WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get()));
- }
-
- websocket_->Connect();
-
- if (throttling == THROTTLING_ON) {
- EXPECT_EQ(OK, WaitForResult());
- EXPECT_TRUE(websocket_->IsWaiting());
-
- // Remove the former WebSocket object from throttling queue to unblock the
- // latter.
- block_websocket->state_ = WebSocketJob::CLOSED;
- WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get());
- block_websocket = NULL;
- }
-
- EXPECT_EQ(OK, WaitForResult());
- EXPECT_TRUE(data_->at_read_eof());
- EXPECT_TRUE(data_->at_write_eof());
- EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
-}
-
-void WebSocketJobTest::TestConnectBySpdy(
- SpdyOption spdy, ThrottlingOption throttling) {
- // This is a test for verifying cooperation between WebSocketJob and
- // SocketStream in the situation we have SPDY session to the server. If
- // |throttling| was |THROTTLING_ON|, throttling limits the latter connection.
- // If you enabled spdy, you should specify |spdy| as |SPDY_ON|. Expected
- // results depend on its configuration.
- MockWrite writes_websocket[] = {
- MockWrite(ASYNC,
- kHandshakeRequestWithoutCookie,
- kHandshakeRequestWithoutCookieLength,
- 1),
- MockWrite(ASYNC,
- kDataHello,
- kDataHelloLength,
- 3)
- };
- MockRead reads_websocket[] = {
- MockRead(ASYNC,
- kHandshakeResponseWithoutCookie,
- kHandshakeResponseWithoutCookieLength,
- 2),
- MockRead(ASYNC,
- kDataWorld,
- kDataWorldLength,
- 4),
- MockRead(SYNCHRONOUS, 0, 5) // EOF
- };
-
- scoped_ptr<SpdyHeaderBlock> request_headers(new SpdyHeaderBlock());
- spdy_util_.SetHeader("path", "/demo", request_headers.get());
- spdy_util_.SetHeader("version", "WebSocket/13", request_headers.get());
- spdy_util_.SetHeader("scheme", "ws", request_headers.get());
- spdy_util_.SetHeader("host", "example.com", request_headers.get());
- spdy_util_.SetHeader("origin", "http://example.com", request_headers.get());
- spdy_util_.SetHeader("sec-websocket-protocol", "sample",
- request_headers.get());
-
- scoped_ptr<SpdyHeaderBlock> response_headers(new SpdyHeaderBlock());
- spdy_util_.SetHeader("status", "101 Switching Protocols",
- response_headers.get());
- spdy_util_.SetHeader("sec-websocket-protocol", "sample",
- response_headers.get());
-
- const SpdyStreamId kStreamId = 1;
- scoped_ptr<SpdyFrame> request_frame(
- spdy_util_.ConstructSpdyWebSocketHandshakeRequestFrame(
- request_headers.Pass(),
- kStreamId,
- MEDIUM));
- scoped_ptr<SpdyFrame> response_frame(
- spdy_util_.ConstructSpdyWebSocketHandshakeResponseFrame(
- response_headers.Pass(),
- kStreamId,
- MEDIUM));
- scoped_ptr<SpdyFrame> data_hello_frame(
- spdy_util_.ConstructSpdyWebSocketDataFrame(
- kDataHello,
- kDataHelloLength,
- kStreamId,
- false));
- scoped_ptr<SpdyFrame> data_world_frame(
- spdy_util_.ConstructSpdyWebSocketDataFrame(
- kDataWorld,
- kDataWorldLength,
- kStreamId,
- false));
- MockWrite writes_spdy[] = {
- CreateMockWrite(*request_frame.get(), 1),
- CreateMockWrite(*data_hello_frame.get(), 3),
- };
- MockRead reads_spdy[] = {
- CreateMockRead(*response_frame.get(), 2),
- CreateMockRead(*data_world_frame.get(), 4),
- MockRead(SYNCHRONOUS, 0, 5) // EOF
- };
-
- if (spdy == SPDY_ON)
- data_.reset(new OrderedSocketData(
- reads_spdy, arraysize(reads_spdy),
- writes_spdy, arraysize(writes_spdy)));
- else
- data_.reset(new OrderedSocketData(
- reads_websocket, arraysize(reads_websocket),
- writes_websocket, arraysize(writes_websocket)));
-
- GURL url("ws://example.com/demo");
- MockSocketStreamDelegate delegate;
- WebSocketJobTest* test = this;
- if (throttling == THROTTLING_ON)
- delegate.SetOnStartOpenConnection(
- base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
- delegate.SetOnConnected(
- base::Bind(&WebSocketJobTest::DoSendRequest,
- base::Unretained(test)));
- delegate.SetOnReceivedData(
- base::Bind(&WebSocketJobTest::DoSendData, base::Unretained(test)));
- delegate.SetOnClose(
- base::Bind(&WebSocketJobTest::DoSync, base::Unretained(test)));
- InitWebSocketJob(url, &delegate, STREAM_SPDY_WEBSOCKET);
-
- scoped_refptr<WebSocketJob> block_websocket;
- if (throttling == THROTTLING_ON) {
- // Create former WebSocket object which obstructs the latter one.
- block_websocket = new WebSocketJob(NULL);
- block_websocket->addresses_ = AddressList(websocket_->address_list());
- ASSERT_TRUE(
- WebSocketThrottle::GetInstance()->PutInQueue(block_websocket.get()));
- }
-
- websocket_->Connect();
-
- if (throttling == THROTTLING_ON) {
- EXPECT_EQ(OK, WaitForResult());
- EXPECT_TRUE(websocket_->IsWaiting());
-
- // Remove the former WebSocket object from throttling queue to unblock the
- // latter.
- block_websocket->state_ = WebSocketJob::CLOSED;
- WebSocketThrottle::GetInstance()->RemoveFromQueue(block_websocket.get());
- block_websocket = NULL;
- }
-
- EXPECT_EQ(OK, WaitForResult());
- EXPECT_TRUE(data_->at_read_eof());
- EXPECT_TRUE(data_->at_write_eof());
- EXPECT_EQ(WebSocketJob::CLOSED, GetWebSocketJobState());
-}
-
-void WebSocketJobTest::TestThrottlingLimit() {
- std::vector<scoped_refptr<WebSocketJob> > jobs;
- const int kMaxWebSocketJobsThrottled = 1024;
- IPAddressNumber ip;
- ParseIPLiteralToNumber("127.0.0.1", &ip);
- for (int i = 0; i < kMaxWebSocketJobsThrottled + 1; ++i) {
- scoped_refptr<WebSocketJob> job = new WebSocketJob(NULL);
- job->addresses_ = AddressList(AddressList::CreateFromIPAddress(ip, 80));
- if (i >= kMaxWebSocketJobsThrottled)
- EXPECT_FALSE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
- else
- EXPECT_TRUE(WebSocketThrottle::GetInstance()->PutInQueue(job.get()));
- jobs.push_back(job);
- }
-
- // Close the jobs in reverse order. Otherwise, We need to make them prepared
- // for Wakeup call.
- for (std::vector<scoped_refptr<WebSocketJob> >::reverse_iterator iter =
- jobs.rbegin();
- iter != jobs.rend();
- ++iter) {
- WebSocketJob* job = (*iter).get();
- job->state_ = WebSocketJob::CLOSED;
- WebSocketThrottle::GetInstance()->RemoveFromQueue(job);
- }
-}
-
-// Execute tests in both spdy-disabled mode and spdy-enabled mode.
-TEST_P(WebSocketJobTest, SimpleHandshake) {
- TestSimpleHandshake();
-}
-
-TEST_P(WebSocketJobTest, SlowHandshake) {
- TestSlowHandshake();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookie) {
- TestHandshakeWithCookie();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowed) {
- TestHandshakeWithCookieButNotAllowed();
-}
-
-TEST_P(WebSocketJobTest, HSTSUpgrade) {
- TestHSTSUpgrade();
-}
-
-TEST_P(WebSocketJobTest, InvalidSendData) {
- TestInvalidSendData();
-}
-
-TEST_P(WebSocketJobTest, SimpleHandshakeSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestSimpleHandshake();
-}
-
-TEST_P(WebSocketJobTest, SlowHandshakeSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestSlowHandshake();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookieSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestHandshakeWithCookie();
-}
-
-TEST_P(WebSocketJobTest, HandshakeWithCookieButNotAllowedSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestHandshakeWithCookieButNotAllowed();
-}
-
-TEST_P(WebSocketJobTest, HSTSUpgradeSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestHSTSUpgrade();
-}
-
-TEST_P(WebSocketJobTest, InvalidSendDataSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestInvalidSendData();
-}
-
-TEST_P(WebSocketJobTest, ConnectByWebSocket) {
- enable_websocket_over_spdy_ = true;
- TestConnectByWebSocket(THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ConnectByWebSocketSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestConnectByWebSocket(THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ConnectBySpdy) {
- TestConnectBySpdy(SPDY_OFF, THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ConnectBySpdySpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestConnectBySpdy(SPDY_ON, THROTTLING_OFF);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingWebSocket) {
- TestConnectByWebSocket(THROTTLING_ON);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingMaxNumberOfThrottledJobLimit) {
- TestThrottlingLimit();
-}
-
-TEST_P(WebSocketJobTest, ThrottlingWebSocketSpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestConnectByWebSocket(THROTTLING_ON);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingSpdy) {
- TestConnectBySpdy(SPDY_OFF, THROTTLING_ON);
-}
-
-TEST_P(WebSocketJobTest, ThrottlingSpdySpdyEnabled) {
- enable_websocket_over_spdy_ = true;
- TestConnectBySpdy(SPDY_ON, THROTTLING_ON);
-}
-
-TEST_F(WebSocketJobDeleteTest, OnClose) {
- SetDeleteNext();
- job()->OnClose(socket_.get());
- // OnClose() sets WebSocketJob::_socket to NULL before we can detach it, so
- // socket_->delegate is still set at this point. Clear it to avoid hitting
- // DCHECK(!delegate_) in the SocketStream destructor. SocketStream::Finish()
- // is the only caller of this method in real code, and it also sets delegate_
- // to NULL.
- socket_->DetachDelegate();
- EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnAuthRequired) {
- SetDeleteNext();
- job()->OnAuthRequired(socket_.get(), NULL);
- EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnSSLCertificateError) {
- SSLInfo ssl_info;
- SetDeleteNext();
- job()->OnSSLCertificateError(socket_.get(), ssl_info, true);
- EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnError) {
- SetDeleteNext();
- job()->OnError(socket_.get(), ERR_CONNECTION_RESET);
- EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnSentSpdyHeaders) {
- job()->Connect();
- SetDeleteNext();
- job()->OnSentSpdyHeaders();
- EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, OnSentHandshakeRequest) {
- static const char kMinimalRequest[] =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==\r\n"
- "Origin: http://example.com\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "\r\n";
- const size_t kMinimalRequestSize = arraysize(kMinimalRequest) - 1;
- job()->Connect();
- job()->SendData(kMinimalRequest, kMinimalRequestSize);
- SetDeleteNext();
- job()->OnSentData(socket_.get(), kMinimalRequestSize);
- EXPECT_FALSE(job());
-}
-
-TEST_F(WebSocketJobDeleteTest, NotifyHeadersComplete) {
- static const char kMinimalResponse[] =
- "HTTP/1.1 101 Switching Protocols\r\n"
- "Upgrade: websocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=\r\n"
- "\r\n";
- job()->Connect();
- SetDeleteNext();
- job()->OnReceivedData(
- socket_.get(), kMinimalResponse, arraysize(kMinimalResponse) - 1);
- EXPECT_FALSE(job());
-}
-
-// TODO(toyoshim): Add tests to verify throttling, SPDY stream limitation.
-// TODO(toyoshim,yutak): Add tests to verify closing handshake.
-} // namespace net
diff --git a/net/websockets/websocket_net_log_params.cc b/net/websockets/websocket_net_log_params.cc
deleted file mode 100644
index dd9bdde..0000000
--- a/net/websockets/websocket_net_log_params.cc
+++ /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.
-
-#include "net/websockets/websocket_net_log_params.h"
-
-#include "base/strings/stringprintf.h"
-#include "base/values.h"
-
-namespace net {
-
-base::Value* NetLogWebSocketHandshakeCallback(
- const std::string* headers,
- NetLog::LogLevel /* log_level */) {
- base::DictionaryValue* dict = new base::DictionaryValue();
- base::ListValue* header_list = new base::ListValue();
-
- size_t last = 0;
- size_t headers_size = headers->size();
- size_t pos = 0;
- while (pos <= headers_size) {
- if (pos == headers_size ||
- ((*headers)[pos] == '\r' &&
- pos + 1 < headers_size && (*headers)[pos + 1] == '\n')) {
- std::string entry = headers->substr(last, pos - last);
- pos += 2;
- last = pos;
-
- header_list->Append(new base::StringValue(entry));
-
- if (entry.empty()) {
- // Dump WebSocket key3.
- std::string key;
- for (; pos < headers_size; ++pos) {
- key += base::StringPrintf("\\x%02x", (*headers)[pos] & 0xff);
- }
- header_list->Append(new base::StringValue(key));
- break;
- }
- } else {
- ++pos;
- }
- }
-
- dict->Set("headers", header_list);
- return dict;
-}
-
-} // namespace net
diff --git a/net/websockets/websocket_net_log_params.h b/net/websockets/websocket_net_log_params.h
deleted file mode 100644
index 45dabb0..0000000
--- a/net/websockets/websocket_net_log_params.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_
-#define NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_
-
-#include <string>
-
-#include "net/base/net_export.h"
-#include "net/base/net_log.h"
-
-namespace net {
-
-NET_EXPORT_PRIVATE base::Value* NetLogWebSocketHandshakeCallback(
- const std::string* headers,
- NetLog::LogLevel /* log_level */);
-
-} // namespace net
-
-#endif // NET_WEBSOCKETS_WEBSOCKET_NET_LOG_PARAMS_H_
diff --git a/net/websockets/websocket_net_log_params_test.cc b/net/websockets/websocket_net_log_params_test.cc
deleted file mode 100644
index d6d2a0d..0000000
--- a/net/websockets/websocket_net_log_params_test.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_net_log_params.h"
-
-#include <string>
-
-#include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/values.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-TEST(NetLogWebSocketHandshakeParameterTest, ToValue) {
- base::ListValue* list = new base::ListValue();
- list->Append(new base::StringValue("GET /demo HTTP/1.1"));
- list->Append(new base::StringValue("Host: example.com"));
- list->Append(new base::StringValue("Connection: Upgrade"));
- list->Append(new base::StringValue("Sec-WebSocket-Key2: 12998 5 Y3 1 .P00"));
- list->Append(new base::StringValue("Sec-WebSocket-Protocol: sample"));
- list->Append(new base::StringValue("Upgrade: WebSocket"));
- list->Append(new base::StringValue(
- "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5"));
- list->Append(new base::StringValue("Origin: http://example.com"));
- list->Append(new base::StringValue(std::string()));
- list->Append(new base::StringValue(
- "\\x00\\x01\\x0a\\x0d\\xff\\xfe\\x0d\\x0a"));
-
- base::DictionaryValue expected;
- expected.Set("headers", list);
-
- const std::string key("\x00\x01\x0a\x0d\xff\xfe\x0d\x0a", 8);
- const std::string testInput =
- "GET /demo HTTP/1.1\r\n"
- "Host: example.com\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Key2: 12998 5 Y3 1 .P00\r\n"
- "Sec-WebSocket-Protocol: sample\r\n"
- "Upgrade: WebSocket\r\n"
- "Sec-WebSocket-Key1: 4 @1 46546xW%0l 1 5\r\n"
- "Origin: http://example.com\r\n"
- "\r\n" +
- key;
-
- scoped_ptr<base::Value> actual(
- net::NetLogWebSocketHandshakeCallback(&testInput,
- net::NetLog::LOG_ALL));
-
- EXPECT_TRUE(expected.Equals(actual.get()));
-}
diff --git a/net/websockets/websocket_throttle.cc b/net/websockets/websocket_throttle.cc
deleted file mode 100644
index 59e73fd..0000000
--- a/net/websockets/websocket_throttle.cc
+++ /dev/null
@@ -1,144 +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/websockets/websocket_throttle.h"
-
-#include <algorithm>
-#include <set>
-#include <string>
-#include <utility>
-
-#include "base/memory/singleton.h"
-#include "base/message_loop/message_loop.h"
-#include "base/strings/string_number_conversions.h"
-#include "base/strings/string_util.h"
-#include "base/strings/stringprintf.h"
-#include "net/base/io_buffer.h"
-#include "net/socket_stream/socket_stream.h"
-#include "net/websockets/websocket_job.h"
-
-namespace net {
-
-namespace {
-
-const size_t kMaxWebSocketJobsThrottled = 1024;
-
-} // namespace
-
-WebSocketThrottle::WebSocketThrottle() {
-}
-
-WebSocketThrottle::~WebSocketThrottle() {
- DCHECK(queue_.empty());
- DCHECK(addr_map_.empty());
-}
-
-// static
-WebSocketThrottle* WebSocketThrottle::GetInstance() {
- return Singleton<WebSocketThrottle>::get();
-}
-
-bool WebSocketThrottle::PutInQueue(WebSocketJob* job) {
- if (queue_.size() >= kMaxWebSocketJobsThrottled)
- return false;
-
- queue_.push_back(job);
- const AddressList& address_list = job->address_list();
- std::set<IPEndPoint> address_set;
- for (AddressList::const_iterator addr_iter = address_list.begin();
- addr_iter != address_list.end();
- ++addr_iter) {
- const IPEndPoint& address = *addr_iter;
- // If |address| is already processed, don't do it again.
- if (!address_set.insert(address).second)
- continue;
-
- ConnectingAddressMap::iterator iter = addr_map_.find(address);
- if (iter == addr_map_.end()) {
- ConnectingAddressMap::iterator new_queue =
- addr_map_.insert(make_pair(address, ConnectingQueue())).first;
- new_queue->second.push_back(job);
- } else {
- DCHECK(!iter->second.empty());
- iter->second.push_back(job);
- job->SetWaiting();
- DVLOG(1) << "Waiting on " << address.ToString();
- }
- }
-
- return true;
-}
-
-void WebSocketThrottle::RemoveFromQueue(WebSocketJob* job) {
- ConnectingQueue::iterator queue_iter =
- std::find(queue_.begin(), queue_.end(), job);
- if (queue_iter == queue_.end())
- return;
- queue_.erase(queue_iter);
-
- std::set<WebSocketJob*> wakeup_candidates;
-
- const AddressList& resolved_address_list = job->address_list();
- std::set<IPEndPoint> address_set;
- for (AddressList::const_iterator addr_iter = resolved_address_list.begin();
- addr_iter != resolved_address_list.end();
- ++addr_iter) {
- const IPEndPoint& address = *addr_iter;
- // If |address| is already processed, don't do it again.
- if (!address_set.insert(address).second)
- continue;
-
- ConnectingAddressMap::iterator map_iter = addr_map_.find(address);
- DCHECK(map_iter != addr_map_.end());
-
- ConnectingQueue& per_address_queue = map_iter->second;
- DCHECK(!per_address_queue.empty());
- // Job may not be front of the queue if the socket is closed while waiting.
- ConnectingQueue::iterator per_address_queue_iter =
- std::find(per_address_queue.begin(), per_address_queue.end(), job);
- bool was_front = false;
- if (per_address_queue_iter != per_address_queue.end()) {
- was_front = (per_address_queue_iter == per_address_queue.begin());
- per_address_queue.erase(per_address_queue_iter);
- }
- if (per_address_queue.empty()) {
- addr_map_.erase(map_iter);
- } else if (was_front) {
- // The new front is a wake-up candidate.
- wakeup_candidates.insert(per_address_queue.front());
- }
- }
-
- WakeupSocketIfNecessary(wakeup_candidates);
-}
-
-void WebSocketThrottle::WakeupSocketIfNecessary(
- const std::set<WebSocketJob*>& wakeup_candidates) {
- for (std::set<WebSocketJob*>::const_iterator iter = wakeup_candidates.begin();
- iter != wakeup_candidates.end();
- ++iter) {
- WebSocketJob* job = *iter;
- if (!job->IsWaiting())
- continue;
-
- bool should_wakeup = true;
- const AddressList& resolved_address_list = job->address_list();
- for (AddressList::const_iterator addr_iter = resolved_address_list.begin();
- addr_iter != resolved_address_list.end();
- ++addr_iter) {
- const IPEndPoint& address = *addr_iter;
- ConnectingAddressMap::iterator map_iter = addr_map_.find(address);
- DCHECK(map_iter != addr_map_.end());
- const ConnectingQueue& per_address_queue = map_iter->second;
- if (job != per_address_queue.front()) {
- should_wakeup = false;
- break;
- }
- }
- if (should_wakeup)
- job->Wakeup();
- }
-}
-
-} // namespace net
diff --git a/net/websockets/websocket_throttle.h b/net/websockets/websocket_throttle.h
deleted file mode 100644
index 0b7a39f..0000000
--- a/net/websockets/websocket_throttle.h
+++ /dev/null
@@ -1,75 +0,0 @@
-// Copyright (c) 2011 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_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
-#define NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
-
-#include <deque>
-#include <map>
-#include <set>
-#include <string>
-
-#include "net/base/ip_endpoint.h"
-#include "net/base/net_export.h"
-
-template <typename T> struct DefaultSingletonTraits;
-
-namespace net {
-
-class SocketStream;
-class WebSocketJob;
-
-// SocketStreamThrottle for WebSocket protocol.
-// Implements the client-side requirements in the spec.
-// http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol
-// 4.1 Handshake
-// 1. If the user agent already has a Web Socket connection to the
-// remote host (IP address) identified by /host/, even if known by
-// another name, wait until that connection has been established or
-// for that connection to have failed.
-class NET_EXPORT_PRIVATE WebSocketThrottle {
- public:
- // Returns the singleton instance.
- static WebSocketThrottle* GetInstance();
-
- // Puts |job| in |queue_| and queues for the destination addresses
- // of |job|.
- // If other job is using the same destination address, set |job| waiting.
- //
- // Returns true if successful. If the number of pending jobs will exceed
- // the limit, does nothing and returns false.
- bool PutInQueue(WebSocketJob* job);
-
- // Removes |job| from |queue_| and queues for the destination addresses
- // of |job|, and then wakes up jobs that can now resume establishing a
- // connection.
- void RemoveFromQueue(WebSocketJob* job);
-
- private:
- typedef std::deque<WebSocketJob*> ConnectingQueue;
- typedef std::map<IPEndPoint, ConnectingQueue> ConnectingAddressMap;
-
- WebSocketThrottle();
- ~WebSocketThrottle();
- friend struct DefaultSingletonTraits<WebSocketThrottle>;
-
- // Examines if any of the given jobs can resume establishing a connection. If
- // for all per-address queues for each resolved addresses
- // (job->address_list()) of a job, the job is at the front of the queues, the
- // job can resume establishing a connection, so wakes up the job.
- void WakeupSocketIfNecessary(
- const std::set<WebSocketJob*>& wakeup_candidates);
-
- // Key: string of host's address. Value: queue of sockets for the address.
- ConnectingAddressMap addr_map_;
-
- // Queue of sockets for websockets in opening state.
- ConnectingQueue queue_;
-
- DISALLOW_COPY_AND_ASSIGN(WebSocketThrottle);
-};
-
-} // namespace net
-
-#endif // NET_WEBSOCKETS_WEBSOCKET_THROTTLE_H_
diff --git a/net/websockets/websocket_throttle_test.cc b/net/websockets/websocket_throttle_test.cc
deleted file mode 100644
index 4e27c83..0000000
--- a/net/websockets/websocket_throttle_test.cc
+++ /dev/null
@@ -1,359 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/websockets/websocket_throttle.h"
-
-#include <string>
-
-#include "base/message_loop/message_loop.h"
-#include "net/base/address_list.h"
-#include "net/base/test_completion_callback.h"
-#include "net/socket_stream/socket_stream.h"
-#include "net/url_request/url_request_test_util.h"
-#include "net/websockets/websocket_job.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/platform_test.h"
-#include "url/gurl.h"
-
-namespace net {
-
-namespace {
-
-class DummySocketStreamDelegate : public SocketStream::Delegate {
- public:
- DummySocketStreamDelegate() {}
- ~DummySocketStreamDelegate() override {}
- void OnConnected(SocketStream* socket,
- int max_pending_send_allowed) override {}
- void OnSentData(SocketStream* socket, int amount_sent) override {}
- void OnReceivedData(SocketStream* socket,
- const char* data,
- int len) override {}
- void OnClose(SocketStream* socket) override {}
-};
-
-class WebSocketThrottleTestContext : public TestURLRequestContext {
- public:
- explicit WebSocketThrottleTestContext(bool enable_websocket_over_spdy)
- : TestURLRequestContext(true) {
- HttpNetworkSession::Params params;
- params.enable_websocket_over_spdy = enable_websocket_over_spdy;
- Init();
- }
-};
-
-} // namespace
-
-class WebSocketThrottleTest : public PlatformTest {
- protected:
- static IPEndPoint MakeAddr(int a1, int a2, int a3, int a4) {
- IPAddressNumber ip;
- ip.push_back(a1);
- ip.push_back(a2);
- ip.push_back(a3);
- ip.push_back(a4);
- return IPEndPoint(ip, 0);
- }
-
- static void MockSocketStreamConnect(
- SocketStream* socket, const AddressList& list) {
- socket->set_addresses(list);
- // TODO(toyoshim): We should introduce additional tests on cases via proxy.
- socket->proxy_info_.UseDirect();
- // In SocketStream::Connect(), it adds reference to socket, which is
- // balanced with SocketStream::Finish() that is finally called from
- // SocketStream::Close() or SocketStream::DetachDelegate(), when
- // next_state_ is not STATE_NONE.
- // If next_state_ is STATE_NONE, SocketStream::Close() or
- // SocketStream::DetachDelegate() won't call SocketStream::Finish(),
- // so Release() won't be called. Thus, we don't need socket->AddRef()
- // here.
- DCHECK_EQ(socket->next_state_, SocketStream::STATE_NONE);
- }
-};
-
-TEST_F(WebSocketThrottleTest, Throttle) {
- // TODO(toyoshim): We need to consider both spdy-enabled and spdy-disabled
- // configuration.
- WebSocketThrottleTestContext context(true);
- DummySocketStreamDelegate delegate;
-
- // For host1: 1.2.3.4, 1.2.3.5, 1.2.3.6
- AddressList addr;
- addr.push_back(MakeAddr(1, 2, 3, 4));
- addr.push_back(MakeAddr(1, 2, 3, 5));
- addr.push_back(MakeAddr(1, 2, 3, 6));
- scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s1(
- new SocketStream(GURL("ws://host1/"), w1.get(), &context, NULL));
- w1->InitSocketStream(s1.get());
- WebSocketThrottleTest::MockSocketStreamConnect(s1.get(), addr);
-
- DVLOG(1) << "socket1";
- TestCompletionCallback callback_s1;
- // Trying to open connection to host1 will start without wait.
- EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback()));
-
- // Now connecting to host1, so waiting queue looks like
- // Address | head -> tail
- // 1.2.3.4 | w1
- // 1.2.3.5 | w1
- // 1.2.3.6 | w1
-
- // For host2: 1.2.3.4
- addr.clear();
- addr.push_back(MakeAddr(1, 2, 3, 4));
- scoped_refptr<WebSocketJob> w2(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s2(
- new SocketStream(GURL("ws://host2/"), w2.get(), &context, NULL));
- w2->InitSocketStream(s2.get());
- WebSocketThrottleTest::MockSocketStreamConnect(s2.get(), addr);
-
- DVLOG(1) << "socket2";
- TestCompletionCallback callback_s2;
- // Trying to open connection to host2 will wait for w1.
- EXPECT_EQ(ERR_IO_PENDING,
- w2->OnStartOpenConnection(s2.get(), callback_s2.callback()));
- // Now waiting queue looks like
- // Address | head -> tail
- // 1.2.3.4 | w1 w2
- // 1.2.3.5 | w1
- // 1.2.3.6 | w1
-
- // For host3: 1.2.3.5
- addr.clear();
- addr.push_back(MakeAddr(1, 2, 3, 5));
- scoped_refptr<WebSocketJob> w3(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s3(
- new SocketStream(GURL("ws://host3/"), w3.get(), &context, NULL));
- w3->InitSocketStream(s3.get());
- WebSocketThrottleTest::MockSocketStreamConnect(s3.get(), addr);
-
- DVLOG(1) << "socket3";
- TestCompletionCallback callback_s3;
- // Trying to open connection to host3 will wait for w1.
- EXPECT_EQ(ERR_IO_PENDING,
- w3->OnStartOpenConnection(s3.get(), callback_s3.callback()));
- // Address | head -> tail
- // 1.2.3.4 | w1 w2
- // 1.2.3.5 | w1 w3
- // 1.2.3.6 | w1
-
- // For host4: 1.2.3.4, 1.2.3.6
- addr.clear();
- addr.push_back(MakeAddr(1, 2, 3, 4));
- addr.push_back(MakeAddr(1, 2, 3, 6));
- scoped_refptr<WebSocketJob> w4(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s4(
- new SocketStream(GURL("ws://host4/"), w4.get(), &context, NULL));
- w4->InitSocketStream(s4.get());
- WebSocketThrottleTest::MockSocketStreamConnect(s4.get(), addr);
-
- DVLOG(1) << "socket4";
- TestCompletionCallback callback_s4;
- // Trying to open connection to host4 will wait for w1, w2.
- EXPECT_EQ(ERR_IO_PENDING,
- w4->OnStartOpenConnection(s4.get(), callback_s4.callback()));
- // Address | head -> tail
- // 1.2.3.4 | w1 w2 w4
- // 1.2.3.5 | w1 w3
- // 1.2.3.6 | w1 w4
-
- // For host5: 1.2.3.6
- addr.clear();
- addr.push_back(MakeAddr(1, 2, 3, 6));
- scoped_refptr<WebSocketJob> w5(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s5(
- new SocketStream(GURL("ws://host5/"), w5.get(), &context, NULL));
- w5->InitSocketStream(s5.get());
- WebSocketThrottleTest::MockSocketStreamConnect(s5.get(), addr);
-
- DVLOG(1) << "socket5";
- TestCompletionCallback callback_s5;
- // Trying to open connection to host5 will wait for w1, w4
- EXPECT_EQ(ERR_IO_PENDING,
- w5->OnStartOpenConnection(s5.get(), callback_s5.callback()));
- // Address | head -> tail
- // 1.2.3.4 | w1 w2 w4
- // 1.2.3.5 | w1 w3
- // 1.2.3.6 | w1 w4 w5
-
- // For host6: 1.2.3.6
- addr.clear();
- addr.push_back(MakeAddr(1, 2, 3, 6));
- scoped_refptr<WebSocketJob> w6(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s6(
- new SocketStream(GURL("ws://host6/"), w6.get(), &context, NULL));
- w6->InitSocketStream(s6.get());
- WebSocketThrottleTest::MockSocketStreamConnect(s6.get(), addr);
-
- DVLOG(1) << "socket6";
- TestCompletionCallback callback_s6;
- // Trying to open connection to host6 will wait for w1, w4, w5
- EXPECT_EQ(ERR_IO_PENDING,
- w6->OnStartOpenConnection(s6.get(), callback_s6.callback()));
- // Address | head -> tail
- // 1.2.3.4 | w1 w2 w4
- // 1.2.3.5 | w1 w3
- // 1.2.3.6 | w1 w4 w5 w6
-
- // Receive partial response on w1, still connecting.
- DVLOG(1) << "socket1 1";
- static const char kHeader[] = "HTTP/1.1 101 WebSocket Protocol\r\n";
- w1->OnReceivedData(s1.get(), kHeader, sizeof(kHeader) - 1);
- EXPECT_FALSE(callback_s2.have_result());
- EXPECT_FALSE(callback_s3.have_result());
- EXPECT_FALSE(callback_s4.have_result());
- EXPECT_FALSE(callback_s5.have_result());
- EXPECT_FALSE(callback_s6.have_result());
-
- // Receive rest of handshake response on w1.
- DVLOG(1) << "socket1 2";
- static const char kHeader2[] =
- "Upgrade: WebSocket\r\n"
- "Connection: Upgrade\r\n"
- "Sec-WebSocket-Origin: http://www.google.com\r\n"
- "Sec-WebSocket-Location: ws://websocket.chromium.org\r\n"
- "\r\n"
- "8jKS'y:G*Co,Wxa-";
- w1->OnReceivedData(s1.get(), kHeader2, sizeof(kHeader2) - 1);
- base::MessageLoopForIO::current()->RunUntilIdle();
- // Now, w1 is open.
- EXPECT_EQ(WebSocketJob::OPEN, w1->state());
- // So, w2 and w3 can start connecting. w4 needs to wait w2 (1.2.3.4)
- EXPECT_TRUE(callback_s2.have_result());
- EXPECT_TRUE(callback_s3.have_result());
- EXPECT_FALSE(callback_s4.have_result());
- // Address | head -> tail
- // 1.2.3.4 | w2 w4
- // 1.2.3.5 | w3
- // 1.2.3.6 | w4 w5 w6
-
- // Closing s1 doesn't change waiting queue.
- DVLOG(1) << "socket1 close";
- w1->OnClose(s1.get());
- base::MessageLoopForIO::current()->RunUntilIdle();
- EXPECT_FALSE(callback_s4.have_result());
- s1->DetachDelegate();
- // Address | head -> tail
- // 1.2.3.4 | w2 w4
- // 1.2.3.5 | w3
- // 1.2.3.6 | w4 w5 w6
-
- // w5 can close while waiting in queue.
- DVLOG(1) << "socket5 close";
- // w5 close() closes SocketStream that change state to STATE_CLOSE, calls
- // DoLoop(), so OnClose() callback will be called.
- w5->OnClose(s5.get());
- base::MessageLoopForIO::current()->RunUntilIdle();
- EXPECT_FALSE(callback_s4.have_result());
- // Address | head -> tail
- // 1.2.3.4 | w2 w4
- // 1.2.3.5 | w3
- // 1.2.3.6 | w4 w6
- s5->DetachDelegate();
-
- // w6 close abnormally (e.g. renderer finishes) while waiting in queue.
- DVLOG(1) << "socket6 close abnormally";
- w6->DetachDelegate();
- base::MessageLoopForIO::current()->RunUntilIdle();
- EXPECT_FALSE(callback_s4.have_result());
- // Address | head -> tail
- // 1.2.3.4 | w2 w4
- // 1.2.3.5 | w3
- // 1.2.3.6 | w4
-
- // Closing s2 kicks w4 to start connecting.
- DVLOG(1) << "socket2 close";
- w2->OnClose(s2.get());
- base::MessageLoopForIO::current()->RunUntilIdle();
- EXPECT_TRUE(callback_s4.have_result());
- // Address | head -> tail
- // 1.2.3.4 | w4
- // 1.2.3.5 | w3
- // 1.2.3.6 | w4
- s2->DetachDelegate();
-
- DVLOG(1) << "socket3 close";
- w3->OnClose(s3.get());
- base::MessageLoopForIO::current()->RunUntilIdle();
- s3->DetachDelegate();
- w4->OnClose(s4.get());
- s4->DetachDelegate();
- DVLOG(1) << "Done";
- base::MessageLoopForIO::current()->RunUntilIdle();
-}
-
-TEST_F(WebSocketThrottleTest, NoThrottleForDuplicateAddress) {
- WebSocketThrottleTestContext context(true);
- DummySocketStreamDelegate delegate;
-
- // For localhost: 127.0.0.1, 127.0.0.1
- AddressList addr;
- addr.push_back(MakeAddr(127, 0, 0, 1));
- addr.push_back(MakeAddr(127, 0, 0, 1));
- scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s1(
- new SocketStream(GURL("ws://localhost/"), w1.get(), &context, NULL));
- w1->InitSocketStream(s1.get());
- WebSocketThrottleTest::MockSocketStreamConnect(s1.get(), addr);
-
- DVLOG(1) << "socket1";
- TestCompletionCallback callback_s1;
- // Trying to open connection to localhost will start without wait.
- EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback()));
-
- DVLOG(1) << "socket1 close";
- w1->OnClose(s1.get());
- s1->DetachDelegate();
- DVLOG(1) << "Done";
- base::MessageLoopForIO::current()->RunUntilIdle();
-}
-
-// A connection should not be blocked by another connection to the same IP
-// with a different port.
-TEST_F(WebSocketThrottleTest, NoThrottleForDistinctPort) {
- WebSocketThrottleTestContext context(false);
- DummySocketStreamDelegate delegate;
- IPAddressNumber localhost;
- ParseIPLiteralToNumber("127.0.0.1", &localhost);
-
- // socket1: 127.0.0.1:80
- scoped_refptr<WebSocketJob> w1(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s1(
- new SocketStream(GURL("ws://localhost:80/"), w1.get(), &context, NULL));
- w1->InitSocketStream(s1.get());
- MockSocketStreamConnect(s1.get(),
- AddressList::CreateFromIPAddress(localhost, 80));
-
- DVLOG(1) << "connecting socket1";
- TestCompletionCallback callback_s1;
- // Trying to open connection to localhost:80 will start without waiting.
- EXPECT_EQ(OK, w1->OnStartOpenConnection(s1.get(), callback_s1.callback()));
-
- // socket2: 127.0.0.1:81
- scoped_refptr<WebSocketJob> w2(new WebSocketJob(&delegate));
- scoped_refptr<SocketStream> s2(
- new SocketStream(GURL("ws://localhost:81/"), w2.get(), &context, NULL));
- w2->InitSocketStream(s2.get());
- MockSocketStreamConnect(s2.get(),
- AddressList::CreateFromIPAddress(localhost, 81));
-
- DVLOG(1) << "connecting socket2";
- TestCompletionCallback callback_s2;
- // Trying to open connection to localhost:81 will start without waiting.
- EXPECT_EQ(OK, w2->OnStartOpenConnection(s2.get(), callback_s2.callback()));
-
- DVLOG(1) << "closing socket1";
- w1->OnClose(s1.get());
- s1->DetachDelegate();
-
- DVLOG(1) << "closing socket2";
- w2->OnClose(s2.get());
- s2->DetachDelegate();
- DVLOG(1) << "Done";
- base::MessageLoopForIO::current()->RunUntilIdle();
-}
-
-} // namespace net
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index f73d8df..23baf4e 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -229,6 +229,8 @@
"services/thread_helpers.h",
"services/yama.h",
"services/yama.cc",
+ "syscall_broker/broker_channel.cc",
+ "syscall_broker/broker_channel.h",
"syscall_broker/broker_client.cc",
"syscall_broker/broker_client.h",
"syscall_broker/broker_common.h",
diff --git a/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc
index c56c819..b3d9126 100644
--- a/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc
+++ b/sandbox/linux/bpf_dsl/bpf_dsl_more_unittest.cc
@@ -759,26 +759,29 @@
allowed_files.push_back("/proc/allowed");
allowed_files.push_back("/proc/cpuinfo");
- broker_process_.reset(
- new BrokerProcess(EPERM, allowed_files, std::vector<std::string>()));
+ broker_process_.reset(new syscall_broker::BrokerProcess(
+ EPERM, allowed_files, std::vector<std::string>()));
BPF_ASSERT(broker_process() != NULL);
BPF_ASSERT(broker_process_->Init(base::Bind(&NoOpCallback)));
initialized_ = true;
}
bool initialized() { return initialized_; }
- class BrokerProcess* broker_process() { return broker_process_.get(); }
+ class syscall_broker::BrokerProcess* broker_process() {
+ return broker_process_.get();
+ }
private:
bool initialized_;
- scoped_ptr<class BrokerProcess> broker_process_;
+ scoped_ptr<class syscall_broker::BrokerProcess> broker_process_;
DISALLOW_COPY_AND_ASSIGN(InitializedOpenBroker);
};
intptr_t BrokerOpenTrapHandler(const struct arch_seccomp_data& args,
void* aux) {
BPF_ASSERT(aux);
- BrokerProcess* broker_process = static_cast<BrokerProcess*>(aux);
+ syscall_broker::BrokerProcess* broker_process =
+ static_cast<syscall_broker::BrokerProcess*>(aux);
switch (args.nr) {
case __NR_faccessat: // access is a wrapper of faccessat in android
BPF_ASSERT(static_cast<int>(args.args[0]) == AT_FDCWD);
@@ -824,7 +827,7 @@
#endif
case __NR_openat:
// We get a InitializedOpenBroker class, but our trap handler wants
- // the BrokerProcess object.
+ // the syscall_broker::BrokerProcess object.
return Trap(BrokerOpenTrapHandler, iob_->broker_process());
default:
return Allow();
@@ -844,7 +847,7 @@
DenyOpenPolicy,
InitializedOpenBroker /* (*BPF_AUX) */) {
BPF_ASSERT(BPF_AUX->initialized());
- BrokerProcess* broker_process = BPF_AUX->broker_process();
+ syscall_broker::BrokerProcess* broker_process = BPF_AUX->broker_process();
BPF_ASSERT(broker_process != NULL);
// First, use the broker "manually"
diff --git a/sandbox/linux/sandbox_linux.gypi b/sandbox/linux/sandbox_linux.gypi
index ba530c0..aa6341d 100644
--- a/sandbox/linux/sandbox_linux.gypi
+++ b/sandbox/linux/sandbox_linux.gypi
@@ -228,6 +228,8 @@
'services/thread_helpers.h',
'services/yama.cc',
'services/yama.h',
+ 'syscall_broker/broker_channel.cc',
+ 'syscall_broker/broker_channel.h',
'syscall_broker/broker_client.cc',
'syscall_broker/broker_client.h',
'syscall_broker/broker_common.h',
diff --git a/sandbox/linux/syscall_broker/broker_channel.cc b/sandbox/linux/syscall_broker/broker_channel.cc
new file mode 100644
index 0000000..fa0f761
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_channel.cc
@@ -0,0 +1,35 @@
+// 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 "sandbox/linux/syscall_broker/broker_channel.h"
+
+#include <sys/socket.h>
+#include <sys/types.h>
+
+#include "base/logging.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// static
+void BrokerChannel::CreatePair(EndPoint* reader, EndPoint* writer) {
+ DCHECK(reader);
+ DCHECK(writer);
+ int socket_pair[2];
+ // Use SOCK_SEQPACKET, to preserve message boundaries but we also want to be
+ // notified (recvmsg should return and not block) when the connection has
+ // been broken which could mean that the other end has been closed.
+ PCHECK(0 == socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socket_pair));
+
+ reader->reset(socket_pair[0]);
+ PCHECK(0 == shutdown(reader->get(), SHUT_WR));
+
+ writer->reset(socket_pair[1]);
+ PCHECK(0 == shutdown(writer->get(), SHUT_RD));
+}
+
+} // namespace syscall_broker
+
+} // namespace sandbox
diff --git a/sandbox/linux/syscall_broker/broker_channel.h b/sandbox/linux/syscall_broker/broker_channel.h
new file mode 100644
index 0000000..2abdba4
--- /dev/null
+++ b/sandbox/linux/syscall_broker/broker_channel.h
@@ -0,0 +1,31 @@
+// 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 SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
+
+#include "base/files/scoped_file.h"
+#include "base/macros.h"
+
+namespace sandbox {
+
+namespace syscall_broker {
+
+// A small class to create a pipe-like communication channel. It is based on a
+// SOCK_SEQPACKET unix socket, which is connection-based and guaranteed to
+// preserve message boundaries.
+class BrokerChannel {
+ public:
+ typedef base::ScopedFD EndPoint;
+ static void CreatePair(EndPoint* reader, EndPoint* writer);
+
+ private:
+ DISALLOW_IMPLICIT_CONSTRUCTORS(BrokerChannel);
+};
+
+} // namespace syscall_broker
+
+} // namespace sandbox
+
+#endif // SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CHANNEL_H_
diff --git a/sandbox/linux/syscall_broker/broker_client.cc b/sandbox/linux/syscall_broker/broker_client.cc
index 60dc9ba..e63205f 100644
--- a/sandbox/linux/syscall_broker/broker_client.cc
+++ b/sandbox/linux/syscall_broker/broker_client.cc
@@ -14,6 +14,7 @@
#include "base/logging.h"
#include "base/pickle.h"
#include "base/posix/unix_domain_socket_linux.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
#include "sandbox/linux/syscall_broker/broker_common.h"
#include "sandbox/linux/syscall_broker/broker_policy.h"
@@ -75,12 +76,9 @@
// temporary socketpair (created internally by SendRecvMsg()).
// Then read the reply on this new socketpair in reply_buf and put an
// eventual attached file descriptor in |returned_fd|.
- ssize_t msg_len = UnixDomainSocket::SendRecvMsgWithFlags(ipc_channel_,
- reply_buf,
- sizeof(reply_buf),
- recvmsg_flags,
- &returned_fd,
- write_pickle);
+ ssize_t msg_len = UnixDomainSocket::SendRecvMsgWithFlags(
+ ipc_channel_.get(), reply_buf, sizeof(reply_buf), recvmsg_flags,
+ &returned_fd, write_pickle);
if (msg_len <= 0) {
if (!quiet_failures_for_tests_)
RAW_LOG(ERROR, "Could not make request to broker process");
@@ -119,11 +117,11 @@
}
BrokerClient::BrokerClient(const BrokerPolicy& broker_policy,
- int ipc_channel,
+ BrokerChannel::EndPoint ipc_channel,
bool fast_check_in_client,
bool quiet_failures_for_tests)
: broker_policy_(broker_policy),
- ipc_channel_(ipc_channel),
+ ipc_channel_(ipc_channel.Pass()),
fast_check_in_client_(fast_check_in_client),
quiet_failures_for_tests_(quiet_failures_for_tests) {
}
diff --git a/sandbox/linux/syscall_broker/broker_client.h b/sandbox/linux/syscall_broker/broker_client.h
index 7d06175..2dfef81 100644
--- a/sandbox/linux/syscall_broker/broker_client.h
+++ b/sandbox/linux/syscall_broker/broker_client.h
@@ -6,6 +6,7 @@
#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_CLIENT_H_
#include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
#include "sandbox/linux/syscall_broker/broker_common.h"
namespace sandbox {
@@ -30,7 +31,7 @@
// |fast_check_in_client| should be set to true and
// |quiet_failures_for_tests| to false unless you are writing tests.
BrokerClient(const BrokerPolicy& policy,
- int ipc_channel,
+ BrokerChannel::EndPoint ipc_channel,
bool fast_check_in_client,
bool quiet_failures_for_tests);
~BrokerClient();
@@ -48,9 +49,12 @@
// This is async signal safe.
int Open(const char* pathname, int flags) const;
+ // Get the file descriptor used for IPC. This is used for tests.
+ int GetIPCDescriptor() const { return ipc_channel_.get(); }
+
private:
const BrokerPolicy& broker_policy_;
- const int ipc_channel_;
+ const BrokerChannel::EndPoint ipc_channel_;
const bool fast_check_in_client_; // Whether to forward a request that we
// know will be denied to the broker. (Used
// for tests).
diff --git a/sandbox/linux/syscall_broker/broker_host.cc b/sandbox/linux/syscall_broker/broker_host.cc
index 995641d..29300f7 100644
--- a/sandbox/linux/syscall_broker/broker_host.cc
+++ b/sandbox/linux/syscall_broker/broker_host.cc
@@ -154,8 +154,9 @@
} // namespace
-BrokerHost::BrokerHost(const BrokerPolicy& broker_policy, int ipc_channel)
- : broker_policy_(broker_policy), ipc_channel_(ipc_channel) {
+BrokerHost::BrokerHost(const BrokerPolicy& broker_policy,
+ BrokerChannel::EndPoint ipc_channel)
+ : broker_policy_(broker_policy), ipc_channel_(ipc_channel.Pass()) {
}
BrokerHost::~BrokerHost() {
@@ -165,17 +166,16 @@
// A request should have a file descriptor attached on which we will reply and
// that we will then close.
// A request should start with an int that will be used as the command type.
-bool BrokerHost::HandleRequest() const {
+BrokerHost::RequestStatus BrokerHost::HandleRequest() const {
ScopedVector<base::ScopedFD> fds;
char buf[kMaxMessageLength];
errno = 0;
const ssize_t msg_len =
- UnixDomainSocket::RecvMsg(ipc_channel_, buf, sizeof(buf), &fds);
+ UnixDomainSocket::RecvMsg(ipc_channel_.get(), buf, sizeof(buf), &fds);
if (msg_len == 0 || (msg_len == -1 && errno == ECONNRESET)) {
// EOF from the client, or the client died, we should die.
- // TODO(jln): change this.
- _exit(0);
+ return RequestStatus::LOST_CLIENT;
}
// The client should send exactly one file descriptor, on which we
@@ -183,7 +183,7 @@
// TODO(mdempsky): ScopedVector doesn't have 'at()', only 'operator[]'.
if (msg_len < 0 || fds.size() != 1 || fds[0]->get() < 0) {
PLOG(ERROR) << "Error reading message from the client";
- return false;
+ return RequestStatus::FAILURE;
}
base::ScopedFD temporary_ipc(fds[0]->Pass());
@@ -192,28 +192,32 @@
PickleIterator iter(pickle);
int command_type;
if (pickle.ReadInt(&iter, &command_type)) {
- bool r = false;
+ bool command_handled = false;
// Go through all the possible IPC messages.
switch (command_type) {
case COMMAND_ACCESS:
case COMMAND_OPEN:
// We reply on the file descriptor sent to us via the IPC channel.
- r = HandleRemoteCommand(broker_policy_,
- static_cast<IPCCommand>(command_type),
- temporary_ipc.get(),
- pickle,
- iter);
+ command_handled = HandleRemoteCommand(
+ broker_policy_, static_cast<IPCCommand>(command_type),
+ temporary_ipc.get(), pickle, iter);
break;
default:
NOTREACHED();
- r = false;
break;
}
- return r;
+
+ if (command_handled) {
+ return RequestStatus::SUCCESS;
+ } else {
+ return RequestStatus::FAILURE;
+ }
+
+ NOTREACHED();
}
LOG(ERROR) << "Error parsing IPC request";
- return false;
+ return RequestStatus::FAILURE;
}
} // namespace syscall_broker
diff --git a/sandbox/linux/syscall_broker/broker_host.h b/sandbox/linux/syscall_broker/broker_host.h
index 04c20ed..9866507 100644
--- a/sandbox/linux/syscall_broker/broker_host.h
+++ b/sandbox/linux/syscall_broker/broker_host.h
@@ -6,6 +6,7 @@
#define SANDBOX_LINUX_SYSCALL_BROKER_BROKER_HOST_H_
#include "base/macros.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
namespace sandbox {
@@ -18,14 +19,18 @@
// |ipc_channel| according to |broker_policy|.
class BrokerHost {
public:
- BrokerHost(const BrokerPolicy& broker_policy, int ipc_channel);
+ enum class RequestStatus { LOST_CLIENT = 0, SUCCESS, FAILURE };
+
+ BrokerHost(const BrokerPolicy& broker_policy,
+ BrokerChannel::EndPoint ipc_channel);
~BrokerHost();
- bool HandleRequest() const;
+ RequestStatus HandleRequest() const;
private:
const BrokerPolicy& broker_policy_;
- const int ipc_channel_;
+ const BrokerChannel::EndPoint ipc_channel_;
+
DISALLOW_COPY_AND_ASSIGN(BrokerHost);
};
diff --git a/sandbox/linux/syscall_broker/broker_process.cc b/sandbox/linux/syscall_broker/broker_process.cc
index 66b7660..ebd7d05 100644
--- a/sandbox/linux/syscall_broker/broker_process.cc
+++ b/sandbox/linux/syscall_broker/broker_process.cc
@@ -6,7 +6,6 @@
#include <fcntl.h>
#include <signal.h>
-#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/syscall.h>
#include <sys/types.h>
@@ -23,30 +22,33 @@
#include "base/posix/eintr_wrapper.h"
#include "base/process/process_metrics.h"
#include "build/build_config.h"
+#include "sandbox/linux/syscall_broker/broker_channel.h"
#include "sandbox/linux/syscall_broker/broker_client.h"
#include "sandbox/linux/syscall_broker/broker_host.h"
namespace sandbox {
+namespace syscall_broker {
+
BrokerProcess::BrokerProcess(int denied_errno,
const std::vector<std::string>& allowed_r_files,
const std::vector<std::string>& allowed_w_files,
bool fast_check_in_client,
bool quiet_failures_for_tests)
: initialized_(false),
- is_child_(false),
fast_check_in_client_(fast_check_in_client),
quiet_failures_for_tests_(quiet_failures_for_tests),
broker_pid_(-1),
- policy_(denied_errno, allowed_r_files, allowed_w_files),
- ipc_socketpair_(-1) {
+ policy_(denied_errno, allowed_r_files, allowed_w_files) {
}
BrokerProcess::~BrokerProcess() {
- if (initialized_ && ipc_socketpair_ != -1) {
- // Closing the socket should be enough to notify the child to die,
- // unless it has been duplicated.
- PCHECK(0 == IGNORE_EINTR(close(ipc_socketpair_)));
+ if (initialized_) {
+ if (broker_client_.get()) {
+ // Closing the socket should be enough to notify the child to die,
+ // unless it has been duplicated.
+ CloseChannel();
+ }
PCHECK(0 == kill(broker_pid_, SIGKILL));
siginfo_t process_info;
// Reap the child.
@@ -58,59 +60,50 @@
bool BrokerProcess::Init(
const base::Callback<bool(void)>& broker_process_init_callback) {
CHECK(!initialized_);
- int socket_pair[2];
- // Use SOCK_SEQPACKET, because we need to preserve message boundaries
- // but we also want to be notified (recvmsg should return and not block)
- // when the connection has been broken (one of the processes died).
- if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, socket_pair)) {
- LOG(ERROR) << "Failed to create socketpair";
- return false;
- }
+ BrokerChannel::EndPoint ipc_reader;
+ BrokerChannel::EndPoint ipc_writer;
+ BrokerChannel::CreatePair(&ipc_reader, &ipc_writer);
#if !defined(THREAD_SANITIZER)
DCHECK_EQ(1, base::GetNumberOfThreads(base::GetCurrentProcessHandle()));
#endif
int child_pid = fork();
if (child_pid == -1) {
- close(socket_pair[0]);
- close(socket_pair[1]);
return false;
}
if (child_pid) {
// We are the parent and we have just forked our broker process.
- close(socket_pair[0]);
- // We should only be able to write to the IPC channel. We'll always send
- // a new file descriptor to receive the reply on.
- shutdown(socket_pair[1], SHUT_RD);
- ipc_socketpair_ = socket_pair[1];
- is_child_ = false;
+ ipc_reader.reset();
broker_pid_ = child_pid;
- broker_client_.reset(
- new syscall_broker::BrokerClient(policy_,
- ipc_socketpair_,
- fast_check_in_client_,
- quiet_failures_for_tests_));
+ broker_client_.reset(new BrokerClient(policy_, ipc_writer.Pass(),
+ fast_check_in_client_,
+ quiet_failures_for_tests_));
initialized_ = true;
return true;
} else {
- // We are the broker.
- close(socket_pair[1]);
- // We should only be able to read from this IPC channel. We will send our
- // replies on a new file descriptor attached to the requests.
- shutdown(socket_pair[0], SHUT_WR);
- ipc_socketpair_ = socket_pair[0];
- is_child_ = true;
+ // We are the broker process. Make sure to close the writer's end so that
+ // we get notified if the client disappears.
+ ipc_writer.reset();
CHECK(broker_process_init_callback.Run());
- syscall_broker::BrokerHost broker_host(policy_, ipc_socketpair_);
- initialized_ = true;
+ BrokerHost broker_host(policy_, ipc_reader.Pass());
for (;;) {
- broker_host.HandleRequest();
+ switch (broker_host.HandleRequest()) {
+ case BrokerHost::RequestStatus::LOST_CLIENT:
+ _exit(1);
+ case BrokerHost::RequestStatus::SUCCESS:
+ case BrokerHost::RequestStatus::FAILURE:
+ continue;
+ }
}
_exit(1);
}
NOTREACHED();
}
+void BrokerProcess::CloseChannel() {
+ broker_client_.reset();
+}
+
int BrokerProcess::Access(const char* pathname, int mode) const {
RAW_CHECK(initialized_);
return broker_client_->Access(pathname, mode);
@@ -121,4 +114,6 @@
return broker_client_->Open(pathname, flags);
}
+} // namespace syscall_broker
+
} // namespace sandbox.
diff --git a/sandbox/linux/syscall_broker/broker_process.h b/sandbox/linux/syscall_broker/broker_process.h
index d5b521b..50e7eee 100644
--- a/sandbox/linux/syscall_broker/broker_process.h
+++ b/sandbox/linux/syscall_broker/broker_process.h
@@ -19,8 +19,8 @@
namespace sandbox {
namespace syscall_broker {
+
class BrokerClient;
-}
// Create a new "broker" process to which we can send requests via an IPC
// channel by forking the current process.
@@ -68,21 +68,24 @@
int broker_pid() const { return broker_pid_; }
private:
+ friend class BrokerProcessTestHelper;
+
+ // Close the IPC channel with the other party. This should only be used
+ // by tests an none of the class methods should be used afterwards.
+ void CloseChannel();
+
bool initialized_; // Whether we've been through Init() yet.
- bool is_child_; // Whether we're the child (broker process).
- bool fast_check_in_client_;
- bool quiet_failures_for_tests_;
+ const bool fast_check_in_client_;
+ const bool quiet_failures_for_tests_;
pid_t broker_pid_; // The PID of the broker (child).
syscall_broker::BrokerPolicy policy_; // The sandboxing policy.
- scoped_ptr<syscall_broker::BrokerClient>
- broker_client_; // Can only exist if is_child_ is true.
+ scoped_ptr<syscall_broker::BrokerClient> broker_client_;
- int ipc_socketpair_; // Our communication channel to parent or child.
DISALLOW_COPY_AND_ASSIGN(BrokerProcess);
-
- friend class BrokerProcessTestHelper;
};
+} // namespace syscall_broker
+
} // namespace sandbox
#endif // SANDBOX_LINUX_SERVICES_BROKER_PROCESS_H_
diff --git a/sandbox/linux/syscall_broker/broker_process_unittest.cc b/sandbox/linux/syscall_broker/broker_process_unittest.cc
index e7d5442..997667c 100644
--- a/sandbox/linux/syscall_broker/broker_process_unittest.cc
+++ b/sandbox/linux/syscall_broker/broker_process_unittest.cc
@@ -6,6 +6,7 @@
#include <errno.h>
#include <fcntl.h>
+#include <poll.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -24,6 +25,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/posix/eintr_wrapper.h"
#include "base/posix/unix_domain_socket_linux.h"
+#include "sandbox/linux/syscall_broker/broker_client.h"
#include "sandbox/linux/tests/scoped_temporary_file.h"
#include "sandbox/linux/tests/test_utils.h"
#include "sandbox/linux/tests/unit_tests.h"
@@ -31,10 +33,15 @@
namespace sandbox {
+namespace syscall_broker {
+
class BrokerProcessTestHelper {
public:
- static int get_ipc_socketpair(const BrokerProcess* broker) {
- return broker->ipc_socketpair_;
+ static void CloseChannel(BrokerProcess* broker) { broker->CloseChannel(); }
+ // Get the client's IPC descriptor to send IPC requests directly.
+ // TODO(jln): refator tests to get rid of this.
+ static int GetIPCDescriptor(const BrokerProcess* broker) {
+ return broker->broker_client_->GetIPCDescriptor();
}
};
@@ -453,7 +460,7 @@
BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>());
SANDBOX_ASSERT(open_broker.Init(base::Bind(&NoOpCallback)));
- const int ipc_fd = BrokerProcessTestHelper::get_ipc_socketpair(&open_broker);
+ const int ipc_fd = BrokerProcessTestHelper::GetIPCDescriptor(&open_broker);
SANDBOX_ASSERT(ipc_fd >= 0);
static const char kBogus[] = "not a pickle";
@@ -472,4 +479,60 @@
SANDBOX_ASSERT(0 == IGNORE_EINTR(close(fd)));
}
+bool CloseFD(int fd) {
+ PCHECK(0 == IGNORE_EINTR(close(fd)));
+ return true;
+}
+
+// Return true if the other end of the |reader| pipe was closed,
+// false if |timeout_in_seconds| was reached or another event
+// or error occured.
+bool WaitForClosedPipeWriter(int reader, int timeout_in_ms) {
+ struct pollfd poll_fd = {reader, POLLIN | POLLRDHUP, 0};
+ const int num_events = HANDLE_EINTR(poll(&poll_fd, 1, timeout_in_ms));
+ if (1 == num_events && poll_fd.revents | POLLHUP)
+ return true;
+ return false;
+}
+
+// Closing the broker client's IPC channel should terminate the broker
+// process.
+TEST(BrokerProcess, BrokerDiesOnClosedChannel) {
+ std::vector<std::string> read_whitelist;
+ read_whitelist.push_back("/proc/cpuinfo");
+
+ // Get the writing end of a pipe into the broker (child) process so
+ // that we can reliably detect when it dies.
+ int lifeline_fds[2];
+ PCHECK(0 == pipe(lifeline_fds));
+
+ BrokerProcess open_broker(EPERM, read_whitelist, std::vector<std::string>(),
+ true /* fast_check_in_client */,
+ false /* quiet_failures_for_tests */);
+ ASSERT_TRUE(open_broker.Init(base::Bind(&CloseFD, lifeline_fds[0])));
+ // Make sure the writing end only exists in the broker process.
+ CloseFD(lifeline_fds[1]);
+ base::ScopedFD reader(lifeline_fds[0]);
+
+ const pid_t broker_pid = open_broker.broker_pid();
+
+ // This should cause the broker process to exit.
+ BrokerProcessTestHelper::CloseChannel(&open_broker);
+
+ const int kTimeoutInMilliseconds = 5000;
+ const bool broker_lifeline_closed =
+ WaitForClosedPipeWriter(reader.get(), kTimeoutInMilliseconds);
+ // If the broker exited, its lifeline fd should be closed.
+ ASSERT_TRUE(broker_lifeline_closed);
+ // Now check that the broker has exited, but do not reap it.
+ siginfo_t process_info;
+ ASSERT_EQ(0, HANDLE_EINTR(waitid(P_PID, broker_pid, &process_info,
+ WEXITED | WNOWAIT)));
+ EXPECT_EQ(broker_pid, process_info.si_pid);
+ EXPECT_EQ(CLD_EXITED, process_info.si_code);
+ EXPECT_EQ(1, process_info.si_status);
+}
+
+} // namespace syscall_broker
+
} // namespace sandbox
diff --git a/sandbox/linux/tests/unit_tests.h b/sandbox/linux/tests/unit_tests.h
index f745e13..6f150ac 100644
--- a/sandbox/linux/tests/unit_tests.h
+++ b/sandbox/linux/tests/unit_tests.h
@@ -99,6 +99,13 @@
((expr) ? static_cast<void>(0) : sandbox::UnitTests::AssertionFailure( \
SANDBOX_STR(expr), __FILE__, __LINE__))
+#define SANDBOX_ASSERT_EQ(x, y) SANDBOX_ASSERT((x) == (y))
+#define SANDBOX_ASSERT_NE(x, y) SANDBOX_ASSERT((x) != (y))
+#define SANDBOX_ASSERT_LT(x, y) SANDBOX_ASSERT((x) < (y))
+#define SANDBOX_ASSERT_GT(x, y) SANDBOX_ASSERT((x) > (y))
+#define SANDBOX_ASSERT_LE(x, y) SANDBOX_ASSERT((x) <= (y))
+#define SANDBOX_ASSERT_GE(x, y) SANDBOX_ASSERT((x) >= (y))
+
// This class allows to run unittests in their own process. The main method is
// RunTestInProcess().
class UnitTests {
diff --git a/sdch/BUILD.gn b/sdch/BUILD.gn
index 7a95f1f..727fb49 100644
--- a/sdch/BUILD.gn
+++ b/sdch/BUILD.gn
@@ -45,6 +45,24 @@
"//third_party/zlib",
]
+ # gn orders flags on a target before flags from configs. The default config
+ # adds -Wall, and these flags have to be after -Wall -- so they need to come
+ # from a config and can't be on the target directly.
+ config("sdch_warnings") {
+ cflags = []
+ if (is_linux) {
+ # TODO(mostynb): remove this if open-vcdiff is ever updated for c++11:
+ cflags += [ "-Wno-deprecated-declarations" ]
+ }
+
+ if (is_clang) {
+ # sdch uses the pre-c++11 typedef-as-static_assert hack.
+ # https://code.google.com/p/open-vcdiff/issues/detail?id=44
+ cflags += [ "-Wno-unused-local-typedef" ]
+ }
+ }
+ configs += [ ":sdch_warnings" ]
+
if (is_linux || is_android) {
include_dirs = [ "linux" ]
} else if (is_ios) {
@@ -69,9 +87,5 @@
} else {
logging_file = rebase_path("logging_forward.h", root_build_dir)
cflags = [ "-include", logging_file ]
- if (is_linux) {
- # TODO(mostynb): remove this if open-vcdiff is ever updated for c++11:
- cflags += [ "-Wno-deprecated-declarations" ]
- }
}
}
diff --git a/sdch/sdch.gyp b/sdch/sdch.gyp
index 52a92f3..e886288 100644
--- a/sdch/sdch.gyp
+++ b/sdch/sdch.gyp
@@ -71,6 +71,11 @@
# introduce static initializers, and which prevents open-vcdiff's
# logging.h from being used).
'variables': {
+ 'clang_warning_flags': [
+ # sdch uses the pre-c++11 typedef-as-static_assert hack.
+ # https://code.google.com/p/open-vcdiff/issues/detail?id=44
+ '-Wno-unused-local-typedef',
+ ],
'logging_path': 'logging_forward.h',
'conditions': [
# gyp leaves unspecified what the cwd is when running the compiler,
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index a57b6a1..7daabd4 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -302,8 +302,6 @@
"ext/vector_canvas.h",
"ext/vector_platform_device_emf_win.cc",
"ext/vector_platform_device_emf_win.h",
- "ext/vector_platform_device_skia.cc",
- "ext/vector_platform_device_skia.h",
]
# The skia gypi values are relative to the skia_dir, so we need to rebase.
@@ -416,16 +414,12 @@
if (is_posix) {
sources -= [ "ext/SkThread_chrome.cc" ]
}
- if (is_ios) {
- sources -= [ "ext/vector_platform_device_skia.cc" ]
- }
if (is_win) {
sources -= [ "ext/SkThread_chrome.cc" ]
}
if (is_android && (!enable_basic_printing && !enable_print_preview)) {
sources -= [
"ext/skia_utils_base.cc",
- "ext/vector_platform_device_skia.cc"
]
}
diff --git a/skia/ext/bitmap_platform_device_cairo.cc b/skia/ext/bitmap_platform_device_cairo.cc
index 6d5d77c..97fc92a 100644
--- a/skia/ext/bitmap_platform_device_cairo.cc
+++ b/skia/ext/bitmap_platform_device_cairo.cc
@@ -167,11 +167,11 @@
cairo_destroy(cairo_);
}
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
- Usage /*usage*/) {
- SkASSERT(info.colorType() == kN32_SkColorType);
- return BitmapPlatformDevice::Create(info.width(), info.height(),
- info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+ const CreateInfo& info) {
+ SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+ return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(),
+ info.fInfo.isOpaque());
}
cairo_t* BitmapPlatformDevice::BeginPlatformPaint() {
diff --git a/skia/ext/bitmap_platform_device_cairo.h b/skia/ext/bitmap_platform_device_cairo.h
index 2932111..67a2f19 100644
--- a/skia/ext/bitmap_platform_device_cairo.h
+++ b/skia/ext/bitmap_platform_device_cairo.h
@@ -93,8 +93,8 @@
const PlatformRect* src_rect) override;
protected:
- virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
- Usage usage) override;
+ virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info)
+ override;
private:
static BitmapPlatformDevice* Create(int width, int height, bool is_opaque,
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc
index 5204468..871ca83 100644
--- a/skia/ext/bitmap_platform_device_mac.cc
+++ b/skia/ext/bitmap_platform_device_mac.cc
@@ -237,11 +237,12 @@
ReleaseBitmapContext();
}
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
- Usage /*usage*/) {
- SkASSERT(info.colorType() == kN32_SkColorType);
- return BitmapPlatformDevice::CreateAndClear(info.width(), info.height(),
- info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+ const CreateInfo& info) {
+ SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+ return BitmapPlatformDevice::CreateAndClear(info.fInfo.width(),
+ info.fInfo.height(),
+ info.fInfo.isOpaque());
}
// PlatformCanvas impl
diff --git a/skia/ext/bitmap_platform_device_mac.h b/skia/ext/bitmap_platform_device_mac.h
index dc78562..8921117 100644
--- a/skia/ext/bitmap_platform_device_mac.h
+++ b/skia/ext/bitmap_platform_device_mac.h
@@ -66,7 +66,7 @@
BitmapPlatformDevice(CGContextRef context,
const SkBitmap& bitmap);
- SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) override;
+ SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info) override;
private:
void ReleaseBitmapContext();
diff --git a/skia/ext/bitmap_platform_device_skia.cc b/skia/ext/bitmap_platform_device_skia.cc
index ee44e26..1dcf13b 100644
--- a/skia/ext/bitmap_platform_device_skia.cc
+++ b/skia/ext/bitmap_platform_device_skia.cc
@@ -51,11 +51,11 @@
BitmapPlatformDevice::~BitmapPlatformDevice() {
}
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
- Usage /*usage*/) {
- SkASSERT(info.colorType() == kN32_SkColorType);
- return BitmapPlatformDevice::Create(info.width(), info.height(),
- info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+ const CreateInfo& info) {
+ SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+ return BitmapPlatformDevice::Create(info.fInfo.width(), info.fInfo.height(),
+ info.fInfo.isOpaque());
}
PlatformSurface BitmapPlatformDevice::BeginPlatformPaint() {
diff --git a/skia/ext/bitmap_platform_device_skia.h b/skia/ext/bitmap_platform_device_skia.h
index f670dea..3b8a28d 100644
--- a/skia/ext/bitmap_platform_device_skia.h
+++ b/skia/ext/bitmap_platform_device_skia.h
@@ -47,8 +47,8 @@
const PlatformRect* src_rect) override;
protected:
- virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
- Usage usage) override;
+ virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info)
+ override;
private:
DISALLOW_COPY_AND_ASSIGN(BitmapPlatformDevice);
diff --git a/skia/ext/bitmap_platform_device_win.cc b/skia/ext/bitmap_platform_device_win.cc
index e10a6de..3901ad5 100644
--- a/skia/ext/bitmap_platform_device_win.cc
+++ b/skia/ext/bitmap_platform_device_win.cc
@@ -270,11 +270,12 @@
return SkBitmapDevice::onAccessBitmap();
}
-SkBaseDevice* BitmapPlatformDevice::onCreateDevice(const SkImageInfo& info,
- Usage /*usage*/) {
- SkASSERT(info.colorType() == kN32_SkColorType);
- return BitmapPlatformDevice::CreateAndClear(info.width(), info.height(),
- info.isOpaque());
+SkBaseDevice* BitmapPlatformDevice::onCreateCompatibleDevice(
+ const CreateInfo& info) {
+ SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
+ return BitmapPlatformDevice::CreateAndClear(info.fInfo.width(),
+ info.fInfo.height(),
+ info.fInfo.isOpaque());
}
// PlatformCanvas impl
diff --git a/skia/ext/bitmap_platform_device_win.h b/skia/ext/bitmap_platform_device_win.h
index a8b7d83..92b1408 100644
--- a/skia/ext/bitmap_platform_device_win.h
+++ b/skia/ext/bitmap_platform_device_win.h
@@ -68,8 +68,8 @@
// starts accessing pixel data.
virtual const SkBitmap& onAccessBitmap() override;
- virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
- Usage usage) override;
+ virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info)
+ override;
private:
// Private constructor.
diff --git a/skia/ext/vector_platform_device_emf_win.cc b/skia/ext/vector_platform_device_emf_win.cc
index 19e3066..1271b16 100644
--- a/skia/ext/vector_platform_device_emf_win.cc
+++ b/skia/ext/vector_platform_device_emf_win.cc
@@ -695,11 +695,11 @@
LoadClippingRegionToDC(hdc_, clip_region_, t);
}
-SkBaseDevice* VectorPlatformDeviceEmf::onCreateDevice(const SkImageInfo& info,
- Usage /*usage*/) {
- SkASSERT(info.colorType() == kN32_SkColorType);
+SkBaseDevice* VectorPlatformDeviceEmf::onCreateCompatibleDevice(
+ const CreateInfo& info) {
+ SkASSERT(info.fInfo.colorType() == kN32_SkColorType);
return VectorPlatformDeviceEmf::CreateDevice(
- info.width(), info.height(), info.isOpaque(), NULL);
+ info.fInfo.width(), info.fInfo.height(), info.fInfo.isOpaque(), NULL);
}
bool VectorPlatformDeviceEmf::CreateBrush(bool use_brush, COLORREF color) {
diff --git a/skia/ext/vector_platform_device_emf_win.h b/skia/ext/vector_platform_device_emf_win.h
index f65390f..8d5b393 100644
--- a/skia/ext/vector_platform_device_emf_win.h
+++ b/skia/ext/vector_platform_device_emf_win.h
@@ -79,8 +79,7 @@
void LoadClipRegion();
protected:
- virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
- Usage usage) override;
+ virtual SkBaseDevice* onCreateCompatibleDevice(const CreateInfo& info) override;
private:
// Applies the SkPaint's painting properties in the current GDI context, if
diff --git a/skia/ext/vector_platform_device_skia.cc b/skia/ext/vector_platform_device_skia.cc
deleted file mode 100644
index 5b8217c..0000000
--- a/skia/ext/vector_platform_device_skia.cc
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "skia/ext/vector_platform_device_skia.h"
-
-#include "skia/ext/bitmap_platform_device.h"
-#include "third_party/skia/include/core/SkClipStack.h"
-#include "third_party/skia/include/core/SkDraw.h"
-#include "third_party/skia/include/core/SkRect.h"
-#include "third_party/skia/include/core/SkRegion.h"
-#include "third_party/skia/include/core/SkScalar.h"
-
-namespace skia {
-
-static inline SkBitmap makeABitmap(int width, int height) {
- SkBitmap bitmap;
- bitmap.setInfo(SkImageInfo::MakeUnknown(width, height));
- return bitmap;
-}
-
-VectorPlatformDeviceSkia::VectorPlatformDeviceSkia(
- const SkISize& pageSize,
- const SkISize& contentSize,
- const SkMatrix& initialTransform)
- : SkPDFDevice(pageSize, contentSize, initialTransform) {
- SetPlatformDevice(this, this);
-}
-
-VectorPlatformDeviceSkia::~VectorPlatformDeviceSkia() {
-}
-
-bool VectorPlatformDeviceSkia::SupportsPlatformPaint() {
- return false;
-}
-
-PlatformSurface VectorPlatformDeviceSkia::BeginPlatformPaint() {
- // Even when drawing a vector representation of the page, we have to
- // provide a raster surface for plugins to render into - they don't have
- // a vector interface. Therefore we create a BitmapPlatformDevice here
- // and return the context from it, then layer on the raster data as an
- // image in EndPlatformPaint.
- DCHECK(raster_surface_ == NULL);
- raster_surface_ = skia::AdoptRef(
- BitmapPlatformDevice::CreateAndClear(width(), height(), false));
- return raster_surface_->BeginPlatformPaint();
-}
-
-void VectorPlatformDeviceSkia::EndPlatformPaint() {
- DCHECK(raster_surface_ != NULL);
- SkPaint paint;
- // SkPDFDevice checks the passed SkDraw for an empty clip (only). Fake
- // it out by setting a non-empty clip.
- SkDraw draw;
- SkRegion clip(SkIRect::MakeWH(width(), height()));
- draw.fClip=&clip;
- drawSprite(draw, raster_surface_->accessBitmap(false), 0, 0, paint);
- // BitmapPlatformDevice matches begin and end calls.
- raster_surface_->EndPlatformPaint();
- raster_surface_.clear();
-}
-
-#if defined(OS_WIN)
-void VectorPlatformDeviceSkia::DrawToNativeContext(HDC dc,
- int x,
- int y,
- const RECT* src_rect) {
- SkASSERT(false);
-}
-#elif defined(OS_MACOSX)
-void VectorPlatformDeviceSkia::DrawToNativeContext(CGContext* context, int x,
- int y, const CGRect* src_rect) {
- SkASSERT(false);
-}
-
-CGContextRef VectorPlatformDeviceSkia::GetBitmapContext() {
- SkASSERT(false);
- return NULL;
-}
-#elif defined(OS_POSIX)
-void VectorPlatformDeviceSkia::DrawToNativeContext(
- PlatformSurface surface, int x, int y, const PlatformRect* src_rect) {
- // Should never be called on Linux.
- SkASSERT(false);
-}
-#endif
-
-} // namespace skia
diff --git a/skia/ext/vector_platform_device_skia.h b/skia/ext/vector_platform_device_skia.h
deleted file mode 100644
index 528eac9..0000000
--- a/skia/ext/vector_platform_device_skia.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef SKIA_EXT_VECTOR_PLATFORM_DEVICE_SKIA_H_
-#define SKIA_EXT_VECTOR_PLATFORM_DEVICE_SKIA_H_
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/logging.h"
-#include "skia/ext/platform_device.h"
-#include "skia/ext/refptr.h"
-#include "third_party/skia/include/pdf/SkPDFDevice.h"
-
-class SkMatrix;
-
-namespace skia {
-
-class BitmapPlatformDevice;
-
-class VectorPlatformDeviceSkia : public SkPDFDevice, public PlatformDevice {
- public:
- SK_API VectorPlatformDeviceSkia(const SkISize& pageSize,
- const SkISize& contentSize,
- const SkMatrix& initialTransform);
- ~VectorPlatformDeviceSkia() override;
-
- // PlatformDevice methods.
- bool SupportsPlatformPaint() override;
-
- PlatformSurface BeginPlatformPaint() override;
- void EndPlatformPaint() override;
-#if defined(OS_WIN)
- virtual void DrawToNativeContext(HDC dc,
- int x,
- int y,
- const RECT* src_rect) override;
-#elif defined(OS_MACOSX)
- void DrawToNativeContext(CGContext* context,
- int x,
- int y,
- const CGRect* src_rect) override;
- CGContextRef GetBitmapContext() override;
-#elif defined(OS_POSIX)
- virtual void DrawToNativeContext(PlatformSurface surface,
- int x,
- int y,
- const PlatformRect* src_rect) override;
-#endif
-
- private:
- skia::RefPtr<BitmapPlatformDevice> raster_surface_;
-
- DISALLOW_COPY_AND_ASSIGN(VectorPlatformDeviceSkia);
-};
-
-} // namespace skia
-
-#endif // SKIA_EXT_VECTOR_PLATFORM_DEVICE_SKIA_H_
diff --git a/skia/skia_chrome.gypi b/skia/skia_chrome.gypi
index 0f97556..7db9009 100644
--- a/skia/skia_chrome.gypi
+++ b/skia/skia_chrome.gypi
@@ -83,8 +83,6 @@
'ext/vector_canvas.h',
'ext/vector_platform_device_emf_win.cc',
'ext/vector_platform_device_emf_win.h',
- 'ext/vector_platform_device_skia.cc',
- 'ext/vector_platform_device_skia.h',
],
'conditions': [
[ 'OS == "android" and '
@@ -93,15 +91,7 @@
'ext/skia_utils_base.cc',
],
}],
- [ 'enable_basic_printing==0 and enable_print_preview==0', {
- 'sources!': [
- 'ext/vector_platform_device_skia.cc',
- ],
- }],
['OS == "ios"', {
- 'sources/': [
- ['exclude', '^ext/vector_platform_device_skia\\.'],
- ],
'dependencies!': [
'skia_chrome_opts',
],
diff --git a/sky/engine/core/css/CSSFontSelector.cpp b/sky/engine/core/css/CSSFontSelector.cpp
index cd8faa2..8a18163 100644
--- a/sky/engine/core/css/CSSFontSelector.cpp
+++ b/sky/engine/core/css/CSSFontSelector.cpp
@@ -97,15 +97,15 @@
static AtomicString familyNameFromSettings(const GenericFontFamilySettings& settings, const FontDescription& fontDescription, const AtomicString& genericFamilyName)
{
- UScriptCode script = fontDescription.script();
-
#if OS(ANDROID)
if (fontDescription.genericFamily() == FontDescription::StandardFamily)
- return FontCache::getGenericFamilyNameForScript(FontFamilyNames::webkit_standard, script);
+ return FontCache::getGenericFamilyNameForScript(FontFamilyNames::webkit_standard, fontDescription);
if (genericFamilyName.startsWith("-webkit-"))
- return FontCache::getGenericFamilyNameForScript(genericFamilyName, script);
+ return FontCache::getGenericFamilyNameForScript(genericFamilyName, fontDescription);
#else
+ UScriptCode script = fontDescription.script();
+
if (fontDescription.genericFamily() == FontDescription::StandardFamily)
return settings.standard(script);
if (genericFamilyName == FontFamilyNames::webkit_serif)
diff --git a/sky/engine/platform/fonts/FontCache.h b/sky/engine/platform/fonts/FontCache.h
index e68a6cc..c41c6ad 100644
--- a/sky/engine/platform/fonts/FontCache.h
+++ b/sky/engine/platform/fonts/FontCache.h
@@ -94,7 +94,7 @@
#endif
#if OS(ANDROID)
- static AtomicString getGenericFamilyNameForScript(const AtomicString& familyName, UScriptCode);
+ static AtomicString getGenericFamilyNameForScript(const AtomicString& familyName, const FontDescription&);
#else
struct PlatformFallbackFont {
String name;
diff --git a/sky/engine/platform/fonts/android/FontCacheAndroid.cpp b/sky/engine/platform/fonts/android/FontCacheAndroid.cpp
index 8f070e8..25c4c75 100644
--- a/sky/engine/platform/fonts/android/FontCacheAndroid.cpp
+++ b/sky/engine/platform/fonts/android/FontCacheAndroid.cpp
@@ -31,7 +31,7 @@
#include "config.h"
#include "platform/fonts/FontCache.h"
-
+#include "platform/Language.h"
#include "platform/fonts/SimpleFontData.h"
#include "platform/fonts/FontDescription.h"
#include "platform/fonts/FontFaceCreationParams.h"
@@ -40,31 +40,19 @@
namespace blink {
-static AtomicString getFamilyNameForCharacter(UChar32 c, UScriptCode script)
+static AtomicString getFamilyNameForCharacter(UChar32 c, const FontDescription& fontDescription)
{
- // This is a hack to use the preferred font for CJK scripts.
- // FIXME: Use new Skia API once Android system supports per-family and per-script fallback fonts.
- const char* locale;
- switch (script) {
- case USCRIPT_SIMPLIFIED_HAN:
- locale = "zh-CN";
- break;
- case USCRIPT_TRADITIONAL_HAN:
- locale = "zh-TW";
- break;
- case USCRIPT_KATAKANA_OR_HIRAGANA:
- locale = "ja";
- break;
- case USCRIPT_HANGUL:
- locale = "ko";
- break;
- default:
- locale = 0;
- break;
- }
-
RefPtr<SkFontMgr> fm = adoptRef(SkFontMgr::RefDefault());
- RefPtr<SkTypeface> typeface = adoptRef(fm->matchFamilyStyleCharacter(0, SkFontStyle(), locale, c));
+ const char* bcp47Locales[2];
+ int localeCount = 0;
+ CString defaultLocale = defaultLanguage().ascii();
+ bcp47Locales[localeCount++] = defaultLocale.data();
+ CString fontLocale;
+ if (!fontDescription.locale().isEmpty()) {
+ fontLocale = fontDescription.locale().ascii();
+ bcp47Locales[localeCount++] = fontLocale.data();
+ }
+ RefPtr<SkTypeface> typeface = adoptRef(fm->matchFamilyStyleCharacter(0, SkFontStyle(), bcp47Locales, localeCount, c));
if (!typeface)
return emptyAtom;
@@ -75,19 +63,19 @@
PassRefPtr<SimpleFontData> FontCache::fallbackFontForCharacter(const FontDescription& fontDescription, UChar32 c, const SimpleFontData*)
{
- AtomicString familyName = getFamilyNameForCharacter(c, fontDescription.script());
+ AtomicString familyName = getFamilyNameForCharacter(c, fontDescription);
if (familyName.isEmpty())
return getLastResortFallbackFont(fontDescription, DoNotRetain);
return fontDataFromFontPlatformData(getFontPlatformData(fontDescription, FontFaceCreationParams(familyName)), DoNotRetain);
}
// static
-AtomicString FontCache::getGenericFamilyNameForScript(const AtomicString& familyName, UScriptCode script)
+AtomicString FontCache::getGenericFamilyNameForScript(const AtomicString& familyName, const FontDescription& fontDescription)
{
// This is a hack to use the preferred font for CJK scripts.
// FIXME: Use new Skia API once Android system supports per-family and per-script fallback fonts.
UChar32 examplerChar;
- switch (script) {
+ switch (fontDescription.script()) {
case USCRIPT_SIMPLIFIED_HAN:
case USCRIPT_TRADITIONAL_HAN:
case USCRIPT_KATAKANA_OR_HIRAGANA:
@@ -101,7 +89,7 @@
return familyName;
}
- return getFamilyNameForCharacter(examplerChar, script);
+ return getFamilyNameForCharacter(examplerChar, fontDescription);
}
} // namespace blink
diff --git a/sky/viewer/platform/weblayertreeview_impl.cc b/sky/viewer/platform/weblayertreeview_impl.cc
index 2aa5486..f718fc3 100644
--- a/sky/viewer/platform/weblayertreeview_impl.cc
+++ b/sky/viewer/platform/weblayertreeview_impl.cc
@@ -7,6 +7,7 @@
#include "base/message_loop/message_loop_proxy.h"
#include "cc/layers/layer.h"
#include "cc/output/begin_frame_args.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/trees/layer_tree_host.h"
#include "mojo/cc/context_provider_mojo.h"
#include "mojo/cc/output_surface_mojo.h"
@@ -47,7 +48,8 @@
gpu_memory_buffer_manager,
settings,
base::MessageLoopProxy::current(),
- compositor_message_loop_proxy);
+ compositor_message_loop_proxy,
+ nullptr);
DCHECK(layer_tree_host_);
}
diff --git a/testing/android/java/AndroidManifest.xml b/testing/android/java/AndroidManifest.xml
index c704cc4..a561f0c 100644
--- a/testing/android/java/AndroidManifest.xml
+++ b/testing/android/java/AndroidManifest.xml
@@ -24,6 +24,10 @@
</activity>
</application>
+ <instrumentation android:name="org.chromium.native_test.ChromiumNativeTestInstrumentationTestRunner"
+ android:targetPackage="org.chromium.native_test"
+ android:label="Instrumentation entry point for org.chromium.native_test"/>
+
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
diff --git a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
index f5d381a..42befe5 100644
--- a/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
+++ b/testing/android/java/src/org/chromium/native_test/ChromeNativeTestActivity.java
@@ -22,6 +22,11 @@
* the native activity class loader.
*/
public class ChromeNativeTestActivity extends Activity {
+ public static final String EXTRA_COMMAND_LINE_FILE =
+ "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFile";
+ public static final String EXTRA_COMMAND_LINE_FLAGS =
+ "org.chromium.native_test.ChromeNativeTestActivity.CommandLineFlags";
+
private static final String TAG = "ChromeNativeTestActivity";
private static final String EXTRA_RUN_IN_SUB_THREAD = "RunInSubThread";
// We post a delayed task to run tests so that we do not block onCreate().
@@ -66,8 +71,15 @@
}
private void runTests() {
+ String commandLineFlags = getIntent().getStringExtra(EXTRA_COMMAND_LINE_FLAGS);
+ if (commandLineFlags == null) commandLineFlags = "";
+
+ String commandLineFilePath = getIntent().getStringExtra(EXTRA_COMMAND_LINE_FILE);
+ if (commandLineFilePath == null) commandLineFilePath = "";
+
// This directory is used by build/android/pylib/test_package_apk.py.
- nativeRunTests(getFilesDir().getAbsolutePath(), getApplicationContext());
+ nativeRunTests(commandLineFlags, commandLineFilePath, getFilesDir().getAbsolutePath(),
+ getApplicationContext());
}
// Signal a failure of the native test loader to python scripts
@@ -85,5 +97,6 @@
}
}
- private native void nativeRunTests(String filesDir, Context appContext);
+ private native void nativeRunTests(String commandLineFlags, String commandLineFilePath,
+ String filesDir, Context appContext);
}
diff --git a/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java b/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java
new file mode 100644
index 0000000..5e8d8e5
--- /dev/null
+++ b/testing/android/java/src/org/chromium/native_test/ChromiumNativeTestInstrumentationTestRunner.java
@@ -0,0 +1,196 @@
+// 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.native_test;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * An Instrumentation that runs tests based on ChromeNativeTestActivity.
+ */
+public class ChromiumNativeTestInstrumentationTestRunner extends Instrumentation {
+
+ private static final String TAG = "ChromiumNativeTestInstrumentationTestRunner";
+ private static final Pattern RE_TEST_OUTPUT = Pattern.compile("\\[ *([^ ]*) *\\] ?([^ ]*) .*");
+
+ private static interface ResultsBundleGenerator {
+ public Bundle generate(Map<String, TestResult> rawResults);
+ }
+
+ private String mCommandLineFile;
+ private String mCommandLineFlags;
+ private Bundle mLogBundle;
+ private ResultsBundleGenerator mBundleGenerator;
+
+ @Override
+ public void onCreate(Bundle arguments) {
+ mCommandLineFile = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE);
+ mCommandLineFlags = arguments.getString(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS);
+ mLogBundle = new Bundle();
+ mBundleGenerator = new RobotiumBundleGenerator();
+ start();
+ }
+
+ @Override
+ public void onStart() {
+ super.onStart();
+ Bundle results = runTests();
+ finish(Activity.RESULT_OK, results);
+ }
+
+ /** Runs the tests in the ChromeNativeTestActivity and returns a Bundle containing the results.
+ */
+ private Bundle runTests() {
+ Log.i(TAG, "Creating activity.");
+ Activity activityUnderTest = startNativeTestActivity();
+
+ Log.i(TAG, "Getting results from FIFO.");
+ Map<String, TestResult> results = parseResultsFromFifo(activityUnderTest);
+
+ Log.i(TAG, "Finishing activity.");
+ activityUnderTest.finish();
+
+ Log.i(TAG, "Parsing results and generating output.");
+ return mBundleGenerator.generate(results);
+ }
+
+ /** Starts the ChromeNativeTestActivty.
+ */
+ private Activity startNativeTestActivity() {
+ Intent i = new Intent(Intent.ACTION_MAIN);
+ i.setComponent(new ComponentName(
+ "org.chromium.native_test",
+ "org.chromium.native_test.ChromeNativeTestActivity"));
+ i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ if (mCommandLineFile != null) {
+ Log.i(TAG, "Passing command line file extra: " + mCommandLineFile);
+ i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FILE, mCommandLineFile);
+ }
+ if (mCommandLineFlags != null) {
+ Log.i(TAG, "Passing command line flag extra: " + mCommandLineFlags);
+ i.putExtra(ChromeNativeTestActivity.EXTRA_COMMAND_LINE_FLAGS, mCommandLineFlags);
+ }
+ return startActivitySync(i);
+ }
+
+ private static enum TestResult {
+ PASSED, FAILED, ERROR, UNKNOWN
+ }
+
+ /**
+ * Generates a map between test names and test results from the instrumented Activity's FIFO.
+ */
+ private Map<String, TestResult> parseResultsFromFifo(Activity activityUnderTest) {
+ Map<String, TestResult> results = new HashMap<String, TestResult>();
+
+ File fifo = null;
+ BufferedReader r = null;
+
+ try {
+ // Wait for the test to create the FIFO.
+ fifo = new File(getTargetContext().getFilesDir().getAbsolutePath(), "test.fifo");
+ while (!fifo.exists()) {
+ Thread.sleep(1000);
+ }
+
+ r = new BufferedReader(
+ new InputStreamReader(new BufferedInputStream(new FileInputStream(fifo))));
+
+ StringBuilder resultsStr = new StringBuilder();
+ for (String l = r.readLine(); l != null && !l.equals("<<ScopedMainEntryLogger");
+ l = r.readLine()) {
+ Matcher m = RE_TEST_OUTPUT.matcher(l);
+ if (m.matches()) {
+ if (m.group(1).equals("RUN")) {
+ results.put(m.group(2), TestResult.UNKNOWN);
+ } else if (m.group(1).equals("FAILED")) {
+ results.put(m.group(2), TestResult.FAILED);
+ } else if (m.group(1).equals("OK")) {
+ results.put(m.group(2), TestResult.PASSED);
+ }
+ }
+ resultsStr.append(l);
+ resultsStr.append("\n");
+ }
+ mLogBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT, resultsStr.toString());
+ sendStatus(0, mLogBundle);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while waiting for FIFO file creation: " + e.toString());
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Couldn't find FIFO file: " + e.toString());
+ } catch (IOException e) {
+ Log.e(TAG, "Error handling FIFO file: " + e.toString());
+ } finally {
+ if (r != null) {
+ try {
+ r.close();
+ } catch (IOException e) {
+ Log.e(TAG, "Error while closing FIFO reader.");
+ }
+ }
+ if (fifo != null) {
+ if (!fifo.delete()) {
+ Log.e(TAG, "Unable to delete " + fifo.getAbsolutePath());
+ }
+ }
+ }
+ return results;
+ }
+
+ /**
+ * Creates a results bundle that emulates the one created by Robotium.
+ */
+ private static class RobotiumBundleGenerator implements ResultsBundleGenerator {
+ public Bundle generate(Map<String, TestResult> rawResults) {
+ Bundle resultsBundle = new Bundle();
+
+ int testsPassed = 0;
+ int testsFailed = 0;
+
+ for (Map.Entry<String, TestResult> entry : rawResults.entrySet()) {
+ switch (entry.getValue()) {
+ case PASSED:
+ ++testsPassed;
+ break;
+ case FAILED:
+ ++testsFailed;
+ break;
+ default:
+ Log.w(TAG, "Unhandled: " + entry.getKey() + ", "
+ + entry.getValue().toString());
+ break;
+ }
+ }
+
+ StringBuilder resultBuilder = new StringBuilder();
+ resultBuilder.append("\nOK (" + Integer.toString(testsPassed) + " tests)");
+ if (testsFailed > 0) {
+ resultBuilder.append(
+ "\nFAILURES!!! Tests run: " + Integer.toString(rawResults.size())
+ + ", Failures: " + Integer.toString(testsFailed) + ", Errors: 0");
+ }
+ resultsBundle.putString(Instrumentation.REPORT_KEY_STREAMRESULT,
+ resultBuilder.toString());
+ return resultsBundle;
+ }
+ }
+
+}
diff --git a/testing/android/native_test_launcher.cc b/testing/android/native_test_launcher.cc
index 63e389a..b7c9d28 100644
--- a/testing/android/native_test_launcher.cc
+++ b/testing/android/native_test_launcher.cc
@@ -30,6 +30,7 @@
using testing::native_test_util::ArgsToArgv;
using testing::native_test_util::ParseArgsFromCommandLineFile;
+using testing::native_test_util::ParseArgsFromString;
using testing::native_test_util::ScopedMainEntryLogger;
// The main function of the program to be wrapped as a test apk.
@@ -117,6 +118,8 @@
static void RunTests(JNIEnv* env,
jobject obj,
+ jstring jcommand_line_flags,
+ jstring jcommand_line_file_path,
jstring jfiles_dir,
jobject app_context) {
base::AtExitManager exit_manager;
@@ -132,7 +135,17 @@
base::android::RegisterJni(env);
std::vector<std::string> args;
- ParseArgsFromCommandLineFile(kCommandLineFilePath, &args);
+
+ const std::string command_line_file_path(
+ base::android::ConvertJavaStringToUTF8(env, jcommand_line_file_path));
+ if (command_line_file_path.empty())
+ ParseArgsFromCommandLineFile(kCommandLineFilePath, &args);
+ else
+ ParseArgsFromCommandLineFile(command_line_file_path.c_str(), &args);
+
+ const std::string command_line_flags(
+ base::android::ConvertJavaStringToUTF8(env, jcommand_line_flags));
+ ParseArgsFromString(command_line_flags, &args);
std::vector<char*> argv;
int argc = ArgsToArgv(args, &argv);
diff --git a/testing/android/native_test_util.cc b/testing/android/native_test_util.cc
index 98f32c7..885f297 100644
--- a/testing/android/native_test_util.cc
+++ b/testing/android/native_test_util.cc
@@ -9,7 +9,8 @@
#include "base/strings/string_tokenizer.h"
#include "base/strings/string_util.h"
-namespace {
+namespace testing {
+namespace native_test_util {
void ParseArgsFromString(const std::string& command_line,
std::vector<std::string>* args) {
@@ -22,11 +23,6 @@
}
}
-} // namespace
-
-namespace testing {
-namespace native_test_util {
-
void ParseArgsFromCommandLineFile(
const char* path, std::vector<std::string>* args) {
base::FilePath command_line(path);
diff --git a/testing/android/native_test_util.h b/testing/android/native_test_util.h
index a756739..ef17e52 100644
--- a/testing/android/native_test_util.h
+++ b/testing/android/native_test_util.h
@@ -27,6 +27,8 @@
}
};
+void ParseArgsFromString(
+ const std::string& command_line, std::vector<std::string>* args);
void ParseArgsFromCommandLineFile(
const char* path, std::vector<std::string>* args);
int ArgsToArgv(const std::vector<std::string>& args, std::vector<char*>* argv);
diff --git a/testing/buildbot/chromium.chromiumos.json b/testing/buildbot/chromium.chromiumos.json
index 2595ad8..d763318 100644
--- a/testing/buildbot/chromium.chromiumos.json
+++ b/testing/buildbot/chromium.chromiumos.json
@@ -61,7 +61,7 @@
"test": "sandbox_linux_unittests",
"args": ["--test-launcher-print-test-stdio=always"]
},
- "ui_unittests",
+ "ui_base_unittests",
"views_unittests",
"wm_unittests",
"aura_unittests",
@@ -133,7 +133,7 @@
},
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
"unit_tests",
"url_unittests",
"views_unittests",
@@ -180,7 +180,7 @@
"test": "sandbox_linux_unittests",
"args": ["--test-launcher-print-test-stdio=always"]
},
- "ui_unittests",
+ "ui_base_unittests",
"views_unittests",
"wm_unittests",
"aura_unittests",
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index c1c7be4..c9869f7 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -32,7 +32,7 @@
"printing_unittests",
"remoting_unittests",
"sandbox_linux_unittests",
- "ui_unittests",
+ "ui_base_unittests",
"ipc_tests",
"sync_unit_tests",
"unit_tests",
@@ -98,7 +98,7 @@
"printing_unittests",
"remoting_unittests",
"sandbox_linux_unittests",
- "ui_unittests",
+ "ui_base_unittests",
"ipc_tests",
"sync_unit_tests",
"unit_tests",
@@ -164,7 +164,7 @@
"printing_unittests",
"remoting_unittests",
"sandbox_linux_unittests",
- "ui_unittests",
+ "ui_base_unittests",
"ipc_tests",
"sync_unit_tests",
"unit_tests",
@@ -230,7 +230,7 @@
"printing_unittests",
"remoting_unittests",
"sandbox_linux_unittests",
- "ui_unittests",
+ "ui_base_unittests",
"ipc_tests",
"sync_unit_tests",
"unit_tests",
@@ -308,7 +308,7 @@
"sql_unittests",
"sync_integration_tests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
"unit_tests",
"url_unittests",
"browser_tests"
@@ -400,7 +400,7 @@
"sandbox_linux_unittests",
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
"unit_tests",
"url_unittests",
"views_unittests",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 4fa07e6..850beb4 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -75,7 +75,7 @@
"remoting_unittests",
"sandbox_linux_unittests",
"sql_unittests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "sync_integration_tests",
"swarming": {
@@ -184,7 +184,7 @@
"remoting_unittests",
"sandbox_linux_unittests",
"sql_unittests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "sync_integration_tests",
"swarming": {
@@ -289,7 +289,7 @@
"args": ["--test-launcher-print-test-stdio=always"]
},
"sql_unittests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "sync_integration_tests",
"swarming": {
@@ -346,7 +346,7 @@
"sandbox_linux_unittests",
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
"unit_tests"
]
}
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index c1bdf11..cff26cd 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -73,7 +73,7 @@
}
},
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
@@ -171,7 +171,7 @@
}
},
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
@@ -269,7 +269,7 @@
}
},
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
@@ -360,7 +360,7 @@
}
},
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index adc4165..577ff7d 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -42,7 +42,7 @@
"sandbox_linux_unittests",
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
"unit_tests",
"url_unittests",
"views_unittests",
diff --git a/testing/buildbot/chromium.memory.json b/testing/buildbot/chromium.memory.json
index 1216d6e..8f72e65 100644
--- a/testing/buildbot/chromium.memory.json
+++ b/testing/buildbot/chromium.memory.json
@@ -62,7 +62,7 @@
"sandbox_linux_unittests",
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
@@ -150,7 +150,7 @@
"remoting_unittests",
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
"url_unittests"
]
},
@@ -211,7 +211,7 @@
"remoting_unittests",
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
@@ -303,7 +303,7 @@
"shards": 2
}
},
- "ui_unittests",
+ "ui_base_unittests",
"url_unittests",
"views_unittests"
]
diff --git a/testing/buildbot/chromium.webkit.json b/testing/buildbot/chromium.webkit.json
index b121217..434d369 100644
--- a/testing/buildbot/chromium.webkit.json
+++ b/testing/buildbot/chromium.webkit.json
@@ -58,7 +58,7 @@
"printing_unittests",
"remoting_unittests",
"sandbox_linux_unittests",
- "ui_unittests",
+ "ui_base_unittests",
"views_unittests",
"wm_unittests",
"aura_unittests",
@@ -124,7 +124,7 @@
"printing_unittests",
"remoting_unittests",
"sandbox_linux_unittests",
- "ui_unittests",
+ "ui_base_unittests",
"views_unittests",
"wm_unittests",
"aura_unittests",
diff --git a/testing/buildbot/chromium.win.json b/testing/buildbot/chromium.win.json
index d8c9672..0910b9f 100644
--- a/testing/buildbot/chromium.win.json
+++ b/testing/buildbot/chromium.win.json
@@ -82,7 +82,7 @@
"can_use_on_swarming_builders": true
}
},
- "ui_unittests",
+ "ui_base_unittests",
"url_unittests",
"views_unittests",
"wm_unittests"
@@ -191,7 +191,7 @@
"can_use_on_swarming_builders": true
}
},
- "ui_unittests",
+ "ui_base_unittests",
"url_unittests",
"views_unittests",
"wm_unittests"
@@ -209,6 +209,7 @@
},
"Win7 Tests (1)": {
"gtest_tests": [
+ "app_installer_unittests",
"accessibility_unittests",
{
"test": "ash_unittests",
@@ -296,7 +297,7 @@
}
},
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
@@ -402,7 +403,7 @@
},
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
@@ -513,7 +514,7 @@
}
},
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
diff --git a/testing/buildbot/chromium_memory_trybot.json b/testing/buildbot/chromium_memory_trybot.json
index 161071d..357735f 100644
--- a/testing/buildbot/chromium_memory_trybot.json
+++ b/testing/buildbot/chromium_memory_trybot.json
@@ -65,7 +65,7 @@
},
"sql_unittests",
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
diff --git a/testing/buildbot/chromium_trybot.json b/testing/buildbot/chromium_trybot.json
index 9c7f5c9..6e3cff5 100644
--- a/testing/buildbot/chromium_trybot.json
+++ b/testing/buildbot/chromium_trybot.json
@@ -4,6 +4,10 @@
],
"gtest_tests": [
"accessibility_unittests",
+ {
+ "test": "app_installer_unittests",
+ "platforms": ["win"]
+ },
"app_list_unittests",
{
"test": "ash_unittests",
@@ -33,7 +37,7 @@
"test": "browser_tests",
"swarming": {
"can_use_on_swarming_builders": true,
- "shards": 5
+ "shards": 8
}
},
"cacheinvalidation_unittests",
@@ -153,7 +157,7 @@
}
},
"sync_unit_tests",
- "ui_unittests",
+ "ui_base_unittests",
{
"test": "unit_tests",
"swarming": {
diff --git a/testing/chromoting/browser_test_commands_linux.txt b/testing/chromoting/browser_test_commands_linux.txt
index af64c09..3b6a61b 100644
--- a/testing/chromoting/browser_test_commands_linux.txt
+++ b/testing/chromoting/browser_test_commands_linux.txt
@@ -1,4 +1,6 @@
/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting
/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd
-/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
\ No newline at end of file
+/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
+/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp.v2 --extension-name=Chromoting
+/usr/bin/python ../xvfb.py $(PROD_DIR) $(PROD_DIR)/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=20000 --webapp-unpacked=$(PROD_DIR)/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
diff --git a/testing/chromoting/browser_tests_launcher.py b/testing/chromoting/browser_tests_launcher.py
index 66b54fe..8f4bba1 100644
--- a/testing/chromoting/browser_tests_launcher.py
+++ b/testing/chromoting/browser_tests_launcher.py
@@ -14,14 +14,14 @@
cmd_line = [command]
try:
- results = subprocess.check_output(
- cmd_line, stderr=subprocess.STDOUT, shell=True)
+ p = subprocess.Popen(cmd_line, stdout=subprocess.PIPE, shell=True)
+ results, err = p.communicate()
+ if 'SUCCESS: all tests passed.' not in results:
+ raise Exception('Test failed\n%s\n%s' % (results, err))
except subprocess.CalledProcessError, e:
raise Exception('Exception %s running command %s' % (e, command))
else:
print results
- finally:
- pass
def main():
diff --git a/testing/chromoting/chromoting_integration_tests.isolate b/testing/chromoting/chromoting_integration_tests.isolate
index db21d82..cdfd8c4 100644
--- a/testing/chromoting/chromoting_integration_tests.isolate
+++ b/testing/chromoting/chromoting_integration_tests.isolate
@@ -16,7 +16,6 @@
'../xvfb.py',
'./browser_tests_launcher.py',
'./browser_test_commands_linux.txt',
- '../../remoting/tools/internal/test_accounts.json',
'<(PRODUCT_DIR)/libffmpegsumo.so',
'<(PRODUCT_DIR)/libosmesa.so',
'<(PRODUCT_DIR)/nacl_irt_x86_64.nexe',
@@ -36,7 +35,9 @@
'../test_env.py',
'<(PRODUCT_DIR)/browser_tests<(EXECUTABLE_SUFFIX)',
'<(PRODUCT_DIR)/remoting/remoting.webapp/',
+ '<(PRODUCT_DIR)/remoting/remoting.webapp.v2/',
'<(PRODUCT_DIR)/resources.pak',
+ '../../remoting/tools/internal/test_accounts.json',
],
'read_only': 1,
},
@@ -83,4 +84,4 @@
'includes': [
'../../base/base.isolate',
],
-}
+}
\ No newline at end of file
diff --git a/testing/chromoting/integration_tests.gyp b/testing/chromoting/integration_tests.gyp
index 23fcf6f..78c1368 100644
--- a/testing/chromoting/integration_tests.gyp
+++ b/testing/chromoting/integration_tests.gyp
@@ -20,6 +20,13 @@
'sources': [
'chromoting_integration_tests.isolate',
],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'dependencies': [
+ '../../remoting/remoting.gyp:remoting_me2me_host_archive',
+ ],
+ }], # OS=="linux"
+ ],
},
],
}],
diff --git a/testing/iossim/iossim.mm b/testing/iossim/iossim.mm
index 5eaed5c..83cfe92 100644
--- a/testing/iossim/iossim.mm
+++ b/testing/iossim/iossim.mm
@@ -504,13 +504,22 @@
[NSCharacterSet newlineCharacterSet]];
NSString* simulatedAppPID =
[NSString stringWithFormat:@"%d", session.simulatedApplicationPID];
+ NSArray* kErrorStrings = @[
+ @"Service exited with abnormal code:",
+ @"Service exited due to signal:",
+ ];
for (NSString* line in lines) {
- NSString* const kErrorString = @"Service exited with abnormal code:";
- if ([line rangeOfString:kErrorString].location != NSNotFound &&
- [line rangeOfString:simulatedAppPID].location != NSNotFound) {
- LogWarning(@"Console message: %@", line);
- badEntryFound = YES;
- break;
+ if ([line rangeOfString:simulatedAppPID].location != NSNotFound) {
+ for (NSString* errorString in kErrorStrings) {
+ if ([line rangeOfString:errorString].location != NSNotFound) {
+ LogWarning(@"Console message: %@", line);
+ badEntryFound = YES;
+ break;
+ }
+ }
+ if (badEntryFound) {
+ break;
+ }
}
}
// Remove the log file so subsequent invocations of iossim won't be
diff --git a/third_party/boringssl/boringssl_tests.gypi b/third_party/boringssl/boringssl_tests.gypi
index 3f7cd53..cf2aff4 100644
--- a/third_party/boringssl/boringssl_tests.gypi
+++ b/third_party/boringssl/boringssl_tests.gypi
@@ -85,6 +85,19 @@
'msvs_disabled_warnings': [ 4267, ],
},
{
+ 'target_name': 'boringssl_constant_time_test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'boringssl.gyp:boringssl',
+ ],
+ 'sources': [
+ 'src/crypto/constant_time_test.c',
+ ],
+ # TODO(davidben): Fix size_t truncations in BoringSSL.
+ # https://crbug.com/429039
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
'target_name': 'boringssl_dh_test',
'type': 'executable',
'dependencies': [
@@ -98,6 +111,19 @@
'msvs_disabled_warnings': [ 4267, ],
},
{
+ 'target_name': 'boringssl_digest_test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'boringssl.gyp:boringssl',
+ ],
+ 'sources': [
+ 'src/crypto/digest/digest_test.c',
+ ],
+ # TODO(davidben): Fix size_t truncations in BoringSSL.
+ # https://crbug.com/429039
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
'target_name': 'boringssl_dsa_test',
'type': 'executable',
'dependencies': [
@@ -111,6 +137,19 @@
'msvs_disabled_warnings': [ 4267, ],
},
{
+ 'target_name': 'boringssl_ec_test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'boringssl.gyp:boringssl',
+ ],
+ 'sources': [
+ 'src/crypto/ec/ec_test.c',
+ ],
+ # TODO(davidben): Fix size_t truncations in BoringSSL.
+ # https://crbug.com/429039
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
'target_name': 'boringssl_example_mul',
'type': 'executable',
'dependencies': [
@@ -189,19 +228,6 @@
'msvs_disabled_warnings': [ 4267, ],
},
{
- 'target_name': 'boringssl_md5_test',
- 'type': 'executable',
- 'dependencies': [
- 'boringssl.gyp:boringssl',
- ],
- 'sources': [
- 'src/crypto/md5/md5_test.c',
- ],
- # TODO(davidben): Fix size_t truncations in BoringSSL.
- # https://crbug.com/429039
- 'msvs_disabled_warnings': [ 4267, ],
- },
- {
'target_name': 'boringssl_gcm_test',
'type': 'executable',
'dependencies': [
@@ -241,19 +267,6 @@
'msvs_disabled_warnings': [ 4267, ],
},
{
- 'target_name': 'boringssl_sha1_test',
- 'type': 'executable',
- 'dependencies': [
- 'boringssl.gyp:boringssl',
- ],
- 'sources': [
- 'src/crypto/sha/sha1_test.c',
- ],
- # TODO(davidben): Fix size_t truncations in BoringSSL.
- # https://crbug.com/429039
- 'msvs_disabled_warnings': [ 4267, ],
- },
- {
'target_name': 'boringssl_pkcs7_test',
'type': 'executable',
'dependencies': [
@@ -301,8 +314,11 @@
'boringssl_bn_test',
'boringssl_bytestring_test',
'boringssl_cipher_test',
+ 'boringssl_constant_time_test',
'boringssl_dh_test',
+ 'boringssl_digest_test',
'boringssl_dsa_test',
+ 'boringssl_ec_test',
'boringssl_ecdsa_test',
'boringssl_err_test',
'boringssl_evp_test',
@@ -310,12 +326,10 @@
'boringssl_gcm_test',
'boringssl_hmac_test',
'boringssl_lhash_test',
- 'boringssl_md5_test',
'boringssl_pkcs12_test',
'boringssl_pkcs7_test',
'boringssl_pqueue_test',
'boringssl_rsa_test',
- 'boringssl_sha1_test',
'boringssl_ssl_test',
],
}
diff --git a/third_party/boringssl/boringssl_unittest.cc b/third_party/boringssl/boringssl_unittest.cc
index 1a62cac..6d54ad2 100644
--- a/third_party/boringssl/boringssl_unittest.cc
+++ b/third_party/boringssl/boringssl_unittest.cc
@@ -156,6 +156,10 @@
TestSimple("bytestring_test");
}
+TEST(BoringSSL, ConstantTime) {
+ TestSimple("constant_time_test");
+}
+
TEST(BoringSSL, Cipher) {
base::FilePath data_file;
ASSERT_TRUE(CryptoCipherPath(&data_file));
@@ -171,10 +175,18 @@
TestSimple("dh_test");
}
+TEST(BoringSSL, Digest) {
+ TestSimple("digest_test");
+}
+
TEST(BoringSSL, DSA) {
TestSimple("dsa_test");
}
+TEST(BoringSSL, EC) {
+ TestSimple("ec_test");
+}
+
TEST(BoringSSL, ECDSA) {
TestSimple("ecdsa_test");
}
@@ -195,18 +207,10 @@
TestSimple("lhash_test");
}
-TEST(BoringSSL, MD5) {
- TestSimple("md5_test");
-}
-
TEST(BoringSSL, RSA) {
TestSimple("rsa_test");
}
-TEST(BoringSSL, SHA1) {
- TestSimple("sha1_test");
-}
-
TEST(BoringSSL, PKCS7) {
TestSimple("pkcs7_test");
}
diff --git a/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm b/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm
index 30e8a85..e1c9e0e 100644
--- a/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm
+++ b/third_party/boringssl/win-x86_64/crypto/aes/aesni-x86_64.asm
@@ -519,6 +519,12 @@
mov r8,QWORD[40+rsp]
+ lea rsp,[((-88))+rsp]
+ movaps XMMWORD[rsp],xmm6
+ movaps XMMWORD[16+rsp],xmm7
+ movaps XMMWORD[32+rsp],xmm8
+ movaps XMMWORD[48+rsp],xmm9
+$L$ecb_enc_body:
and rdx,-16
jz NEAR $L$ecb_ret
@@ -813,6 +819,12 @@
movups XMMWORD[80+rsi],xmm7
$L$ecb_ret:
+ movaps xmm6,XMMWORD[rsp]
+ movaps xmm7,XMMWORD[16+rsp]
+ movaps xmm8,XMMWORD[32+rsp]
+ movaps xmm9,XMMWORD[48+rsp]
+ lea rsp,[88+rsp]
+$L$ecb_enc_ret:
mov rdi,QWORD[8+rsp] ;WIN64 epilogue
mov rsi,QWORD[16+rsp]
DB 0F3h,0C3h ;repret
@@ -3378,26 +3390,7 @@
EXTERN __imp_RtlVirtualUnwind
ALIGN 16
-ecb_se_handler:
- push rsi
- push rdi
- push rbx
- push rbp
- push r12
- push r13
- push r14
- push r15
- pushfq
- sub rsp,64
-
- mov rax,QWORD[152+r8]
-
- jmp NEAR $L$common_seh_tail
-
-
-
-ALIGN 16
-ccm64_se_handler:
+ecb_ccm64_se_handler:
push rsi
push rdi
push rbx
@@ -3600,14 +3593,15 @@
ALIGN 8
$L$SEH_info_ecb:
DB 9,0,0,0
- DD ecb_se_handler wrt ..imagebase
+ DD ecb_ccm64_se_handler wrt ..imagebase
+ DD $L$ecb_enc_body wrt ..imagebase,$L$ecb_enc_ret wrt ..imagebase
$L$SEH_info_ccm64_enc:
DB 9,0,0,0
- DD ccm64_se_handler wrt ..imagebase
+ DD ecb_ccm64_se_handler wrt ..imagebase
DD $L$ccm64_enc_body wrt ..imagebase,$L$ccm64_enc_ret wrt ..imagebase
$L$SEH_info_ccm64_dec:
DB 9,0,0,0
- DD ccm64_se_handler wrt ..imagebase
+ DD ecb_ccm64_se_handler wrt ..imagebase
DD $L$ccm64_dec_body wrt ..imagebase,$L$ccm64_dec_ret wrt ..imagebase
$L$SEH_info_ctr32:
DB 9,0,0,0
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index 7f5b2e3..195c5c8 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+import("//build/config/linux/pkg_config.gni")
+
# The GYP build supports system harfbuzz for non-official builds when using
# pangoft2 1.31.0 or greater (which pulls it in).
# TODO(brettw) we can consider doing this as well, although the benefit is
@@ -11,7 +13,28 @@
# don't want to bloat the binary more by including another copy.
declare_args() {
- use_system_harfbuzz = is_chromeos
+ if (is_chromeos) {
+ # ChromeOS includes an up-to-date system harfbuzz that we have control
+ # over, so it use the system one by default.
+ use_system_harfbuzz = true
+ } else if (is_official_build) {
+ # For official builds, we want to control the Harbuzz version so always
+ # use our included one. Currently the sysroot includes a version of pangoft
+ # that doesn't link to harfbuzz, so there are no linker problems. If we
+ # update that version, we'll need to work around the duplicate symbols some
+ # other way.
+ use_system_harfbuzz = false
+ } else if (is_linux) {
+ # Use the system harfbuzz for newer versions of pangoft, and not for older
+ # ones. pangoft links to the system harfbuzz starting with 1.31.0, which
+ # causes duplicate symbols when we link our own version.
+ use_system_harfbuzz = exec_script(
+ pkg_config_script,
+ pkg_config_args + [ "--atleast-version=1.31.0", "pangoft2" ],
+ "value")
+ } else {
+ use_system_harfbuzz = false
+ }
}
if (use_system_harfbuzz) {
@@ -28,7 +51,7 @@
include_dirs = [ "src" ]
}
- source_set("harfbuzz-ng") {
+ static_library("harfbuzz-ng") {
sources = [
"src/hb-atomic-private.hh",
"src/hb-blob.cc",
diff --git a/third_party/libxml/BUILD.gn b/third_party/libxml/BUILD.gn
index d42e0df..73bb3dc 100644
--- a/third_party/libxml/BUILD.gn
+++ b/third_party/libxml/BUILD.gn
@@ -153,7 +153,6 @@
if (is_win) {
cflags_c = [
"/wd4101", # Unreferenced local variable.
- "/wd4267", # TODO(jschuh): crbug.com/167187 size_t to int truncations.
]
} else if (is_mac || is_android) {
# http://www.xmlsoft.org/threads.html says that this is required when using
diff --git a/third_party/mesa/mesa.gyp b/third_party/mesa/mesa.gyp
index 6ccbb2a..bc115e1 100644
--- a/third_party/mesa/mesa.gyp
+++ b/third_party/mesa/mesa.gyp
@@ -657,14 +657,6 @@
'_GLAPI_NO_EXPORTS',
],
}],
- ['ubsan==1', {
- # Due to a bug in LLVM (http://llvm.org/bugs/show_bug.cgi?id=21349),
- # compilation hangs for some Mesa source files. Disable -O2
- # temporarily until http://crbug.com/426271 is fixed.
- 'cflags!': [
- '-O2',
- ],
- }],
],
},
# Building this target will hide the native OpenGL shared library and
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index 923e8eb..5dbec0f 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -12,9 +12,10 @@
cflags = [ "-msse2", "-msse4.2", "-mpclmul" ]
} else {
sources = [ "simd_stub.c"]
- }
- if (is_win) {
- cflags = [ "/wd4324" ]
+ if (is_win) {
+ # TODO(GYP): crbug.com/431462 disable warning about structure padding.
+ cflags = [ "/wd4324" ]
+ }
}
}
diff --git a/third_party/zlib/simd_stub.c b/third_party/zlib/simd_stub.c
index bb2ddc3..796f1f6 100644
--- a/third_party/zlib/simd_stub.c
+++ b/third_party/zlib/simd_stub.c
@@ -7,7 +7,7 @@
#include "deflate.h"
#include "x86.h"
-int x86_cpu_enable_simd;
+int x86_cpu_enable_simd = 0;
void ZLIB_INTERNAL crc_fold_init(deflate_state *const s) {
assert(0);
diff --git a/third_party/zlib/x86.c b/third_party/zlib/x86.c
index 35ec516..0649306 100644
--- a/third_party/zlib/x86.c
+++ b/third_party/zlib/x86.c
@@ -10,7 +10,7 @@
#include "x86.h"
-int x86_cpu_enable_simd;
+int x86_cpu_enable_simd = 0;
#ifndef _MSC_VER
#include <pthread.h>
diff --git a/third_party/zlib/zlib.gyp b/third_party/zlib/zlib.gyp
index 8c5ae44..22a48a3 100644
--- a/third_party/zlib/zlib.gyp
+++ b/third_party/zlib/zlib.gyp
@@ -8,9 +8,11 @@
'target_name' : 'zlib_x86_simd',
'type': 'static_library',
'conditions': [
- # See http://crbug.com/420616 gyp on mac & ios doesn't apply cflags
- ['OS!="ios" and OS!="mac" and (target_arch=="ia32" or target_arch=="x64")', {
+ ['OS!="ios" and (target_arch=="ia32" or target_arch=="x64")', {
'cflags' : ["-msse2", "-msse4.2", "-mpclmul"],
+ 'xcode_settings' : {
+ 'OTHER_CFLAGS' : ["-msse4.2", "-mpclmul"],
+ },
'sources' : [ 'crc_folding.c',
'fill_window_sse.c']
}, {
@@ -65,7 +67,7 @@
],
},
'conditions': [
- ['OS!="ios" and OS!="mac" and (target_arch=="ia32" or target_arch=="x64")', {
+ ['OS!="ios" and (target_arch=="ia32" or target_arch=="x64")', {
'sources' : [ 'x86.c', ],
}],
['OS!="win"', {
diff --git a/tools/clang/empty_string/EmptyStringConverter.cpp b/tools/clang/empty_string/EmptyStringConverter.cpp
index 28cc602..d056755 100644
--- a/tools/clang/empty_string/EmptyStringConverter.cpp
+++ b/tools/clang/empty_string/EmptyStringConverter.cpp
@@ -196,8 +196,8 @@
// tools.
llvm::outs() << "==== BEGIN EDITS ====\n";
for (const auto& r : replacements) {
- llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
- << r.getLength() << ":" << r.getReplacementText() << "\n";
+ llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() << ":::"
+ << r.getLength() << ":::" << r.getReplacementText() << "\n";
}
llvm::outs() << "==== END EDITS ====\n";
diff --git a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
index b2cd31f..fe9d860 100644
--- a/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
+++ b/tools/clang/rewrite_scoped_refptr/RewriteScopedRefptr.cpp
@@ -419,8 +419,8 @@
for (const auto& r : replacements) {
std::string replacement_text = r.getReplacementText().str();
std::replace(replacement_text.begin(), replacement_text.end(), '\n', '\0');
- llvm::outs() << "r:" << r.getFilePath() << ":" << r.getOffset() << ":"
- << r.getLength() << ":" << replacement_text << "\n";
+ llvm::outs() << "r:::" << r.getFilePath() << ":::" << r.getOffset() << ":::"
+ << r.getLength() << ":::" << replacement_text << "\n";
}
llvm::outs() << "==== END EDITS ====\n";
diff --git a/tools/clang/scripts/run_tool.py b/tools/clang/scripts/run_tool.py
index 33bb462..61417e4 100755
--- a/tools/clang/scripts/run_tool.py
+++ b/tools/clang/scripts/run_tool.py
@@ -54,12 +54,17 @@
Args:
paths: Prefix filter for the returned paths. May contain multiple entries.
"""
- args = ['git', 'ls-files']
+ args = []
+ if sys.platform == 'win32':
+ args.append('git.bat')
+ else:
+ args.append('git')
+ args.append('ls-files')
if paths:
args.extend(paths)
command = subprocess.Popen(args, stdout=subprocess.PIPE)
output, _ = command.communicate()
- return output.splitlines()
+ return [os.path.realpath(p) for p in output.splitlines()]
def _ExtractEditsFromStdout(build_directory, stdout):
@@ -81,11 +86,10 @@
edits = collections.defaultdict(list)
for line in lines[start_index + 1:end_index]:
try:
- edit_type, path, offset, length, replacement = line.split(':', 4)
+ edit_type, path, offset, length, replacement = line.split(':::', 4)
replacement = replacement.replace("\0", "\n");
- # Normalize the file path emitted by the clang tool to be relative to the
- # current working directory.
- path = os.path.relpath(os.path.join(build_directory, path))
+ # Normalize the file path emitted by the clang tool.
+ path = os.path.realpath(os.path.join(build_directory, path))
edits[path].append(Edit(edit_type, int(offset), int(length), replacement))
except ValueError:
print 'Unable to parse edit: %s' % line
@@ -140,6 +144,7 @@
self.__filenames = filenames
self.__success_count = 0
self.__failed_count = 0
+ self.__edit_count = 0
self.__edits = collections.defaultdict(list)
@property
@@ -172,6 +177,7 @@
self.__success_count += 1
for k, v in result['edits'].iteritems():
self.__edits[k].extend(v)
+ self.__edit_count += len(v)
else:
self.__failed_count += 1
sys.stdout.write('\nFailed to process %s\n' % result['filename'])
@@ -180,8 +186,9 @@
percentage = (
float(self.__success_count + self.__failed_count) /
len(self.__filenames)) * 100
- sys.stdout.write('Succeeded: %d, Failed: %d [%.2f%%]\r' % (
- self.__success_count, self.__failed_count, percentage))
+ sys.stdout.write('Succeeded: %d, Failed: %d, Edits: %d [%.2f%%]\r' % (
+ self.__success_count, self.__failed_count, self.__edit_count,
+ percentage))
sys.stdout.flush()
@@ -283,7 +290,9 @@
'../../../third_party/llvm/tools/clang/tools/clang-format',
'clang-format-diff.py')
# TODO(dcheng): Allow this to be controlled with a flag as well.
- if not os.path.isfile(clang_format_diff_path):
+ # TODO(dcheng): Shell escaping of args to git diff to clang-format is broken
+ # on Windows.
+ if not os.path.isfile(clang_format_diff_path) or sys.platform == 'win32':
clang_format_diff_path = None
filenames = frozenset(_GetFilesFromGit(argv[2:]))
@@ -297,7 +306,7 @@
# useful to modify files that aren't under source control--typically, these
# are generated files or files in a git submodule that's not part of Chromium.
_ApplyEdits({k : v for k, v in dispatcher.edits.iteritems()
- if k in filenames},
+ if os.path.realpath(k) in filenames},
clang_format_diff_path)
if dispatcher.failed_count != 0:
return 2
diff --git a/tools/clang/scripts/test_tool.py b/tools/clang/scripts/test_tool.py
index d14dfda..1f64be4 100755
--- a/tools/clang/scripts/test_tool.py
+++ b/tools/clang/scripts/test_tool.py
@@ -20,7 +20,7 @@
include_path_flags = ' '.join('-I %s' % include_path
for include_path in include_paths)
return json.dumps([{'directory': '.',
- 'command': 'clang++ -fsyntax-only %s -c %s' % (
+ 'command': 'clang++ -std=c++11 -fsyntax-only %s -c %s' % (
include_path_flags, f),
'file': f} for f in files], indent=2)
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 5ee7c30..25aa5a5 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -32,6 +32,7 @@
'Release+Asserts')
COMPILER_RT_BUILD_DIR = os.path.join(LLVM_BUILD_DIR, '32bit-compiler-rt')
CLANG_DIR = os.path.join(LLVM_DIR, 'tools', 'clang')
+LLD_DIR = os.path.join(LLVM_DIR, 'tools', 'lld')
COMPILER_RT_DIR = os.path.join(LLVM_DIR, 'projects', 'compiler-rt')
STAMP_FILE = os.path.join(LLVM_BUILD_DIR, 'cr_build_revision')
@@ -179,6 +180,7 @@
Checkout('LLVM', LLVM_REPO_URL + '/llvm/trunk', LLVM_DIR)
Checkout('Clang', LLVM_REPO_URL + '/cfe/trunk', CLANG_DIR)
+ Checkout('LLD', LLVM_REPO_URL + '/lld/trunk', LLD_DIR)
Checkout('compiler-rt', LLVM_REPO_URL + '/compiler-rt/trunk', COMPILER_RT_DIR)
if not os.path.exists(LLVM_BUILD_DIR):
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index 4681b25..f80cdd0 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -133,6 +133,10 @@
"includes": [23000],
"structures": [23200],
},
+ "chrome/browser/resources/options_test_resources.grd": {
+ "includes": [23400],
+ "structures": [23450],
+ },
"cloud_print/virtual_driver/win/install/virtual_driver_setup_resources.grd": {
"messages": [23500],
"includes": [23550],
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index 8735e0d..27d554e 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -129,11 +129,14 @@
# TODO(timurrrr): also check TSan and MSan?
# `nm` might not be available, so use try-except.
try:
- nm_output = subprocess.check_output(["nm", exe_path])
- if nm_output.find("__asan_init") != -1:
- raise BadBinary("You're trying to run an executable instrumented "
- "with AddressSanitizer under %s. Please provide "
- "an uninstrumented executable." % tool_name)
+ # Do not perform this check on OS X, as 'nm' on 10.6 can't handle
+ # binaries built with Clang 3.5+.
+ if not common.IsMac():
+ nm_output = subprocess.check_output(["nm", exe_path])
+ if nm_output.find("__asan_init") != -1:
+ raise BadBinary("You're trying to run an executable instrumented "
+ "with AddressSanitizer under %s. Please provide "
+ "an uninstrumented executable." % tool_name)
except OSError:
pass
diff --git a/tools/valgrind/drmemory/suppressions.txt b/tools/valgrind/drmemory/suppressions.txt
index 5840dc1..96ae6fa 100644
--- a/tools/valgrind/drmemory/suppressions.txt
+++ b/tools/valgrind/drmemory/suppressions.txt
@@ -550,15 +550,6 @@
*!content::BrowserThreadImpl::CacheThreadRun
*!content::BrowserThreadImpl::Run
-UNADDRESSABLE ACCESS
-name=http://crbug.com/379204
-...
-*!WTF::MessageQueue<>::waitForMessageWithTimeout
-*!blink::WorkerRunLoop::run
-*!blink::WorkerRunLoop::run
-*!blink::WorkerThread::workerThread
-*!WTF::threadEntryPoint
-
GDI USAGE ERROR
name=379774
system call NtUserCallOneParam.RELEASEDC
@@ -667,3 +658,10 @@
blink_web.dll!blink::FrameView::prepareForDetach
blink_web.dll!blink::LocalFrame::setView
blink_web.dll!blink::FrameTree::~FrameTree
+
+UNADDRESSABLE ACCESS
+name=http://crbug.com/432070
+blink_web.dll!blink::Frame::detach
+content.dll!content::RenderFrameProxy::OnDeleteProxy
+content.dll!content::RenderFrameProxy::OnMessageReceived
+content.dll!content::MessageRouter::RouteMessage
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index ebe6a15..3cd6ca0 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1864,3 +1864,10 @@
name=bug_425097
...
*!ash::test::ShelfViewTest_CheckDragAndDropFromOverflowBubbleToShelf_Test::TestBody
+
+UNINITIALIZED READ
+name=bug_432067
+system call NtCreateFile parameter #9
+MSWSOCK.dll!*
+content.dll!content::AppCacheStorageImpl::DatabaseTask::CallRun
+
diff --git a/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt b/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt
index 321f281..69ce8dc 100644
--- a/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/aura_unittests.gtest.txt
@@ -1,5 +1,2 @@
# Flaky under Valgrind, see http://crbug.com/348331
WindowEventDispatcherTest.TouchMovesHeld
-
-# Failing on cros/win. crbug.com/427729
-GestureRecognizerTest.GestureEventSmallPinchEnabled
diff --git a/tools/valgrind/gtest_exclude/gfx_unittests.gtest-memcheck.txt b/tools/valgrind/gtest_exclude/gfx_unittests.gtest-memcheck.txt
new file mode 100644
index 0000000..3aaaafc
--- /dev/null
+++ b/tools/valgrind/gtest_exclude/gfx_unittests.gtest-memcheck.txt
@@ -0,0 +1,2 @@
+# http://crbug.com/402209
+FontRenderParamsTest.Default
diff --git a/tools/valgrind/gtest_exclude/ui_unittests.gtest-memcheck_linux.txt b/tools/valgrind/gtest_exclude/ui_unittests.gtest-memcheck_linux.txt
new file mode 100644
index 0000000..282de6b
--- /dev/null
+++ b/tools/valgrind/gtest_exclude/ui_unittests.gtest-memcheck_linux.txt
@@ -0,0 +1,2 @@
+# http://crbug.com/431708
+TouchExplorationTest.TwoFingerTapAndHold
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 852a638..fa0f599 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -2506,19 +2506,6 @@
fun:nssTrustDomain_UpdateCachedTokenCerts
}
{
- bug_331063
- Memcheck:Uninitialized
- ...
- fun:_ZN5blink11RenderImage12imageChangedEPvPKNS_7IntRectE
- fun:_ZN5blink12RenderObject12imageChangedEPNS_13ImageResourceEPKNS_7IntRectE
- fun:_ZN5blink13ImageResource12didAddClientEPNS_14ResourceClientE
- fun:_ZN5blink8Resource9addClientEPNS_14ResourceClientE
- fun:_ZN5blink19RenderImageResource16setImageResourceEPNS_13ImageResourceE
- fun:_ZN5blink30PasswordGeneratorButtonElement11updateImageEv
- fun:_ZN5blink30PasswordGeneratorButtonElement6attachERKNS_4Node13AttachContextE
- fun:_ZN5blink13ContainerNode14attachChildrenERKNS_4Node13AttachContextE
-}
-{
bug_331925
Memcheck:Leak
...
@@ -2845,19 +2832,6 @@
fun:_ZN7content27ServiceWorkerContextWrapper12InitInternalERKN4base8FilePathEPNS1_19SequencedTaskRunnerEPNS1_16MessageLoopProxyEPN5quota17QuotaManagerProxyE
}
{
- bug_379359
- Memcheck:Leak
- fun:_Znw*
- fun:_ZN7content27ServiceWorkerContextWrapperC1EPNS_14BrowserContextE
- fun:_ZN7content20StoragePartitionImpl6CreateEPNS_14BrowserContextEbRKN4base8FilePathE
- fun:_ZN7content23StoragePartitionImplMap3GetERKSsS2_b
- fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContext*
- fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE
- fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_
- fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv
- fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv
-}
-{
bug_379943
Memcheck:Leak
fun:_Znw*
@@ -2867,6 +2841,7 @@
fun:_ZN7content12_GLOBAL__N_129GetStoragePartitionFromConfigEPNS_14BrowserContext*
fun:_ZN7content14BrowserContext19GetStoragePartitionEPS0_PNS_12SiteInstanceE
fun:_ZN7content14BrowserContext26GetDefaultStoragePartitionEPS0_
+ ...
fun:_ZN7content21ShellBrowserMainParts21PreMainMessageLoopRunEv
fun:_ZN7content15BrowserMainLoop21PreMainMessageLoopRunEv
}
@@ -3435,3 +3410,28 @@
fun:_ZN7content19TestRenderFrameHost41SendNavigateWithTransitionAndResponseCodeEiRK4GURLN2ui14PageTransitionEi
fun:_ZN7content19TestRenderFrameHost26SendNavigateWithTransitionEiRK4GURLN2ui14PageTransitionE
}
+{
+ bug_431209a
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN8remoting13ClipboardAuraC1E13scoped_refptrIN4base22SingleThreadTaskRunnerEE
+ fun:_ZN8remoting17ClipboardAuraTest5SetUpEv
+}
+{
+ bug_431209b
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN2ui9Clipboard6CreateEv
+ fun:_ZN2ui9Clipboard19GetForCurrentThreadEv
+ fun:_ZN2ui21ScopedClipboardWriterD1Ev
+ fun:_ZN8remoting13ClipboardAura4Core20InjectClipboardEventERKNS_8protocol14ClipboardEventE
+}
+{
+ bug_431213
+ Memcheck:Leak
+ fun:_Znw*
+ fun:_ZN3gin22CreateFunctionTemplateIFSsPN4mojo2js13HandleWrapperEEEEN2v85LocalINS6_16FunctionTemplateEEEPNS6_7IsolateEN4base8CallbackIT_EEi
+ fun:_ZN3gin12_GLOBAL__N_114CallbackTraitsIMN4mojo2js13HandleWrapperEFSsvEvE14CreateTemplateEPN2v87IsolateES6_
+ fun:_ZN3gin21ObjectTemplateBuilder9SetMethodIMN4mojo2js13HandleWrapperEFSsvEEERS0_RKN4base16BasicStringPieceISsEERKT_
+ fun:_ZN4mojo2js13HandleWrapper24GetObjectTemplateBuilderEPN2v87IsolateE
+}
diff --git a/tools/valgrind/memcheck/suppressions_mac.txt b/tools/valgrind/memcheck/suppressions_mac.txt
index fe8f8a1..154e4e9 100644
--- a/tools/valgrind/memcheck/suppressions_mac.txt
+++ b/tools/valgrind/memcheck/suppressions_mac.txt
@@ -194,19 +194,6 @@
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
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index c9ad475..6bcb02a 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -18,6 +18,7 @@
#include "cc/base/switches.h"
#include "cc/input/input_handler.h"
#include "cc/layers/layer.h"
+#include "cc/scheduler/begin_frame_source.h"
#include "cc/output/begin_frame_args.h"
#include "cc/output/context_provider.h"
#include "cc/surfaces/surface_id_allocator.h"
@@ -168,7 +169,8 @@
context_factory_->GetGpuMemoryBufferManager(),
settings,
task_runner_,
- compositor_thread_loop_);
+ compositor_thread_loop_,
+ nullptr);
} else {
host_ = cc::LayerTreeHost::CreateSingleThreaded(
this,
@@ -176,7 +178,8 @@
context_factory_->GetSharedBitmapManager(),
context_factory_->GetGpuMemoryBufferManager(),
settings,
- task_runner_);
+ task_runner_,
+ nullptr);
}
UMA_HISTOGRAM_TIMES("GPU.CreateBrowserCompositor",
base::TimeTicks::Now() - before_create);
diff --git a/ui/compositor/float_animation_curve_adapter.cc b/ui/compositor/float_animation_curve_adapter.cc
index 308fc1e..3b5e155 100644
--- a/ui/compositor/float_animation_curve_adapter.cc
+++ b/ui/compositor/float_animation_curve_adapter.cc
@@ -17,8 +17,8 @@
duration_(duration) {
}
-double FloatAnimationCurveAdapter::Duration() const {
- return duration_.InSecondsF();
+base::TimeDelta FloatAnimationCurveAdapter::Duration() const {
+ return duration_;
}
scoped_ptr<cc::AnimationCurve> FloatAnimationCurveAdapter::Clone() const {
diff --git a/ui/compositor/float_animation_curve_adapter.h b/ui/compositor/float_animation_curve_adapter.h
index 1c7b8b3..88d5870 100644
--- a/ui/compositor/float_animation_curve_adapter.h
+++ b/ui/compositor/float_animation_curve_adapter.h
@@ -21,7 +21,7 @@
~FloatAnimationCurveAdapter() override {}
// FloatAnimationCurve implementation.
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<cc::AnimationCurve> Clone() const override;
float GetValue(double t) const override;
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index abf7e02..ea30852 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -9,6 +9,7 @@
#include "base/command_line.h"
#include "base/debug/trace_event.h"
#include "base/json/json_writer.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "cc/base/scoped_ptr_algorithm.h"
@@ -578,7 +579,7 @@
scoped_refptr<cc::SurfaceLayer> new_layer =
cc::SurfaceLayer::Create(satisfy_callback, require_callback);
- new_layer->SetSurfaceId(id);
+ new_layer->SetSurfaceId(id, 1.f, frame_size_in_dip);
SwitchToLayer(new_layer);
surface_layer_ = new_layer;
diff --git a/ui/compositor/transform_animation_curve_adapter.cc b/ui/compositor/transform_animation_curve_adapter.cc
index fa73140..2c11488 100644
--- a/ui/compositor/transform_animation_curve_adapter.cc
+++ b/ui/compositor/transform_animation_curve_adapter.cc
@@ -22,8 +22,8 @@
TransformAnimationCurveAdapter::~TransformAnimationCurveAdapter() {
}
-double TransformAnimationCurveAdapter::Duration() const {
- return duration_.InSecondsF();
+base::TimeDelta TransformAnimationCurveAdapter::Duration() const {
+ return duration_;
}
scoped_ptr<cc::AnimationCurve> TransformAnimationCurveAdapter::Clone() const {
@@ -86,8 +86,8 @@
InverseTransformCurveAdapter::~InverseTransformCurveAdapter() {
}
-double InverseTransformCurveAdapter::Duration() const {
- return duration_.InSeconds();
+base::TimeDelta InverseTransformCurveAdapter::Duration() const {
+ return duration_;
}
scoped_ptr<cc::AnimationCurve> InverseTransformCurveAdapter::Clone() const {
diff --git a/ui/compositor/transform_animation_curve_adapter.h b/ui/compositor/transform_animation_curve_adapter.h
index 7aa318e..c08024d 100644
--- a/ui/compositor/transform_animation_curve_adapter.h
+++ b/ui/compositor/transform_animation_curve_adapter.h
@@ -25,7 +25,7 @@
~TransformAnimationCurveAdapter() override;
// TransformAnimationCurve implementation.
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
gfx::Transform GetValue(double t) const override;
bool AnimatedBoundsForBox(const gfx::BoxF& box,
@@ -55,7 +55,7 @@
~InverseTransformCurveAdapter() override;
- double Duration() const override;
+ base::TimeDelta Duration() const override;
scoped_ptr<AnimationCurve> Clone() const override;
gfx::Transform GetValue(double t) const override;
bool AnimatedBoundsForBox(const gfx::BoxF& box,
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 641f51d..6968f2c 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -204,6 +204,8 @@
sources += [
"gl_context_cgl.cc",
"gl_context_cgl.h",
+ "gl_fence_apple.cc",
+ "gl_fence_apple.h",
"gl_image_io_surface.cc",
"gl_image_io_surface.h",
"scoped_cgl.cc",
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 7670ec8..0156806 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -67,6 +67,23 @@
'names': ['glBindTexture'],
'arguments': 'GLenum target, GLuint texture', },
{ 'return_type': 'void',
+ 'known_as': 'glBindVertexArrayOES',
+ 'versions': [{ 'name': 'glBindVertexArray',
+ 'gl_versions': ['gl3', 'gl4', 'es3'] },
+ { 'name': 'glBindVertexArray',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glBindVertexArrayOES' },
+ { 'name': 'glBindVertexArrayAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLuint array' },
+{ 'return_type': 'void',
+ 'known_as': 'glBlendBarrierKHR',
+ 'versions': [{ 'name': 'glBlendBarrierNV',
+ 'extensions': ['GL_NV_blend_equation_advanced'] },
+ { 'name': 'glBlendBarrierKHR',
+ 'extensions': ['GL_KHR_blend_equation_advanced'] }],
+ 'arguments': 'void' },
+{ 'return_type': 'void',
'names': ['glBlendColor'],
'arguments': 'GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha', },
{ 'return_type': 'void',
@@ -88,12 +105,12 @@
'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
'GLbitfield mask, GLenum filter', },
{ 'return_type': 'void',
- 'names': ['glBlitFramebufferEXT', 'glBlitFramebuffer'],
+ 'names': ['glBlitFramebufferANGLE', 'glBlitFramebuffer'],
'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
'GLbitfield mask, GLenum filter', },
{ 'return_type': 'void',
- 'names': ['glBlitFramebufferANGLE', 'glBlitFramebuffer'],
+ 'names': ['glBlitFramebufferEXT', 'glBlitFramebuffer'],
'arguments': 'GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, '
'GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, '
'GLbitfield mask, GLenum filter', },
@@ -127,6 +144,9 @@
{ 'return_type': 'void',
'names': ['glClearStencil'],
'arguments': 'GLint s', },
+{ 'return_type': 'GLenum',
+ 'names': ['glClientWaitSync'],
+ 'arguments': 'GLsync sync, GLbitfield flags, GLuint64 timeout', },
{ 'return_type': 'void',
'names': ['glColorMask'],
'arguments':
@@ -168,6 +188,14 @@
'names': ['glDeleteBuffersARB', 'glDeleteBuffers'],
'arguments': 'GLsizei n, const GLuint* buffers', },
{ 'return_type': 'void',
+ 'known_as': 'glDeleteFencesAPPLE',
+ 'versions': [{ 'name': 'glDeleteFencesAPPLE',
+ 'extensions': ['GL_APPLE_fence'] }],
+ 'arguments': 'GLsizei n, const GLuint* fences', },
+{ 'return_type': 'void',
+ 'names': ['glDeleteFencesNV'],
+ 'arguments': 'GLsizei n, const GLuint* fences', },
+{ 'return_type': 'void',
'names': ['glDeleteFramebuffersEXT', 'glDeleteFramebuffers'],
'arguments': 'GLsizei n, const GLuint* framebuffers', },
{ 'return_type': 'void',
@@ -186,9 +214,22 @@
'names': ['glDeleteShader'],
'arguments': 'GLuint shader', },
{ 'return_type': 'void',
+ 'names': ['glDeleteSync'],
+ 'arguments': 'GLsync sync', },
+{ 'return_type': 'void',
'names': ['glDeleteTextures'],
'arguments': 'GLsizei n, const GLuint* textures', },
{ 'return_type': 'void',
+ 'known_as': 'glDeleteVertexArraysOES',
+ 'versions': [{ 'name': 'glDeleteVertexArrays',
+ 'gl_versions': ['gl3', 'gl4', 'es3'] },
+ { 'name': 'glDeleteVertexArrays',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glDeleteVertexArraysOES' },
+ { 'name': 'glDeleteVertexArraysAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLsizei n, const GLuint* arrays' },
+{ 'return_type': 'void',
'names': ['glDepthFunc'],
'arguments': 'GLenum func', },
{ 'return_type': 'void',
@@ -210,9 +251,23 @@
'names': ['glDisableVertexAttribArray'],
'arguments': 'GLuint index', },
{ 'return_type': 'void',
+ 'known_as': 'glDiscardFramebufferEXT',
+ 'versions': [{ 'name': 'glInvalidateFramebuffer',
+ 'gl_versions': ['es3'],
+ 'extensions': [] },
+ { 'name': 'glDiscardFramebufferEXT',
+ 'gl_versions': ['es1', 'es2'] }],
+ 'arguments': 'GLenum target, GLsizei numAttachments, '
+ 'const GLenum* attachments' },
+{ 'return_type': 'void',
'names': ['glDrawArrays'],
'arguments': 'GLenum mode, GLint first, GLsizei count', },
{ 'return_type': 'void',
+ 'known_as': 'glDrawArraysInstancedANGLE',
+ 'names': ['glDrawArraysInstancedARB', 'glDrawArraysInstancedANGLE',
+ 'glDrawArraysInstanced'],
+ 'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', },
+{ 'return_type': 'void',
'names': ['glDrawBuffer'],
'arguments': 'GLenum mode', },
{ 'return_type': 'void',
@@ -223,12 +278,19 @@
'arguments':
'GLenum mode, GLsizei count, GLenum type, const void* indices', },
{ 'return_type': 'void',
- 'names': ['glEGLImageTargetTexture2DOES'],
- 'arguments': 'GLenum target, GLeglImageOES image', },
+ 'known_as': 'glDrawElementsInstancedANGLE',
+ 'names': ['glDrawElementsInstancedARB', 'glDrawElementsInstancedANGLE',
+ 'glDrawElementsInstanced'],
+ 'arguments':
+ 'GLenum mode, GLsizei count, GLenum type, const void* indices, '
+ 'GLsizei primcount', },
{ 'return_type': 'void',
'names': ['glEGLImageTargetRenderbufferStorageOES'],
'arguments': 'GLenum target, GLeglImageOES image', },
{ 'return_type': 'void',
+ 'names': ['glEGLImageTargetTexture2DOES'],
+ 'arguments': 'GLenum target, GLeglImageOES image', },
+{ 'return_type': 'void',
'names': ['glEnable'],
'arguments': 'GLenum cap', },
{ 'return_type': 'void',
@@ -240,15 +302,29 @@
{ 'return_type': 'void',
'names': ['glEndQueryARB', 'glEndQueryEXT'],
'arguments': 'GLenum target', },
+{ 'return_type': 'GLsync',
+ 'names': ['glFenceSync'],
+ 'arguments': 'GLenum condition, GLbitfield flags', },
{ 'return_type': 'void',
'names': ['glFinish'],
'arguments': 'void', },
{ 'return_type': 'void',
+ 'known_as': 'glFinishFenceAPPLE',
+ 'versions': [{ 'name': 'glFinishFenceAPPLE',
+ 'extensions': ['GL_APPLE_fence'] }],
+ 'arguments': 'GLuint fence', },
+{ 'return_type': 'void',
+ 'names': ['glFinishFenceNV'],
+ 'arguments': 'GLuint fence', },
+{ 'return_type': 'void',
'names': ['glFlush'],
'arguments': 'void', },
{ 'return_type': 'void',
+ 'names': ['glFlushMappedBufferRange'],
+ 'arguments': 'GLenum target, GLintptr offset, GLsizeiptr length', },
+{ 'return_type': 'void',
'names': ['glFramebufferRenderbufferEXT', 'glFramebufferRenderbuffer'],
- 'arguments': \
+ 'arguments':
'GLenum target, GLenum attachment, GLenum renderbuffertarget, '
'GLuint renderbuffer', },
{ 'return_type': 'void',
@@ -273,24 +349,42 @@
'names': ['glGenBuffersARB', 'glGenBuffers'],
'arguments': 'GLsizei n, GLuint* buffers', },
{ 'return_type': 'void',
+ 'names': ['glGenerateMipmapEXT', 'glGenerateMipmap'],
+ 'arguments': 'GLenum target', },
+{ 'return_type': 'void',
+ 'known_as': 'glGenFencesAPPLE',
+ 'versions': [{ 'name': 'glGenFencesAPPLE',
+ 'extensions': ['GL_APPLE_fence'] }],
+ 'arguments': 'GLsizei n, GLuint* fences', },
+{ 'return_type': 'void',
+ 'names': ['glGenFencesNV'],
+ 'arguments': 'GLsizei n, GLuint* fences', },
+{ 'return_type': 'void',
+ 'names': ['glGenFramebuffersEXT', 'glGenFramebuffers'],
+ 'arguments': 'GLsizei n, GLuint* framebuffers', },
+{ 'return_type': 'void',
'names': ['glGenQueries'],
'arguments': 'GLsizei n, GLuint* ids', },
{ 'return_type': 'void',
'names': ['glGenQueriesARB', 'glGenQueriesEXT'],
'arguments': 'GLsizei n, GLuint* ids', },
{ 'return_type': 'void',
- 'names': ['glGenerateMipmapEXT', 'glGenerateMipmap'],
- 'arguments': 'GLenum target', },
-{ 'return_type': 'void',
- 'names': ['glGenFramebuffersEXT', 'glGenFramebuffers'],
- 'arguments': 'GLsizei n, GLuint* framebuffers', },
-{ 'return_type': 'void',
'names': ['glGenRenderbuffersEXT', 'glGenRenderbuffers'],
'arguments': 'GLsizei n, GLuint* renderbuffers', },
{ 'return_type': 'void',
'names': ['glGenTextures'],
'arguments': 'GLsizei n, GLuint* textures', },
{ 'return_type': 'void',
+ 'known_as': 'glGenVertexArraysOES',
+ 'versions': [{ 'name': 'glGenVertexArrays',
+ 'gl_versions': ['gl3', 'gl4', 'es3'] },
+ { 'name': 'glGenVertexArrays',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glGenVertexArraysOES' },
+ { 'name': 'glGenVertexArraysAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLsizei n, GLuint* arrays', },
+{ 'return_type': 'void',
'names': ['glGetActiveAttrib'],
'arguments':
'GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, '
@@ -320,6 +414,9 @@
GL_SERVICE_LOG("GL_RESULT: " << GLES2Util::GetStringError(result));
""", },
{ 'return_type': 'void',
+ 'names': ['glGetFenceivNV'],
+ 'arguments': 'GLuint fence, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
'names': ['glGetFloatv'],
'arguments': 'GLenum pname, GLfloat* params', },
{ 'return_type': 'void',
@@ -334,12 +431,12 @@
'glGetGraphicsResetStatus'],
'arguments': 'void', },
{ 'return_type': 'void',
- 'names': ['glGetIntegerv'],
- 'arguments': 'GLenum pname, GLint* params', },
-{ 'return_type': 'void',
'names': ['glGetInteger64v'],
'arguments': 'GLenum pname, GLint64* params', },
{ 'return_type': 'void',
+ 'names': ['glGetIntegerv'],
+ 'arguments': 'GLenum pname, GLint* params', },
+{ 'return_type': 'void',
'known_as': 'glGetProgramBinary',
'versions': [{ 'name': 'glGetProgramBinaryOES' },
{ 'name': 'glGetProgramBinary',
@@ -348,13 +445,13 @@
'arguments': 'GLuint program, GLsizei bufSize, GLsizei* length, '
'GLenum* binaryFormat, GLvoid* binary' },
{ 'return_type': 'void',
- 'names': ['glGetProgramiv'],
- 'arguments': 'GLuint program, GLenum pname, GLint* params', },
-{ 'return_type': 'void',
'names': ['glGetProgramInfoLog'],
'arguments':
'GLuint program, GLsizei bufsize, GLsizei* length, char* infolog', },
{ 'return_type': 'void',
+ 'names': ['glGetProgramiv'],
+ 'arguments': 'GLuint program, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
'names': ['glGetQueryiv'],
'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'void',
@@ -364,6 +461,10 @@
'names': ['glGetQueryObjecti64v'],
'arguments': 'GLuint id, GLenum pname, GLint64* params', },
{ 'return_type': 'void',
+ 'names': ['glGetQueryObjectiv', 'glGetQueryObjectivARB',
+ 'glGetQueryObjectivEXT'],
+ 'arguments': 'GLuint id, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
'names': ['glGetQueryObjectui64v', 'glGetQueryObjectui64vEXT'],
'arguments': 'GLuint id, GLenum pname, GLuint64* params', },
{ 'return_type': 'void',
@@ -373,20 +474,16 @@
'names': ['glGetQueryObjectuivARB', 'glGetQueryObjectuivEXT'],
'arguments': 'GLuint id, GLenum pname, GLuint* params', },
{ 'return_type': 'void',
- 'names': ['glGetQueryObjectiv', 'glGetQueryObjectivARB',
- 'glGetQueryObjectivEXT'],
- 'arguments': 'GLuint id, GLenum pname, GLint* params', },
-{ 'return_type': 'void',
'names': ['glGetRenderbufferParameterivEXT', 'glGetRenderbufferParameteriv'],
'arguments': 'GLenum target, GLenum pname, GLint* params', },
{ 'return_type': 'void',
- 'names': ['glGetShaderiv'],
- 'arguments': 'GLuint shader, GLenum pname, GLint* params', },
-{ 'return_type': 'void',
'names': ['glGetShaderInfoLog'],
'arguments':
'GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog', },
{ 'return_type': 'void',
+ 'names': ['glGetShaderiv'],
+ 'arguments': 'GLuint shader, GLenum pname, GLint* params', },
+{ 'return_type': 'void',
'names': ['glGetShaderPrecisionFormat'],
'arguments': 'GLenum shadertype, GLenum precisiontype, '
'GLint* range, GLint* precision', },
@@ -398,6 +495,11 @@
'names': ['glGetString'],
'arguments': 'GLenum name', },
{ 'return_type': 'void',
+ 'names': ['glGetSynciv'],
+ 'arguments':
+ 'GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length,'
+ 'GLint* values', },
+{ 'return_type': 'void',
'names': ['glGetTexLevelParameterfv'],
'arguments': 'GLenum target, GLint level, GLenum pname, GLfloat* params', },
{ 'return_type': 'void',
@@ -444,6 +546,14 @@
'names': ['glIsEnabled'],
'arguments': 'GLenum cap', },
{ 'return_type': 'GLboolean',
+ 'known_as': 'glIsFenceAPPLE',
+ 'versions': [{ 'name': 'glIsFenceAPPLE',
+ 'extensions': ['GL_APPLE_fence'] }],
+ 'arguments': 'GLuint fence', },
+{ 'return_type': 'GLboolean',
+ 'names': ['glIsFenceNV'],
+ 'arguments': 'GLuint fence', },
+{ 'return_type': 'GLboolean',
'names': ['glIsFramebufferEXT', 'glIsFramebuffer'],
'arguments': 'GLuint framebuffer', },
{ 'return_type': 'GLboolean',
@@ -459,8 +569,21 @@
'names': ['glIsShader'],
'arguments': 'GLuint shader', },
{ 'return_type': 'GLboolean',
+ 'names': ['glIsSync'],
+ 'arguments': 'GLsync sync', },
+{ 'return_type': 'GLboolean',
'names': ['glIsTexture'],
'arguments': 'GLuint texture', },
+{ 'return_type': 'GLboolean',
+ 'known_as': 'glIsVertexArrayOES',
+ 'versions': [{ 'name': 'glIsVertexArray',
+ 'gl_versions': ['gl3', 'gl4'] },
+ { 'name': 'glIsVertexArray',
+ 'extensions': ['GL_ARB_vertex_array_object'] },
+ { 'name': 'glIsVertexArrayOES' },
+ { 'name': 'glIsVertexArrayAPPLE',
+ 'extensions': ['GL_APPLE_vertex_array_object'] }],
+ 'arguments': 'GLuint array' },
{ 'return_type': 'void',
'names': ['glLineWidth'],
'arguments': 'GLfloat width', },
@@ -476,8 +599,23 @@
'arguments':
'GLenum target, GLintptr offset, GLsizeiptr length, GLenum access', },
{ 'return_type': 'void',
- 'names': ['glFlushMappedBufferRange'],
- 'arguments': 'GLenum target, GLintptr offset, GLsizeiptr length', },
+ 'known_as': 'glMatrixLoadfEXT',
+ 'versions': [{ 'name': 'glMatrixLoadfEXT',
+ 'gl_versions': ['gl4'],
+ 'extensions': ['GL_EXT_direct_state_access'] },
+ { 'name': 'glMatrixLoadfEXT',
+ 'gl_versions': ['es3'],
+ 'extensions': ['GL_NV_path_rendering'] }],
+ 'arguments': 'GLenum matrixMode, const GLfloat* m' },
+{ 'return_type': 'void',
+ 'known_as': 'glMatrixLoadIdentityEXT',
+ 'versions': [{ 'name': 'glMatrixLoadIdentityEXT',
+ 'gl_versions': ['gl4'],
+ 'extensions': ['GL_EXT_direct_state_access'] },
+ { 'name': 'glMatrixLoadIdentityEXT',
+ 'gl_versions': ['es3'],
+ 'extensions': ['GL_NV_path_rendering'] }],
+ 'arguments': 'GLenum matrixMode' },
{ 'return_type': 'void',
'names': ['glPixelStorei'],
'arguments': 'GLenum pname, GLint param', },
@@ -533,9 +671,18 @@
# function name appearing multiple times.
# This is the ES3 function, which requires explicit resolve:
{ 'return_type': 'void',
+ 'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'],
+ 'arguments':
+ 'GLenum target, GLenum internalformat, GLsizei width, GLsizei height', },
+{ 'return_type': 'void',
'names': ['glRenderbufferStorageMultisample'],
'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
'GLsizei width, GLsizei height', },
+{ 'return_type': 'void',
+ 'names': ['glRenderbufferStorageMultisampleANGLE',
+ 'glRenderbufferStorageMultisample'],
+ 'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
+ 'GLsizei width, GLsizei height', },
# In desktop GL, EXT and core versions both have an explicit resolve step,
# though desktop core GL implicitly resolves when drawing to a window.
# TODO(oetuaho@nvidia.com): Right now this function also doubles as ES2 EXT
@@ -547,25 +694,24 @@
'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
'GLsizei width, GLsizei height', },
{ 'return_type': 'void',
- 'names': ['glRenderbufferStorageMultisampleANGLE',
- 'glRenderbufferStorageMultisample'],
- 'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
- 'GLsizei width, GLsizei height', },
-{ 'return_type': 'void',
'names': ['glRenderbufferStorageMultisampleIMG'],
'arguments': 'GLenum target, GLsizei samples, GLenum internalformat, '
'GLsizei width, GLsizei height', },
{ 'return_type': 'void',
- 'names': ['glRenderbufferStorageEXT', 'glRenderbufferStorage'],
- 'arguments':
- 'GLenum target, GLenum internalformat, GLsizei width, GLsizei height', },
-{ 'return_type': 'void',
'names': ['glSampleCoverage'],
'arguments': 'GLclampf value, GLboolean invert', },
{ 'return_type': 'void',
'names': ['glScissor'],
'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
{ 'return_type': 'void',
+ 'known_as': 'glSetFenceAPPLE',
+ 'versions': [{ 'name': 'glSetFenceAPPLE',
+ 'extensions': ['GL_APPLE_fence'] }],
+ 'arguments': 'GLuint fence', },
+{ 'return_type': 'void',
+ 'names': ['glSetFenceNV'],
+ 'arguments': 'GLuint fence, GLenum condition', },
+{ 'return_type': 'void',
'names': ['glShaderBinary'],
'arguments': 'GLsizei n, const GLuint* shaders, GLenum binaryformat, '
'const void* binary, GLsizei length', },
@@ -607,6 +753,14 @@
{ 'return_type': 'void',
'names': ['glStencilOpSeparate'],
'arguments': 'GLenum face, GLenum fail, GLenum zfail, GLenum zpass', },
+{ 'return_type': 'GLboolean',
+ 'known_as': 'glTestFenceAPPLE',
+ 'versions': [{ 'name': 'glTestFenceAPPLE',
+ 'extensions': ['GL_APPLE_fence'] }],
+ 'arguments': 'GLuint fence', },
+{ 'return_type': 'GLboolean',
+ 'names': ['glTestFenceNV'],
+ 'arguments': 'GLuint fence', },
{ 'return_type': 'void',
'names': ['glTexImage2D'],
'arguments':
@@ -736,150 +890,28 @@
'names': ['glVertexAttrib4fv'],
'arguments': 'GLuint indx, const GLfloat* values', },
{ 'return_type': 'void',
- 'names': ['glVertexAttribPointer'],
- 'arguments': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, '
- 'GLsizei stride, const void* ptr', },
-{ 'return_type': 'void',
- 'names': ['glViewport'],
- 'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
-{ 'return_type': 'void',
- 'names': ['glGenFencesNV'],
- 'arguments': 'GLsizei n, GLuint* fences', },
-{ 'return_type': 'void',
- 'names': ['glDeleteFencesNV'],
- 'arguments': 'GLsizei n, const GLuint* fences', },
-{ 'return_type': 'void',
- 'names': ['glSetFenceNV'],
- 'arguments': 'GLuint fence, GLenum condition', },
-{ 'return_type': 'GLboolean',
- 'names': ['glTestFenceNV'],
- 'arguments': 'GLuint fence', },
-{ 'return_type': 'void',
- 'names': ['glFinishFenceNV'],
- 'arguments': 'GLuint fence', },
-{ 'return_type': 'GLboolean',
- 'names': ['glIsFenceNV'],
- 'arguments': 'GLuint fence', },
-{ 'return_type': 'void',
- 'names': ['glGetFenceivNV'],
- 'arguments': 'GLuint fence, GLenum pname, GLint* params', },
-{ 'return_type': 'GLsync',
- 'names': ['glFenceSync'],
- 'arguments': 'GLenum condition, GLbitfield flags', },
-{ 'return_type': 'GLboolean',
- 'names': ['glIsSync'],
- 'arguments': 'GLsync sync', },
-{ 'return_type': 'void',
- 'names': ['glDeleteSync'],
- 'arguments': 'GLsync sync', },
-{ 'return_type': 'void',
- 'names': ['glGetSynciv'],
- 'arguments':
- 'GLsync sync, GLenum pname, GLsizei bufSize, GLsizei* length,'
- 'GLint* values', },
-{ 'return_type': 'GLenum',
- 'names': ['glClientWaitSync'],
- 'arguments':
- 'GLsync sync, GLbitfield flags, GLuint64 timeout', },
-{ 'return_type': 'GLenum',
- 'names': ['glWaitSync'],
- 'arguments':
- 'GLsync sync, GLbitfield flags, GLuint64 timeout', },
-{ 'return_type': 'void',
- 'known_as': 'glDrawArraysInstancedANGLE',
- 'names': ['glDrawArraysInstancedARB', 'glDrawArraysInstancedANGLE',
- 'glDrawArraysInstanced'],
- 'arguments': 'GLenum mode, GLint first, GLsizei count, GLsizei primcount', },
-{ 'return_type': 'void',
- 'known_as': 'glDrawElementsInstancedANGLE',
- 'names': ['glDrawElementsInstancedARB', 'glDrawElementsInstancedANGLE',
- 'glDrawElementsInstanced'],
- 'arguments':
- 'GLenum mode, GLsizei count, GLenum type, const void* indices, '
- 'GLsizei primcount', },
-{ 'return_type': 'void',
'known_as': 'glVertexAttribDivisorANGLE',
'names': ['glVertexAttribDivisorARB', 'glVertexAttribDivisorANGLE',
'glVertexAttribDivisor'],
'arguments':
'GLuint index, GLuint divisor', },
{ 'return_type': 'void',
- 'known_as': 'glGenVertexArraysOES',
- 'versions': [{ 'name': 'glGenVertexArrays',
- 'gl_versions': ['gl3', 'gl4', 'es3'] },
- { 'name': 'glGenVertexArrays',
- 'extensions': ['GL_ARB_vertex_array_object'] },
- { 'name': 'glGenVertexArraysOES' },
- { 'name': 'glGenVertexArraysAPPLE',
- 'extensions': ['GL_APPLE_vertex_array_object'] }],
- 'arguments': 'GLsizei n, GLuint* arrays', },
+ 'names': ['glVertexAttribPointer'],
+ 'arguments': 'GLuint indx, GLint size, GLenum type, GLboolean normalized, '
+ 'GLsizei stride, const void* ptr', },
{ 'return_type': 'void',
- 'known_as': 'glDeleteVertexArraysOES',
- 'versions': [{ 'name': 'glDeleteVertexArrays',
- 'gl_versions': ['gl3', 'gl4', 'es3'] },
- { 'name': 'glDeleteVertexArrays',
- 'extensions': ['GL_ARB_vertex_array_object'] },
- { 'name': 'glDeleteVertexArraysOES' },
- { 'name': 'glDeleteVertexArraysAPPLE',
- 'extensions': ['GL_APPLE_vertex_array_object'] }],
- 'arguments': 'GLsizei n, const GLuint* arrays' },
-{ 'return_type': 'void',
- 'known_as': 'glBindVertexArrayOES',
- 'versions': [{ 'name': 'glBindVertexArray',
- 'gl_versions': ['gl3', 'gl4', 'es3'] },
- { 'name': 'glBindVertexArray',
- 'extensions': ['GL_ARB_vertex_array_object'] },
- { 'name': 'glBindVertexArrayOES' },
- { 'name': 'glBindVertexArrayAPPLE',
- 'extensions': ['GL_APPLE_vertex_array_object'] }],
- 'arguments': 'GLuint array' },
-{ 'return_type': 'GLboolean',
- 'known_as': 'glIsVertexArrayOES',
- 'versions': [{ 'name': 'glIsVertexArray',
- 'gl_versions': ['gl3', 'gl4'] },
- { 'name': 'glIsVertexArray',
- 'extensions': ['GL_ARB_vertex_array_object'] },
- { 'name': 'glIsVertexArrayOES' },
- { 'name': 'glIsVertexArrayAPPLE',
- 'extensions': ['GL_APPLE_vertex_array_object'] }],
- 'arguments': 'GLuint array' },
-{ 'return_type': 'void',
- 'known_as': 'glDiscardFramebufferEXT',
- 'versions': [{ 'name': 'glInvalidateFramebuffer',
- 'gl_versions': ['es3'],
- 'extensions': [] },
- { 'name': 'glDiscardFramebufferEXT',
- 'gl_versions': ['es1', 'es2'] }],
- 'arguments': 'GLenum target, GLsizei numAttachments, '
- 'const GLenum* attachments' },
-{ 'return_type': 'void',
- 'known_as': 'glMatrixLoadfEXT',
- 'versions': [{ 'name': 'glMatrixLoadfEXT',
- 'gl_versions': ['gl4'],
- 'extensions': ['GL_EXT_direct_state_access'] },
- { 'name': 'glMatrixLoadfEXT',
- 'gl_versions': ['es3'],
- 'extensions': ['GL_NV_path_rendering'] }],
- 'arguments': 'GLenum matrixMode, const GLfloat* m' },
-{ 'return_type': 'void',
- 'known_as': 'glMatrixLoadIdentityEXT',
- 'versions': [{ 'name': 'glMatrixLoadIdentityEXT',
- 'gl_versions': ['gl4'],
- 'extensions': ['GL_EXT_direct_state_access'] },
- { 'name': 'glMatrixLoadIdentityEXT',
- 'gl_versions': ['es3'],
- 'extensions': ['GL_NV_path_rendering'] }],
- 'arguments': 'GLenum matrixMode' },
- { 'return_type': 'void',
- 'known_as': 'glBlendBarrierKHR',
- 'versions': [{ 'name': 'glBlendBarrierNV',
- 'extensions': ['GL_NV_blend_equation_advanced'] },
- { 'name': 'glBlendBarrierKHR',
- 'extensions': ['GL_KHR_blend_equation_advanced'] }],
- 'arguments': 'void' },
+ 'names': ['glViewport'],
+ 'arguments': 'GLint x, GLint y, GLsizei width, GLsizei height', },
+{ 'return_type': 'GLenum',
+ 'names': ['glWaitSync'],
+ 'arguments':
+ 'GLsync sync, GLbitfield flags, GLuint64 timeout', },
]
OSMESA_FUNCTIONS = [
+{ 'return_type': 'void',
+ 'names': ['OSMesaColorClamp'],
+ 'arguments': 'GLboolean enable', },
{ 'return_type': 'OSMesaContext',
'names': ['OSMesaCreateContext'],
'arguments': 'GLenum format, OSMesaContext sharelist', },
@@ -892,69 +924,56 @@
'names': ['OSMesaDestroyContext'],
'arguments': 'OSMesaContext ctx', },
{ 'return_type': 'GLboolean',
- 'names': ['OSMesaMakeCurrent'],
- 'arguments': 'OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, '
- 'GLsizei height', },
+ 'names': ['OSMesaGetColorBuffer'],
+ 'arguments': 'OSMesaContext c, GLint* width, GLint* height, GLint* format, '
+ 'void** buffer', },
{ 'return_type': 'OSMesaContext',
'names': ['OSMesaGetCurrentContext'],
'arguments': 'void', },
-{ 'return_type': 'void',
- 'names': ['OSMesaPixelStore'],
- 'arguments': 'GLint pname, GLint value', },
-{ 'return_type': 'void',
- 'names': ['OSMesaGetIntegerv'],
- 'arguments': 'GLint pname, GLint* value', },
{ 'return_type': 'GLboolean',
'names': ['OSMesaGetDepthBuffer'],
'arguments':
'OSMesaContext c, GLint* width, GLint* height, GLint* bytesPerValue, '
'void** buffer', },
-{ 'return_type': 'GLboolean',
- 'names': ['OSMesaGetColorBuffer'],
- 'arguments': 'OSMesaContext c, GLint* width, GLint* height, GLint* format, '
- 'void** buffer', },
+{ 'return_type': 'void',
+ 'names': ['OSMesaGetIntegerv'],
+ 'arguments': 'GLint pname, GLint* value', },
{ 'return_type': 'OSMESAproc',
'names': ['OSMesaGetProcAddress'],
'arguments': 'const char* funcName', },
+{ 'return_type': 'GLboolean',
+ 'names': ['OSMesaMakeCurrent'],
+ 'arguments': 'OSMesaContext ctx, void* buffer, GLenum type, GLsizei width, '
+ 'GLsizei height', },
{ 'return_type': 'void',
- 'names': ['OSMesaColorClamp'],
- 'arguments': 'GLboolean enable', },
+ 'names': ['OSMesaPixelStore'],
+ 'arguments': 'GLint pname, GLint value', },
]
EGL_FUNCTIONS = [
-{ 'return_type': 'EGLint',
- 'names': ['eglGetError'],
- 'arguments': 'void', },
-{ 'return_type': 'EGLDisplay',
- 'names': ['eglGetDisplay'],
- 'arguments': 'EGLNativeDisplayType display_id', },
-{ 'return_type': 'EGLDisplay',
- 'known_as': 'eglGetPlatformDisplayEXT',
- 'versions': [{ 'name': 'eglGetPlatformDisplayEXT',
- 'extensions': ['EGL_ANGLE_platform_angle'] }],
- 'arguments': 'EGLenum platform, void* native_display, '
- 'const EGLint* attrib_list', },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglInitialize'],
- 'arguments': 'EGLDisplay dpy, EGLint* major, EGLint* minor', },
+ 'names': ['eglBindAPI'],
+ 'arguments': 'EGLenum api', },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglTerminate'],
- 'arguments': 'EGLDisplay dpy', },
-{ 'return_type': 'const char*',
- 'names': ['eglQueryString'],
- 'arguments': 'EGLDisplay dpy, EGLint name', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglGetConfigs'],
- 'arguments': 'EGLDisplay dpy, EGLConfig* configs, EGLint config_size, '
- 'EGLint* num_config', },
+ 'names': ['eglBindTexImage'],
+ 'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
{ 'return_type': 'EGLBoolean',
'names': ['eglChooseConfig'],
'arguments': 'EGLDisplay dpy, const EGLint* attrib_list, EGLConfig* configs, '
'EGLint config_size, EGLint* num_config', },
+{ 'return_type': 'EGLint',
+ 'versions': [{ 'name': 'eglClientWaitSyncKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
+ 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
+ 'EGLTimeKHR timeout' },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglGetConfigAttrib'],
+ 'names': ['eglCopyBuffers'],
'arguments':
- 'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', },
+ 'EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target', },
+{ 'return_type': 'EGLContext',
+ 'names': ['eglCreateContext'],
+ 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLContext share_context, '
+ 'const EGLint* attrib_list', },
{ 'return_type': 'EGLImageKHR',
'versions': [{ 'name': 'eglCreateImageKHR',
'extensions':
@@ -962,14 +981,11 @@
'arguments':
'EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, '
'const EGLint* attrib_list' },
-{ 'return_type': 'EGLBoolean',
- 'versions': [{ 'name' : 'eglDestroyImageKHR',
- 'extensions': ['EGL_KHR_image_base'] }],
- 'arguments': 'EGLDisplay dpy, EGLImageKHR image' },
{ 'return_type': 'EGLSurface',
- 'names': ['eglCreateWindowSurface'],
- 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, '
- 'const EGLint* attrib_list', },
+ 'names': ['eglCreatePbufferFromClientBuffer'],
+ 'arguments':
+ 'EGLDisplay dpy, EGLenum buftype, void* buffer, EGLConfig config, '
+ 'const EGLint* attrib_list', },
{ 'return_type': 'EGLSurface',
'names': ['eglCreatePbufferSurface'],
'arguments': 'EGLDisplay dpy, EGLConfig config, const EGLint* attrib_list', },
@@ -977,144 +993,184 @@
'names': ['eglCreatePixmapSurface'],
'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, '
'const EGLint* attrib_list', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglDestroySurface'],
- 'arguments': 'EGLDisplay dpy, EGLSurface surface', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglQuerySurface'],
- 'arguments':
- 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglBindAPI'],
- 'arguments': 'EGLenum api', },
-{ 'return_type': 'EGLenum',
- 'names': ['eglQueryAPI'],
- 'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglWaitClient'],
- 'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglReleaseThread'],
- 'arguments': 'void', },
+{ 'return_type': 'EGLSyncKHR',
+ 'versions': [{ 'name': 'eglCreateSyncKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
+ 'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list' },
{ 'return_type': 'EGLSurface',
- 'names': ['eglCreatePbufferFromClientBuffer'],
- 'arguments':
- 'EGLDisplay dpy, EGLenum buftype, void* buffer, EGLConfig config, '
- 'const EGLint* attrib_list', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglSurfaceAttrib'],
- 'arguments':
- 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglBindTexImage'],
- 'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglReleaseTexImage'],
- 'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglSwapInterval'],
- 'arguments': 'EGLDisplay dpy, EGLint interval', },
-{ 'return_type': 'EGLContext',
- 'names': ['eglCreateContext'],
- 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLContext share_context, '
- 'const EGLint* attrib_list', },
+ 'names': ['eglCreateWindowSurface'],
+ 'arguments': 'EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, '
+ 'const EGLint* attrib_list', },
{ 'return_type': 'EGLBoolean',
'names': ['eglDestroyContext'],
'arguments': 'EGLDisplay dpy, EGLContext ctx', },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglMakeCurrent'],
+ 'versions': [{ 'name' : 'eglDestroyImageKHR',
+ 'extensions': ['EGL_KHR_image_base'] }],
+ 'arguments': 'EGLDisplay dpy, EGLImageKHR image' },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglDestroySurface'],
+ 'arguments': 'EGLDisplay dpy, EGLSurface surface', },
+{ 'return_type': 'EGLBoolean',
+ 'versions': [{ 'name': 'eglDestroySyncKHR',
+ 'extensions': ['EGL_KHR_fence_sync'] }],
+ 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync' },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglGetConfigAttrib'],
'arguments':
- 'EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx', },
+ 'EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint* value', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglGetConfigs'],
+ 'arguments': 'EGLDisplay dpy, EGLConfig* configs, EGLint config_size, '
+ 'EGLint* num_config', },
{ 'return_type': 'EGLContext',
'names': ['eglGetCurrentContext'],
'arguments': 'void', },
+{ 'return_type': 'EGLDisplay',
+ 'names': ['eglGetCurrentDisplay'],
+ 'arguments': 'void', },
{ 'return_type': 'EGLSurface',
'names': ['eglGetCurrentSurface'],
'arguments': 'EGLint readdraw', },
{ 'return_type': 'EGLDisplay',
- 'names': ['eglGetCurrentDisplay'],
+ 'names': ['eglGetDisplay'],
+ 'arguments': 'EGLNativeDisplayType display_id', },
+{ 'return_type': 'EGLint',
+ 'names': ['eglGetError'],
'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglQueryContext'],
- 'arguments':
- 'EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglWaitGL'],
- 'arguments': 'void', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglWaitNative'],
- 'arguments': 'EGLint engine', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglSwapBuffers'],
- 'arguments': 'EGLDisplay dpy, EGLSurface surface', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglCopyBuffers'],
- 'arguments':
- 'EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target', },
+{ 'return_type': 'EGLDisplay',
+ 'known_as': 'eglGetPlatformDisplayEXT',
+ 'versions': [{ 'name': 'eglGetPlatformDisplayEXT',
+ 'extensions': ['EGL_ANGLE_platform_angle'] }],
+ 'arguments': 'EGLenum platform, void* native_display, '
+ 'const EGLint* attrib_list', },
{ 'return_type': '__eglMustCastToProperFunctionPointerType',
'names': ['eglGetProcAddress'],
'arguments': 'const char* procname', },
{ 'return_type': 'EGLBoolean',
- 'names': ['eglPostSubBufferNV'],
- 'arguments': 'EGLDisplay dpy, EGLSurface surface, '
- 'EGLint x, EGLint y, EGLint width, EGLint height', },
-{ 'return_type': 'EGLBoolean',
- 'names': ['eglQuerySurfacePointerANGLE'],
- 'arguments':
- 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', },
-{ 'return_type': 'EGLSyncKHR',
- 'versions': [{ 'name': 'eglCreateSyncKHR',
- 'extensions': ['EGL_KHR_fence_sync'] }],
- 'arguments': 'EGLDisplay dpy, EGLenum type, const EGLint* attrib_list' },
-{ 'return_type': 'EGLint',
- 'versions': [{ 'name': 'eglClientWaitSyncKHR',
- 'extensions': ['EGL_KHR_fence_sync'] }],
- 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, '
- 'EGLTimeKHR timeout' },
-{ 'return_type': 'EGLBoolean',
'versions': [{ 'name': 'eglGetSyncAttribKHR',
'extensions': ['EGL_KHR_fence_sync'] }],
'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, '
'EGLint* value' },
{ 'return_type': 'EGLBoolean',
- 'versions': [{ 'name': 'eglDestroySyncKHR',
- 'extensions': ['EGL_KHR_fence_sync'] }],
- 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync' },
-{ 'return_type': 'EGLBoolean',
'names': ['eglGetSyncValuesCHROMIUM'],
'arguments':
'EGLDisplay dpy, EGLSurface surface, '
'EGLuint64CHROMIUM* ust, EGLuint64CHROMIUM* msc, '
'EGLuint64CHROMIUM* sbc', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglInitialize'],
+ 'arguments': 'EGLDisplay dpy, EGLint* major, EGLint* minor', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglMakeCurrent'],
+ 'arguments':
+ 'EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglPostSubBufferNV'],
+ 'arguments': 'EGLDisplay dpy, EGLSurface surface, '
+ 'EGLint x, EGLint y, EGLint width, EGLint height', },
+{ 'return_type': 'EGLenum',
+ 'names': ['eglQueryAPI'],
+ 'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglQueryContext'],
+ 'arguments':
+ 'EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint* value', },
+{ 'return_type': 'const char*',
+ 'names': ['eglQueryString'],
+ 'arguments': 'EGLDisplay dpy, EGLint name', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglQuerySurface'],
+ 'arguments':
+ 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint* value', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglQuerySurfacePointerANGLE'],
+ 'arguments':
+ 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, void** value', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglReleaseTexImage'],
+ 'arguments': 'EGLDisplay dpy, EGLSurface surface, EGLint buffer', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglReleaseThread'],
+ 'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglSurfaceAttrib'],
+ 'arguments':
+ 'EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglSwapBuffers'],
+ 'arguments': 'EGLDisplay dpy, EGLSurface surface', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglSwapInterval'],
+ 'arguments': 'EGLDisplay dpy, EGLint interval', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglTerminate'],
+ 'arguments': 'EGLDisplay dpy', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglWaitClient'],
+ 'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglWaitGL'],
+ 'arguments': 'void', },
+{ 'return_type': 'EGLBoolean',
+ 'names': ['eglWaitNative'],
+ 'arguments': 'EGLint engine', },
{ 'return_type': 'EGLint',
'versions': [{ 'name': 'eglWaitSyncKHR',
'extensions': ['EGL_KHR_fence_sync', 'EGL_KHR_wait_sync'] }],
- 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags' }
+ 'arguments': 'EGLDisplay dpy, EGLSyncKHR sync, EGLint flags' },
]
WGL_FUNCTIONS = [
+{ 'return_type': 'BOOL',
+ 'names': ['wglChoosePixelFormatARB'],
+ 'arguments':
+ 'HDC dc, const int* int_attrib_list, const float* float_attrib_list, '
+ 'UINT max_formats, int* formats, UINT* num_formats', },
+{ 'return_type': 'BOOL',
+ 'names': ['wglCopyContext'],
+ 'arguments': 'HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask', },
{ 'return_type': 'HGLRC',
'names': ['wglCreateContext'],
'arguments': 'HDC hdc', },
{ 'return_type': 'HGLRC',
'names': ['wglCreateLayerContext'],
'arguments': 'HDC hdc, int iLayerPlane', },
-{ 'return_type': 'BOOL',
- 'names': ['wglCopyContext'],
- 'arguments': 'HGLRC hglrcSrc, HGLRC hglrcDst, UINT mask', },
+{ 'return_type': 'HPBUFFERARB',
+ 'names': ['wglCreatePbufferARB'],
+ 'arguments': 'HDC hDC, int iPixelFormat, int iWidth, int iHeight, '
+ 'const int* piAttribList', },
{ 'return_type': 'BOOL',
'names': ['wglDeleteContext'],
'arguments': 'HGLRC hglrc', },
+{ 'return_type': 'BOOL',
+ 'names': ['wglDestroyPbufferARB'],
+ 'arguments': 'HPBUFFERARB hPbuffer', },
{ 'return_type': 'HGLRC',
'names': ['wglGetCurrentContext'],
'arguments': '', },
{ 'return_type': 'HDC',
'names': ['wglGetCurrentDC'],
'arguments': '', },
+{ 'return_type': 'const char*',
+ 'names': ['wglGetExtensionsStringARB'],
+ 'arguments': 'HDC hDC', },
+{ 'return_type': 'const char*',
+ 'names': ['wglGetExtensionsStringEXT'],
+ 'arguments': '', },
+{ 'return_type': 'HDC',
+ 'names': ['wglGetPbufferDCARB'],
+ 'arguments': 'HPBUFFERARB hPbuffer', },
{ 'return_type': 'BOOL',
'names': ['wglMakeCurrent'],
'arguments': 'HDC hdc, HGLRC hglrc', },
{ 'return_type': 'BOOL',
+ 'names': ['wglQueryPbufferARB'],
+ 'arguments': 'HPBUFFERARB hPbuffer, int iAttribute, int* piValue', },
+{ 'return_type': 'int',
+ 'names': ['wglReleasePbufferDCARB'],
+ 'arguments': 'HPBUFFERARB hPbuffer, HDC hDC', },
+{ 'return_type': 'BOOL',
'names': ['wglShareLists'],
'arguments': 'HGLRC hglrc1, HGLRC hglrc2', },
{ 'return_type': 'BOOL',
@@ -1123,43 +1179,25 @@
{ 'return_type': 'BOOL',
'names': ['wglSwapLayerBuffers'],
'arguments': 'HDC hdc, UINT fuPlanes', },
-{ 'return_type': 'const char*',
- 'names': ['wglGetExtensionsStringARB'],
- 'arguments': 'HDC hDC', },
-{ 'return_type': 'const char*',
- 'names': ['wglGetExtensionsStringEXT'],
- 'arguments': '', },
-{ 'return_type': 'BOOL',
- 'names': ['wglChoosePixelFormatARB'],
- 'arguments':
- 'HDC dc, const int* int_attrib_list, const float* float_attrib_list, '
- 'UINT max_formats, int* formats, UINT* num_formats', },
-{ 'return_type': 'HPBUFFERARB',
- 'names': ['wglCreatePbufferARB'],
- 'arguments': 'HDC hDC, int iPixelFormat, int iWidth, int iHeight, '
- 'const int* piAttribList', },
-{ 'return_type': 'HDC',
- 'names': ['wglGetPbufferDCARB'],
- 'arguments': 'HPBUFFERARB hPbuffer', },
-{ 'return_type': 'int',
- 'names': ['wglReleasePbufferDCARB'],
- 'arguments': 'HPBUFFERARB hPbuffer, HDC hDC', },
-{ 'return_type': 'BOOL',
- 'names': ['wglDestroyPbufferARB'],
- 'arguments': 'HPBUFFERARB hPbuffer', },
-{ 'return_type': 'BOOL',
- 'names': ['wglQueryPbufferARB'],
- 'arguments': 'HPBUFFERARB hPbuffer, int iAttribute, int* piValue', },
]
GLX_FUNCTIONS = [
-{ 'return_type': 'int',
- 'names': ['glXWaitVideoSyncSGI'],
- 'arguments': 'int divisor, int remainder, unsigned int* count', },
+{ 'return_type': 'void',
+ 'names': ['glXBindTexImageEXT'],
+ 'arguments':
+ 'Display* dpy, GLXDrawable drawable, int buffer, int* attribList', },
+{ 'return_type': 'GLXFBConfig*',
+ 'names': ['glXChooseFBConfig'],
+ 'arguments':
+ 'Display* dpy, int screen, const int* attribList, int* nitems', },
{ 'return_type': 'XVisualInfo*',
'names': ['glXChooseVisual'],
'arguments': 'Display* dpy, int screen, int* attribList', },
{ 'return_type': 'void',
+ 'names': ['glXCopyContext'],
+ 'arguments':
+ 'Display* dpy, GLXContext src, GLXContext dst, unsigned long mask', },
+{ 'return_type': 'void',
'names': ['glXCopySubBufferMESA'],
'arguments': 'Display* dpy, GLXDrawable drawable, '
'int x, int y, int width, int height', },
@@ -1167,152 +1205,143 @@
'names': ['glXCreateContext'],
'arguments':
'Display* dpy, XVisualInfo* vis, GLXContext shareList, int direct', },
-{ 'return_type': 'void',
- 'names': ['glXBindTexImageEXT'],
+{ 'return_type': 'GLXContext',
+ 'names': ['glXCreateContextAttribsARB'],
'arguments':
- 'Display* dpy, GLXDrawable drawable, int buffer, int* attribList', },
-{ 'return_type': 'void',
- 'names': ['glXReleaseTexImageEXT'],
- 'arguments': 'Display* dpy, GLXDrawable drawable, int buffer', },
-{ 'return_type': 'void',
- 'names': ['glXDestroyContext'],
- 'arguments': 'Display* dpy, GLXContext ctx', },
-{ 'return_type': 'int',
- 'names': ['glXMakeCurrent'],
- 'arguments': 'Display* dpy, GLXDrawable drawable, GLXContext ctx', },
-{ 'return_type': 'void',
- 'names': ['glXCopyContext'],
- 'arguments':
- 'Display* dpy, GLXContext src, GLXContext dst, unsigned long mask', },
-{ 'return_type': 'void',
- 'names': ['glXSwapBuffers'],
- 'arguments': 'Display* dpy, GLXDrawable drawable', },
+ 'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, '
+ 'const int* attrib_list', },
{ 'return_type': 'GLXPixmap',
'names': ['glXCreateGLXPixmap'],
'arguments': 'Display* dpy, XVisualInfo* visual, Pixmap pixmap', },
+{ 'return_type': 'GLXContext',
+ 'names': ['glXCreateNewContext'],
+ 'arguments': 'Display* dpy, GLXFBConfig config, int renderType, '
+ 'GLXContext shareList, int direct', },
+{ 'return_type': 'GLXPbuffer',
+ 'names': ['glXCreatePbuffer'],
+ 'arguments': 'Display* dpy, GLXFBConfig config, const int* attribList', },
+{ 'return_type': 'GLXPixmap',
+ 'names': ['glXCreatePixmap'],
+ 'arguments': 'Display* dpy, GLXFBConfig config, '
+ 'Pixmap pixmap, const int* attribList', },
+{ 'return_type': 'GLXWindow',
+ 'names': ['glXCreateWindow'],
+ 'arguments':
+ 'Display* dpy, GLXFBConfig config, Window win, const int* attribList', },
+{ 'return_type': 'void',
+ 'names': ['glXDestroyContext'],
+ 'arguments': 'Display* dpy, GLXContext ctx', },
{ 'return_type': 'void',
'names': ['glXDestroyGLXPixmap'],
'arguments': 'Display* dpy, GLXPixmap pixmap', },
-{ 'return_type': 'int',
- 'names': ['glXQueryExtension'],
- 'arguments': 'Display* dpy, int* errorb, int* event', },
-{ 'return_type': 'int',
- 'names': ['glXQueryVersion'],
- 'arguments': 'Display* dpy, int* maj, int* min', },
-{ 'return_type': 'int',
- 'names': ['glXIsDirect'],
- 'arguments': 'Display* dpy, GLXContext ctx', },
+{ 'return_type': 'void',
+ 'names': ['glXDestroyPbuffer'],
+ 'arguments': 'Display* dpy, GLXPbuffer pbuf', },
+{ 'return_type': 'void',
+ 'names': ['glXDestroyPixmap'],
+ 'arguments': 'Display* dpy, GLXPixmap pixmap', },
+{ 'return_type': 'void',
+ 'names': ['glXDestroyWindow'],
+ 'arguments': 'Display* dpy, GLXWindow window', },
+{ 'return_type': 'const char*',
+ 'names': ['glXGetClientString'],
+ 'arguments': 'Display* dpy, int name', },
{ 'return_type': 'int',
'names': ['glXGetConfig'],
'arguments': 'Display* dpy, XVisualInfo* visual, int attrib, int* value', },
{ 'return_type': 'GLXContext',
'names': ['glXGetCurrentContext'],
'arguments': 'void', },
+{ 'return_type': 'Display*',
+ 'names': ['glXGetCurrentDisplay'],
+ 'arguments': 'void', },
{ 'return_type': 'GLXDrawable',
'names': ['glXGetCurrentDrawable'],
'arguments': 'void', },
-{ 'return_type': 'void',
- 'names': ['glXWaitGL'],
+{ 'return_type': 'GLXDrawable',
+ 'names': ['glXGetCurrentReadDrawable'],
'arguments': 'void', },
+{ 'return_type': 'int',
+ 'names': ['glXGetFBConfigAttrib'],
+ 'arguments': 'Display* dpy, GLXFBConfig config, int attribute, int* value', },
+{ 'return_type': 'GLXFBConfig',
+ 'names': ['glXGetFBConfigFromVisualSGIX'],
+ 'arguments': 'Display* dpy, XVisualInfo* visualInfo', },
+{ 'return_type': 'GLXFBConfig*',
+ 'names': ['glXGetFBConfigs'],
+ 'arguments': 'Display* dpy, int screen, int* nelements', },
+{ 'return_type': 'bool',
+ 'names': ['glXGetMscRateOML'],
+ 'arguments':
+ 'Display* dpy, GLXDrawable drawable, int32* numerator, '
+ 'int32* denominator' },
{ 'return_type': 'void',
- 'names': ['glXWaitX'],
- 'arguments': 'void', },
+ 'names': ['glXGetSelectedEvent'],
+ 'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long* mask', },
+{ 'return_type': 'bool',
+ 'names': ['glXGetSyncValuesOML'],
+ 'arguments':
+ 'Display* dpy, GLXDrawable drawable, int64* ust, int64* msc, '
+ 'int64* sbc' },
+{ 'return_type': 'XVisualInfo*',
+ 'names': ['glXGetVisualFromFBConfig'],
+ 'arguments': 'Display* dpy, GLXFBConfig config', },
+{ 'return_type': 'int',
+ 'names': ['glXIsDirect'],
+ 'arguments': 'Display* dpy, GLXContext ctx', },
+{ 'return_type': 'int',
+ 'names': ['glXMakeContextCurrent'],
+ 'arguments':
+ 'Display* dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx', },
+{ 'return_type': 'int',
+ 'names': ['glXMakeCurrent'],
+ 'arguments': 'Display* dpy, GLXDrawable drawable, GLXContext ctx', },
+{ 'return_type': 'int',
+ 'names': ['glXQueryContext'],
+ 'arguments': 'Display* dpy, GLXContext ctx, int attribute, int* value', },
{ 'return_type': 'void',
- 'names': ['glXUseXFont'],
- 'arguments': 'Font font, int first, int count, int list', },
+ 'names': ['glXQueryDrawable'],
+ 'arguments':
+ 'Display* dpy, GLXDrawable draw, int attribute, unsigned int* value', },
+{ 'return_type': 'int',
+ 'names': ['glXQueryExtension'],
+ 'arguments': 'Display* dpy, int* errorb, int* event', },
{ 'return_type': 'const char*',
'names': ['glXQueryExtensionsString'],
'arguments': 'Display* dpy, int screen', },
{ 'return_type': 'const char*',
'names': ['glXQueryServerString'],
'arguments': 'Display* dpy, int screen, int name', },
-{ 'return_type': 'const char*',
- 'names': ['glXGetClientString'],
- 'arguments': 'Display* dpy, int name', },
-{ 'return_type': 'Display*',
- 'names': ['glXGetCurrentDisplay'],
- 'arguments': 'void', },
-{ 'return_type': 'GLXFBConfig*',
- 'names': ['glXChooseFBConfig'],
- 'arguments':
- 'Display* dpy, int screen, const int* attribList, int* nitems', },
{ 'return_type': 'int',
- 'names': ['glXGetFBConfigAttrib'],
- 'arguments': 'Display* dpy, GLXFBConfig config, int attribute, int* value', },
-{ 'return_type': 'GLXFBConfig*',
- 'names': ['glXGetFBConfigs'],
- 'arguments': 'Display* dpy, int screen, int* nelements', },
-{ 'return_type': 'XVisualInfo*',
- 'names': ['glXGetVisualFromFBConfig'],
- 'arguments': 'Display* dpy, GLXFBConfig config', },
-{ 'return_type': 'GLXWindow',
- 'names': ['glXCreateWindow'],
- 'arguments':
- 'Display* dpy, GLXFBConfig config, Window win, const int* attribList', },
+ 'names': ['glXQueryVersion'],
+ 'arguments': 'Display* dpy, int* maj, int* min', },
{ 'return_type': 'void',
- 'names': ['glXDestroyWindow'],
- 'arguments': 'Display* dpy, GLXWindow window', },
-{ 'return_type': 'GLXPixmap',
- 'names': ['glXCreatePixmap'],
- 'arguments': 'Display* dpy, GLXFBConfig config, '
- 'Pixmap pixmap, const int* attribList', },
-{ 'return_type': 'void',
- 'names': ['glXDestroyPixmap'],
- 'arguments': 'Display* dpy, GLXPixmap pixmap', },
-{ 'return_type': 'GLXPbuffer',
- 'names': ['glXCreatePbuffer'],
- 'arguments': 'Display* dpy, GLXFBConfig config, const int* attribList', },
-{ 'return_type': 'void',
- 'names': ['glXDestroyPbuffer'],
- 'arguments': 'Display* dpy, GLXPbuffer pbuf', },
-{ 'return_type': 'void',
- 'names': ['glXQueryDrawable'],
- 'arguments':
- 'Display* dpy, GLXDrawable draw, int attribute, unsigned int* value', },
-{ 'return_type': 'GLXContext',
- 'names': ['glXCreateNewContext'],
- 'arguments': 'Display* dpy, GLXFBConfig config, int renderType, '
- 'GLXContext shareList, int direct', },
-{ 'return_type': 'int',
- 'names': ['glXMakeContextCurrent'],
- 'arguments':
- 'Display* dpy, GLXDrawable draw, GLXDrawable read, GLXContext ctx', },
-{ 'return_type': 'GLXDrawable',
- 'names': ['glXGetCurrentReadDrawable'],
- 'arguments': 'void', },
-{ 'return_type': 'int',
- 'names': ['glXQueryContext'],
- 'arguments': 'Display* dpy, GLXContext ctx, int attribute, int* value', },
+ 'names': ['glXReleaseTexImageEXT'],
+ 'arguments': 'Display* dpy, GLXDrawable drawable, int buffer', },
{ 'return_type': 'void',
'names': ['glXSelectEvent'],
'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long mask', },
{ 'return_type': 'void',
- 'names': ['glXGetSelectedEvent'],
- 'arguments': 'Display* dpy, GLXDrawable drawable, unsigned long* mask', },
+ 'names': ['glXSwapBuffers'],
+ 'arguments': 'Display* dpy, GLXDrawable drawable', },
+{ 'return_type': 'void',
+ 'names': ['glXSwapIntervalEXT'],
+ 'arguments': 'Display* dpy, GLXDrawable drawable, int interval', },
{ 'return_type': 'void',
'names': ['glXSwapIntervalMESA'],
'arguments': 'unsigned int interval', },
{ 'return_type': 'void',
- 'names': ['glXSwapIntervalEXT'],
- 'arguments': 'Display* dpy, GLXDrawable drawable, int interval', },
-{ 'return_type': 'GLXFBConfig',
- 'names': ['glXGetFBConfigFromVisualSGIX'],
- 'arguments': 'Display* dpy, XVisualInfo* visualInfo', },
-{ 'return_type': 'GLXContext',
- 'names': ['glXCreateContextAttribsARB'],
- 'arguments':
- 'Display* dpy, GLXFBConfig config, GLXContext share_context, int direct, '
- 'const int* attrib_list', },
-{ 'return_type': 'bool',
- 'names': ['glXGetSyncValuesOML'],
- 'arguments':
- 'Display* dpy, GLXDrawable drawable, int64* ust, int64* msc, '
- 'int64* sbc' },
-{ 'return_type': 'bool',
- 'names': ['glXGetMscRateOML'],
- 'arguments':
- 'Display* dpy, GLXDrawable drawable, int32* numerator, '
- 'int32* denominator' },
+ 'names': ['glXUseXFont'],
+ 'arguments': 'Font font, int first, int count, int list', },
+{ 'return_type': 'void',
+ 'names': ['glXWaitGL'],
+ 'arguments': 'void', },
+{ 'return_type': 'int',
+ 'names': ['glXWaitVideoSyncSGI'],
+ 'arguments': 'int divisor, int remainder, unsigned int* count', },
+{ 'return_type': 'void',
+ 'names': ['glXWaitX'],
+ 'arguments': 'void', },
]
FUNCTION_SETS = [
@@ -1339,6 +1368,7 @@
[GLX_FUNCTIONS, 'glx', ['GL/glx.h', 'GL/glxext.h'], []],
]
+
def GenerateHeader(file, functions, set_name, used_extensions):
"""Generates gl_bindings_autogen_x.h"""
@@ -2028,6 +2058,7 @@
parser = optparse.OptionParser()
parser.add_option('--inputs', action='store_true')
parser.add_option('--header-paths')
+ parser.add_option('--verify-order', action='store_true')
options, args = parser.parse_args(argv)
@@ -2056,6 +2087,16 @@
if 'names' in func:
del func['names']
+ # Check function names in each set is sorted in alphabetical order.
+ for index in range(len(functions) - 1):
+ func_name = functions[index]['known_as']
+ next_func_name = functions[index + 1]['known_as']
+ if func_name.lower() > next_func_name.lower():
+ raise Exception(
+ 'function %s is not in alphabetical order' % next_func_name)
+ if options.verify_order:
+ continue
+
extension_headers = [ResolveHeader(h, options.header_paths)
for h in extension_headers]
used_extensions = FillExtensionsFromHeaders(
@@ -2077,20 +2118,21 @@
GenerateSource(source_file, functions, set_name, used_extensions)
source_file.close()
- header_file = open(
- os.path.join(directory, 'gl_mock_autogen_gl.h'), 'wb')
- GenerateMockHeader(header_file, GL_FUNCTIONS, 'gl')
- header_file.close()
+ if not options.verify_order:
+ header_file = open(
+ os.path.join(directory, 'gl_mock_autogen_gl.h'), 'wb')
+ GenerateMockHeader(header_file, GL_FUNCTIONS, 'gl')
+ header_file.close()
- header_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.h'),
- 'wb')
- GenerateMockBindingsHeader(header_file, GL_FUNCTIONS)
- header_file.close()
+ header_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.h'),
+ 'wb')
+ GenerateMockBindingsHeader(header_file, GL_FUNCTIONS)
+ header_file.close()
- source_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.cc'),
- 'wb')
- GenerateMockBindingsSource(source_file, GL_FUNCTIONS)
- source_file.close()
+ source_file = open(os.path.join(directory, 'gl_bindings_autogen_mock.cc'),
+ 'wb')
+ GenerateMockBindingsSource(source_file, GL_FUNCTIONS)
+ source_file.close()
return 0
diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp
index cd0a852..cd33d7a 100644
--- a/ui/gl/gl.gyp
+++ b/ui/gl/gl.gyp
@@ -263,6 +263,8 @@
'sources': [
'gl_context_cgl.cc',
'gl_context_cgl.h',
+ 'gl_fence_apple.cc',
+ 'gl_fence_apple.h',
'gl_image_io_surface.cc',
'gl_image_io_surface.h',
'scoped_cgl.cc',
@@ -310,14 +312,6 @@
'../android/ui_android.gyp:ui_java',
],
}],
- ['ubsan==1', {
- # Due to a bug in LLVM (http://llvm.org/bugs/show_bug.cgi?id=21349),
- # compilation hangs for some GL source files. Disable -O2 temporarily
- # until http://crbug.com/426271 is fixed.
- 'cflags!': [
- '-O2',
- ],
- }],
],
},
{
diff --git a/ui/gl/gl_bindings.h b/ui/gl/gl_bindings.h
index dd737f4..aea47fc 100644
--- a/ui/gl/gl_bindings.h
+++ b/ui/gl/gl_bindings.h
@@ -143,6 +143,10 @@
#define GL_OVERLAY_TRANSFORM_ROTATE_180_CHROMIUM 0x9249
#define GL_OVERLAY_TRANSFORM_ROTATE_270_CHROMIUM 0x924A
+// GL_CHROMIUM_subscribe_uniforms
+#define GL_SUBSCRIBED_VALUES_BUFFER_CHROMIUM 0x924B
+#define GL_MOUSE_POSITION_CHROMIUM 0x924C
+
// GL_OES_texure_3D
#define GL_SAMPLER_3D_OES 0x8B5F
diff --git a/ui/gl/gl_context_egl.cc b/ui/gl/gl_context_egl.cc
index 41c10dc..733ad8d 100644
--- a/ui/gl/gl_context_egl.cc
+++ b/ui/gl/gl_context_egl.cc
@@ -183,8 +183,6 @@
if (!eglSwapInterval(display_, interval)) {
LOG(ERROR) << "eglSwapInterval failed with error "
<< GetLastEGLErrorString();
- } else {
- GLSurface::GetCurrent()->SetSwapInterval(interval);
}
}
diff --git a/ui/gl/gl_fence.cc b/ui/gl/gl_fence.cc
index 5186f23..c254411 100644
--- a/ui/gl/gl_fence.cc
+++ b/ui/gl/gl_fence.cc
@@ -13,6 +13,10 @@
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_version_info.h"
+#if defined(OS_MACOSX)
+#include "ui/gl/gl_fence_apple.h"
+#endif
+
namespace gfx {
namespace {
@@ -27,7 +31,10 @@
if (g_driver_gl.ext.b_GL_ARB_sync ||
GetGLVersionInfo()->is_es3) {
fence.reset(new GLFenceARB(flush));
-#if !defined(OS_MACOSX)
+#if defined(OS_MACOSX)
+ } else if (g_driver_gl.ext.b_GL_APPLE_fence) {
+ fence.reset(new GLFenceAPPLE(flush));
+#else
} else if (g_driver_egl.ext.b_EGL_KHR_fence_sync) {
fence.reset(new GLFenceEGL(flush));
#endif
@@ -50,7 +57,9 @@
bool GLFence::IsSupported() {
DCHECK(GetGLVersionInfo());
return g_driver_gl.ext.b_GL_ARB_sync || GetGLVersionInfo()->is_es3 ||
-#if !defined(OS_MACOSX)
+#if defined(OS_MACOSX)
+ g_driver_gl.ext.b_GL_APPLE_fence ||
+#else
g_driver_egl.ext.b_EGL_KHR_fence_sync ||
#endif
g_driver_gl.ext.b_GL_NV_fence;
diff --git a/ui/gl/gl_fence_apple.cc b/ui/gl/gl_fence_apple.cc
new file mode 100644
index 0000000..9df0cad
--- /dev/null
+++ b/ui/gl/gl_fence_apple.cc
@@ -0,0 +1,47 @@
+// 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 "ui/gl/gl_fence_apple.h"
+
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+
+namespace gfx {
+
+GLFenceAPPLE::GLFenceAPPLE(bool flush) {
+ glGenFencesAPPLE(1, &fence_);
+ glSetFenceAPPLE(fence_);
+ DCHECK(glIsFenceAPPLE(fence_));
+ if (flush) {
+ glFlush();
+ } else {
+ flush_event_ = GLContext::GetCurrent()->SignalFlush();
+ }
+}
+
+bool GLFenceAPPLE::HasCompleted() {
+ DCHECK(glIsFenceAPPLE(fence_));
+ return !!glTestFenceAPPLE(fence_);
+}
+
+void GLFenceAPPLE::ClientWait() {
+ DCHECK(glIsFenceAPPLE(fence_));
+ if (!flush_event_.get() || flush_event_->IsSignaled()) {
+ glFinishFenceAPPLE(fence_);
+ } else {
+ LOG(ERROR) << "Trying to wait for uncommitted fence. Skipping...";
+ }
+}
+
+void GLFenceAPPLE::ServerWait() {
+ DCHECK(glIsFenceAPPLE(fence_));
+ ClientWait();
+}
+
+GLFenceAPPLE::~GLFenceAPPLE() {
+ DCHECK(glIsFenceAPPLE(fence_));
+ glDeleteFencesAPPLE(1, &fence_);
+}
+
+} // namespace gfx
diff --git a/ui/gl/gl_fence_apple.h b/ui/gl/gl_fence_apple.h
new file mode 100644
index 0000000..6c8633d
--- /dev/null
+++ b/ui/gl/gl_fence_apple.h
@@ -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.
+
+#ifndef UI_GL_GL_FENCE_APPLE_H_
+#define UI_GL_GL_FENCE_APPLE_H_
+
+#include "base/macros.h"
+#include "ui/gl/gl_bindings.h"
+#include "ui/gl/gl_context.h"
+#include "ui/gl/gl_fence.h"
+
+namespace gfx {
+
+class GL_EXPORT GLFenceAPPLE : public GLFence {
+ public:
+ GLFenceAPPLE(bool flush);
+ ~GLFenceAPPLE() override;
+
+ // GLFence implementation:
+ bool HasCompleted() override;
+ void ClientWait() override;
+ void ServerWait() override;
+
+ private:
+ GLuint fence_;
+ scoped_refptr<GLContext::FlushEvent> flush_event_;
+
+ DISALLOW_COPY_AND_ASSIGN(GLFenceAPPLE);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_GL_FENCE_APPLE_H_
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc
index a818a60..4459d48 100644
--- a/ui/gl/gl_surface.cc
+++ b/ui/gl/gl_surface.cc
@@ -266,9 +266,6 @@
return extensions.find(delimited_name) != std::string::npos;
}
-void GLSurface::SetSwapInterval(int interval) {
-}
-
GLSurfaceAdapter::GLSurfaceAdapter(GLSurface* surface) : surface_(surface) {}
bool GLSurfaceAdapter::Initialize() {
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h
index 0a7607f..d458063 100644
--- a/ui/gl/gl_surface.h
+++ b/ui/gl/gl_surface.h
@@ -134,8 +134,6 @@
static GLSurface* GetCurrent();
- virtual void SetSwapInterval(int interval);
-
protected:
virtual ~GLSurface();
static bool InitializeOneOffImplementation(GLImplementation impl,
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc
index c34ca0e..19119a9 100644
--- a/ui/gl/gl_surface_egl.cc
+++ b/ui/gl/gl_surface_egl.cc
@@ -45,8 +45,11 @@
#if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
#endif
-#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
+#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
+#endif
+#if !defined(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE)
+#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
#endif
#endif // defined(OS_WIN)
@@ -54,8 +57,6 @@
namespace gfx {
-unsigned int NativeViewGLSurfaceEGL::current_swap_generation_ = 0;
-
namespace {
EGLConfig g_config;
@@ -252,8 +253,8 @@
#if defined(OS_WIN)
static const EGLint kDisplayAttribsWarp[] {
- EGL_PLATFORM_ANGLE_TYPE_ANGLE,
- EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE,
+ EGL_PLATFORM_ANGLE_TYPE_ANGLE, EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE,
+ EGL_PLATFORM_ANGLE_USE_WARP_ANGLE, EGL_TRUE,
EGL_NONE
};
@@ -288,9 +289,7 @@
surface_(NULL),
supports_post_sub_buffer_(false),
config_(NULL),
- size_(1, 1),
- swap_interval_(1),
- swap_generation_(0) {
+ size_(1, 1) {
#if defined(OS_ANDROID)
if (window)
ANativeWindow_acquire(window);
@@ -454,37 +453,12 @@
"width", GetSize().width(),
"height", GetSize().height());
-#if defined(OS_WIN)
- bool force_no_vsync = false;
- if (swap_interval_ != 0) {
- // This code is a simple way of enforcing that only one surface actually
- // vsyncs per frame. This provides single window cases a stable refresh
- // while allowing multi-window cases to not slow down due to multiple syncs
- // on a single thread. A better way to fix this problem would be to have
- // each surface present on its own thread.
- if (current_swap_generation_ == swap_generation_) {
- current_swap_generation_++;
- } else {
- force_no_vsync = true;
- eglSwapInterval(GetDisplay(), 0);
- }
-
- swap_generation_ = current_swap_generation_;
- }
-#endif
-
if (!eglSwapBuffers(GetDisplay(), surface_)) {
DVLOG(1) << "eglSwapBuffers failed with error "
<< GetLastEGLErrorString();
return false;
}
-#if defined(OS_WIN)
- if (force_no_vsync) {
- eglSwapInterval(GetDisplay(), swap_interval_);
- }
-#endif
-
return true;
}
@@ -559,10 +533,6 @@
return vsync_provider_.get();
}
-void NativeViewGLSurfaceEGL::SetSwapInterval(int interval) {
- swap_interval_ = interval;
-}
-
NativeViewGLSurfaceEGL::~NativeViewGLSurfaceEGL() {
Destroy();
#if defined(OS_ANDROID)
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h
index b832ef6..952ccad 100644
--- a/ui/gl/gl_surface_egl.h
+++ b/ui/gl/gl_surface_egl.h
@@ -82,8 +82,6 @@
EGLNativeWindowType window_;
- virtual void SetSwapInterval(int interval) override;
-
private:
EGLSurface surface_;
bool supports_post_sub_buffer_;
@@ -92,10 +90,6 @@
scoped_ptr<VSyncProvider> vsync_provider_;
- int swap_interval_;
- unsigned int swap_generation_;
- static unsigned int current_swap_generation_;
-
DISALLOW_COPY_AND_ASSIGN(NativeViewGLSurfaceEGL);
};
diff --git a/ui/gl/gl_surface_win.cc b/ui/gl/gl_surface_win.cc
index c424e87..5cf68af 100644
--- a/ui/gl/gl_surface_win.cc
+++ b/ui/gl/gl_surface_win.cc
@@ -31,8 +31,11 @@
#if !defined(EGL_PLATFORM_ANGLE_TYPE_ANGLE)
#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3202
#endif
-#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE)
-#define EGL_PLATFORM_ANGLE_TYPE_D3D11_WARP_ANGLE 0x3206
+#if !defined(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3207
+#endif
+#if !defined(EGL_PLATFORM_ANGLE_USE_WARP_ANGLE)
+#define EGL_PLATFORM_ANGLE_USE_WARP_ANGLE 0x3208
#endif
namespace gfx {