Chromium -> Mojo roll.
Update from https://crrev.com/321900
Changes:
(1) OpenTypeSanitizer.cpp: Removed use of ots::EnableWOFF2() which was
removed from library and implementation was empty anyways.
(2) GraphicsContext.cpp: Header location for SkMatrixImageFilter.h moved.
(3) SkiaImageFilterBuilder.cpp: Header location for SkMatrixImageFilter.h moved.
(4) FEDropShadow.cpp: Function signature changed.
R=davemoore@chromium.org, jamesr@chromium.org
BUG=453591
Review URL: https://codereview.chromium.org/1028333002
diff --git a/DEPS b/DEPS
index 8280b31..c3abc80 100644
--- a/DEPS
+++ b/DEPS
@@ -21,19 +21,19 @@
'chromium_git': 'https://chromium.googlesource.com',
'dart_svn': 'https://dart.googlecode.com',
'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
- 'skia_revision': 'cdeca446197329de91d87d12ad689d03d7e4d261',
+ 'skia_revision': '92d04da38f03dfabd8cd9a7244588a49be9a2f41',
# 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': '2a8ff45e5c7fce5037cf975c4997718c324744dd',
+ 'v8_revision': '230d131d173ab2d60291d303177bc04ec3f6e519',
# 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': '524e3bde19d0df76cc9d1c5926345f5d0ec4d3f8',
+ 'angle_revision': 'bdd419f9f5b006e913606e7363125942c8ae06bc',
# 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': 'd4dd4f79f60bf019625b3a1436979b0a42c892df',
+ 'buildtools_revision': '3b302fef93f7cc58d9b8168466905237484b2772',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Dart
# and whatever else without interference from each other.
@@ -41,11 +41,11 @@
# 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': '28ddd48bfd84c55cc51d0b16fa533c51affdeb5b',
+ 'pdfium_revision': 'b0115665b0f33971f1b7077740d51e155583cec0',
# 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': 'bf0df92964565f819881e78ff3bfb5343e95e130',
+ 'boringssl_revision': '642f1498d056dbba3e50ed5a232ab2f482626dec',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling lss
# and whatever else without interference from each other.
@@ -79,7 +79,7 @@
Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'),
'src/third_party/icu':
- Var('chromium_git') + '/chromium/deps/icu.git' + '@' + 'eda9e75b1fa17f57ffa369ee3543a2301b68d0a9',
+ Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '7c81740601355556e630da515b74d889ba2f8d08',
'src/tools/grit':
Var('chromium_git') + '/external/grit-i18n.git' + '@' + '0287c187b11ed53590254e4d817e836a44a7a1a7', # from svn revision 186
@@ -150,7 +150,7 @@
Var('chromium_git') + '/external/jsr-305.git' + '@' + '642c508235471f7220af6d5df2d3210e3bfc0919',
'src/third_party/android_tools':
- Var('chromium_git') + '/android_tools.git' + '@' + '98a434576d8d9a65f9bdb8ea161e158142c0c5e5',
+ Var('chromium_git') + '/android_tools.git' + '@' + 'a1ffd63322c438627d78ea56eb73fb8779e06950',
'src/third_party/appurify-python/src':
Var('chromium_git') + '/external/github.com/appurify/appurify-python.git' + '@' + 'ee7abd5c5ae3106f72b2a0b9d2cb55094688e867',
diff --git a/base/BUILD.gn b/base/BUILD.gn
index f103446..8b9b5bf 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -370,6 +370,10 @@
"profiler/scoped_profile.h",
"profiler/scoped_tracker.cc",
"profiler/scoped_tracker.h",
+ "profiler/stack_sampling_profiler.cc",
+ "profiler/stack_sampling_profiler.h",
+ "profiler/stack_sampling_profiler_posix.cc",
+ "profiler/stack_sampling_profiler_win.cc",
"profiler/tracked_time.cc",
"profiler/tracked_time.h",
"rand_util.cc",
@@ -484,6 +488,8 @@
"threading/non_thread_safe_impl.h",
"threading/platform_thread.h",
"threading/platform_thread_android.cc",
+ "threading/platform_thread_internal_posix.cc",
+ "threading/platform_thread_internal_posix.h",
"threading/platform_thread_linux.cc",
"threading/platform_thread_mac.mm",
"threading/platform_thread_posix.cc",
@@ -740,6 +746,7 @@
sources -= [
"native_library_posix.cc",
"strings/sys_string_conversions_posix.cc",
+ "threading/platform_thread_internal_posix.cc",
]
} else {
# Non-Mac.
@@ -1188,6 +1195,7 @@
"process/process_unittest.cc",
"process/process_util_unittest.cc",
"process/process_util_unittest_ios.cc",
+ "profiler/stack_sampling_profiler_unittest.cc",
"profiler/tracked_time_unittest.cc",
"rand_util_unittest.cc",
"scoped_clear_errno_unittest.cc",
@@ -1248,15 +1256,6 @@
"timer/mock_timer_unittest.cc",
"timer/timer_unittest.cc",
"tools_sanity_unittest.cc",
- "trace_event/memory_dump_manager_unittest.cc",
- "trace_event/process_memory_maps_dump_provider_unittest.cc",
- "trace_event/process_memory_totals_dump_provider_unittest.cc",
- "trace_event/trace_event_argument_unittest.cc",
- "trace_event/trace_event_memory_unittest.cc",
- "trace_event/trace_event_synthetic_delay_unittest.cc",
- "trace_event/trace_event_system_stats_monitor_unittest.cc",
- "trace_event/trace_event_unittest.cc",
- "trace_event/trace_event_win_unittest.cc",
"tracked_objects_unittest.cc",
"tuple_unittest.cc",
"values_unittest.cc",
@@ -1294,6 +1293,7 @@
"//base/test:test_support",
"//base/third_party/dynamic_annotations",
"//base/third_party/nspr",
+ "//base/trace_event:trace_event_unittests",
"//testing/gmock",
"//testing/gtest",
"//third_party/icu",
diff --git a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
index 4198853..71b79b1 100644
--- a/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
+++ b/base/android/java/src/org/chromium/base/ApiCompatibilityUtils.java
@@ -14,6 +14,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
@@ -480,4 +482,25 @@
window.setStatusBarColor(statusBarColor);
}
}
+
+ /**
+ * @see android.content.res.Resources#getDrawable(int id).
+ */
+ @SuppressWarnings("deprecation")
+ public static Drawable getDrawable(Resources res, int id) throws NotFoundException {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ return res.getDrawable(id, null);
+ } else {
+ return res.getDrawable(id);
+ }
+ }
+
+ /**
+ * @see android.view.View#announceForAccessibility(CharSequence text)
+ */
+ public static void announceForAccessibility(View view, CharSequence text) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
+ view.announceForAccessibility(text);
+ }
+ }
}
diff --git a/base/android/java/src/org/chromium/base/CommandLine.java b/base/android/java/src/org/chromium/base/CommandLine.java
index 43e0004..9f54079 100644
--- a/base/android/java/src/org/chromium/base/CommandLine.java
+++ b/base/android/java/src/org/chromium/base/CommandLine.java
@@ -306,8 +306,9 @@
// Append the switch and update the switches/arguments divider mArgsBegin.
String combinedSwitchString = SWITCH_PREFIX + switchString;
- if (value != null && !value.isEmpty())
+ if (value != null && !value.isEmpty()) {
combinedSwitchString += SWITCH_VALUE_SEPARATOR + value;
+ }
mArgs.add(mArgsBegin++, combinedSwitchString);
}
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
index bbf76cb..dbeb758 100644
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -237,9 +237,9 @@
System.loadLibrary(TAG + ".cr");
}
sRelroSharingSupported = nativeCanUseSharedRelro();
- if (!sRelroSharingSupported)
+ if (!sRelroSharingSupported) {
Log.w(TAG, "This system cannot safely share RELRO sections");
- else {
+ } else {
if (DEBUG) Log.i(TAG, "This system supports safe shared RELRO sections");
}
@@ -255,8 +255,9 @@
case BROWSER_SHARED_RELRO_CONFIG_LOW_RAM_ONLY:
sBrowserUsesSharedRelro =
(sMemoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW);
- if (sBrowserUsesSharedRelro)
+ if (sBrowserUsesSharedRelro) {
Log.w(TAG, "Low-memory device: shared RELROs used in all processes");
+ }
break;
case BROWSER_SHARED_RELRO_CONFIG_ALWAYS:
Log.w(TAG, "Beware: shared RELROs used in all processes!");
@@ -345,10 +346,11 @@
assert memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW
|| memoryDeviceConfig == MEMORY_DEVICE_CONFIG_NORMAL;
if (DEBUG) {
- if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW)
+ if (memoryDeviceConfig == MEMORY_DEVICE_CONFIG_LOW) {
Log.i(TAG, "Simulating a low-memory device");
- else
+ } else {
Log.i(TAG, "Simulating a regular-memory device");
+ }
}
sMemoryDeviceConfig = memoryDeviceConfig;
}
@@ -363,8 +365,7 @@
// Only GYP targets that are APKs and have the 'use_chromium_linker' variable
// defined as 1 will use this linker. For all others (the default), the
// auto-generated NativeLibraries.sUseLinker variable will be false.
- if (!NativeLibraries.sUseLinker)
- return false;
+ if (!NativeLibraries.sUseLinker) return false;
synchronized (Linker.class) {
ensureInitializedLocked();
@@ -693,8 +694,7 @@
}
// In service processes, close all file descriptors from the map now.
- if (!sInBrowserProcess)
- closeLibInfoMap(relroMap);
+ if (!sInBrowserProcess) closeLibInfoMap(relroMap);
if (DEBUG) Log.i(TAG, "Linker.useSharedRelrosLocked() exiting");
}
diff --git a/base/base.gyp b/base/base.gyp
index c7a2481..ac37a89 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -595,6 +595,7 @@
'process/process_metrics_unittest_ios.cc',
'process/process_unittest.cc',
'process/process_util_unittest.cc',
+ 'profiler/stack_sampling_profiler_unittest.cc',
'profiler/tracked_time_unittest.cc',
'rand_util_unittest.cc',
'scoped_clear_errno_unittest.cc',
@@ -656,15 +657,6 @@
'timer/mock_timer_unittest.cc',
'timer/timer_unittest.cc',
'tools_sanity_unittest.cc',
- 'trace_event/memory_dump_manager_unittest.cc',
- 'trace_event/process_memory_maps_dump_provider_unittest.cc',
- 'trace_event/process_memory_totals_dump_provider_unittest.cc',
- 'trace_event/trace_event_argument_unittest.cc',
- 'trace_event/trace_event_memory_unittest.cc',
- 'trace_event/trace_event_synthetic_delay_unittest.cc',
- 'trace_event/trace_event_system_stats_monitor_unittest.cc',
- 'trace_event/trace_event_unittest.cc',
- 'trace_event/trace_event_win_unittest.cc',
'tracked_objects_unittest.cc',
'tuple_unittest.cc',
'values_unittest.cc',
@@ -689,6 +681,7 @@
'win/startup_information_unittest.cc',
'win/win_util_unittest.cc',
'win/wrapped_window_proc_unittest.cc',
+ '<@(trace_event_test_sources)',
],
'dependencies': [
'base',
@@ -975,8 +968,8 @@
'test/simple_test_tick_clock.h',
'test/task_runner_test_template.cc',
'test/task_runner_test_template.h',
- 'test/test_discardable_memory_shmem_allocator.cc',
- 'test/test_discardable_memory_shmem_allocator.h',
+ 'test/test_discardable_memory_allocator.cc',
+ 'test/test_discardable_memory_allocator.h',
'test/test_file_util.cc',
'test/test_file_util.h',
'test/test_file_util_android.cc',
diff --git a/base/base.gypi b/base/base.gypi
index 13cba85..825bca1 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -3,6 +3,9 @@
# found in the LICENSE file.
{
+ 'includes': [
+ 'trace_event/trace_event.gypi',
+ ],
'target_defaults': {
'variables': {
'base_target': 0,
@@ -318,10 +321,8 @@
'memory/aligned_memory.h',
'memory/discardable_memory.cc',
'memory/discardable_memory.h',
- 'memory/discardable_memory_shmem.cc',
- 'memory/discardable_memory_shmem.h',
- 'memory/discardable_memory_shmem_allocator.cc',
- 'memory/discardable_memory_shmem_allocator.h',
+ 'memory/discardable_memory_allocator.cc',
+ 'memory/discardable_memory_allocator.h',
'memory/discardable_shared_memory.cc',
'memory/discardable_shared_memory.h',
'memory/linked_ptr.h',
@@ -487,6 +488,10 @@
'profiler/scoped_profile.h',
'profiler/scoped_tracker.cc',
'profiler/scoped_tracker.h',
+ 'profiler/stack_sampling_profiler.cc',
+ 'profiler/stack_sampling_profiler.h',
+ 'profiler/stack_sampling_profiler_posix.cc',
+ 'profiler/stack_sampling_profiler_win.cc',
'profiler/tracked_time.cc',
'profiler/tracked_time.h',
'rand_util.cc',
@@ -602,6 +607,8 @@
'threading/non_thread_safe_impl.h',
'threading/platform_thread.h',
'threading/platform_thread_android.cc',
+ 'threading/platform_thread_internal_posix.cc',
+ 'threading/platform_thread_internal_posix.h',
'threading/platform_thread_linux.cc',
'threading/platform_thread_mac.mm',
'threading/platform_thread_posix.cc',
@@ -660,34 +667,6 @@
'timer/mock_timer.h',
'timer/timer.cc',
'timer/timer.h',
- 'trace_event/memory_dump_manager.cc',
- 'trace_event/memory_dump_manager.h',
- 'trace_event/memory_dump_provider.h',
- 'trace_event/process_memory_dump.cc',
- 'trace_event/process_memory_dump.h',
- 'trace_event/process_memory_maps.cc',
- 'trace_event/process_memory_maps.h',
- 'trace_event/process_memory_maps_dump_provider.cc',
- 'trace_event/process_memory_maps_dump_provider.h',
- 'trace_event/process_memory_totals.cc',
- 'trace_event/process_memory_totals.h',
- 'trace_event/process_memory_totals_dump_provider.cc',
- 'trace_event/process_memory_totals_dump_provider.h',
- 'trace_event/trace_event.h',
- 'trace_event/trace_event_android.cc',
- 'trace_event/trace_event_argument.cc',
- 'trace_event/trace_event_argument.h',
- 'trace_event/trace_event_impl.cc',
- 'trace_event/trace_event_impl.h',
- 'trace_event/trace_event_impl_constants.cc',
- 'trace_event/trace_event_memory.cc',
- 'trace_event/trace_event_memory.h',
- 'trace_event/trace_event_synthetic_delay.cc',
- 'trace_event/trace_event_synthetic_delay.h',
- 'trace_event/trace_event_system_stats_monitor.cc',
- 'trace_event/trace_event_system_stats_monitor.h',
- 'trace_event/trace_event_win.cc',
- 'trace_event/trace_event_win.h',
'tracked_objects.cc',
'tracked_objects.h',
'tracking_info.cc',
@@ -750,6 +729,7 @@
'win/windows_version.h',
'win/wrapped_window_proc.cc',
'win/wrapped_window_proc.h',
+ '<@(trace_event_sources)',
],
'defines': [
'BASE_IMPLEMENTATION',
@@ -896,6 +876,7 @@
['include', '^process/.*_ios\.(cc|mm)$'],
['include', '^process/memory_stubs\.cc$'],
['include', '^process/process_handle_posix\.cc$'],
+ ['exclude', '^threading/platform_thread_internal_posix\\.(h|cc)'],
['exclude', 'files/file_path_watcher_fsevents.cc'],
['exclude', 'files/file_path_watcher_fsevents.h'],
['include', 'files/file_path_watcher_mac.cc'],
@@ -963,10 +944,11 @@
}],
['(OS == "mac" or OS == "ios") and >(nacl_untrusted_build)==0', {
'sources/': [
- ['exclude', '^files/file_path_watcher_stub\\.cc$'],
['exclude', '^base_paths_posix\\.cc$'],
+ ['exclude', '^files/file_path_watcher_stub\\.cc$'],
['exclude', '^native_library_posix\\.cc$'],
['exclude', '^strings/sys_string_conversions_posix\\.cc$'],
+ ['exclude', '^threading/platform_thread_internal_posix\\.cc$'],
],
}],
['<(os_bsd)==1 and >(nacl_untrusted_build)==0', {
diff --git a/base/files/file.h b/base/files/file.h
index 7b6366c..13c8a96 100644
--- a/base/files/file.h
+++ b/base/files/file.h
@@ -128,9 +128,9 @@
// Used to hold information about a given file.
// If you add more fields to this structure (platform-specific fields are OK),
- // make sure to update all functions that use it in file_util_{win|posix}.cc
- // too, and the ParamTraits<base::PlatformFileInfo> implementation in
- // chrome/common/common_param_traits.cc.
+ // make sure to update all functions that use it in file_util_{win|posix}.cc,
+ // too, and the ParamTraits<base::File::Info> implementation in
+ // ipc/ipc_message_utils.cc.
struct BASE_EXPORT Info {
Info();
~Info();
@@ -145,7 +145,8 @@
// True if the file corresponds to a directory.
bool is_directory;
- // True if the file corresponds to a symbolic link.
+ // True if the file corresponds to a symbolic link. For Windows currently
+ // not supported and thus always false.
bool is_symbolic_link;
// The last modified time of a file.
@@ -287,6 +288,13 @@
// Unlock a file previously locked.
Error Unlock();
+ // Returns a new object referencing this file for use within the current
+ // process. Handling of FLAG_DELETE_ON_CLOSE varies by OS. On POSIX, the File
+ // object that was created or initialized with this flag will have unlinked
+ // the underlying file when it was created or opened. On Windows, the
+ // underlying file is deleted when the last handle to it is closed.
+ File Duplicate();
+
bool async() const { return async_; }
#if defined(OS_WIN)
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 663f099..517390f 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -463,6 +463,20 @@
return CallFctnlFlock(file_.get(), false);
}
+File File::Duplicate() {
+ if (!IsValid())
+ return File();
+
+ PlatformFile other_fd = dup(GetPlatformFile());
+ if (other_fd == -1)
+ return File(OSErrorToFileError(errno));
+
+ File other(other_fd);
+ if (async())
+ other.async_ = true;
+ return other.Pass();
+}
+
// Static.
File::Error File::OSErrorToFileError(int saved_errno) {
switch (saved_errno) {
diff --git a/base/files/file_unittest.cc b/base/files/file_unittest.cc
index 3bc2db6..5c59424 100644
--- a/base/files/file_unittest.cc
+++ b/base/files/file_unittest.cc
@@ -443,6 +443,49 @@
EXPECT_EQ(kOffset, file.Seek(base::File::FROM_END, -kOffset));
}
+TEST(FileTest, Duplicate) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath file_path = temp_dir.path().AppendASCII("file");
+ File file(file_path,(base::File::FLAG_CREATE |
+ base::File::FLAG_READ |
+ base::File::FLAG_WRITE));
+ ASSERT_TRUE(file.IsValid());
+
+ File file2(file.Duplicate());
+ ASSERT_TRUE(file2.IsValid());
+
+ // Write through one handle, close it, read through the other.
+ static const char kData[] = "now is a good time.";
+ static const int kDataLen = sizeof(kData) - 1;
+
+ ASSERT_EQ(0, file.Seek(base::File::FROM_CURRENT, 0));
+ ASSERT_EQ(0, file2.Seek(base::File::FROM_CURRENT, 0));
+ ASSERT_EQ(kDataLen, file.WriteAtCurrentPos(kData, kDataLen));
+ ASSERT_EQ(kDataLen, file.Seek(base::File::FROM_CURRENT, 0));
+ ASSERT_EQ(kDataLen, file2.Seek(base::File::FROM_CURRENT, 0));
+ file.Close();
+ char buf[kDataLen];
+ ASSERT_EQ(kDataLen, file2.Read(0, &buf[0], kDataLen));
+ ASSERT_EQ(std::string(kData, kDataLen), std::string(&buf[0], kDataLen));
+}
+
+TEST(FileTest, DuplicateDeleteOnClose) {
+ base::ScopedTempDir temp_dir;
+ ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
+ FilePath file_path = temp_dir.path().AppendASCII("file");
+ File file(file_path,(base::File::FLAG_CREATE |
+ base::File::FLAG_READ |
+ base::File::FLAG_WRITE |
+ base::File::FLAG_DELETE_ON_CLOSE));
+ ASSERT_TRUE(file.IsValid());
+ File file2(file.Duplicate());
+ ASSERT_TRUE(file2.IsValid());
+ file.Close();
+ file2.Close();
+ ASSERT_FALSE(base::PathExists(file_path));
+}
+
#if defined(OS_WIN)
TEST(FileTest, GetInfoForDirectory) {
base::ScopedTempDir temp_dir;
diff --git a/base/files/file_win.cc b/base/files/file_win.cc
index 727b5ce..9f3033c 100644
--- a/base/files/file_win.cc
+++ b/base/files/file_win.cc
@@ -309,6 +309,28 @@
return FILE_OK;
}
+File File::Duplicate() {
+ if (!IsValid())
+ return File();
+
+ HANDLE other_handle = nullptr;
+
+ if (!::DuplicateHandle(GetCurrentProcess(), // hSourceProcessHandle
+ GetPlatformFile(),
+ GetCurrentProcess(), // hTargetProcessHandle
+ &other_handle,
+ 0, // dwDesiredAccess ignored due to SAME_ACCESS
+ FALSE, // !bInheritHandle
+ DUPLICATE_SAME_ACCESS)) {
+ return File(OSErrorToFileError(GetLastError()));
+ }
+
+ File other(other_handle);
+ if (async())
+ other.async_ = true;
+ return other.Pass();
+}
+
// Static.
File::Error File::OSErrorToFileError(DWORD last_error) {
switch (last_error) {
diff --git a/base/memory/BUILD.gn b/base/memory/BUILD.gn
index 3d4c22c..a0608e8 100644
--- a/base/memory/BUILD.gn
+++ b/base/memory/BUILD.gn
@@ -8,10 +8,8 @@
"aligned_memory.h",
"discardable_memory.cc",
"discardable_memory.h",
- "discardable_memory_shmem.cc",
- "discardable_memory_shmem.h",
- "discardable_memory_shmem_allocator.cc",
- "discardable_memory_shmem_allocator.h",
+ "discardable_memory_allocator.cc",
+ "discardable_memory_allocator.h",
"discardable_shared_memory.cc",
"discardable_shared_memory.h",
"linked_ptr.h",
@@ -42,10 +40,8 @@
sources -= [
"discardable_memory.cc",
"discardable_memory.h",
- "discardable_memory_shmem.cc",
- "discardable_memory_shmem.h",
- "discardable_memory_shmem_allocator.cc",
- "discardable_memory_shmem_allocator.h",
+ "discardable_memory_allocator.cc",
+ "discardable_memory_allocator.h",
"discardable_shared_memory.cc",
"discardable_shared_memory.h",
"shared_memory_posix.cc",
diff --git a/base/memory/discardable_memory.cc b/base/memory/discardable_memory.cc
index 0e3b58a..d50f185 100644
--- a/base/memory/discardable_memory.cc
+++ b/base/memory/discardable_memory.cc
@@ -4,14 +4,12 @@
#include "base/memory/discardable_memory.h"
-#include "base/memory/discardable_memory_shmem.h"
-
namespace base {
-// static
-scoped_ptr<DiscardableMemory> DiscardableMemory::CreateLockedMemory(
- size_t size) {
- return make_scoped_ptr(new internal::DiscardableMemoryShmem(size));
+DiscardableMemory::DiscardableMemory() {
+}
+
+DiscardableMemory::~DiscardableMemory() {
}
} // namespace base
diff --git a/base/memory/discardable_memory.h b/base/memory/discardable_memory.h
index ce0f0bb..a0882cc 100644
--- a/base/memory/discardable_memory.h
+++ b/base/memory/discardable_memory.h
@@ -5,26 +5,24 @@
#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_H_
#define BASE_MEMORY_DISCARDABLE_MEMORY_H_
-#include <string>
-#include <vector>
-
#include "base/base_export.h"
#include "base/basictypes.h"
#include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
namespace base {
-// Platform abstraction for discardable memory. DiscardableMemory is used to
-// cache large objects without worrying about blowing out memory, both on mobile
-// devices where there is no swap, and desktop devices where unused free memory
-// should be used to help the user experience. This is preferable to releasing
-// memory in response to an OOM signal because it is simpler, though it has less
-// flexibility as to which objects get discarded.
+// Discardable memory is used to cache large objects without worrying about
+// blowing out memory, both on mobile devices where there is no swap, and
+// desktop devices where unused free memory should be used to help the user
+// experience. This is preferable to releasing memory in response to an OOM
+// signal because it is simpler and provides system-wide management of
+// purgable memory, though it has less flexibility as to which objects get
+// discarded.
//
// Discardable memory has two states: locked and unlocked. While the memory is
-// locked, it will not be discarded. Unlocking the memory allows the OS to
-// reclaim it if needed. Locks do not nest.
+// locked, it will not be discarded. Unlocking the memory allows the
+// discardable memory system and the OS to reclaim it if needed. Locks do not
+// nest.
//
// Notes:
// - The paging behavior of memory while it is locked is not specified. While
@@ -39,19 +37,10 @@
// responsibility of users of discardable memory to ensure there are no
// races.
//
-// References:
-// - Linux: http://lwn.net/Articles/452035/
-// - Mac: http://trac.webkit.org/browser/trunk/Source/WebCore/platform/mac/PurgeableBufferMac.cpp
-// the comment starting with "vm_object_purgable_control" at
-// http://www.opensource.apple.com/source/xnu/xnu-792.13.8/osfmk/vm/vm_object.c
-//
-// Thread-safety: DiscardableMemory instances are not thread-safe.
class BASE_EXPORT DiscardableMemory {
public:
- virtual ~DiscardableMemory() {}
-
- // Create a DiscardableMemory instance with |size|.
- static scoped_ptr<DiscardableMemory> CreateLockedMemory(size_t size);
+ DiscardableMemory();
+ virtual ~DiscardableMemory();
// Locks the memory so that it will not be purged by the system. Returns
// true on success. If the return value is false then this object should be
diff --git a/base/memory/discardable_memory_allocator.cc b/base/memory/discardable_memory_allocator.cc
new file mode 100644
index 0000000..002a3ba
--- /dev/null
+++ b/base/memory/discardable_memory_allocator.cc
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/memory/discardable_memory_allocator.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace {
+
+DiscardableMemoryAllocator* g_allocator = nullptr;
+
+} // namespace
+
+// static
+void DiscardableMemoryAllocator::SetInstance(
+ DiscardableMemoryAllocator* allocator) {
+ DCHECK(allocator);
+
+ // Make sure this function is only called once before the first call
+ // to GetInstance().
+ DCHECK(!g_allocator);
+
+ g_allocator = allocator;
+}
+
+// static
+DiscardableMemoryAllocator* DiscardableMemoryAllocator::GetInstance() {
+ DCHECK(g_allocator);
+ return g_allocator;
+}
+
+} // namespace base
diff --git a/base/memory/discardable_memory_allocator.h b/base/memory/discardable_memory_allocator.h
new file mode 100644
index 0000000..400f87a
--- /dev/null
+++ b/base/memory/discardable_memory_allocator.h
@@ -0,0 +1,32 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include "base/base_export.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class DiscardableMemory;
+
+class BASE_EXPORT DiscardableMemoryAllocator {
+ public:
+ // Returns the allocator instance.
+ static DiscardableMemoryAllocator* GetInstance();
+
+ // Sets the allocator instance. Can only be called once, e.g. on startup.
+ // Ownership of |instance| remains with the caller.
+ static void SetInstance(DiscardableMemoryAllocator* allocator);
+
+ virtual scoped_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+ size_t size) = 0;
+
+ protected:
+ virtual ~DiscardableMemoryAllocator() {}
+};
+
+} // namespace base
+
+#endif // BASE_MEMORY_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/base/memory/discardable_memory_shmem.cc b/base/memory/discardable_memory_shmem.cc
deleted file mode 100644
index 059d84c..0000000
--- a/base/memory/discardable_memory_shmem.cc
+++ /dev/null
@@ -1,50 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/discardable_memory_shmem.h"
-
-#include "base/lazy_instance.h"
-#include "base/memory/discardable_memory_shmem_allocator.h"
-
-namespace base {
-namespace internal {
-
-DiscardableMemoryShmem::DiscardableMemoryShmem(size_t bytes)
- : chunk_(DiscardableMemoryShmemAllocator::GetInstance()
- ->AllocateLockedDiscardableMemory(bytes)),
- is_locked_(true) {
- DCHECK(chunk_);
-}
-
-DiscardableMemoryShmem::~DiscardableMemoryShmem() {
- if (is_locked_)
- Unlock();
-}
-
-bool DiscardableMemoryShmem::Lock() {
- DCHECK(!is_locked_);
- DCHECK(chunk_);
-
- if (!chunk_->Lock()) {
- chunk_.reset();
- return false;
- }
-
- is_locked_ = true;
- return true;
-}
-
-void DiscardableMemoryShmem::Unlock() {
- DCHECK(is_locked_);
- chunk_->Unlock();
- is_locked_ = false;
-}
-
-void* DiscardableMemoryShmem::Memory() const {
- DCHECK(is_locked_);
- return chunk_->Memory();
-}
-
-} // namespace internal
-} // namespace base
diff --git a/base/memory/discardable_memory_shmem.h b/base/memory/discardable_memory_shmem.h
deleted file mode 100644
index f394562..0000000
--- a/base/memory/discardable_memory_shmem.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_H_
-
-#include "base/memory/discardable_memory.h"
-
-namespace base {
-class DiscardableMemoryShmemChunk;
-
-namespace internal {
-
-class DiscardableMemoryShmem : public DiscardableMemory {
- public:
- explicit DiscardableMemoryShmem(size_t bytes);
- ~DiscardableMemoryShmem() override;
-
- bool Initialize();
-
- // Overridden from DiscardableMemory:
- bool Lock() override;
- void Unlock() override;
- void* Memory() const override;
-
- private:
- scoped_ptr<DiscardableMemoryShmemChunk> chunk_;
- bool is_locked_;
-
- DISALLOW_COPY_AND_ASSIGN(DiscardableMemoryShmem);
-};
-
-} // namespace internal
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_H_
diff --git a/base/memory/discardable_memory_shmem_allocator.cc b/base/memory/discardable_memory_shmem_allocator.cc
deleted file mode 100644
index a87c58d..0000000
--- a/base/memory/discardable_memory_shmem_allocator.cc
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/memory/discardable_memory_shmem_allocator.h"
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/memory/discardable_shared_memory.h"
-
-namespace base {
-namespace {
-
-DiscardableMemoryShmemAllocator* g_allocator = nullptr;
-
-} // namespace
-
-// static
-void DiscardableMemoryShmemAllocator::SetInstance(
- DiscardableMemoryShmemAllocator* allocator) {
- DCHECK(allocator);
-
- // Make sure this function is only called once before the first call
- // to GetInstance().
- DCHECK(!g_allocator);
-
- g_allocator = allocator;
-}
-
-// static
-DiscardableMemoryShmemAllocator*
-DiscardableMemoryShmemAllocator::GetInstance() {
- DCHECK(g_allocator);
- return g_allocator;
-}
-
-} // namespace base
diff --git a/base/memory/discardable_memory_shmem_allocator.h b/base/memory/discardable_memory_shmem_allocator.h
deleted file mode 100644
index ac4118e..0000000
--- a/base/memory/discardable_memory_shmem_allocator.h
+++ /dev/null
@@ -1,42 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
-#define BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
-
-#include "base/base_export.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace base {
-
-// TODO(reveman): Remove this by having allocator interface return
-// real DiscardableMemory instances. crbug.com/442945
-class BASE_EXPORT DiscardableMemoryShmemChunk {
- public:
- virtual ~DiscardableMemoryShmemChunk() {}
-
- virtual bool Lock() = 0;
- virtual void Unlock() = 0;
- virtual void* Memory() const = 0;
-};
-
-class BASE_EXPORT DiscardableMemoryShmemAllocator {
- public:
- // Returns the allocator instance.
- static DiscardableMemoryShmemAllocator* GetInstance();
-
- // Sets the allocator instance. Can only be called once, e.g. on startup.
- // Ownership of |instance| remains with the caller.
- static void SetInstance(DiscardableMemoryShmemAllocator* allocator);
-
- virtual scoped_ptr<DiscardableMemoryShmemChunk>
- AllocateLockedDiscardableMemory(size_t size) = 0;
-
- protected:
- virtual ~DiscardableMemoryShmemAllocator() {}
-};
-
-} // namespace base
-
-#endif // BASE_MEMORY_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
diff --git a/base/message_loop/message_loop.cc b/base/message_loop/message_loop.cc
index daa7782..eb0f968 100644
--- a/base/message_loop/message_loop.cc
+++ b/base/message_loop/message_loop.cc
@@ -275,31 +275,27 @@
void MessageLoop::PostTask(
const tracked_objects::Location& from_here,
const Closure& task) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), true);
+ message_loop_proxy_->PostTask(from_here, task);
}
void MessageLoop::PostDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, true);
+ message_loop_proxy_->PostDelayedTask(from_here, task, delay);
}
void MessageLoop::PostNonNestableTask(
const tracked_objects::Location& from_here,
const Closure& task) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, TimeDelta(), false);
+ message_loop_proxy_->PostNonNestableTask(from_here, task);
}
void MessageLoop::PostNonNestableDelayedTask(
const tracked_objects::Location& from_here,
const Closure& task,
TimeDelta delay) {
- DCHECK(!task.is_null()) << from_here.ToString();
- incoming_task_queue_->AddToIncomingQueue(from_here, task, delay, false);
+ message_loop_proxy_->PostNonNestableDelayedTask(from_here, task, delay);
}
void MessageLoop::Run() {
diff --git a/base/message_loop/message_loop.h b/base/message_loop/message_loop.h
index 7c76616..fd7596a 100644
--- a/base/message_loop/message_loop.h
+++ b/base/message_loop/message_loop.h
@@ -155,6 +155,9 @@
// DestructionObserver is receiving a notification callback.
void RemoveDestructionObserver(DestructionObserver* destruction_observer);
+ // NOTE: Deprecated; prefer task_runner() and the TaskRunner interfaces.
+ // TODO(skyostil): Remove these functions (crbug.com/465354).
+ //
// The "PostTask" family of methods call the task's Run method asynchronously
// from within a message loop at some point in the future.
//
@@ -300,6 +303,8 @@
}
// Gets the TaskRunner associated with this message loop.
+ // TODO(skyostil): Change this to return a const reference to a refptr
+ // once the internal type matches what is being returned (crbug.com/465354).
scoped_refptr<SingleThreadTaskRunner> task_runner() {
return message_loop_proxy_;
}
diff --git a/base/profiler/stack_sampling_profiler.cc b/base/profiler/stack_sampling_profiler.cc
new file mode 100644
index 0000000..57b7b35
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler.cc
@@ -0,0 +1,261 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/stack_sampling_profiler.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "base/memory/singleton.h"
+#include "base/synchronization/lock.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/timer/elapsed_timer.h"
+
+template <typename T> struct DefaultSingletonTraits;
+
+namespace base {
+
+namespace {
+
+// Thread-safe singleton class that stores collected profiles waiting to be
+// processed.
+class PendingProfiles {
+ public:
+ PendingProfiles();
+ ~PendingProfiles();
+
+ static PendingProfiles* GetInstance();
+
+ // Appends |profiles|. This function is thread safe.
+ void PutProfiles(const std::vector<StackSamplingProfiler::Profile>& profiles);
+ // Gets the pending profiles into *|profiles|. This function is thread safe.
+ void GetProfiles(std::vector<StackSamplingProfiler::Profile>* profiles);
+
+ private:
+ Lock profiles_lock_;
+ std::vector<StackSamplingProfiler::Profile> profiles_;
+
+ DISALLOW_COPY_AND_ASSIGN(PendingProfiles);
+};
+
+PendingProfiles::PendingProfiles() {}
+
+PendingProfiles::~PendingProfiles() {}
+
+// static
+PendingProfiles* PendingProfiles::GetInstance() {
+ return Singleton<PendingProfiles>::get();
+}
+
+void PendingProfiles::PutProfiles(
+ const std::vector<StackSamplingProfiler::Profile>& profiles) {
+ AutoLock scoped_lock(profiles_lock_);
+ profiles_.insert(profiles_.end(), profiles.begin(), profiles.end());
+}
+
+void PendingProfiles::GetProfiles(
+ std::vector<StackSamplingProfiler::Profile>* profiles) {
+ profiles->clear();
+
+ AutoLock scoped_lock(profiles_lock_);
+ profiles_.swap(*profiles);
+}
+} // namespace
+
+StackSamplingProfiler::Module::Module() : base_address(nullptr) {}
+
+StackSamplingProfiler::Module::~Module() {}
+
+StackSamplingProfiler::Frame::Frame()
+ : instruction_pointer(nullptr),
+ module_index(-1) {}
+
+StackSamplingProfiler::Frame::~Frame() {}
+
+StackSamplingProfiler::Profile::Profile() : preserve_sample_ordering(false) {}
+
+StackSamplingProfiler::Profile::~Profile() {}
+
+class StackSamplingProfiler::SamplingThread : public PlatformThread::Delegate {
+ public:
+ // Samples stacks using |native_sampler|. When complete, invokes
+ // |profiles_callback| with the collected profiles. |profiles_callback| must
+ // be thread-safe and may consume the contents of the vector.
+ SamplingThread(
+ scoped_ptr<NativeStackSampler> native_sampler,
+ const SamplingParams& params,
+ Callback<void(const std::vector<Profile>&)> completed_callback);
+ ~SamplingThread() override;
+
+ // Implementation of PlatformThread::Delegate:
+ void ThreadMain() override;
+
+ void Stop();
+
+ private:
+ // Collects a profile from a single burst. Returns true if the profile was
+ // collected, or false if collection was stopped before it completed.
+ bool CollectProfile(Profile* profile, TimeDelta* elapsed_time);
+ // Collects profiles from all bursts, or until the sampling is stopped. If
+ // stopped before complete, |profiles| will contains only full bursts.
+ void CollectProfiles(std::vector<Profile>* profiles);
+
+ scoped_ptr<NativeStackSampler> native_sampler_;
+
+ const SamplingParams params_;
+
+ WaitableEvent stop_event_;
+
+ Callback<void(const std::vector<Profile>&)> completed_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(SamplingThread);
+};
+
+StackSamplingProfiler::SamplingThread::SamplingThread(
+ scoped_ptr<NativeStackSampler> native_sampler,
+ const SamplingParams& params,
+ Callback<void(const std::vector<Profile>&)> completed_callback)
+ : native_sampler_(native_sampler.Pass()),
+ params_(params),
+ stop_event_(false, false),
+ completed_callback_(completed_callback) {
+}
+
+StackSamplingProfiler::SamplingThread::~SamplingThread() {}
+
+void StackSamplingProfiler::SamplingThread::ThreadMain() {
+ PlatformThread::SetName("Chrome_SamplingProfilerThread");
+
+ std::vector<Profile> profiles;
+ CollectProfiles(&profiles);
+ completed_callback_.Run(profiles);
+}
+
+bool StackSamplingProfiler::SamplingThread::CollectProfile(
+ Profile* profile,
+ TimeDelta* elapsed_time) {
+ ElapsedTimer profile_timer;
+ Profile current_profile;
+ native_sampler_->ProfileRecordingStarting(¤t_profile);
+ current_profile.sampling_period = params_.sampling_interval;
+ bool stopped_early = false;
+ for (int i = 0; i < params_.samples_per_burst; ++i) {
+ ElapsedTimer sample_timer;
+ current_profile.samples.push_back(Sample());
+ native_sampler_->RecordStackSample(¤t_profile.samples.back());
+ TimeDelta elapsed_sample_time = sample_timer.Elapsed();
+ if (i != params_.samples_per_burst - 1) {
+ if (stop_event_.TimedWait(
+ std::max(params_.sampling_interval - elapsed_sample_time,
+ TimeDelta()))) {
+ stopped_early = true;
+ break;
+ }
+ }
+ }
+
+ *elapsed_time = profile_timer.Elapsed();
+ current_profile.profile_duration = *elapsed_time;
+ native_sampler_->ProfileRecordingStopped();
+
+ if (!stopped_early)
+ *profile = current_profile;
+
+ return !stopped_early;
+}
+
+void StackSamplingProfiler::SamplingThread::CollectProfiles(
+ std::vector<Profile>* profiles) {
+ if (stop_event_.TimedWait(params_.initial_delay))
+ return;
+
+ for (int i = 0; i < params_.bursts; ++i) {
+ Profile profile;
+ TimeDelta elapsed_profile_time;
+ if (CollectProfile(&profile, &elapsed_profile_time))
+ profiles->push_back(profile);
+ else
+ return;
+
+ if (stop_event_.TimedWait(
+ std::max(params_.burst_interval - elapsed_profile_time,
+ TimeDelta())))
+ return;
+ }
+}
+
+void StackSamplingProfiler::SamplingThread::Stop() {
+ stop_event_.Signal();
+}
+
+void StackSamplingProfiler::SamplingThreadDeleter::operator()(
+ SamplingThread* thread) const {
+ delete thread;
+}
+
+StackSamplingProfiler::NativeStackSampler::NativeStackSampler() {}
+
+StackSamplingProfiler::NativeStackSampler::~NativeStackSampler() {}
+
+StackSamplingProfiler::SamplingParams::SamplingParams()
+ : initial_delay(TimeDelta::FromMilliseconds(0)),
+ bursts(1),
+ burst_interval(TimeDelta::FromMilliseconds(10000)),
+ samples_per_burst(300),
+ sampling_interval(TimeDelta::FromMilliseconds(100)),
+ preserve_sample_ordering(false) {
+}
+
+StackSamplingProfiler::StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params)
+ : thread_id_(thread_id), params_(params) {}
+
+StackSamplingProfiler::~StackSamplingProfiler() {}
+
+void StackSamplingProfiler::Start() {
+ native_sampler_ = NativeStackSampler::Create(thread_id_);
+ if (!native_sampler_)
+ return;
+
+ sampling_thread_.reset(
+ new SamplingThread(
+ native_sampler_.Pass(), params_,
+ (custom_completed_callback_.is_null() ?
+ Bind(&PendingProfiles::PutProfiles,
+ Unretained(PendingProfiles::GetInstance())) :
+ custom_completed_callback_)));
+ if (!PlatformThread::CreateNonJoinable(0, sampling_thread_.get()))
+ LOG(ERROR) << "failed to create thread";
+}
+
+void StackSamplingProfiler::Stop() {
+ if (sampling_thread_)
+ sampling_thread_->Stop();
+}
+
+// static
+void StackSamplingProfiler::GetPendingProfiles(std::vector<Profile>* profiles) {
+ PendingProfiles::GetInstance()->GetProfiles(profiles);
+}
+
+void StackSamplingProfiler::SetCustomCompletedCallback(
+ Callback<void(const std::vector<Profile>&)> callback) {
+ custom_completed_callback_ = callback;
+}
+
+bool operator==(const StackSamplingProfiler::Frame &a,
+ const StackSamplingProfiler::Frame &b) {
+ return a.instruction_pointer == b.instruction_pointer &&
+ a.module_index == b.module_index;
+}
+
+bool operator<(const StackSamplingProfiler::Frame &a,
+ const StackSamplingProfiler::Frame &b) {
+ return (a.module_index < b.module_index) ||
+ (a.module_index == b.module_index &&
+ a.instruction_pointer < b.instruction_pointer);
+}
+
+} // namespace base
diff --git a/base/profiler/stack_sampling_profiler.h b/base/profiler/stack_sampling_profiler.h
new file mode 100644
index 0000000..8d7671e
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler.h
@@ -0,0 +1,206 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
+#define BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/base_export.h"
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string16.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+
+namespace base {
+
+// StackSamplingProfiler periodically stops a thread to sample its stack, for
+// the purpose of collecting information about which code paths are
+// executing. This information is used in aggregate by UMA to identify hot
+// and/or janky code paths.
+//
+// Sample StackStackSamplingProfiler usage:
+//
+// // Create and customize params as desired.
+// base::StackStackSamplingProfiler::SamplingParams params;
+// // Any thread's ID may be passed as the target.
+// base::StackSamplingProfiler profiler(base::PlatformThread::CurrentId()),
+// params);
+//
+// // To process the profiles within Chrome rather than via UMA, set a custom
+// // completed callback:
+// base::Callback<void(const std::vector<Profile>&)>
+// thread_safe_callback = ...;
+// profiler.SetCustomCompletedCallback(thread_safe_callback);
+//
+// profiler.Start();
+// // ... work being done on the target thread here ...
+// profiler.Stop(); // optional, stops collection before complete per params
+//
+// When all profiles are complete or the profiler is stopped, if the custom
+// completed callback was set it will be called from the profiler thread with
+// the completed profiles. If no callback was set, the profiles are stored
+// internally and retrieved for UMA through
+// GetPendingProfiles(). GetPendingProfiles() should never be called by other
+// code; to retrieve profiles for in-process processing, set a completed
+// callback.
+class BASE_EXPORT StackSamplingProfiler {
+ public:
+ // Module represents the module (DLL or exe) corresponding to a stack frame.
+ struct BASE_EXPORT Module {
+ Module();
+ ~Module();
+
+ // Points to the base address of the module.
+ const void* base_address;
+ // An opaque binary string that uniquely identifies a particular program
+ // version with high probability. This is parsed from headers of the loaded
+ // module.
+ // For binaries generated by GNU tools:
+ // Contents of the .note.gnu.build-id field.
+ // On Windows:
+ // GUID + AGE in the debug image headers of a module.
+ std::string id;
+ // The filename of the module.
+ FilePath filename;
+ };
+
+ // Frame represents an individual sampled stack frame with module information.
+ struct BASE_EXPORT Frame {
+ Frame();
+ ~Frame();
+
+ // The sampled instruction pointer within the function.
+ const void* instruction_pointer;
+ // Index of the module in the array of modules. We don't represent module
+ // state directly here to save space.
+ int module_index;
+ };
+
+ // Sample represents a set of stack frames.
+ using Sample = std::vector<Frame>;
+
+ // Profile represents a set of samples.
+ struct BASE_EXPORT Profile {
+ Profile();
+ ~Profile();
+
+ std::vector<Module> modules;
+ std::vector<Sample> samples;
+ // Duration of this profile.
+ TimeDelta profile_duration;
+ // Time between samples.
+ TimeDelta sampling_period;
+ // True if sample ordering is important and should be preserved if and when
+ // this profile is compressed and processed.
+ bool preserve_sample_ordering;
+ };
+
+ // NativeStackSampler abstracts the native implementation required to record a
+ // stack sample for a given thread.
+ class NativeStackSampler {
+ public:
+ virtual ~NativeStackSampler();
+
+ // Create a stack sampler that records samples for |thread_handle|. Returns
+ // null if this platform does not support stack sampling.
+ static scoped_ptr<NativeStackSampler> Create(PlatformThreadId thread_id);
+
+ // Notify the sampler that we're starting to record a new profile. This
+ // function is called on the SamplingThread.
+ virtual void ProfileRecordingStarting(Profile* profile) = 0;
+
+ // Record a stack sample. This function is called on the SamplingThread.
+ virtual void RecordStackSample(Sample* sample) = 0;
+
+ // Notify the sampler that we've stopped recording the current profile. This
+ // function is called on the SamplingThread.
+ virtual void ProfileRecordingStopped() = 0;
+
+ protected:
+ NativeStackSampler();
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(NativeStackSampler);
+ };
+
+ // Represents parameters that configure the sampling.
+ struct BASE_EXPORT SamplingParams {
+ SamplingParams();
+
+ // Time to delay before first samples are taken. Defaults to 0.
+ TimeDelta initial_delay;
+ // Number of sampling bursts to perform. Defaults to 1.
+ int bursts;
+ // Interval between sampling bursts. This is the desired duration from the
+ // start of one burst to the start of the next burst. Defaults to 10s.
+ TimeDelta burst_interval;
+ // Number of samples to record per burst. Defaults to 300.
+ int samples_per_burst;
+ // Interval between samples during a sampling burst. This is the desired
+ // duration from the start of one burst to the start of the next
+ // burst. Defaults to 100ms.
+ TimeDelta sampling_interval;
+ // True if sample ordering is important and should be preserved if and when
+ // this profile is compressed and processed. Defaults to false.
+ bool preserve_sample_ordering;
+ };
+
+ StackSamplingProfiler(PlatformThreadId thread_id,
+ const SamplingParams& params);
+ ~StackSamplingProfiler();
+
+ // Initializes the profiler and starts sampling.
+ void Start();
+ // Stops the profiler and any ongoing sampling. Calling this function is
+ // optional; if not invoked profiling will terminate when all the profiling
+ // bursts specified in the SamplingParams are completed.
+ void Stop();
+
+ // Gets the pending profiles into *|profiles| and clears the internal
+ // storage. This function is thread safe.
+ //
+ // ***This is intended for use only by UMA.*** Callers who want to process the
+ // collected profiles should use SetCustomCompletedCallback.
+ static void GetPendingProfiles(std::vector<Profile>* profiles);
+
+ // By default, collected profiles are stored internally and can be retrieved
+ // by GetPendingProfiles. If a callback is provided via this function,
+ // however, it will be called with the collected profiles instead. Note that
+ // this call to the callback occurs *on the profiler thread*.
+ void SetCustomCompletedCallback(
+ Callback<void(const std::vector<Profile>&)> callback);
+
+ private:
+ class SamplingThread;
+ struct SamplingThreadDeleter {
+ void operator() (SamplingThread* thread) const;
+ };
+
+ // The thread whose stack will be sampled.
+ PlatformThreadId thread_id_;
+
+ const SamplingParams params_;
+
+ scoped_ptr<SamplingThread, SamplingThreadDeleter> sampling_thread_;
+ scoped_ptr<NativeStackSampler> native_sampler_;
+
+ Callback<void(const std::vector<Profile>&)> custom_completed_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(StackSamplingProfiler);
+};
+
+// Defined to allow equality check of Samples.
+BASE_EXPORT bool operator==(const StackSamplingProfiler::Frame& a,
+ const StackSamplingProfiler::Frame& b);
+// Defined to allow ordering of Samples.
+BASE_EXPORT bool operator<(const StackSamplingProfiler::Frame& a,
+ const StackSamplingProfiler::Frame& b);
+
+} // namespace base
+
+#endif // BASE_PROFILER_STACK_SAMPLING_PROFILER_H_
diff --git a/base/profiler/stack_sampling_profiler_posix.cc b/base/profiler/stack_sampling_profiler_posix.cc
new file mode 100644
index 0000000..6a44d7e
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_posix.cc
@@ -0,0 +1,14 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/stack_sampling_profiler.h"
+
+namespace base {
+
+scoped_ptr<StackSamplingProfiler::NativeStackSampler>
+StackSamplingProfiler::NativeStackSampler::Create(PlatformThreadId thread_id) {
+ return scoped_ptr<NativeStackSampler>();
+}
+
+} // namespace base
diff --git a/base/profiler/stack_sampling_profiler_unittest.cc b/base/profiler/stack_sampling_profiler_unittest.cc
new file mode 100644
index 0000000..ad9e926
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_unittest.cc
@@ -0,0 +1,321 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <sstream>
+
+#include "base/bind.h"
+#include "base/compiler_specific.h"
+#include "base/path_service.h"
+#include "base/profiler/stack_sampling_profiler.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+
+using Frame = StackSamplingProfiler::Frame;
+using Module = StackSamplingProfiler::Module;
+using Sample = StackSamplingProfiler::Sample;
+using Profile = StackSamplingProfiler::Profile;
+
+namespace {
+// A thread to target for profiling, whose stack is guaranteed to contain
+// SignalAndWaitUntilSignaled() when coordinated with the main thread.
+class TargetThread : public PlatformThread::Delegate {
+ public:
+ TargetThread();
+
+ // Implementation of PlatformThread::Delegate:
+ void ThreadMain() override;
+
+ // Wait for the thread to have started and be executing in
+ // SignalAndWaitUntilSignaled().
+ void WaitForThreadStart();
+ // Allow the thread to return from SignalAndWaitUntilSignaled() and finish
+ // execution.
+ void SignalThreadToFinish();
+
+ // This function is guaranteed to be executing between calls to
+ // WaitForThreadStart() and SignalThreadToFinish().
+ static void SignalAndWaitUntilSignaled(WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event);
+
+ PlatformThreadId id() const { return id_; }
+
+ private:
+ WaitableEvent thread_started_event_;
+ WaitableEvent finish_event_;
+ PlatformThreadId id_;
+
+ DISALLOW_COPY_AND_ASSIGN(TargetThread);
+};
+
+TargetThread::TargetThread()
+ : thread_started_event_(false, false), finish_event_(false, false),
+ id_(0) {}
+
+void TargetThread::ThreadMain() {
+ id_ = PlatformThread::CurrentId();
+ SignalAndWaitUntilSignaled(&thread_started_event_, &finish_event_);
+}
+
+void TargetThread::WaitForThreadStart() {
+ thread_started_event_.Wait();
+}
+
+void TargetThread::SignalThreadToFinish() {
+ finish_event_.Signal();
+}
+
+// static
+// Disable inlining for this function so that it gets its own stack frame.
+NOINLINE void TargetThread::SignalAndWaitUntilSignaled(
+ WaitableEvent* thread_started_event,
+ WaitableEvent* finish_event) {
+ thread_started_event->Signal();
+ volatile int x = 1;
+ finish_event->Wait();
+ x = 0; // Prevent tail call to WaitableEvent::Wait().
+ ALLOW_UNUSED_LOCAL(x);
+}
+
+// Called on the profiler thread when complete. Collects profiles produced by
+// the profiler, and signals an event to allow the main thread to know that that
+// the profiler is done.
+void SaveProfilesAndSignalEvent(std::vector<Profile>* profiles,
+ WaitableEvent* event,
+ const std::vector<Profile>& pending_profiles) {
+ *profiles = pending_profiles;
+ event->Signal();
+}
+
+// Captures profiles as specified by |params| on the TargetThread, and returns
+// them in |profiles|. Waits up to |profiler_wait_time| for the profiler to
+// complete.
+void CaptureProfiles(const StackSamplingProfiler::SamplingParams& params,
+ std::vector<Profile>* profiles,
+ TimeDelta profiler_wait_time) {
+ TargetThread target_thread;
+ PlatformThreadHandle target_thread_handle;
+ EXPECT_TRUE(PlatformThread::Create(0, &target_thread, &target_thread_handle));
+
+ target_thread.WaitForThreadStart();
+
+ WaitableEvent sampling_thread_completed(true, false);
+ profiles->clear();
+ StackSamplingProfiler profiler(target_thread.id(), params);
+ profiler.SetCustomCompletedCallback(
+ Bind(&SaveProfilesAndSignalEvent, Unretained(profiles),
+ Unretained(&sampling_thread_completed)));
+ profiler.Start();
+ sampling_thread_completed.TimedWait(profiler_wait_time);
+ profiler.Stop();
+ sampling_thread_completed.Wait();
+
+ target_thread.SignalThreadToFinish();
+
+ PlatformThread::Join(target_thread_handle);
+}
+
+// If this executable was linked with /INCREMENTAL (the default for non-official
+// debug and release builds on Windows), function addresses do not correspond to
+// function code itself, but instead to instructions in the Incremental Link
+// Table that jump to the functions. Check for a jump instruction and if present
+// do a little decompilation to find the function's actual starting address.
+const void* MaybeFixupFunctionAddressForILT(const void* function_address) {
+#if defined(_WIN64)
+ const unsigned char* opcode =
+ reinterpret_cast<const unsigned char*>(function_address);
+ if (*opcode == 0xe9) {
+ // This is a relative jump instruction. Assume we're in the ILT and compute
+ // the function start address from the instruction offset.
+ const unsigned char* offset = opcode + 1;
+ const unsigned char* next_instruction = opcode + 5;
+ return next_instruction +
+ static_cast<int64>(*reinterpret_cast<const int32*>(offset));
+ }
+#endif
+ return function_address;
+}
+
+// Searches through the frames in |sample|, returning an iterator to the first
+// frame that has an instruction pointer between |function_address| and
+// |function_address| + |size|. Returns sample.end() if no such frames are
+// found.
+Sample::const_iterator FindFirstFrameWithinFunction(
+ const Sample& sample,
+ const void* function_address,
+ int function_size) {
+ function_address = MaybeFixupFunctionAddressForILT(function_address);
+ for (auto it = sample.begin(); it != sample.end(); ++it) {
+ if ((reinterpret_cast<const unsigned char*>(it->instruction_pointer) >=
+ reinterpret_cast<const unsigned char*>(function_address)) &&
+ (reinterpret_cast<const unsigned char*>(it->instruction_pointer) <
+ (reinterpret_cast<const unsigned char*>(function_address) +
+ function_size)))
+ return it;
+ }
+ return sample.end();
+}
+
+// Formats a sample into a string that can be output for test diagnostics.
+std::string FormatSampleForDiagnosticOutput(
+ const Sample& sample,
+ const std::vector<Module>& modules) {
+ std::ostringstream stream;
+ for (const Frame& frame: sample) {
+ stream << frame.instruction_pointer << " "
+ << modules[frame.module_index].filename.value() << std::endl;
+ }
+ return stream.str();
+}
+
+// Returns a duration that is longer than the test timeout. We would use
+// TimeDelta::Max() but https://crbug.com/465948.
+TimeDelta AVeryLongTimeDelta() { return TimeDelta::FromDays(1); }
+} // namespace
+
+
+// The tests below are enabled for Win x64 only, pending implementation of the
+// tested functionality on other platforms/architectures.
+
+// Checks that the basic expected information is present in a sampled profile.
+#if defined(_WIN64)
+#define MAYBE_Basic Basic
+#else
+#define MAYBE_Basic DISABLED_Basic
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_Basic) {
+ StackSamplingProfiler::SamplingParams params;
+ params.initial_delay = params.burst_interval = params.sampling_interval =
+ TimeDelta::FromMilliseconds(0);
+ params.bursts = 1;
+ params.samples_per_burst = 1;
+
+ std::vector<Profile> profiles;
+ CaptureProfiles(params, &profiles, AVeryLongTimeDelta());
+
+ // Check that the profile and samples sizes are correct, and the module
+ // indices are in range.
+
+ ASSERT_EQ(1u, profiles.size());
+ const Profile& profile = profiles[0];
+ ASSERT_EQ(1u, profile.samples.size());
+ EXPECT_EQ(params.sampling_interval, profile.sampling_period);
+ const Sample& sample = profile.samples[0];
+ for (const auto& frame : sample) {
+ ASSERT_GE(frame.module_index, 0);
+ ASSERT_LT(frame.module_index, static_cast<int>(profile.modules.size()));
+ }
+
+ // Check that the stack contains a frame for
+ // TargetThread::SignalAndWaitUntilSignaled() and that the frame has this
+ // executable's module.
+
+ // Since we don't have a good way to know the function size, use 100 bytes as
+ // a reasonable window to locate the instruction pointer.
+ Sample::const_iterator loc = FindFirstFrameWithinFunction(
+ sample,
+ reinterpret_cast<const void*>(&TargetThread::SignalAndWaitUntilSignaled),
+ 100);
+ ASSERT_TRUE(loc != sample.end())
+ << "Function at "
+ << MaybeFixupFunctionAddressForILT(
+ reinterpret_cast<const void*>(
+ &TargetThread::SignalAndWaitUntilSignaled))
+ << " was not found in stack:" << std::endl
+ << FormatSampleForDiagnosticOutput(sample, profile.modules);
+
+ FilePath executable_path;
+ bool got_executable_path = PathService::Get(FILE_EXE, &executable_path);
+ EXPECT_TRUE(got_executable_path);
+ EXPECT_EQ(executable_path, profile.modules[loc->module_index].filename);
+}
+
+// Checks that the expected number of profiles and samples are present in the
+// profiles produced.
+#if defined(_WIN64)
+#define MAYBE_MultipleProfilesAndSamples MultipleProfilesAndSamples
+#else
+#define MAYBE_MultipleProfilesAndSamples DISABLED_MultipleProfilesAndSamples
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_MultipleProfilesAndSamples) {
+ StackSamplingProfiler::SamplingParams params;
+ params.initial_delay = params.burst_interval = params.sampling_interval =
+ TimeDelta::FromMilliseconds(0);
+ params.bursts = 2;
+ params.samples_per_burst = 3;
+
+ std::vector<Profile> profiles;
+ CaptureProfiles(params, &profiles, AVeryLongTimeDelta());
+
+ ASSERT_EQ(2u, profiles.size());
+ EXPECT_EQ(3u, profiles[0].samples.size());
+ EXPECT_EQ(3u, profiles[1].samples.size());
+}
+
+// Checks that no profiles are captured if the profiling is stopped during the
+// initial delay.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInitialDelay StopDuringInitialDelay
+#else
+#define MAYBE_StopDuringInitialDelay DISABLED_StopDuringInitialDelay
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInitialDelay) {
+ StackSamplingProfiler::SamplingParams params;
+ params.burst_interval = params.sampling_interval =
+ TimeDelta::FromMilliseconds(0);
+ params.initial_delay = TimeDelta::FromSeconds(60);
+ params.bursts = params.samples_per_burst = 1;
+
+ std::vector<Profile> profiles;
+ CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(0));
+
+ EXPECT_TRUE(profiles.empty());
+}
+
+// Checks that the single completed profile is captured if the profiling is
+// stopped between bursts.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterBurstInterval StopDuringInterBurstInterval
+#else
+#define MAYBE_StopDuringInterBurstInterval DISABLED_StopDuringInterBurstInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterBurstInterval) {
+ StackSamplingProfiler::SamplingParams params;
+ params.initial_delay = params.sampling_interval =
+ TimeDelta::FromMilliseconds(0);
+ params.burst_interval = TimeDelta::FromSeconds(60);
+ params.bursts = 2;
+ params.samples_per_burst = 1;
+
+ std::vector<Profile> profiles;
+ CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(50));
+
+ ASSERT_EQ(1u, profiles.size());
+ EXPECT_EQ(1u, profiles[0].samples.size());
+}
+
+// Checks that only completed profiles are captured.
+#if defined(_WIN64)
+#define MAYBE_StopDuringInterSampleInterval StopDuringInterSampleInterval
+#else
+#define MAYBE_StopDuringInterSampleInterval \
+ DISABLED_StopDuringInterSampleInterval
+#endif
+TEST(StackSamplingProfilerTest, MAYBE_StopDuringInterSampleInterval) {
+ StackSamplingProfiler::SamplingParams params;
+ params.initial_delay = params.burst_interval = TimeDelta::FromMilliseconds(0);
+ params.sampling_interval = TimeDelta::FromSeconds(60);
+ params.bursts = 1;
+ params.samples_per_burst = 2;
+
+ std::vector<Profile> profiles;
+ CaptureProfiles(params, &profiles, TimeDelta::FromMilliseconds(50));
+
+ EXPECT_TRUE(profiles.empty());
+}
+
+} // namespace tracked_objects
diff --git a/base/profiler/stack_sampling_profiler_win.cc b/base/profiler/stack_sampling_profiler_win.cc
new file mode 100644
index 0000000..ba46cf0
--- /dev/null
+++ b/base/profiler/stack_sampling_profiler_win.cc
@@ -0,0 +1,325 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/profiler/stack_sampling_profiler.h"
+
+#include <dbghelp.h>
+#include <map>
+#include <utility>
+#include <windows.h>
+
+#include "base/logging.h"
+#include "base/time/time.h"
+#include "base/win/pe_image.h"
+#include "base/win/scoped_handle.h"
+
+namespace base {
+
+namespace {
+
+class NativeStackSamplerWin : public StackSamplingProfiler::NativeStackSampler {
+ public:
+ explicit NativeStackSamplerWin(win::ScopedHandle thread_handle);
+ ~NativeStackSamplerWin() override;
+
+ // StackSamplingProfiler::NativeStackSampler:
+ void ProfileRecordingStarting(
+ StackSamplingProfiler::Profile* profile) override;
+ void RecordStackSample(StackSamplingProfiler::Sample* sample) override;
+ void ProfileRecordingStopped() override;
+
+ private:
+ static bool GetModuleInfo(HMODULE module,
+ StackSamplingProfiler::Module* module_info);
+
+ void CopyToSample(const void* const instruction_pointers[],
+ const HMODULE modules[],
+ int stack_depth,
+ StackSamplingProfiler::Sample* sample,
+ std::vector<StackSamplingProfiler::Module>* module_infos);
+
+ win::ScopedHandle thread_handle_;
+ // Weak. Points to the profile being recorded between
+ // ProfileRecordingStarting() and ProfileRecordingStopped().
+ StackSamplingProfiler::Profile* current_profile_;
+ // Maps a module to the module's index within current_profile_->modules.
+ std::map<HMODULE, int> profile_module_index_;
+
+ DISALLOW_COPY_AND_ASSIGN(NativeStackSamplerWin);
+};
+
+// Walk the stack represented by |context| from the current frame downwards,
+// recording the instruction pointers for each frame in |instruction_pointers|.
+int RecordStack(CONTEXT* context,
+ int max_stack_size,
+ const void* instruction_pointers[],
+ bool* last_frame_is_unknown_function) {
+#ifdef _WIN64
+ *last_frame_is_unknown_function = false;
+
+ IMAGEHLP_SYMBOL64 sym;
+ sym.SizeOfStruct = sizeof(sym);
+ sym.MaxNameLength = 0;
+
+ for (int i = 0; i < max_stack_size; ++i) {
+ // Try to look up unwind metadata for the current function.
+ ULONG64 image_base;
+ PRUNTIME_FUNCTION runtime_function =
+ RtlLookupFunctionEntry(context->Rip, &image_base, nullptr);
+
+ instruction_pointers[i] = reinterpret_cast<void*>(context->Rip);
+
+ if (runtime_function) {
+ KNONVOLATILE_CONTEXT_POINTERS nvcontext = {0};
+ void* handler_data;
+ ULONG64 establisher_frame;
+ RtlVirtualUnwind(0, image_base, context->Rip, runtime_function, context,
+ &handler_data, &establisher_frame, &nvcontext);
+ } else {
+ // If we don't have a RUNTIME_FUNCTION, then we've encountered
+ // a leaf function. Adjust the stack appropriately.
+ context->Rip = *reinterpret_cast<PDWORD64>(context->Rsp);
+ context->Rsp += 8;
+ *last_frame_is_unknown_function = true;
+ }
+
+ if (!context->Rip)
+ return i;
+ }
+ return max_stack_size;
+#else
+ return 0;
+#endif
+}
+
+// Fills in |modules| corresponding to the pointers to code in |addresses|. The
+// modules are returned with reference counts incremented should be freed with
+// FreeModules.
+void FindModulesForAddresses(const void* const addresses[], HMODULE modules[],
+ int stack_depth,
+ bool last_frame_is_unknown_function) {
+ const int module_frames = last_frame_is_unknown_function ? stack_depth - 1 :
+ stack_depth;
+ for (int i = 0; i < module_frames; ++i) {
+ HMODULE module = NULL;
+ if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
+ reinterpret_cast<LPCTSTR>(addresses[i]),
+ &module)) {
+ // HMODULE is the base address of the module.
+ DCHECK_LT(reinterpret_cast<const void*>(module), addresses[i]);
+ modules[i] = module;
+ }
+ }
+}
+
+// Free the modules returned by FindModulesForAddresses.
+void FreeModules(int stack_depth, HMODULE modules[]) {
+ for (int i = 0; i < stack_depth; ++i) {
+ if (modules[i])
+ ::FreeLibrary(modules[i]);
+ }
+}
+
+// Disables priority boost on a thread for the lifetime of the object.
+class ScopedDisablePriorityBoost {
+ public:
+ ScopedDisablePriorityBoost(HANDLE thread_handle);
+ ~ScopedDisablePriorityBoost();
+
+ private:
+ HANDLE thread_handle_;
+ BOOL got_previous_boost_state_;
+ BOOL boost_state_was_disabled_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedDisablePriorityBoost);
+};
+
+ScopedDisablePriorityBoost::ScopedDisablePriorityBoost(HANDLE thread_handle)
+ : thread_handle_(thread_handle),
+ got_previous_boost_state_(false),
+ boost_state_was_disabled_(false) {
+ got_previous_boost_state_ =
+ ::GetThreadPriorityBoost(thread_handle_, &boost_state_was_disabled_);
+ if (got_previous_boost_state_ && !boost_state_was_disabled_) {
+ // Confusingly, TRUE disables priority boost ...
+ ::SetThreadPriorityBoost(thread_handle_, TRUE);
+ }
+}
+
+ScopedDisablePriorityBoost::~ScopedDisablePriorityBoost() {
+ if (got_previous_boost_state_ && !boost_state_was_disabled_) {
+ // ... and FALSE enables priority boost.
+ ::SetThreadPriorityBoost(thread_handle_, FALSE);
+ }
+}
+
+// Suspends the thread with |thread_handle|, records the stack into
+// |instruction_pointers|, then resumes the thread. Returns the size of the
+// stack.
+int SuspendThreadAndRecordStack(HANDLE thread_handle, int max_stack_size,
+ const void* instruction_pointers[],
+ bool* last_frame_is_unknown_function) {
+#if defined(_WIN64)
+ if (RtlVirtualUnwind == nullptr || RtlLookupFunctionEntry == nullptr)
+ return 0;
+#endif
+
+ if (::SuspendThread(thread_handle) == -1) {
+ LOG(ERROR) << "SuspendThread failed: " << GetLastError();
+ return 0;
+ }
+
+ CONTEXT thread_context = {0};
+ thread_context.ContextFlags = CONTEXT_FULL;
+ if (!::GetThreadContext(thread_handle, &thread_context)) {
+ LOG(ERROR) << "GetThreadContext failed: " << GetLastError();
+ }
+
+ int stack_depth = RecordStack(&thread_context, max_stack_size,
+ instruction_pointers,
+ last_frame_is_unknown_function);
+
+ {
+ ScopedDisablePriorityBoost disable_priority_boost(thread_handle);
+ if (::ResumeThread(thread_handle) == -1)
+ LOG(ERROR) << "ResumeThread failed: " << GetLastError();
+ }
+
+ return stack_depth;
+}
+
+} // namespace
+
+scoped_ptr<StackSamplingProfiler::NativeStackSampler>
+StackSamplingProfiler::NativeStackSampler::Create(PlatformThreadId thread_id) {
+#if _WIN64
+ // Get the thread's handle.
+ HANDLE thread_handle = ::OpenThread(
+ THREAD_GET_CONTEXT | THREAD_SUSPEND_RESUME | THREAD_QUERY_INFORMATION,
+ FALSE,
+ thread_id);
+ DCHECK(thread_handle) << "OpenThread failed";
+
+ return scoped_ptr<NativeStackSampler>(new NativeStackSamplerWin(
+ win::ScopedHandle(thread_handle)));
+#else
+ return scoped_ptr<NativeStackSampler>();
+#endif
+}
+
+NativeStackSamplerWin::NativeStackSamplerWin(win::ScopedHandle thread_handle)
+ : thread_handle_(thread_handle.Take()) {
+#ifdef _WIN64
+ if (RtlVirtualUnwind == nullptr && RtlLookupFunctionEntry == nullptr) {
+ const HMODULE nt_dll_handle = ::GetModuleHandle(L"ntdll.dll");
+ // This should always be non-null, but handle just in case.
+ if (nt_dll_handle) {
+ reinterpret_cast<void*&>(RtlVirtualUnwind) =
+ ::GetProcAddress(nt_dll_handle, "RtlVirtualUnwind");
+ reinterpret_cast<void*&>(RtlLookupFunctionEntry) =
+ ::GetProcAddress(nt_dll_handle, "RtlLookupFunctionEntry");
+ }
+ }
+#endif
+}
+
+NativeStackSamplerWin::~NativeStackSamplerWin() {
+}
+
+void NativeStackSamplerWin::ProfileRecordingStarting(
+ StackSamplingProfiler::Profile* profile) {
+ current_profile_ = profile;
+ profile_module_index_.clear();
+}
+
+void NativeStackSamplerWin::RecordStackSample(
+ StackSamplingProfiler::Sample* sample) {
+ DCHECK(current_profile_);
+
+ const int max_stack_size = 64;
+ const void* instruction_pointers[max_stack_size] = {0};
+ HMODULE modules[max_stack_size] = {0};
+
+ bool last_frame_is_unknown_function = false;
+ int stack_depth = SuspendThreadAndRecordStack(
+ thread_handle_.Get(), max_stack_size, instruction_pointers,
+ &last_frame_is_unknown_function);
+ FindModulesForAddresses(instruction_pointers, modules, stack_depth,
+ last_frame_is_unknown_function);
+ CopyToSample(instruction_pointers, modules, stack_depth, sample,
+ ¤t_profile_->modules);
+ FreeModules(stack_depth, modules);
+}
+
+void NativeStackSamplerWin::ProfileRecordingStopped() {
+ current_profile_ = nullptr;
+}
+
+// static
+bool NativeStackSamplerWin::GetModuleInfo(
+ HMODULE module,
+ StackSamplingProfiler::Module* module_info) {
+ wchar_t module_name[MAX_PATH];
+ DWORD result_length =
+ GetModuleFileName(module, module_name, arraysize(module_name));
+ if (result_length == 0)
+ return false;
+
+ module_info->filename = base::FilePath(module_name);
+
+ module_info->base_address = reinterpret_cast<const void*>(module);
+
+ GUID guid;
+ DWORD age;
+ win::PEImage(module).GetDebugId(&guid, &age);
+ module_info->id.insert(module_info->id.end(),
+ reinterpret_cast<char*>(&guid),
+ reinterpret_cast<char*>(&guid + 1));
+ module_info->id.insert(module_info->id.end(),
+ reinterpret_cast<char*>(&age),
+ reinterpret_cast<char*>(&age + 1));
+
+ return true;
+}
+
+void NativeStackSamplerWin::CopyToSample(
+ const void* const instruction_pointers[],
+ const HMODULE modules[],
+ int stack_depth,
+ StackSamplingProfiler::Sample* sample,
+ std::vector<StackSamplingProfiler::Module>* module_infos) {
+ sample->clear();
+ sample->reserve(stack_depth);
+
+ for (int i = 0; i < stack_depth; ++i) {
+ sample->push_back(StackSamplingProfiler::Frame());
+ StackSamplingProfiler::Frame& frame = sample->back();
+
+ frame.instruction_pointer = instruction_pointers[i];
+
+ // Record an invalid module index if we don't have a valid module.
+ if (!modules[i]) {
+ frame.module_index = -1;
+ continue;
+ }
+
+ auto loc = profile_module_index_.find(modules[i]);
+ if (loc == profile_module_index_.end()) {
+ StackSamplingProfiler::Module module_info;
+ // Record an invalid module index if we have a module but can't find
+ // information on it.
+ if (!GetModuleInfo(modules[i], &module_info)) {
+ frame.module_index = -1;
+ continue;
+ }
+ module_infos->push_back(module_info);
+ loc = profile_module_index_.insert(std::make_pair(
+ modules[i], static_cast<int>(module_infos->size() - 1))).first;
+ }
+
+ frame.module_index = loc->second;
+ }
+}
+
+} // namespace base
diff --git a/base/stl_util.h b/base/stl_util.h
index 3602df0..89a53b0 100644
--- a/base/stl_util.h
+++ b/base/stl_util.h
@@ -148,8 +148,7 @@
void STLDeleteValues(T* container) {
if (!container)
return;
- for (typename T::iterator i(container->begin()); i != container->end(); ++i)
- delete i->second;
+ STLDeleteContainerPairSecondPointers(container->begin(), container->end());
container->clear();
}
diff --git a/base/strings/string16.h b/base/strings/string16.h
index 804dca4..1a01a96 100644
--- a/base/strings/string16.h
+++ b/base/strings/string16.h
@@ -94,7 +94,7 @@
return c16memchr(s, a, n);
}
- static char_type* move(char_type* s1, const char_type* s2, int_type n) {
+ static char_type* move(char_type* s1, const char_type* s2, size_t n) {
return c16memmove(s1, s2, n);
}
diff --git a/base/sys_info.h b/base/sys_info.h
index 660343d..d3476d9 100644
--- a/base/sys_info.h
+++ b/base/sys_info.h
@@ -48,6 +48,10 @@
// or -1 on failure.
static int64 AmountOfFreeDiskSpace(const FilePath& path);
+ // Determine whether the device that services |path| has a seek penalty.
+ // Returns false if it couldn't be determined (e.g., |path| doesn't exist).
+ static bool HasSeekPenalty(const FilePath& path, bool* has_seek_penalty);
+
// Returns system uptime in milliseconds.
static int64 Uptime();
diff --git a/base/sys_info_android.cc b/base/sys_info_android.cc
index 245097f..0f2abc5 100644
--- a/base/sys_info_android.cc
+++ b/base/sys_info_android.cc
@@ -155,6 +155,12 @@
namespace base {
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ // Find a case where this is incorrect and dbeam@ will buy you a beer.
+ *has_seek_penalty = false;
+ return true;
+}
+
std::string SysInfo::OperatingSystemName() {
return "Android";
}
diff --git a/base/sys_info_chromeos.cc b/base/sys_info_chromeos.cc
index ef5f1fe..2a5f5d7 100644
--- a/base/sys_info_chromeos.cc
+++ b/base/sys_info_chromeos.cc
@@ -169,6 +169,11 @@
} // namespace
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ // TODO(dbeam): implement. Can we just use boards/models?
+ return false;
+}
+
// static
void SysInfo::OperatingSystemVersionNumbers(int32* major_version,
int32* minor_version,
diff --git a/base/sys_info_freebsd.cc b/base/sys_info_freebsd.cc
index 832b359..338f1cd 100644
--- a/base/sys_info_freebsd.cc
+++ b/base/sys_info_freebsd.cc
@@ -22,6 +22,10 @@
return static_cast<int64>(pages) * page_size;
}
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ return false;
+}
+
// static
size_t SysInfo::MaxSharedMemorySize() {
size_t limit;
diff --git a/base/sys_info_ios.mm b/base/sys_info_ios.mm
index 49d618c..324bef6 100644
--- a/base/sys_info_ios.mm
+++ b/base/sys_info_ios.mm
@@ -16,6 +16,12 @@
namespace base {
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ // Find a case where this is incorrect and dbeam@ will buy you a beer.
+ *has_seek_penalty = false;
+ return true;
+}
+
// static
std::string SysInfo::OperatingSystemName() {
static dispatch_once_t get_system_name_once;
diff --git a/base/sys_info_linux.cc b/base/sys_info_linux.cc
index c698f91..401d55c 100644
--- a/base/sys_info_linux.cc
+++ b/base/sys_info_linux.cc
@@ -68,6 +68,13 @@
return g_lazy_physical_memory.Get().value();
}
+#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID)
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ // TODO(dbeam): implement.
+ return false;
+}
+#endif
+
// static
size_t SysInfo::MaxSharedMemorySize() {
return g_lazy_max_shared_memory.Get().value();
diff --git a/base/sys_info_mac.cc b/base/sys_info_mac.cc
index 18df624..8635088 100644
--- a/base/sys_info_mac.cc
+++ b/base/sys_info_mac.cc
@@ -76,6 +76,11 @@
vm_info.free_count - vm_info.speculative_count) * PAGE_SIZE;
}
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ // TODO(dbeam): implement.
+ return false;
+}
+
// static
std::string SysInfo::CPUModelName() {
char name[256];
diff --git a/base/sys_info_openbsd.cc b/base/sys_info_openbsd.cc
index edbb2c9..68d2ea1 100644
--- a/base/sys_info_openbsd.cc
+++ b/base/sys_info_openbsd.cc
@@ -48,6 +48,10 @@
return AmountOfMemory(_SC_AVPHYS_PAGES);
}
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ return false;
+}
+
// static
size_t SysInfo::MaxSharedMemorySize() {
int mib[] = { CTL_KERN, KERN_SHMINFO, KERN_SHMINFO_SHMMAX };
diff --git a/base/sys_info_unittest.cc b/base/sys_info_unittest.cc
index 15ae098..da47861 100644
--- a/base/sys_info_unittest.cc
+++ b/base/sys_info_unittest.cc
@@ -41,6 +41,13 @@
<< tmp_path.value();
}
+TEST_F(SysInfoTest, HasSeekPenalty) {
+ FilePath tmp_path;
+ ASSERT_TRUE(base::GetTempDir(&tmp_path));
+ bool unused;
+ base::SysInfo::HasSeekPenalty(tmp_path, &unused);
+}
+
#if defined(OS_WIN) || defined(OS_MACOSX)
TEST_F(SysInfoTest, OperatingSystemVersionNumbers) {
int32 os_major_version = -1;
diff --git a/base/sys_info_win.cc b/base/sys_info_win.cc
index 9cc0cfa..817992c 100644
--- a/base/sys_info_win.cc
+++ b/base/sys_info_win.cc
@@ -5,7 +5,9 @@
#include "base/sys_info.h"
#include <windows.h>
+#include <winioctl.h>
+#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
@@ -24,9 +26,7 @@
}
int64 rv = static_cast<int64>(memory_info.*memory_field);
- if (rv < 0)
- rv = kint64max;
- return rv;
+ return rv < 0 ? kint64max : rv;
}
} // namespace
@@ -55,16 +55,51 @@
// static
int64 SysInfo::AmountOfFreeDiskSpace(const FilePath& path) {
- base::ThreadRestrictions::AssertIOAllowed();
+ ThreadRestrictions::AssertIOAllowed();
ULARGE_INTEGER available, total, free;
- if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free)) {
+ if (!GetDiskFreeSpaceExW(path.value().c_str(), &available, &total, &free))
return -1;
- }
+
int64 rv = static_cast<int64>(available.QuadPart);
- if (rv < 0)
- rv = kint64max;
- return rv;
+ return rv < 0 ? kint64max : rv;
+}
+
+bool SysInfo::HasSeekPenalty(const FilePath& path, bool* has_seek_penalty) {
+ ThreadRestrictions::AssertIOAllowed();
+
+ DCHECK(path.IsAbsolute());
+ DCHECK(has_seek_penalty);
+
+ // TODO(dbeam): Vista, XP support.
+ if (win::GetVersion() < win::VERSION_WIN7)
+ return false;
+
+ std::vector<FilePath::StringType> components;
+ path.GetComponents(&components);
+
+ File drive(FilePath(L"\\\\.\\" + components[0]), File::FLAG_OPEN);
+ if (!drive.IsValid())
+ return false;
+
+ STORAGE_PROPERTY_QUERY query = {};
+ query.QueryType = PropertyStandardQuery;
+ query.PropertyId = StorageDeviceSeekPenaltyProperty;
+
+ DEVICE_SEEK_PENALTY_DESCRIPTOR result;
+ DWORD bytes_returned;
+
+ BOOL success = DeviceIoControl(drive.GetPlatformFile(),
+ IOCTL_STORAGE_QUERY_PROPERTY,
+ &query, sizeof(query),
+ &result, sizeof(result),
+ &bytes_returned,
+ NULL);
+ if (success == FALSE || bytes_returned < sizeof(result))
+ return false;
+
+ *has_seek_penalty = result.IncursSeekPenalty != FALSE;
+ return true;
}
// static
diff --git a/base/test/BUILD.gn b/base/test/BUILD.gn
index f5d2e4c..c4356cb 100644
--- a/base/test/BUILD.gn
+++ b/base/test/BUILD.gn
@@ -81,8 +81,8 @@
"simple_test_tick_clock.h",
"task_runner_test_template.cc",
"task_runner_test_template.h",
- "test_discardable_memory_shmem_allocator.cc",
- "test_discardable_memory_shmem_allocator.h",
+ "test_discardable_memory_allocator.cc",
+ "test_discardable_memory_allocator.h",
"test_file_util.cc",
"test_file_util.h",
"test_file_util_android.cc",
diff --git a/base/test/test_discardable_memory_allocator.cc b/base/test/test_discardable_memory_allocator.cc
new file mode 100644
index 0000000..cb2cccf
--- /dev/null
+++ b/base/test/test_discardable_memory_allocator.cc
@@ -0,0 +1,40 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/test/test_discardable_memory_allocator.h"
+
+#include <stdint.h>
+
+#include "base/memory/discardable_memory.h"
+
+namespace base {
+namespace {
+
+class DiscardableMemoryImpl : public DiscardableMemory {
+ public:
+ explicit DiscardableMemoryImpl(size_t size) : memory_(new uint8_t[size]) {}
+
+ // Overridden from DiscardableMemory:
+ bool Lock() override { return false; }
+ void Unlock() override {}
+ void* Memory() const override { return memory_.get(); }
+
+ private:
+ scoped_ptr<uint8_t[]> memory_;
+};
+
+} // namespace
+
+TestDiscardableMemoryAllocator::TestDiscardableMemoryAllocator() {
+}
+
+TestDiscardableMemoryAllocator::~TestDiscardableMemoryAllocator() {
+}
+
+scoped_ptr<DiscardableMemory>
+TestDiscardableMemoryAllocator::AllocateLockedDiscardableMemory(size_t size) {
+ return make_scoped_ptr(new DiscardableMemoryImpl(size));
+}
+
+} // namespace base
diff --git a/base/test/test_discardable_memory_allocator.h b/base/test/test_discardable_memory_allocator.h
new file mode 100644
index 0000000..df9d469
--- /dev/null
+++ b/base/test/test_discardable_memory_allocator.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+#define BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
+
+#include "base/memory/discardable_memory_allocator.h"
+
+namespace base {
+
+// TestDiscardableMemoryAllocator is a simple DiscardableMemoryAllocator
+// implementation that can be used for testing. It allocates one-shot
+// DiscardableMemory instances backed by heap memory.
+class TestDiscardableMemoryAllocator : public DiscardableMemoryAllocator {
+ public:
+ TestDiscardableMemoryAllocator();
+ ~TestDiscardableMemoryAllocator() override;
+
+ // Overridden from DiscardableMemoryAllocator:
+ scoped_ptr<DiscardableMemory> AllocateLockedDiscardableMemory(
+ size_t size) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TestDiscardableMemoryAllocator);
+};
+
+} // namespace base
+
+#endif // BASE_TEST_TEST_DISCARDABLE_MEMORY_ALLOCATOR_H_
diff --git a/base/test/test_discardable_memory_shmem_allocator.cc b/base/test/test_discardable_memory_shmem_allocator.cc
deleted file mode 100644
index 24185a2..0000000
--- a/base/test/test_discardable_memory_shmem_allocator.cc
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/test/test_discardable_memory_shmem_allocator.h"
-
-#include <stdint.h>
-
-namespace base {
-namespace {
-
-class DiscardableMemoryShmemChunkImpl : public DiscardableMemoryShmemChunk {
- public:
- explicit DiscardableMemoryShmemChunkImpl(size_t size)
- : memory_(new uint8_t[size]) {}
-
- // Overridden from DiscardableMemoryShmemChunk:
- bool Lock() override { return false; }
- void Unlock() override {}
- void* Memory() const override { return memory_.get(); }
-
- private:
- scoped_ptr<uint8_t[]> memory_;
-};
-
-} // namespace
-
-TestDiscardableMemoryShmemAllocator::TestDiscardableMemoryShmemAllocator() {
-}
-
-TestDiscardableMemoryShmemAllocator::~TestDiscardableMemoryShmemAllocator() {
-}
-
-scoped_ptr<DiscardableMemoryShmemChunk>
-TestDiscardableMemoryShmemAllocator::AllocateLockedDiscardableMemory(
- size_t size) {
- return make_scoped_ptr(new DiscardableMemoryShmemChunkImpl(size));
-}
-
-} // namespace base
diff --git a/base/test/test_discardable_memory_shmem_allocator.h b/base/test/test_discardable_memory_shmem_allocator.h
deleted file mode 100644
index a40960e..0000000
--- a/base/test/test_discardable_memory_shmem_allocator.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_TEST_TEST_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
-#define BASE_TEST_TEST_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
-
-#include "base/memory/discardable_memory_shmem_allocator.h"
-
-namespace base {
-
-class TestDiscardableMemoryShmemAllocator
- : public DiscardableMemoryShmemAllocator {
- public:
- TestDiscardableMemoryShmemAllocator();
- ~TestDiscardableMemoryShmemAllocator() override;
-
- // Overridden from DiscardableMemoryShmemAllocator:
- scoped_ptr<DiscardableMemoryShmemChunk> AllocateLockedDiscardableMemory(
- size_t size) override;
-
- private:
- DISALLOW_COPY_AND_ASSIGN(TestDiscardableMemoryShmemAllocator);
-};
-
-} // namespace base
-
-#endif // BASE_TEST_TEST_DISCARDABLE_MEMORY_SHMEM_ALLOCATOR_H_
diff --git a/base/test/test_mock_time_task_runner.cc b/base/test/test_mock_time_task_runner.cc
index 6bcab8b..8cc2e6d 100644
--- a/base/test/test_mock_time_task_runner.cc
+++ b/base/test/test_mock_time_task_runner.cc
@@ -164,6 +164,10 @@
return PostDelayedTask(from_here, task, delay);
}
+bool TestMockTimeTaskRunner::IsElapsingStopped() {
+ return false;
+}
+
void TestMockTimeTaskRunner::OnBeforeSelectingTask() {
// Empty default implementation.
}
@@ -179,7 +183,7 @@
void TestMockTimeTaskRunner::ProcessAllTasksNoLaterThan(TimeDelta max_delta) {
DCHECK_GE(max_delta, TimeDelta());
const TimeTicks original_now_ticks = now_ticks_;
- while (true) {
+ while (!IsElapsingStopped()) {
OnBeforeSelectingTask();
TestPendingTask task_info;
if (!DequeueNextTask(original_now_ticks, max_delta, &task_info))
diff --git a/base/test/test_mock_time_task_runner.h b/base/test/test_mock_time_task_runner.h
index c38fd6d..705af10 100644
--- a/base/test/test_mock_time_task_runner.h
+++ b/base/test/test_mock_time_task_runner.h
@@ -94,6 +94,11 @@
protected:
~TestMockTimeTaskRunner() override;
+ // Whether the elapsing of virtual time is stopped or not. Subclasses can
+ // override this method to perform early exits from a running task runner.
+ // Defaults to always return false.
+ virtual bool IsElapsingStopped();
+
// Called before the next task to run is selected, so that subclasses have a
// last chance to make sure all tasks are posted.
virtual void OnBeforeSelectingTask();
diff --git a/base/threading/platform_thread_android.cc b/base/threading/platform_thread_android.cc
index f8395e5..aab4c19 100644
--- a/base/threading/platform_thread_android.cc
+++ b/base/threading/platform_thread_android.cc
@@ -7,80 +7,57 @@
#include <errno.h>
#include <sys/prctl.h>
#include <sys/resource.h>
+#include <sys/types.h>
+#include <unistd.h>
#include "base/android/jni_android.h"
#include "base/android/thread_utils.h"
#include "base/lazy_instance.h"
#include "base/logging.h"
+#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/tracked_objects.h"
#include "jni/ThreadUtils_jni.h"
namespace base {
-namespace {
-int ThreadNiceValue(ThreadPriority priority) {
- // These nice values are taken from Android, which uses nice
- // values like linux, but defines some preset nice values.
- // Process.THREAD_PRIORITY_AUDIO = -16
- // Process.THREAD_PRIORITY_BACKGROUND = 10
- // Process.THREAD_PRIORITY_DEFAULT = 0;
- // Process.THREAD_PRIORITY_DISPLAY = -4;
- // Process.THREAD_PRIORITY_FOREGROUND = -2;
- // Process.THREAD_PRIORITY_LESS_FAVORABLE = 1;
- // Process.THREAD_PRIORITY_LOWEST = 19;
- // Process.THREAD_PRIORITY_MORE_FAVORABLE = -1;
- // Process.THREAD_PRIORITY_URGENT_AUDIO = -19;
- // Process.THREAD_PRIORITY_URGENT_DISPLAY = -8;
- // We use -6 for display, but we may want to split this
- // into urgent (-8) and non-urgent (-4).
- static const int threadPriorityAudio = -16;
- static const int threadPriorityBackground = 10;
- static const int threadPriorityDefault = 0;
- static const int threadPriorityDisplay = -6;
- switch (priority) {
- case kThreadPriority_RealtimeAudio:
- return threadPriorityAudio;
- case kThreadPriority_Background:
- return threadPriorityBackground;
- case kThreadPriority_Normal:
- return threadPriorityDefault;
- case kThreadPriority_Display:
- return threadPriorityDisplay;
- default:
- NOTREACHED() << "Unknown priority.";
- return 0;
- }
-}
-} // namespace
+namespace internal {
-//static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
+// These nice values are taken from Android, which uses nice values like linux,
+// but defines some preset nice values.
+// Process.THREAD_PRIORITY_AUDIO = -16
+// Process.THREAD_PRIORITY_BACKGROUND = 10
+// Process.THREAD_PRIORITY_DEFAULT = 0;
+// Process.THREAD_PRIORITY_DISPLAY = -4;
+// Process.THREAD_PRIORITY_FOREGROUND = -2;
+// Process.THREAD_PRIORITY_LESS_FAVORABLE = 1;
+// Process.THREAD_PRIORITY_LOWEST = 19;
+// Process.THREAD_PRIORITY_MORE_FAVORABLE = -1;
+// Process.THREAD_PRIORITY_URGENT_AUDIO = -19;
+// Process.THREAD_PRIORITY_URGENT_DISPLAY = -8;
+// We use -6 for display, but we may want to split this into urgent (-8) and
+// non-urgent (-4).
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+ {kThreadPriority_RealtimeAudio, -16},
+ {kThreadPriority_Background, 10},
+ {kThreadPriority_Normal, 0},
+ {kThreadPriority_Display, -6},
+};
+
+bool HandleSetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority) {
// On Android, we set the Audio priority through JNI as Audio priority
// will also allow the process to run while it is backgrounded.
if (priority == kThreadPriority_RealtimeAudio) {
JNIEnv* env = base::android::AttachCurrentThread();
Java_ThreadUtils_setThreadPriorityAudio(env, PlatformThread::CurrentId());
- return;
+ return true;
}
-
- // setpriority(2) should change the whole thread group's (i.e. process)
- // priority. however, on linux it will only change the target thread's
- // priority. see the bugs section in
- // http://man7.org/linux/man-pages/man2/getpriority.2.html.
- // we prefer using 0 rather than the current thread id since they are
- // equivalent but it makes sandboxing easier (https://crbug.com/399473).
- DCHECK_NE(handle.id_, kInvalidThreadId);
- int kNiceSetting = ThreadNiceValue(priority);
- const PlatformThreadId current_id = PlatformThread::CurrentId();
- if (setpriority(PRIO_PROCESS,
- handle.id_ == current_id ? 0 : handle.id_,
- kNiceSetting)) {
- LOG(ERROR) << "Failed to set nice value of thread to " << kNiceSetting;
- }
+ return false;
}
+} // namespace internal
+
void PlatformThread::SetName(const char* name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
tracked_objects::ThreadData::InitializeThreadContext(name);
diff --git a/base/threading/platform_thread_freebsd.cc b/base/threading/platform_thread_freebsd.cc
index 7a24f4e..a163f65 100644
--- a/base/threading/platform_thread_freebsd.cc
+++ b/base/threading/platform_thread_freebsd.cc
@@ -9,39 +9,44 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/safe_strerror_posix.h"
#include "base/threading/thread_id_name_manager.h"
-#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
#if !defined(OS_NACL)
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
+#include <pthread.h>
+#include <sys/prctl.h>
#include <sys/types.h>
#include <unistd.h>
#endif
namespace base {
+namespace internal {
+
namespace {
-int ThreadNiceValue(ThreadPriority priority) {
- switch (priority) {
- case kThreadPriority_RealtimeAudio:
- return -10;
- case kThreadPriority_Background:
- return 10;
- case kThreadPriority_Normal:
- return 0;
- case kThreadPriority_Display:
- return -6;
- default:
- NOTREACHED() << "Unknown priority.";
- return 0;
- }
+#if !defined(OS_NACL)
+const struct sched_param kRealTimePrio = {8};
+#endif
+} // namespace
+
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+ { kThreadPriority_RealtimeAudio, -10 },
+ { kThreadPriority_Background, 10 },
+ { kThreadPriority_Normal, 0 },
+ { kThreadPriority_Display, -6 },
}
-} // namespace
+
+bool HandleSetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority) {
+#if !defined(OS_NACL)
+ return priority == kThreadPriority_RealtimeAudio &&
+ pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+ return false;
+#endif
+}
+
+} // namespace internal
// static
void PlatformThread::SetName(const char* name) {
@@ -59,31 +64,6 @@
#endif // !defined(OS_NACL)
}
-// static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
-#if !defined(OS_NACL)
- if (priority == kThreadPriority_RealtimeAudio) {
- const struct sched_param kRealTimePrio = { 8 };
- if (pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0) {
- // Got real time priority, no need to set nice level.
- return;
- }
- }
-
- // setpriority(2) will set a thread's priority if it is passed a tid as
- // the 'process identifier', not affecting the rest of the threads in the
- // process. Setting this priority will only succeed if the user has been
- // granted permission to adjust nice values on the system.
- DCHECK_NE(handle.id_, kInvalidThreadId);
- const int kNiceSetting = ThreadNiceValue(priority);
- if (setpriority(PRIO_PROCESS, handle.id_, kNiceSetting)) {
- DVPLOG(1) << "Failed to set nice value of thread ("
- << handle.id_ << ") to " << kNiceSetting;
- }
-#endif // !defined(OS_NACL)
-}
-
void InitThreading() {}
void InitOnThread() {}
diff --git a/base/threading/platform_thread_internal_posix.cc b/base/threading/platform_thread_internal_posix.cc
new file mode 100644
index 0000000..7e6604b
--- /dev/null
+++ b/base/threading/platform_thread_internal_posix.cc
@@ -0,0 +1,25 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/threading/platform_thread_internal_posix.h"
+
+#include "base/logging.h"
+
+namespace base {
+
+namespace internal {
+
+int ThreadPriorityToNiceValue(ThreadPriority priority) {
+ for (const ThreadPriorityToNiceValuePair& pair :
+ kThreadPriorityToNiceValueMap) {
+ if (pair.priority == priority)
+ return pair.nice_value;
+ }
+ NOTREACHED() << "Unknown ThreadPriority";
+ return 0;
+}
+
+} // namespace internal
+
+} // namespace base
diff --git a/base/threading/platform_thread_internal_posix.h b/base/threading/platform_thread_internal_posix.h
new file mode 100644
index 0000000..1ae968f
--- /dev/null
+++ b/base/threading/platform_thread_internal_posix.h
@@ -0,0 +1,35 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+#define BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
+
+#include "base/threading/platform_thread.h"
+
+namespace base {
+
+namespace internal {
+
+struct ThreadPriorityToNiceValuePair {
+ ThreadPriority priority;
+ int nice_value;
+};
+extern const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4];
+
+// Returns the nice value matching |priority| based on the platform-specific
+// implementation of kThreadPriorityToNiceValueMap.
+int ThreadPriorityToNiceValue(ThreadPriority priority);
+
+// Allows platform specific tweaks to the generic POSIX solution for
+// SetThreadPriority. Returns true if the platform-specific implementation
+// handled this |priority| change, false if the generic implementation should
+// instead proceed.
+bool HandleSetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority);
+
+} // namespace internal
+
+} // namespace base
+
+#endif // BASE_THREADING_PLATFORM_THREAD_INTERNAL_POSIX_H_
diff --git a/base/threading/platform_thread_linux.cc b/base/threading/platform_thread_linux.cc
index d97a3f4..623a3de 100644
--- a/base/threading/platform_thread_linux.cc
+++ b/base/threading/platform_thread_linux.cc
@@ -9,44 +9,46 @@
#include "base/lazy_instance.h"
#include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/safe_strerror_posix.h"
+#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
-#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
#if !defined(OS_NACL)
+#include <pthread.h>
#include <sys/prctl.h>
-#include <sys/resource.h>
-#include <sys/syscall.h>
-#include <sys/time.h>
+#include <sys/types.h>
#include <unistd.h>
#endif
namespace base {
+namespace internal {
+
namespace {
-
#if !defined(OS_NACL)
-int ThreadNiceValue(ThreadPriority priority) {
- switch (priority) {
- case kThreadPriority_RealtimeAudio:
- return -10;
- case kThreadPriority_Background:
- return 10;
- case kThreadPriority_Normal:
- return 0;
- case kThreadPriority_Display:
- return -6;
- default:
- NOTREACHED() << "Unknown priority.";
- return 0;
- }
-}
-#endif // !defined(OS_NACL)
-
+const struct sched_param kRealTimePrio = {8};
+#endif
} // namespace
+const ThreadPriorityToNiceValuePair kThreadPriorityToNiceValueMap[4] = {
+ {kThreadPriority_RealtimeAudio, -10},
+ {kThreadPriority_Background, 10},
+ {kThreadPriority_Normal, 0},
+ {kThreadPriority_Display, -6},
+};
+
+bool HandleSetThreadPriorityForPlatform(PlatformThreadHandle handle,
+ ThreadPriority priority) {
+#if !defined(OS_NACL)
+ return priority == kThreadPriority_RealtimeAudio &&
+ pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0;
+#else
+ return false;
+#endif
+}
+
+} // namespace internal
+
// static
void PlatformThread::SetName(const char* name) {
ThreadIdNameManager::GetInstance()->SetName(CurrentId(), name);
@@ -72,36 +74,6 @@
#endif // !defined(OS_NACL)
}
-// static
-void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
- ThreadPriority priority) {
-#if !defined(OS_NACL)
- if (priority == kThreadPriority_RealtimeAudio) {
- const struct sched_param kRealTimePrio = {8};
- if (pthread_setschedparam(pthread_self(), SCHED_RR, &kRealTimePrio) == 0) {
- // Got real time priority, no need to set nice level.
- return;
- }
- }
-
- // setpriority(2) should change the whole thread group's (i.e. process)
- // priority. however, on linux it will only change the target thread's
- // priority. see the bugs section in
- // http://man7.org/linux/man-pages/man2/getpriority.2.html.
- // we prefer using 0 rather than the current thread id since they are
- // equivalent but it makes sandboxing easier (https://crbug.com/399473).
- DCHECK_NE(handle.id_, kInvalidThreadId);
- const int kNiceSetting = ThreadNiceValue(priority);
- const PlatformThreadId current_id = PlatformThread::CurrentId();
- if (setpriority(PRIO_PROCESS,
- handle.id_ == current_id ? 0 : handle.id_,
- kNiceSetting)) {
- DVPLOG(1) << "Failed to set nice value of thread (" << handle.id_ << ") to "
- << kNiceSetting;
- }
-#endif // !defined(OS_NACL)
-}
-
void InitThreading() {}
void InitOnThread() {}
diff --git a/base/threading/platform_thread_posix.cc b/base/threading/platform_thread_posix.cc
index 42b416d..5c5023b 100644
--- a/base/threading/platform_thread_posix.cc
+++ b/base/threading/platform_thread_posix.cc
@@ -5,28 +5,25 @@
#include "base/threading/platform_thread.h"
#include <errno.h>
+#include <pthread.h>
#include <sched.h>
+#include <sys/resource.h>
+#include <sys/time.h>
#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/safe_strerror_posix.h"
#include "base/synchronization/waitable_event.h"
+#include "base/threading/platform_thread_internal_posix.h"
#include "base/threading/thread_id_name_manager.h"
#include "base/threading/thread_restrictions.h"
#include "base/tracked_objects.h"
-#if defined(OS_MACOSX)
-#include <sys/resource.h>
-#include <algorithm>
-#endif
-
#if defined(OS_LINUX)
-#include <sys/prctl.h>
-#include <sys/resource.h>
#include <sys/syscall.h>
-#include <sys/time.h>
-#include <unistd.h>
+#elif defined(OS_ANDROID)
+#include <sys/types.h>
#endif
namespace base {
@@ -235,4 +232,31 @@
CHECK_EQ(0, pthread_join(thread_handle.handle_, NULL));
}
+// Mac has its own SetThreadPriority() implementation.
+#if !defined(OS_MACOSX)
+// static
+void PlatformThread::SetThreadPriority(PlatformThreadHandle handle,
+ ThreadPriority priority) {
+#if !defined(OS_NACL)
+ if (internal::HandleSetThreadPriorityForPlatform(handle, priority))
+ return;
+
+ // setpriority(2) should change the whole thread group's (i.e. process)
+ // priority. However, as stated in the bugs section of
+ // http://man7.org/linux/man-pages/man2/getpriority.2.html: "under the current
+ // Linux/NPTL implementation of POSIX threads, the nice value is a per-thread
+ // attribute". Also, 0 is prefered to the current thread id since it is
+ // equivalent but makes sandboxing easier (https://crbug.com/399473).
+ DCHECK_NE(handle.id_, kInvalidThreadId);
+ const int nice_setting = internal::ThreadPriorityToNiceValue(priority);
+ const PlatformThreadId current_id = PlatformThread::CurrentId();
+ if (setpriority(PRIO_PROCESS, handle.id_ == current_id ? 0 : handle.id_,
+ nice_setting)) {
+ DVPLOG(1) << "Failed to set nice value of thread (" << handle.id_ << ") to "
+ << nice_setting;
+ }
+#endif // !defined(OS_NACL)
+}
+#endif // !defined(OS_MACOSX)
+
} // namespace base
diff --git a/base/time/time.cc b/base/time/time.cc
index 951f7ba..321323b 100644
--- a/base/time/time.cc
+++ b/base/time/time.cc
@@ -97,6 +97,33 @@
return delta_;
}
+int64 TimeDelta::SaturatedAdd(int64 value) const {
+ CheckedNumeric<int64> rv(delta_);
+ rv += value;
+ return FromCheckedNumeric(rv);
+}
+
+int64 TimeDelta::SaturatedSub(int64 value) const {
+ CheckedNumeric<int64> rv(delta_);
+ rv -= value;
+ return FromCheckedNumeric(rv);
+}
+
+// static
+int64 TimeDelta::FromCheckedNumeric(const CheckedNumeric<int64> value) {
+ if (value.IsValid())
+ return value.ValueUnsafe();
+
+ // We could return max/min but we don't really expose what the maximum delta
+ // is. Instead, return max/(-max), which is something that clients can reason
+ // about.
+ // TODO(rvargas) crbug.com/332611: don't use internal values.
+ int64 limit = std::numeric_limits<int64>::max();
+ if (value.validity() == internal::RANGE_UNDERFLOW)
+ limit = -limit;
+ return value.ValueOrDefault(limit);
+}
+
std::ostream& operator<<(std::ostream& os, TimeDelta time_delta) {
return os << time_delta.InSecondsF() << "s";
}
diff --git a/base/time/time.h b/base/time/time.h
index 6a45b81..5c8b89c 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -33,6 +33,7 @@
#include "base/base_export.h"
#include "base/basictypes.h"
+#include "base/numerics/safe_math.h"
#include "build/build_config.h"
#if defined(OS_MACOSX)
@@ -140,18 +141,18 @@
// Computations with other deltas.
TimeDelta operator+(TimeDelta other) const {
- return TimeDelta(delta_ + other.delta_);
+ return TimeDelta(SaturatedAdd(other.delta_));
}
TimeDelta operator-(TimeDelta other) const {
- return TimeDelta(delta_ - other.delta_);
+ return TimeDelta(SaturatedSub(other.delta_));
}
TimeDelta& operator+=(TimeDelta other) {
- delta_ += other.delta_;
+ delta_ = SaturatedAdd(other.delta_);
return *this;
}
TimeDelta& operator-=(TimeDelta other) {
- delta_ -= other.delta_;
+ delta_ = SaturatedSub(other.delta_);
return *this;
}
TimeDelta operator-() const {
@@ -161,20 +162,28 @@
// Computations with numeric types.
template<typename T>
TimeDelta operator*(T a) const {
- return TimeDelta(delta_ * a);
+ CheckedNumeric<int64> rv(delta_);
+ rv *= a;
+ return TimeDelta(FromCheckedNumeric(rv));
}
template<typename T>
TimeDelta operator/(T a) const {
- return TimeDelta(delta_ / a);
+ CheckedNumeric<int64> rv(delta_);
+ rv /= a;
+ return TimeDelta(FromCheckedNumeric(rv));
}
template<typename T>
TimeDelta& operator*=(T a) {
- delta_ *= a;
+ CheckedNumeric<int64> rv(delta_);
+ rv *= a;
+ delta_ = FromCheckedNumeric(rv);
return *this;
}
template<typename T>
TimeDelta& operator/=(T a) {
- delta_ /= a;
+ CheckedNumeric<int64> rv(delta_);
+ rv /= a;
+ delta_ = FromCheckedNumeric(rv);
return *this;
}
@@ -216,6 +225,13 @@
explicit TimeDelta(int64 delta_us) : delta_(delta_us) {
}
+ // Add or subtract |value| from this delta.
+ int64 SaturatedAdd(int64 value) const;
+ int64 SaturatedSub(int64 value) const;
+
+ // Clamp |value| on overflow and underflow conditions.
+ static int64 FromCheckedNumeric(const CheckedNumeric<int64> value);
+
// Delta in microseconds.
int64 delta_;
};
@@ -451,20 +467,20 @@
// Modify by some time delta.
Time& operator+=(TimeDelta delta) {
- us_ += delta.delta_;
+ us_ = delta.SaturatedAdd(us_);
return *this;
}
Time& operator-=(TimeDelta delta) {
- us_ -= delta.delta_;
+ us_ = -delta.SaturatedSub(us_);
return *this;
}
// Return a new time modified by some delta.
Time operator+(TimeDelta delta) const {
- return Time(us_ + delta.delta_);
+ return Time(delta.SaturatedAdd(us_));
}
Time operator-(TimeDelta delta) const {
- return Time(us_ - delta.delta_);
+ return Time(-delta.SaturatedSub(us_));
}
// Comparison operators
@@ -583,7 +599,7 @@
}
inline Time TimeDelta::operator+(Time t) const {
- return Time(t.us_ + delta_);
+ return Time(SaturatedAdd(t.us_));
}
// For logging use only.
@@ -665,6 +681,11 @@
return ticks_ == 0;
}
+ // Returns true if the time delta is the maximum delta.
+ bool is_max() const {
+ return ticks_ == std::numeric_limits<int64>::max();
+ }
+
// Converts an integer value representing TimeTicks to a class. This is used
// when deserializing a |TimeTicks| structure, using a value known to be
// compatible. It is not provided as a constructor because the integer type
@@ -705,20 +726,20 @@
// Modify by some time delta.
TimeTicks& operator+=(TimeDelta delta) {
- ticks_ += delta.delta_;
+ ticks_ = delta.SaturatedAdd(ticks_);
return *this;
}
TimeTicks& operator-=(TimeDelta delta) {
- ticks_ -= delta.delta_;
+ ticks_ = -delta.SaturatedSub(ticks_);
return *this;
}
// Return a new TimeTicks modified by some delta.
TimeTicks operator+(TimeDelta delta) const {
- return TimeTicks(ticks_ + delta.delta_);
+ return TimeTicks(delta.SaturatedAdd(ticks_));
}
TimeTicks operator-(TimeDelta delta) const {
- return TimeTicks(ticks_ - delta.delta_);
+ return TimeTicks(-delta.SaturatedSub(ticks_));
}
// Comparison operators
@@ -759,7 +780,7 @@
};
inline TimeTicks TimeDelta::operator+(TimeTicks t) const {
- return TimeTicks(t.ticks_ + delta_);
+ return TimeTicks(SaturatedAdd(t.ticks_));
}
// For logging use only.
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index a96787c..6c12423 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -942,6 +942,77 @@
2 * TimeDelta::FromMilliseconds(1000));
}
+bool IsMin(TimeDelta delta) {
+ return (-delta).is_max();
+}
+
+TEST(TimeDelta, Overflows) {
+ // Some sanity checks.
+ EXPECT_TRUE(TimeDelta::Max().is_max());
+ EXPECT_TRUE(IsMin(-TimeDelta::Max()));
+ EXPECT_GT(TimeDelta(), -TimeDelta::Max());
+
+ TimeDelta large_delta = TimeDelta::Max() - TimeDelta::FromMilliseconds(1);
+ TimeDelta large_negative = -large_delta;
+ EXPECT_GT(TimeDelta(), large_negative);
+ EXPECT_FALSE(large_delta.is_max());
+ EXPECT_FALSE(IsMin(-large_negative));
+ TimeDelta one_second = TimeDelta::FromSeconds(1);
+
+ // Test +, -, * and / operators.
+ EXPECT_TRUE((large_delta + one_second).is_max());
+ EXPECT_TRUE(IsMin(large_negative + (-one_second)));
+ EXPECT_TRUE(IsMin(large_negative - one_second));
+ EXPECT_TRUE((large_delta - (-one_second)).is_max());
+ EXPECT_TRUE((large_delta * 2).is_max());
+ EXPECT_TRUE(IsMin(large_delta * -2));
+ EXPECT_TRUE((large_delta / 0.5).is_max());
+ EXPECT_TRUE(IsMin(large_delta / -0.5));
+
+ // Test +=, -=, *= and /= operators.
+ TimeDelta delta = large_delta;
+ delta += one_second;
+ EXPECT_TRUE(delta.is_max());
+ delta = large_negative;
+ delta += -one_second;
+ EXPECT_TRUE(IsMin(delta));
+
+ delta = large_negative;
+ delta -= one_second;
+ EXPECT_TRUE(IsMin(delta));
+ delta = large_delta;
+ delta -= -one_second;
+ EXPECT_TRUE(delta.is_max());
+
+ delta = large_delta;
+ delta *= 2;
+ EXPECT_TRUE(delta.is_max());
+ delta = large_negative;
+ delta *= 1.5;
+ EXPECT_TRUE(IsMin(delta));
+
+ delta = large_delta;
+ delta /= 0.5;
+ EXPECT_TRUE(delta.is_max());
+ delta = large_negative;
+ delta /= 0.5;
+ EXPECT_TRUE(IsMin(delta));
+
+ // Test operations with Time and TimeTicks.
+ EXPECT_TRUE((large_delta + Time::Now()).is_max());
+ EXPECT_TRUE((large_delta + TimeTicks::Now()).is_max());
+ EXPECT_TRUE((Time::Now() + large_delta).is_max());
+ EXPECT_TRUE((TimeTicks::Now() + large_delta).is_max());
+
+ Time time_now = Time::Now();
+ EXPECT_EQ(one_second, (time_now + one_second) - time_now);
+ EXPECT_EQ(-one_second, (time_now - one_second) - time_now);
+
+ TimeTicks ticks_now = TimeTicks::Now();
+ EXPECT_EQ(-one_second, (ticks_now - one_second) - ticks_now);
+ EXPECT_EQ(one_second, (ticks_now + one_second) - ticks_now);
+}
+
TEST(TimeDeltaLogging, DCheckEqCompiles) {
DCHECK_EQ(TimeDelta(), TimeDelta());
}
diff --git a/base/trace_event/BUILD.gn b/base/trace_event/BUILD.gn
index 10f7ec9..479a918 100644
--- a/base/trace_event/BUILD.gn
+++ b/base/trace_event/BUILD.gn
@@ -1,11 +1,15 @@
-# Copyright (c) 2015 The Chromium Authors. All rights reserved.
+# Copyright 2015 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
source_set("trace_event") {
sources = [
+ "memory_allocator_attributes.h",
+ "memory_allocator_dump.cc",
+ "memory_allocator_dump.h",
"memory_dump_manager.cc",
"memory_dump_manager.h",
+ "memory_dump_provider.cc",
"memory_dump_provider.h",
"process_memory_dump.cc",
"process_memory_dump.h",
@@ -59,3 +63,25 @@
visibility = [ "//base/*" ]
}
+
+source_set("trace_event_unittests") {
+ testonly = true
+ sources = [
+ "memory_allocator_dump_unittest.cc",
+ "memory_dump_manager_unittest.cc",
+ "process_memory_maps_dump_provider_unittest.cc",
+ "process_memory_totals_dump_provider_unittest.cc",
+ "trace_event_argument_unittest.cc",
+ "trace_event_memory_unittest.cc",
+ "trace_event_synthetic_delay_unittest.cc",
+ "trace_event_system_stats_monitor_unittest.cc",
+ "trace_event_unittest.cc",
+ "trace_event_win_unittest.cc",
+ ]
+
+ deps = [
+ "//base/test:test_support",
+ "//testing/gmock",
+ "//testing/gtest",
+ ]
+}
diff --git a/base/trace_event/memory_allocator_attributes.h b/base/trace_event/memory_allocator_attributes.h
new file mode 100644
index 0000000..efae9de
--- /dev/null
+++ b/base/trace_event/memory_allocator_attributes.h
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_H_
+
+#include <string>
+
+#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+
+namespace base {
+namespace trace_event {
+
+struct BASE_EXPORT MemoryAllocatorDeclaredAttribute {
+ std::string name;
+
+ // Refer to src/tools/perf/unit-info.json for the semantic of the type.
+ std::string type;
+};
+
+using MemoryAllocatorDeclaredAttributes =
+ hash_map<std::string, MemoryAllocatorDeclaredAttribute>;
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_ATTRIBUTES_H_
diff --git a/base/trace_event/memory_allocator_dump.cc b/base/trace_event/memory_allocator_dump.cc
new file mode 100644
index 0000000..604af7a
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump.cc
@@ -0,0 +1,91 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
+#include "base/trace_event/memory_allocator_attributes.h"
+#include "base/trace_event/memory_dump_manager.h"
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/trace_event_argument.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryAllocatorDump::MemoryAllocatorDump(const std::string& name,
+ MemoryAllocatorDump* parent)
+ : name_(name),
+ parent_(parent),
+ physical_size_in_bytes_(0),
+ allocated_objects_count_(0),
+ allocated_objects_size_in_bytes_(0) {
+ // Dots are not allowed in the name as the underlying base::DictionaryValue
+ // would treat them magically and split in sub-nodes, which is not intended.
+ DCHECK_EQ(std::string::npos, name.find_first_of('.'));
+}
+
+MemoryAllocatorDump::~MemoryAllocatorDump() {
+}
+
+void MemoryAllocatorDump::SetExtraAttribute(const std::string& name,
+ int value) {
+ extra_attributes_.SetInteger(name, value);
+}
+
+int MemoryAllocatorDump::GetExtraIntegerAttribute(
+ const std::string& name) const {
+ bool res;
+ int value = -1;
+ res = extra_attributes_.GetInteger(name, &value);
+ DCHECK(res) << "Allocator attribute '" << name << "' not found";
+ return value;
+}
+
+void MemoryAllocatorDump::AsValueInto(TracedValue* value) const {
+ static const char kHexFmt[] = "%" PRIx64;
+
+ value->BeginDictionary(name_.c_str());
+
+ value->SetString("parent", parent_ ? parent_->name_ : "");
+ value->SetString("physical_size_in_bytes",
+ StringPrintf(kHexFmt, physical_size_in_bytes_));
+ value->SetString("allocated_objects_count",
+ StringPrintf(kHexFmt, allocated_objects_count_));
+ value->SetString("allocated_objects_size_in_bytes",
+ StringPrintf(kHexFmt, allocated_objects_size_in_bytes_));
+
+ // Copy all the extra attributes.
+ const MemoryDumpProvider* mdp =
+ MemoryDumpManager::GetInstance()->dump_provider_currently_active();
+ const MemoryAllocatorDeclaredAttributes& extra_attributes_types =
+ mdp->allocator_attributes();
+
+ value->BeginDictionary("args");
+ for (DictionaryValue::Iterator it(extra_attributes_); !it.IsAtEnd();
+ it.Advance()) {
+ const std::string& attr_name = it.key();
+ const Value& attr_value = it.value();
+ value->BeginDictionary(attr_name.c_str());
+ value->SetValue("value", attr_value.DeepCopy());
+
+ auto attr_it = extra_attributes_types.find(attr_name);
+ DCHECK(attr_it != extra_attributes_types.end())
+ << "Allocator attribute " << attr_name
+ << " not declared for the dumper " << mdp->GetFriendlyName();
+
+ // TODO(primiano): the "type" should be dumped just once, not repeated on
+ // on every event. The ability of doing so depends on crbug.com/466121.
+ value->SetString("type", attr_it->second.type);
+
+ value->EndDictionary(); // "arg_name": { "type": "...", "value": "..." }
+ }
+ value->EndDictionary(); // "args": {}
+
+ value->EndDictionary(); // "allocator name": {}
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/memory_allocator_dump.h b/base/trace_event/memory_allocator_dump.h
new file mode 100644
index 0000000..4d7293e
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump.h
@@ -0,0 +1,66 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+#define BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/trace_event/memory_allocator_attributes.h"
+#include "base/values.h"
+
+namespace base {
+namespace trace_event {
+
+class MemoryDumpManager;
+class TracedValue;
+
+// Data model for user-land memory allocator dumps.
+class BASE_EXPORT MemoryAllocatorDump {
+ public:
+ MemoryAllocatorDump(const std::string& name, MemoryAllocatorDump* parent);
+ ~MemoryAllocatorDump();
+
+ const std::string& name() const { return name_; }
+ const MemoryAllocatorDump* parent() const { return parent_; }
+
+ void set_physical_size_in_bytes(uint64 value) {
+ physical_size_in_bytes_ = value;
+ }
+ uint64 physical_size_in_bytes() const { return physical_size_in_bytes_; }
+
+ void set_allocated_objects_count(uint64 value) {
+ allocated_objects_count_ = value;
+ }
+ uint64 allocated_objects_count() const { return allocated_objects_count_; }
+
+ void set_allocated_objects_size_in_bytes(uint64 value) {
+ allocated_objects_size_in_bytes_ = value;
+ }
+ uint64 allocated_objects_size_in_bytes() const {
+ return allocated_objects_size_in_bytes_;
+ }
+
+ void SetExtraAttribute(const std::string& name, int value);
+ int GetExtraIntegerAttribute(const std::string& name) const;
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ private:
+ const std::string name_;
+ MemoryAllocatorDump* const parent_; // Not owned.
+ uint64 physical_size_in_bytes_;
+ uint64 allocated_objects_count_;
+ uint64 allocated_objects_size_in_bytes_;
+ DictionaryValue extra_attributes_;
+
+ DISALLOW_COPY_AND_ASSIGN(MemoryAllocatorDump);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_MEMORY_ALLOCATOR_DUMP_H_
diff --git a/base/trace_event/memory_allocator_dump_unittest.cc b/base/trace_event/memory_allocator_dump_unittest.cc
new file mode 100644
index 0000000..8c14560
--- /dev/null
+++ b/base/trace_event/memory_allocator_dump_unittest.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_allocator_dump.h"
+
+#include "base/trace_event/memory_dump_provider.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+namespace {
+class FakeMemoryAllocatorDumpProvider : public MemoryDumpProvider {
+ public:
+ FakeMemoryAllocatorDumpProvider() {
+ DeclareAllocatorAttribute({"attr1", "count"});
+ DeclareAllocatorAttribute({"attr2", "bytes"});
+ }
+
+ bool DumpInto(ProcessMemoryDump* pmd) override {
+ MemoryAllocatorDump* mad_foo = pmd->CreateAllocatorDump("foo");
+ mad_foo->set_physical_size_in_bytes(4096);
+ mad_foo->set_allocated_objects_count(42);
+ mad_foo->set_allocated_objects_size_in_bytes(1000);
+ mad_foo->SetExtraAttribute("attr1", 1234);
+ mad_foo->SetExtraAttribute("attr2", 99);
+
+ MemoryAllocatorDump* mad_bar = pmd->CreateAllocatorDump("foo/bar", mad_foo);
+ mad_bar->set_physical_size_in_bytes(1);
+ mad_bar->set_allocated_objects_count(2);
+ mad_bar->set_allocated_objects_size_in_bytes(3);
+
+ pmd->CreateAllocatorDump("baz");
+ // Leave the rest of |baz| deliberately uninitialized, to check that
+ // CreateAllocatorDump returns a properly zero-initialized object.
+
+ return true;
+ }
+
+ const char* GetFriendlyName() const override { return "mock_allocator"; }
+};
+} // namespace
+
+TEST(MemoryAllocatorDumpTest, DumpIntoProcessMemoryDump) {
+ FakeMemoryAllocatorDumpProvider fmadp;
+ ProcessMemoryDump pmd;
+
+ fmadp.DumpInto(&pmd);
+
+ ASSERT_EQ(3u, pmd.allocator_dumps().size());
+
+ const MemoryAllocatorDump* mad_foo = pmd.GetAllocatorDump("foo");
+ ASSERT_NE(nullptr, mad_foo);
+ EXPECT_EQ("foo", mad_foo->name());
+ ASSERT_EQ(nullptr, mad_foo->parent());
+ EXPECT_EQ(4096u, mad_foo->physical_size_in_bytes());
+ EXPECT_EQ(42u, mad_foo->allocated_objects_count());
+ EXPECT_EQ(1000u, mad_foo->allocated_objects_size_in_bytes());
+
+ // Check the extra attributes of |mad_foo|.
+ EXPECT_EQ(1234, mad_foo->GetExtraIntegerAttribute("attr1"));
+ EXPECT_EQ(99, mad_foo->GetExtraIntegerAttribute("attr2"));
+
+ const MemoryAllocatorDump* mad_bar = pmd.GetAllocatorDump("foo/bar");
+ ASSERT_NE(nullptr, mad_bar);
+ EXPECT_EQ("foo/bar", mad_bar->name());
+ ASSERT_EQ(mad_foo, mad_bar->parent());
+ EXPECT_EQ(1u, mad_bar->physical_size_in_bytes());
+ EXPECT_EQ(2u, mad_bar->allocated_objects_count());
+ EXPECT_EQ(3u, mad_bar->allocated_objects_size_in_bytes());
+
+ const MemoryAllocatorDump* mad_baz = pmd.GetAllocatorDump("baz");
+ ASSERT_NE(nullptr, mad_baz);
+ EXPECT_EQ("baz", mad_baz->name());
+ ASSERT_EQ(nullptr, mad_baz->parent());
+ EXPECT_EQ(0u, mad_baz->physical_size_in_bytes());
+ EXPECT_EQ(0u, mad_baz->allocated_objects_count());
+ EXPECT_EQ(0u, mad_baz->allocated_objects_size_in_bytes());
+}
+
+// DEATH tests are not supported in Android / iOS.
+#if !defined(NDEBUG) && !defined(OS_ANDROID) && !defined(OS_IOS)
+TEST(MemoryAllocatorDumpTest, ForbidDuplicatesDeathTest) {
+ FakeMemoryAllocatorDumpProvider fmadp;
+ ProcessMemoryDump pmd;
+ pmd.CreateAllocatorDump("dump_1");
+ pmd.CreateAllocatorDump("dump_2");
+ ASSERT_DEATH(pmd.CreateAllocatorDump("dump_1"), "");
+}
+#endif
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index 8b2d930..0ec5d19 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -59,7 +59,8 @@
g_instance_for_testing = instance;
}
-MemoryDumpManager::MemoryDumpManager() : memory_tracing_enabled_(0) {
+MemoryDumpManager::MemoryDumpManager()
+ : dump_provider_currently_active_(nullptr), memory_tracing_enabled_(0) {
}
MemoryDumpManager::~MemoryDumpManager() {
@@ -128,17 +129,19 @@
AutoLock lock(lock_);
for (auto it = dump_providers_enabled_.begin();
it != dump_providers_enabled_.end();) {
- MemoryDumpProvider* dump_provider = *it;
- if (dump_provider->DumpInto(pmd.get())) {
+ dump_provider_currently_active_ = *it;
+ if (dump_provider_currently_active_->DumpInto(pmd.get())) {
did_any_provider_dump = true;
++it;
} else {
- LOG(ERROR) << "The memory dumper " << dump_provider->GetFriendlyName()
+ LOG(ERROR) << "The memory dumper "
+ << dump_provider_currently_active_->GetFriendlyName()
<< " failed, possibly due to sandboxing (crbug.com/461788), "
"disabling it for current process. Try restarting chrome "
"with the --no-sandbox switch.";
it = dump_providers_enabled_.erase(it);
}
+ dump_provider_currently_active_ = nullptr;
}
}
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index 8a9b3b7..04d0135 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -49,6 +49,12 @@
void OnTraceLogEnabled() override;
void OnTraceLogDisabled() override;
+ // Returns the MemoryDumpProvider which is currently being dumping into a
+ // ProcessMemoryDump via DumpInto(...) if any, nullptr otherwise.
+ MemoryDumpProvider* dump_provider_currently_active() const {
+ return dump_provider_currently_active_;
+ }
+
private:
friend struct DefaultDeleter<MemoryDumpManager>; // For the testing instance.
friend struct DefaultSingletonTraits<MemoryDumpManager>;
@@ -70,6 +76,9 @@
std::vector<MemoryDumpProvider*> dump_providers_registered_; // Not owned.
std::vector<MemoryDumpProvider*> dump_providers_enabled_; // Not owned.
+ // TODO(primiano): this is required only until crbug.com/466121 gets fixed.
+ MemoryDumpProvider* dump_provider_currently_active_; // Now owned.
+
// Protects from concurrent accesses to the |dump_providers_*|, e.g., tearing
// down logging while creating a dump point on another thread.
Lock lock_;
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index 251a92a..65e719f 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -10,6 +10,7 @@
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
+using testing::Invoke;
using testing::Return;
namespace base {
@@ -51,6 +52,14 @@
public:
MOCK_METHOD1(DumpInto, bool(ProcessMemoryDump* pmd));
+ // DumpInto() override for the ActiveDumpProviderConsistency test,
+ bool DumpIntoAndCheckDumpProviderCurrentlyActive(ProcessMemoryDump* pmd) {
+ EXPECT_EQ(
+ this,
+ MemoryDumpManager::GetInstance()->dump_provider_currently_active());
+ return true;
+ }
+
const char* GetFriendlyName() const override { return "MockDumpProvider"; }
};
@@ -148,5 +157,30 @@
DisableTracing();
}
+// TODO(primiano): remove once crbug.com/466121 gets fixed.
+// Ascertains that calls to MDM::dump_provider_currently_active() actually
+// returns the MemoryDumpProvider currently active during the DumpInto() call.
+TEST_F(MemoryDumpManagerTest, ActiveDumpProviderConsistency) {
+ MockDumpProvider mdp1;
+ MockDumpProvider mdp2;
+
+ mdm_->RegisterDumpProvider(&mdp1);
+ mdm_->RegisterDumpProvider(&mdp2);
+ EnableTracing(kTraceCategory);
+ EXPECT_CALL(mdp1, DumpInto(_))
+ .Times(2)
+ .WillRepeatedly(Invoke(
+ &mdp1,
+ &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
+ EXPECT_CALL(mdp2, DumpInto(_))
+ .Times(2)
+ .WillRepeatedly(Invoke(
+ &mdp2,
+ &MockDumpProvider::DumpIntoAndCheckDumpProviderCurrentlyActive));
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ mdm_->RequestDumpPoint(DumpPointType::EXPLICITLY_TRIGGERED);
+ DisableTracing();
+}
+
} // namespace trace_event
} // namespace base
diff --git a/base/trace_event/memory_dump_provider.cc b/base/trace_event/memory_dump_provider.cc
new file mode 100644
index 0000000..9518461
--- /dev/null
+++ b/base/trace_event/memory_dump_provider.cc
@@ -0,0 +1,27 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/memory_dump_provider.h"
+
+#include "base/logging.h"
+
+namespace base {
+namespace trace_event {
+
+MemoryDumpProvider::MemoryDumpProvider() {
+}
+
+MemoryDumpProvider::~MemoryDumpProvider() {
+}
+
+void MemoryDumpProvider::DeclareAllocatorAttribute(
+ const MemoryAllocatorDeclaredAttribute& attr) {
+ DCHECK_EQ(0u, allocator_attributes_.count(attr.name))
+ << "Allocator attribute " << attr.name << " already declared for dumper "
+ << GetFriendlyName();
+ allocator_attributes_[attr.name] = attr;
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/memory_dump_provider.h b/base/trace_event/memory_dump_provider.h
index 1c5bbb1..5cc3a6e 100644
--- a/base/trace_event/memory_dump_provider.h
+++ b/base/trace_event/memory_dump_provider.h
@@ -6,7 +6,7 @@
#define BASE_TRACE_EVENT_MEMORY_DUMP_PROVIDER_H_
#include "base/base_export.h"
-#include "base/macros.h"
+#include "base/trace_event/memory_allocator_attributes.h"
namespace base {
namespace trace_event {
@@ -22,11 +22,22 @@
virtual const char* GetFriendlyName() const = 0;
+ const MemoryAllocatorDeclaredAttributes& allocator_attributes() const {
+ return allocator_attributes_;
+ }
+
protected:
- MemoryDumpProvider() {}
- virtual ~MemoryDumpProvider() {}
+ MemoryDumpProvider();
+ virtual ~MemoryDumpProvider();
+
+ void DeclareAllocatorAttribute(const MemoryAllocatorDeclaredAttribute& attr);
private:
+ // The map (attribute name -> type) that specifies the semantic of the
+ // extra attributes that the MemoryAllocatorDump(s) produced by this
+ // MemoryDumpProvider will have.
+ MemoryAllocatorDeclaredAttributes allocator_attributes_;
+
DISALLOW_COPY_AND_ASSIGN(MemoryDumpProvider);
};
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 5363db5..bbca36c 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -17,6 +17,27 @@
ProcessMemoryDump::~ProcessMemoryDump() {
}
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+ const std::string& name) {
+ return CreateAllocatorDump(name, nullptr);
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::CreateAllocatorDump(
+ const std::string& name,
+ MemoryAllocatorDump* parent) {
+ DCHECK_EQ(0ul, allocator_dumps_.count(name));
+ MemoryAllocatorDump* mad = new MemoryAllocatorDump(name, parent);
+ allocator_dumps_storage_.push_back(mad);
+ allocator_dumps_[name] = mad;
+ return mad;
+}
+
+MemoryAllocatorDump* ProcessMemoryDump::GetAllocatorDump(
+ const std::string& name) const {
+ auto it = allocator_dumps_.find(name);
+ return it == allocator_dumps_.end() ? nullptr : it->second;
+}
+
void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
// Build up the [dumper name] -> [value] dictionary.
if (has_process_totals_) {
@@ -29,6 +50,12 @@
process_mmaps_.AsValueInto(value);
value->EndDictionary();
}
+ if (allocator_dumps_storage_.size() > 0) {
+ value->BeginDictionary("allocators");
+ for (const MemoryAllocatorDump* allocator_dump : allocator_dumps_storage_)
+ allocator_dump->AsValueInto(value);
+ value->EndDictionary();
+ }
}
} // namespace trace_event
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index 4256c4c..df6cc82 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -6,6 +6,10 @@
#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
#include "base/base_export.h"
+#include "base/containers/hash_tables.h"
+#include "base/containers/small_map.h"
+#include "base/memory/scoped_vector.h"
+#include "base/trace_event/memory_allocator_dump.h"
#include "base/trace_event/process_memory_maps.h"
#include "base/trace_event/process_memory_totals.h"
@@ -13,6 +17,7 @@
namespace trace_event {
class ConvertableToTraceFormat;
+class MemoryDumpManager;
// ProcessMemoryDump is as a strongly typed container which enforces the data
// model for each memory dump point and holds the dumps produced by the
@@ -22,6 +27,9 @@
// dump point time.
class BASE_EXPORT ProcessMemoryDump {
public:
+ using AllocatorDumpsMap =
+ SmallMap<hash_map<std::string, MemoryAllocatorDump*>>;
+
ProcessMemoryDump();
~ProcessMemoryDump();
@@ -36,6 +44,21 @@
bool has_process_mmaps() const { return has_process_mmaps_; }
void set_has_process_mmaps() { has_process_mmaps_ = true; }
+ // Creates a new MemoryAllocatorDump with the given name and returns the
+ // empty object back to the caller. The |name| must be unique in the dump.
+ // ProcessMemoryDump handles the memory ownership of the created object.
+ // |parent| can be used to specify a hierarchical relationship of the
+ // allocator dumps.
+ MemoryAllocatorDump* CreateAllocatorDump(const std::string& name);
+ MemoryAllocatorDump* CreateAllocatorDump(const std::string& name,
+ MemoryAllocatorDump* parent);
+
+ // Returns a MemoryAllocatorDump given its name or nullptr if not found.
+ MemoryAllocatorDump* GetAllocatorDump(const std::string& name) const;
+
+ // Returns the map of the MemoryAllocatorDumps added to this dump.
+ const AllocatorDumpsMap& allocator_dumps() const { return allocator_dumps_; }
+
private:
ProcessMemoryTotals process_totals_;
bool has_process_totals_;
@@ -43,6 +66,13 @@
ProcessMemoryMaps process_mmaps_;
bool has_process_mmaps_;
+ // A maps of "allocator_name" -> MemoryAllocatorDump populated by
+ // allocator dump providers.
+ AllocatorDumpsMap allocator_dumps_;
+
+ // ProcessMemoryDump handles the memory ownership of all its belongings.
+ ScopedVector<MemoryAllocatorDump> allocator_dumps_storage_;
+
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
};
diff --git a/base/trace_event/process_memory_maps.cc b/base/trace_event/process_memory_maps.cc
index bf3c5a0..d553ee8 100644
--- a/base/trace_event/process_memory_maps.cc
+++ b/base/trace_event/process_memory_maps.cc
@@ -4,6 +4,8 @@
#include "base/trace_event/process_memory_maps.h"
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event_argument.h"
namespace base {
@@ -21,19 +23,25 @@
}
void ProcessMemoryMaps::AsValueInto(TracedValue* value) const {
+ static const char kHexFmt[] = "%" PRIx64;
+
+ // Refer to the design doc goo.gl/sxfFY8 for the semantic of these fields.
value->BeginArray("vm_regions");
for (const auto& region : vm_regions_) {
value->BeginDictionary();
- value->SetDouble("start_address", region.start_address);
- value->SetDouble("size_in_bytes", region.size_in_bytes);
- value->SetInteger("protection_flags", region.protection_flags);
- value->SetString("mapped_file", region.mapped_file);
- value->SetDouble("mapped_file_offset", region.mapped_file_offset);
+ value->SetString("sa", StringPrintf(kHexFmt, region.start_address));
+ value->SetString("sz", StringPrintf(kHexFmt, region.size_in_bytes));
+ value->SetInteger("pf", region.protection_flags);
+ value->SetString("mf", region.mapped_file);
- value->BeginDictionary("byte_stats");
- value->SetDouble("resident", region.byte_stats_resident);
- value->SetDouble("anonymous", region.byte_stats_anonymous);
+ value->BeginDictionary("bs"); // byte stats
+ value->SetString(
+ "pss", StringPrintf(kHexFmt, region.byte_stats_proportional_resident));
+ value->SetString("prv",
+ StringPrintf(kHexFmt, region.byte_stats_private_resident));
+ value->SetString("shr",
+ StringPrintf(kHexFmt, region.byte_stats_shared_resident));
value->EndDictionary();
value->EndDictionary();
diff --git a/base/trace_event/process_memory_maps.h b/base/trace_event/process_memory_maps.h
index 70f6610..dc1892f 100644
--- a/base/trace_event/process_memory_maps.h
+++ b/base/trace_event/process_memory_maps.h
@@ -28,9 +28,13 @@
uint64 size_in_bytes;
uint32 protection_flags;
std::string mapped_file;
- uint64 mapped_file_offset;
- uint64 byte_stats_resident;
- uint64 byte_stats_anonymous;
+
+ // private_resident + shared_resident = resident set size.
+ uint64 byte_stats_private_resident;
+ uint64 byte_stats_shared_resident;
+
+ // For multiprocess accounting.
+ uint64 byte_stats_proportional_resident;
};
ProcessMemoryMaps();
diff --git a/base/trace_event/process_memory_maps_dump_provider.cc b/base/trace_event/process_memory_maps_dump_provider.cc
index fbe0eb1..d728bd3 100644
--- a/base/trace_event/process_memory_maps_dump_provider.cc
+++ b/base/trace_event/process_memory_maps_dump_provider.cc
@@ -60,7 +60,7 @@
region->protection_flags |=
ProcessMemoryMaps::VMRegion::kProtectionFlagsExec;
}
- *smaps >> std::hex >> region->mapped_file_offset;
+ *smaps >> ignored; // Ignore mapped file offset.
*smaps >> ignored; // Ignore device maj-min (fc:01 in the example above).
*smaps >> ignored; // Ignore inode number (1234 in the example above).
@@ -73,9 +73,15 @@
return res;
}
+uint64 ReadCounterBytes(std::istream* smaps) {
+ uint64 counter_value = 0;
+ *smaps >> std::dec >> counter_value;
+ return counter_value * 1024;
+}
+
uint32 ParseSmapsCounter(std::istream* smaps,
ProcessMemoryMaps::VMRegion* region) {
- // e.g., "RSS: 0 Kb\n"
+ // A smaps counter lines looks as follows: "RSS: 0 Kb\n"
uint32 res = 0;
std::string counter_name;
*smaps >> counter_name;
@@ -83,13 +89,17 @@
// TODO(primiano): "Swap" should also be accounted as resident. Check
// whether Rss isn't already counting swapped and fix below if that is
// the case.
- if (counter_name == "Rss:") {
- *smaps >> std::dec >> region->byte_stats_resident;
- region->byte_stats_resident *= 1024;
+ if (counter_name == "Pss:") {
+ region->byte_stats_proportional_resident = ReadCounterBytes(smaps);
res = 1;
- } else if (counter_name == "Anonymous:") {
- *smaps >> std::dec >> region->byte_stats_anonymous;
- region->byte_stats_anonymous *= 1024;
+ } else if (counter_name == "Private_Dirty:" ||
+ counter_name == "Private_Clean:") {
+ // For Private and Shared counters keep the sum of the dirty + clean stats.
+ region->byte_stats_private_resident += ReadCounterBytes(smaps);
+ res = 1;
+ } else if (counter_name == "Shared_Dirty:" ||
+ counter_name == "Shared_Clean:") {
+ region->byte_stats_shared_resident += ReadCounterBytes(smaps);
res = 1;
}
@@ -111,7 +121,7 @@
if (!smaps->good())
return 0;
- const uint32 kNumExpectedCountersPerRegion = 2;
+ const uint32 kNumExpectedCountersPerRegion = 5;
uint32 counters_parsed_for_current_region = 0;
uint32 num_valid_regions = 0;
ProcessMemoryMaps::VMRegion region;
diff --git a/base/trace_event/process_memory_maps_dump_provider_unittest.cc b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
index 02fd136..0bf81ac 100644
--- a/base/trace_event/process_memory_maps_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_maps_dump_provider_unittest.cc
@@ -36,12 +36,12 @@
"VmFlags: rd ex mr mw me dw sd\n"
"ff000000-ff800000 -w-p 00001080 fc:01 0 /file/name with space\n"
"Size: 0 kB\n"
- "Rss: 128 kB\n"
+ "Rss: 192 kB\n"
"Pss: 128 kB\n"
- "Shared_Clean: 124 kB\n"
- "Shared_Dirty: 0 kB\n"
- "Private_Clean: 68 kB\n"
- "Private_Dirty: 0 kB\n"
+ "Shared_Clean: 120 kB\n"
+ "Shared_Dirty: 4 kB\n"
+ "Private_Clean: 60 kB\n"
+ "Private_Dirty: 8 kB\n"
"Referenced: 296 kB\n"
"Anonymous: 0 kB\n"
"AnonHugePages: 0 kB\n"
@@ -91,7 +91,7 @@
"7fe7ce79c000-7fe7ce7a8000 ---p 00000000 00:00 0 \n"
"Size: 48 kB\n"
"Rss: 40 kB\n"
- "Pss: 0 kB\n"
+ "Pss: 32 kB\n"
"Shared_Clean: 16 kB\n"
"Shared_Dirty: 12 kB\n"
"Private_Clean: 8 kB\n"
@@ -141,17 +141,17 @@
EXPECT_EQ(0x004be000UL - 0x00400000UL, regions_1[0].size_in_bytes);
EXPECT_EQ(kProtR | kProtX, regions_1[0].protection_flags);
EXPECT_EQ("/file/1", regions_1[0].mapped_file);
- EXPECT_EQ(0UL, regions_1[0].mapped_file_offset);
- EXPECT_EQ(296 * 1024UL, regions_1[0].byte_stats_resident);
- EXPECT_EQ(68 * 1024UL, regions_1[0].byte_stats_anonymous);
+ EXPECT_EQ(162 * 1024UL, regions_1[0].byte_stats_proportional_resident);
+ EXPECT_EQ((228 + 0) * 1024UL, regions_1[0].byte_stats_shared_resident);
+ EXPECT_EQ((0 + 68) * 1024UL, regions_1[0].byte_stats_private_resident);
EXPECT_EQ(0xff000000UL, regions_1[1].start_address);
EXPECT_EQ(0xff800000UL - 0xff000000UL, regions_1[1].size_in_bytes);
EXPECT_EQ(kProtW, regions_1[1].protection_flags);
EXPECT_EQ("/file/name with space", regions_1[1].mapped_file);
- EXPECT_EQ(0x00001080UL, regions_1[1].mapped_file_offset);
- EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_resident);
- EXPECT_EQ(0UL, regions_1[1].byte_stats_anonymous);
+ EXPECT_EQ(128 * 1024UL, regions_1[1].byte_stats_proportional_resident);
+ EXPECT_EQ((120 + 4) * 1024UL, regions_1[1].byte_stats_shared_resident);
+ EXPECT_EQ((60 + 8) * 1024UL, regions_1[1].byte_stats_private_resident);
// Parse the 2nd smaps file.
ProcessMemoryDump pmd_2;
@@ -165,9 +165,9 @@
EXPECT_EQ(0x7fe7ce7a8000UL - 0x7fe7ce79c000UL, regions_2[0].size_in_bytes);
EXPECT_EQ(0U, regions_2[0].protection_flags);
EXPECT_EQ("", regions_2[0].mapped_file);
- EXPECT_EQ(0UL, regions_2[0].mapped_file_offset);
- EXPECT_EQ(40 * 1024UL, regions_2[0].byte_stats_resident);
- EXPECT_EQ(16 * 1024UL, regions_2[0].byte_stats_anonymous);
+ EXPECT_EQ(32 * 1024UL, regions_2[0].byte_stats_proportional_resident);
+ EXPECT_EQ((16 + 12) * 1024UL, regions_2[0].byte_stats_shared_resident);
+ EXPECT_EQ((8 + 4) * 1024UL, regions_2[0].byte_stats_private_resident);
}
#endif // defined(OS_LINUX) || defined(OS_ANDROID)
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
index 41ad788..9b0c377 100644
--- a/base/trace_event/process_memory_totals.cc
+++ b/base/trace_event/process_memory_totals.cc
@@ -4,13 +4,16 @@
#include "base/trace_event/process_memory_totals.h"
+#include "base/format_macros.h"
+#include "base/strings/stringprintf.h"
#include "base/trace_event/trace_event_argument.h"
namespace base {
namespace trace_event {
void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
- value->SetDouble("resident_set_bytes", resident_set_bytes_);
+ value->SetString("resident_set_bytes",
+ StringPrintf("%" PRIx64, resident_set_bytes_));
}
} // namespace trace_event
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
index 1c99152..29c94c9 100644
--- a/base/trace_event/process_memory_totals.h
+++ b/base/trace_event/process_memory_totals.h
@@ -13,10 +13,10 @@
class TracedValue;
-// Dump provider which collects process-wide memory stats.
+// Data model for process-wide memory stats.
class BASE_EXPORT ProcessMemoryTotals {
public:
- ProcessMemoryTotals() {}
+ ProcessMemoryTotals() : resident_set_bytes_(0) {}
// Called at trace generation time to populate the TracedValue.
void AsValueInto(TracedValue* value) const;
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
index c37e612..372db63 100644
--- a/base/trace_event/process_memory_totals_dump_provider_unittest.cc
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -12,18 +12,18 @@
namespace trace_event {
TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
- auto mdptp = ProcessMemoryTotalsDumpProvider::GetInstance();
+ auto pmtdp = ProcessMemoryTotalsDumpProvider::GetInstance();
scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump());
scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump());
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
- mdptp->DumpInto(pmd_before.get());
+ pmtdp->DumpInto(pmd_before.get());
// Pretend that the RSS of the process increased of +1M.
const size_t kAllocSize = 1048576;
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
- mdptp->DumpInto(pmd_after.get());
+ pmtdp->DumpInto(pmd_after.get());
ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
diff --git a/base/trace_event/trace_event.gypi b/base/trace_event/trace_event.gypi
new file mode 100644
index 0000000..ca6c076
--- /dev/null
+++ b/base/trace_event/trace_event.gypi
@@ -0,0 +1,53 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+ 'variables': {
+ 'trace_event_sources' : [
+ 'trace_event/memory_allocator_attributes.h',
+ 'trace_event/memory_allocator_dump.cc',
+ 'trace_event/memory_allocator_dump.h',
+ 'trace_event/memory_dump_manager.cc',
+ 'trace_event/memory_dump_manager.h',
+ 'trace_event/memory_dump_provider.cc',
+ 'trace_event/memory_dump_provider.h',
+ 'trace_event/process_memory_dump.cc',
+ 'trace_event/process_memory_dump.h',
+ 'trace_event/process_memory_maps.cc',
+ 'trace_event/process_memory_maps.h',
+ 'trace_event/process_memory_maps_dump_provider.cc',
+ 'trace_event/process_memory_maps_dump_provider.h',
+ 'trace_event/process_memory_totals.cc',
+ 'trace_event/process_memory_totals.h',
+ 'trace_event/process_memory_totals_dump_provider.cc',
+ 'trace_event/process_memory_totals_dump_provider.h',
+ 'trace_event/trace_event.h',
+ 'trace_event/trace_event_android.cc',
+ 'trace_event/trace_event_argument.cc',
+ 'trace_event/trace_event_argument.h',
+ 'trace_event/trace_event_impl.cc',
+ 'trace_event/trace_event_impl.h',
+ 'trace_event/trace_event_impl_constants.cc',
+ 'trace_event/trace_event_memory.cc',
+ 'trace_event/trace_event_memory.h',
+ 'trace_event/trace_event_synthetic_delay.cc',
+ 'trace_event/trace_event_synthetic_delay.h',
+ 'trace_event/trace_event_system_stats_monitor.cc',
+ 'trace_event/trace_event_system_stats_monitor.h',
+ 'trace_event/trace_event_win.cc',
+ 'trace_event/trace_event_win.h',
+ ],
+ 'trace_event_test_sources' : [
+ 'trace_event/memory_allocator_dump_unittest.cc',
+ 'trace_event/memory_dump_manager_unittest.cc',
+ 'trace_event/process_memory_maps_dump_provider_unittest.cc',
+ 'trace_event/process_memory_totals_dump_provider_unittest.cc',
+ 'trace_event/trace_event_argument_unittest.cc',
+ 'trace_event/trace_event_memory_unittest.cc',
+ 'trace_event/trace_event_synthetic_delay_unittest.cc',
+ 'trace_event/trace_event_system_stats_monitor_unittest.cc',
+ 'trace_event/trace_event_unittest.cc',
+ 'trace_event/trace_event_win_unittest.cc',
+ ],
+ },
+}
diff --git a/base/trace_event/trace_event.h b/base/trace_event/trace_event.h
index 9d8e7d1..1bf9429 100644
--- a/base/trace_event/trace_event.h
+++ b/base/trace_event/trace_event.h
@@ -681,16 +681,20 @@
// events.
// - category and name strings must have application lifetime (statics or
// literals). They may not include " chars.
-// - |id| is used to match the NESTABLE_ASYNC_BEGIN event with the
-// NESTABLE_ASYNC_END event. Events are considered to match if their
-// category_group, name and id values all match. |id| must either be a
-// pointer or an integer value up to 64 bits. If it's a pointer, the bits
-// will be xored with a hash of the process ID so that the same pointer on two
-// different processes will not collide.
+// - A pair of NESTABLE_ASYNC_BEGIN event and NESTABLE_ASYNC_END event is
+// considered as a match if their category_group, name and id all match.
+// - |id| must either be a pointer or an integer value up to 64 bits.
+// If it's a pointer, the bits will be xored with a hash of the process ID so
+// that the same pointer on two different processes will not collide.
+// - |id| is used to match a child NESTABLE_ASYNC event with its parent
+// NESTABLE_ASYNC event. Therefore, events in the same nested event tree must
+// be logged using the same id and category_group.
//
-// Unmatched NESTABLE_ASYNC_END event will be parsed as an instant event,
-// and unmatched NESTABLE_ASYNC_BEGIN event will be parsed as an event that
-// ends at the last NESTABLE_ASYNC_END event of that |id|.
+// Unmatched NESTABLE_ASYNC_END event will be parsed as an event that starts
+// at the first NESTABLE_ASYNC event of that id, and unmatched
+// NESTABLE_ASYNC_BEGIN event will be parsed as an event that ends at the last
+// NESTABLE_ASYNC event of that id. Corresponding warning messages for
+// unmatched events will be shown in the analysis view.
// Records a single NESTABLE_ASYNC_BEGIN event called "name" immediately, with 2
// associated arguments. If the category is not enabled, then this does nothing.
diff --git a/build/android/adb_gdb b/build/android/adb_gdb
index c71b816..3612f90 100755
--- a/build/android/adb_gdb
+++ b/build/android/adb_gdb
@@ -97,6 +97,8 @@
NO_PULL_LIBS=
PACKAGE_NAME=
PID=
+PRIVILEGED=
+PRIVILEGED_INDEX=
PROGRAM_NAME="activity"
PULL_LIBS=
PULL_LIBS_DIR=
@@ -145,6 +147,13 @@
--pid=*)
PID=$optarg
;;
+ --privileged)
+ PRIVILEGED=true
+ ;;
+ --privileged=*)
+ PRIVILEGED=true
+ PRIVILEGED_INDEX=$optarg
+ ;;
--program-name=*)
PROGRAM_NAME=$optarg
;;
@@ -236,8 +245,9 @@
cat <<EOF
This script is used to debug a running $PROGRAM_NAME process.
-This can be a regular Android application process, or a sandboxed
-service, if you use the --sandboxed or --sandboxed=<num> option.
+This can be a regular Android application process, sandboxed (if you use the
+--sandboxed or --sandboxed=<num> option) or a privileged (--privileged or
+--privileged=<num>) service.
This script needs several things to work properly. It will try to pick
them up automatically for you though:
@@ -304,6 +314,8 @@
--symbol-dir=<path> Specify directory with symbol shared libraries.
--out-dir=<path> Specify the out directory.
--package-name=<name> Specify package name (alternative to 1st argument).
+ --privileged Debug first privileged process we find.
+ --privileged=<num> Debug specific privileged process.
--program-name=<name> Specify program name (cosmetic only).
--pid=<pid> Specify application process pid.
--force Kill any previous debugging session, if any.
@@ -818,6 +830,12 @@
PROCESSNAME=$PROCESSNAME:sandboxed_process
PID=$(adb_shell ps | \
awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1)
+ elif [ "$PRIVILEGED_INDEX" ]; then
+ PROCESSNAME=$PROCESSNAME:privileged_process$PRIVILEGED_INDEX
+ elif [ "$PRIVILEGED" ]; then
+ PROCESSNAME=$PROCESSNAME:privileged_process
+ PID=$(adb_shell ps | \
+ awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1)
fi
if [ -z "$PID" ]; then
PID=$(adb_shell ps | \
@@ -834,6 +852,8 @@
log "Found process PID: $PID"
elif [ "$SANDBOXED" ]; then
echo "WARNING: --sandboxed option ignored due to use of --pid."
+elif [ "$PRIVILEGED" ]; then
+ echo "WARNING: --privileged option ignored due to use of --pid."
fi
# Determine if 'adb shell' runs as root or not.
diff --git a/build/android/gyp/generate_v14_compatible_resources.py b/build/android/gyp/generate_v14_compatible_resources.py
index 79a2d5f..7818170 100755
--- a/build/android/gyp/generate_v14_compatible_resources.py
+++ b/build/android/gyp/generate_v14_compatible_resources.py
@@ -11,7 +11,7 @@
1. paddingStart attribute can cause a crash on Galaxy Tab 2.
2. There is a bug that paddingStart does not override paddingLeft on
- JB-MR1. This is fixed on JB-MR2.
+ JB-MR1. This is fixed on JB-MR2. b/8654490
Therefore, this resource generation script can be removed when
we drop the support for JB-MR1.
diff --git a/build/android/gyp/jinja_template.py b/build/android/gyp/jinja_template.py
index 3a93f74..9e9705c 100755
--- a/build/android/gyp/jinja_template.py
+++ b/build/android/gyp/jinja_template.py
@@ -18,18 +18,31 @@
import jinja2 # pylint: disable=F0401
-def ProcessFile(input_filename, output_filename, variables):
- with codecs.open(input_filename, 'r', 'utf-8') as input_file:
- input_ = input_file.read()
- env = jinja2.Environment(undefined=jinja2.StrictUndefined)
- template = env.from_string(input_)
- template.filename = os.path.abspath(input_filename)
+class RecordingFileSystemLoader(jinja2.FileSystemLoader):
+ '''A FileSystemLoader that stores a list of loaded templates.'''
+ def __init__(self, searchpath):
+ jinja2.FileSystemLoader.__init__(self, searchpath)
+ self.loaded_templates = set()
+
+ def get_source(self, environment, template):
+ contents, filename, uptodate = jinja2.FileSystemLoader.get_source(
+ self, environment, template)
+ self.loaded_templates.add(os.path.relpath(filename))
+ return contents, filename, uptodate
+
+ def get_loaded_templates(self):
+ return list(self.loaded_templates)
+
+
+def ProcessFile(env, input_filename, output_filename, variables):
+ input_rel_path = os.path.relpath(input_filename, build_utils.CHROMIUM_SRC)
+ template = env.get_template(input_rel_path)
output = template.render(variables)
with codecs.open(output_filename, 'w', 'utf-8') as output_file:
output_file.write(output)
-def ProcessFiles(input_filenames, inputs_base_dir, outputs_zip, variables):
+def ProcessFiles(env, input_filenames, inputs_base_dir, outputs_zip, variables):
with build_utils.TempDir() as temp_dir:
for input_filename in input_filenames:
relpath = os.path.relpath(os.path.abspath(input_filename),
@@ -41,7 +54,7 @@
output_filename = os.path.join(temp_dir, relpath)
parent_dir = os.path.dirname(output_filename)
build_utils.MakeDirectory(parent_dir)
- ProcessFile(input_filename, output_filename, variables)
+ ProcessFile(env, input_filename, output_filename, variables)
build_utils.ZipDir(outputs_zip, temp_dir)
@@ -82,14 +95,17 @@
name, _, value = v.partition('=')
variables[name] = value
+ loader = RecordingFileSystemLoader(build_utils.CHROMIUM_SRC)
+ env = jinja2.Environment(loader=loader, undefined=jinja2.StrictUndefined,
+ line_comment_prefix='##')
if options.output:
- ProcessFile(inputs[0], options.output, variables)
+ ProcessFile(env, inputs[0], options.output, variables)
else:
- ProcessFiles(inputs, options.inputs_base_dir, options.outputs_zip,
+ ProcessFiles(env, inputs, options.inputs_base_dir, options.outputs_zip,
variables)
if options.depfile:
- deps = inputs + build_utils.GetPythonDependencies()
+ deps = loader.get_loaded_templates() + build_utils.GetPythonDependencies()
build_utils.WriteDepfile(options.depfile, deps)
diff --git a/build/android/jinja_template.gypi b/build/android/jinja_template.gypi
index 25430ca..9c49360 100644
--- a/build/android/jinja_template.gypi
+++ b/build/android/jinja_template.gypi
@@ -45,6 +45,7 @@
'jinja_output%': '',
'jinja_outputs_zip%': '',
'jinja_inputs_base_dir%': '',
+ 'jinja_includes%': [],
'jinja_variables%': [],
'jinja_args': [],
},
@@ -52,6 +53,7 @@
'<(DEPTH)/build/android/gyp/util/build_utils.py',
'<(DEPTH)/build/android/gyp/jinja_template.py',
'<@(jinja_inputs)',
+ '<@(jinja_includes)',
],
'conditions': [
['jinja_output != ""', {
diff --git a/build/android/lint/suppressions.xml b/build/android/lint/suppressions.xml
index ba476d5..b16de84 100644
--- a/build/android/lint/suppressions.xml
+++ b/build/android/lint/suppressions.xml
@@ -70,37 +70,8 @@
<ignore path="org/chromium/base/AnimationFrameTimeHistogram$Recorder.class"/>
<ignore path="org/chromium/base/JavaHandlerThread.class"/>
<ignore path="org/chromium/base/SysUtils.class"/>
- <ignore path="org/chromium/chrome/browser/preferences/website/AddExceptionPreference.class"/>
- <ignore path="org/chromium/chrome/browser/infobar/AnimationHelper$*.class"/>
- <ignore path="org/chromium/chrome/browser/infobar/AppBannerInfoBar.class"/>
- <ignore path="org/chromium/chrome/browser/BookmarkUtils.class"/>
- <ignore path="org/chromium/chrome/browser/widget/ButtonCompat.class"/>
- <ignore path="org/chromium/chrome/browser/autofill/CardUnmaskPrompt.class"/>
- <ignore path="org/chromium/chrome/browser/LollipopTtsPlatformImpl.class"/>
- <ignore path="org/chromium/chrome/browser/LollipopTtsPlatformImpl$*.class"/>
<ignore path="org/chromium/chrome/browser/TtsPlatformImpl.class"/>
<ignore path="org/chromium/chrome/browser/TtsPlatformImpl$*.class"/>
- <ignore path="org/chromium/content/browser/accessibility/BrowserAccessibilityManager.class"/>
- <ignore path="org/chromium/content/browser/ContentViewCore.class"/>
- <ignore path="org/chromium/content/browser/accessibility/JellyBeanAccessibilityInjector.class"/>
- <ignore path="org/chromium/content/browser/accessibility/JellyBeanBrowserAccessibilityManager$*.class"/>
- <ignore path="org/chromium/content/browser/accessibility/LollipopAccessibilityInjector.class"/>
- <ignore path="org/chromium/content/browser/accessibility/LollipopAccessibilityInjector$*.class"/>
- <ignore path="org/chromium/content/browser/accessibility/LollipopBrowserAccessibilityManager.class"/>
- <ignore path="org/chromium/media/AudioManagerAndroid.class"/>
- <ignore path="org/chromium/media/MediaCodecBridge.class"/>
- <ignore path="org/chromium/media/MediaDrmBridge.class"/>
- <ignore path="org/chromium/media/MediaDrmBridge$*.class"/>
- <ignore path="org/chromium/media/VideoCaptureCamera.class"/>
- <ignore path="org/chromium/media/VideoCaptureCamera2.class"/>
- <ignore path="org/chromium/media/VideoCaptureCamera2$*.class"/>
- <ignore path="org/chromium/media/WebAudioMediaCodecBridge.class"/>
- <ignore path="org/chromium/ui/base/Clipboard.class"/>
- <ignore path="org/chromium/ui/ColorPickerAdvancedComponent.class"/>
- <ignore path="org/chromium/ui/gfx/DeviceDisplayInfo.class"/>
- <ignore path="org/chromium/ui/gl/SurfaceTexturePlatformWrapper.class"/>
- <ignore path="org/chromium/ui/widget/TextViewWithClickableSpans.class"/>
- <ignore path="org/chromium/ui/picker/TwoFieldDatePicker.class"/>
</issue>
<issue id="OldTargetApi">
<ignore path="AndroidManifest.xml"/>
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index c954508..36f8f48 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -300,7 +300,8 @@
device_serial=self._device_serial)
def Logcat(self, clear=False, dump=False, filter_specs=None,
- logcat_format=None, timeout=None, retries=_DEFAULT_RETRIES):
+ logcat_format=None, ring_buffer=None, timeout=None,
+ retries=_DEFAULT_RETRIES):
"""Get an iterable over the logcat output.
Args:
@@ -310,6 +311,9 @@
logcat_format: If set, the format in which the logcat should be output.
Options include "brief", "process", "tag", "thread", "raw", "time",
"threadtime", and "long"
+ ring_buffer: If set, a list of alternate ring buffers to request.
+ Options include "main", "system", "radio", "events", "crash" or "all".
+ The default is equivalent to ["main", "system", "crash"].
timeout: (optional) If set, timeout per try in seconds. If clear or dump
is set, defaults to _DEFAULT_TIMEOUT.
retries: (optional) If clear or dump is set, the number of retries to
@@ -328,6 +332,9 @@
use_iter = False
if logcat_format:
cmd.extend(['-v', logcat_format])
+ if ring_buffer:
+ for buffer_name in ring_buffer:
+ cmd.extend(['-b', buffer_name])
if filter_specs:
cmd.extend(filter_specs)
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index 292752a..9f538e1 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -9,6 +9,7 @@
# pylint: disable=unused-argument
import collections
+import contextlib
import itertools
import logging
import multiprocessing
@@ -71,7 +72,6 @@
},
]
-
@decorators.WithExplicitTimeoutAndRetries(
_DEFAULT_TIMEOUT, _DEFAULT_RETRIES)
def GetAVDs():
@@ -1453,8 +1453,16 @@
# Skip the first line, which is just a header.
for line in self.RunShellCommand(
['dumpsys', 'battery'], check_return=True)[1:]:
- k, v = line.split(': ', 1)
- result[k.strip()] = v.strip()
+ # If usb charging has been disabled, an extra line of header exists.
+ if 'UPDATES STOPPED' in line:
+ logging.warning('Dumpsys battery not receiving updates. '
+ 'Run dumpsys battery reset if this is in error.')
+ elif ':' not in line:
+ logging.warning('Unknown line found in dumpsys battery.')
+ logging.warning(line)
+ else:
+ k, v = line.split(': ', 1)
+ result[k.strip()] = v.strip()
return result
@decorators.WithTimeoutAndRetriesFromInstance()
@@ -1504,6 +1512,81 @@
timeout_retry.WaitFor(set_and_verify_charging, wait_period=1)
+ # TODO(rnephew): Make private when all use cases can use the context manager.
+ @decorators.WithTimeoutAndRetriesFromInstance()
+ def DisableBatteryUpdates(self, timeout=None, retries=None):
+ """ Resets battery data and makes device appear like it is not
+ charging so that it will collect power data since last charge.
+
+ Args:
+ timeout: timeout in seconds
+ retries: number of retries
+ """
+ def battery_updates_disabled():
+ return self.GetCharging() is False
+
+ self.RunShellCommand(
+ ['dumpsys', 'batterystats', '--reset'], check_return=True)
+ battery_data = self.RunShellCommand(
+ ['dumpsys', 'batterystats', '--charged', '--checkin'],
+ check_return=True)
+ ROW_TYPE_INDEX = 3
+ PWI_POWER_INDEX = 5
+ for line in battery_data:
+ l = line.split(',')
+ if (len(l) > PWI_POWER_INDEX and l[ROW_TYPE_INDEX] == 'pwi'
+ and l[PWI_POWER_INDEX] != 0):
+ raise device_errors.CommandFailedError(
+ 'Non-zero pmi value found after reset.')
+ self.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '0'],
+ check_return=True)
+ timeout_retry.WaitFor(battery_updates_disabled, wait_period=1)
+
+ # TODO(rnephew): Make private when all use cases can use the context manager.
+ @decorators.WithTimeoutAndRetriesFromInstance()
+ def EnableBatteryUpdates(self, timeout=None, retries=None):
+ """ Restarts device charging so that dumpsys no longer collects power data.
+
+ Args:
+ timeout: timeout in seconds
+ retries: number of retries
+ """
+ def battery_updates_enabled():
+ return self.GetCharging() is True
+
+ self.RunShellCommand(['dumpsys', 'battery', 'set', 'usb', '1'],
+ check_return=True)
+ self.RunShellCommand(['dumpsys', 'battery', 'reset'], check_return=True)
+ timeout_retry.WaitFor(battery_updates_enabled, wait_period=1)
+
+ @contextlib.contextmanager
+ def BatteryMeasurement(self, timeout=None, retries=None):
+ """Context manager that enables battery data collection. It makes
+ the device appear to stop charging so that dumpsys will start collecting
+ power data since last charge. Once the with block is exited, charging is
+ resumed and power data since last charge is no longer collected.
+
+ Only for devices L and higher.
+
+ Example usage:
+ with BatteryMeasurement():
+ browser_actions()
+ get_power_data() # report usage within this block
+ after_measurements() # Anything that runs after power
+ # measurements are collected
+
+ Args:
+ timeout: timeout in seconds
+ retries: number of retries
+ """
+ if self.build_version_sdk < constants.ANDROID_SDK_VERSION_CODES.LOLLIPOP:
+ raise device_errors.CommandFailedError('Device must be L or higher.')
+ try:
+ self.DisableBatteryUpdates(timeout=timeout, retries=retries)
+ yield
+ finally:
+ self.EnableBatteryUpdates(timeout=timeout, retries=retries)
+
@decorators.WithTimeoutAndRetriesFromInstance()
def GetDevicePieWrapper(self, timeout=None, retries=None):
"""Gets the absolute path to the run_pie wrapper on the device.
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 7c20f0d..98e3539 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -1537,6 +1537,29 @@
self.device.SetCharging(False)
+class DeviceUtilsSetBatteryMeasurementTest(DeviceUtilsTest):
+
+ def testBatteryMeasurement(self):
+ with self.assertCalls(
+ (self.call.device.RunShellCommand(
+ mock.ANY, retries=0, single_line=True,
+ timeout=10, check_return=True), '22'),
+ (self.call.device.RunShellCommand(
+ ['dumpsys', 'batterystats', '--reset'], check_return=True), []),
+ (self.call.device.RunShellCommand(
+ ['dumpsys', 'batterystats', '--charged', '--checkin'],
+ check_return=True), []),
+ (self.call.device.RunShellCommand(
+ ['dumpsys', 'battery', 'set', 'usb', '0'], check_return=True), []),
+ (self.call.device.GetCharging(), False),
+ (self.call.device.RunShellCommand(
+ ['dumpsys', 'battery', 'set', 'usb', '1'], check_return=True), []),
+ (self.call.device.RunShellCommand(
+ ['dumpsys', 'battery', 'reset'], check_return=True), []),
+ (self.call.device.GetCharging(), True)):
+ with self.device.BatteryMeasurement():
+ pass
+
class DeviceUtilsStrTest(DeviceUtilsTest):
diff --git a/build/android/pylib/device/logcat_monitor.py b/build/android/pylib/device/logcat_monitor.py
index 1d4cc24..2eebc2d 100644
--- a/build/android/pylib/device/logcat_monitor.py
+++ b/build/android/pylib/device/logcat_monitor.py
@@ -19,8 +19,9 @@
class LogcatMonitor(object):
- # Format: <DATE> <TIME> <PID> <TID> <LEVEL> <COMPONENT>: <MESSAGE>
- _THREADTIME_RE_FORMAT = r'\S* +\S* +(%s) +(%s) +(%s) +(%s): +(%s)$'
+ _THREADTIME_RE_FORMAT = (
+ r'(?P<date>\S*) +(?P<time>\S*) +(?P<proc_id>%s) +(?P<thread_id>%s) +'
+ r'(?P<log_level>%s) +(?P<component>%s) *: +(?P<message>%s)$')
def __init__(self, adb, clear=True, filter_specs=None):
"""Create a LogcatMonitor instance.
@@ -97,18 +98,12 @@
log_level: The log level to match. If None, matches any log level.
component: The component to match. If None, matches any component.
- Returns:
- An iterable containing objects with five attributes:
- |proc_id|: the process ID
- |thread_id|: the thread ID
- |log_level|: the log level
- |component|: the component
- |message|: the logcat message
+ Yields:
+ A match object for each matching line in the logcat. The match object
+ will always contain, in addition to groups defined in |message_regex|,
+ the following named groups: 'date', 'time', 'proc_id', 'thread_id',
+ 'log_level', 'component', and 'message'.
"""
- LogcatLine = collections.namedtuple(
- 'LogcatLine',
- ['proc_id', 'thread_id', 'log_level', 'component', 'message'])
-
if proc_id is None:
proc_id = r'\d+'
if thread_id is None:
@@ -121,11 +116,10 @@
type(self)._THREADTIME_RE_FORMAT % (
proc_id, thread_id, log_level, component, message_regex))
- regexed_lines = (
- re.match(threadtime_re, l)
- for l in self._adb.Logcat(dump=True, logcat_format='threadtime'))
- only_matches = (m for m in regexed_lines if m)
- return (LogcatLine(*m.group(1, 2, 3, 4, 5)) for m in only_matches)
+ for line in self._adb.Logcat(dump=True, logcat_format='threadtime'):
+ m = re.match(threadtime_re, line)
+ if m:
+ yield m
def Start(self):
"""Starts the logcat monitor.
diff --git a/build/android/pylib/device/logcat_monitor_test.py b/build/android/pylib/device/logcat_monitor_test.py
index 7a6bf56..db397e5 100755
--- a/build/android/pylib/device/logcat_monitor_test.py
+++ b/build/android/pylib/device/logcat_monitor_test.py
@@ -50,11 +50,11 @@
self.assertIsNotNone(
actual,
msg='actual is missing elements starting with %s' % str(expected))
- self.assertEqual(actual.proc_id, expected[0])
- self.assertEqual(actual.thread_id, expected[1])
- self.assertEqual(actual.log_level, expected[2])
- self.assertEqual(actual.component, expected[3])
- self.assertEqual(actual.message, expected[4])
+ self.assertEqual(actual.group('proc_id'), expected[0])
+ self.assertEqual(actual.group('thread_id'), expected[1])
+ self.assertEqual(actual.group('log_level'), expected[2])
+ self.assertEqual(actual.group('component'), expected[3])
+ self.assertEqual(actual.group('message'), expected[4])
with self.assertRaises(StopIteration):
next(actual_iter)
diff --git a/build/android/pylib/forwarder.py b/build/android/pylib/forwarder.py
index 3859669..eb83d68 100644
--- a/build/android/pylib/forwarder.py
+++ b/build/android/pylib/forwarder.py
@@ -51,18 +51,12 @@
_DEVICE_FORWARDER_PATH = (constants.TEST_EXECUTABLE_DIR +
'/forwarder/device_forwarder')
_LOCK_PATH = '/tmp/chrome.forwarder.lock'
- _MULTIPROCESSING_ENV_VAR = 'CHROME_FORWARDER_USE_MULTIPROCESSING'
# Defined in host_forwarder_main.cc
_HOST_FORWARDER_LOG = '/tmp/host_forwarder_log'
_instance = None
@staticmethod
- def UseMultiprocessing():
- """Tells the forwarder that multiprocessing is used."""
- os.environ[Forwarder._MULTIPROCESSING_ENV_VAR] = '1'
-
- @staticmethod
def Map(port_pairs, device, tool=None):
"""Runs the forwarder.
@@ -245,13 +239,10 @@
def _GetPidForLock():
"""Returns the PID used for host_forwarder initialization.
- In case multi-process sharding is used, the PID of the "sharder" is used.
- The "sharder" is the initial process that forks that is the parent process.
- By default, multi-processing is not used. In that case the PID of the
- current process is returned.
+ The PID of the "sharder" is used to handle multiprocessing. The "sharder"
+ is the initial process that forks that is the parent process.
"""
- use_multiprocessing = Forwarder._MULTIPROCESSING_ENV_VAR in os.environ
- return os.getpgrp() if use_multiprocessing else os.getpid()
+ return os.getpgrp()
def _InitHostLocked(self):
"""Initializes the host forwarder daemon.
diff --git a/build/android/pylib/junit/test_runner.py b/build/android/pylib/junit/test_runner.py
index 35ac666..b85967b 100644
--- a/build/android/pylib/junit/test_runner.py
+++ b/build/android/pylib/junit/test_runner.py
@@ -22,9 +22,13 @@
def RunTest(self, _test):
"""Runs junit tests from |self._test_suite|."""
+
command = ['java',
+ '-Drobolectric.dependency.dir=%s' %
+ os.path.join(constants.GetOutDirectory(), 'lib.java'),
'-jar', os.path.join(constants.GetOutDirectory(), 'lib.java',
'%s.jar' % self._test_suite)]
+
if self._test_filter:
command.extend(['-gtest-filter', self._test_filter])
if self._package_filter:
diff --git a/build/android/pylib/perf/setup.py b/build/android/pylib/perf/setup.py
index 99c3e19..8884d60 100644
--- a/build/android/pylib/perf/setup.py
+++ b/build/android/pylib/perf/setup.py
@@ -72,7 +72,6 @@
# Before running the tests, kill any leftover server.
test_environment.CleanupLeftoverProcesses()
- forwarder.Forwarder.UseMultiprocessing()
# We want to keep device affinity, so return all devices ever seen.
all_devices = _GetAllDevices()
diff --git a/build/android/pylib/remote/device/remote_device_gtest_run.py b/build/android/pylib/remote/device/remote_device_gtest_run.py
index 76d1d45..973eebe 100644
--- a/build/android/pylib/remote/device/remote_device_gtest_run.py
+++ b/build/android/pylib/remote/device/remote_device_gtest_run.py
@@ -73,20 +73,15 @@
def _ParseTestResults(self):
logging.info('Parsing results from stdout.')
results = base_test_result.TestRunResults()
- if self._results['results']['exception']:
+ output = self._results['results']['output'].splitlines()
+ output = (l[len(self._INSTRUMENTATION_STREAM_LEADER):] for l in output
+ if l.startswith(self._INSTRUMENTATION_STREAM_LEADER))
+ results_list = self._test_instance.ParseGTestOutput(output)
+ results.AddResults(results_list)
+ if self._env.only_output_failures:
+ logging.info('See logcat for more results information.')
+ if not self._results['results']['pass']:
results.AddResult(base_test_result.BaseTestResult(
- self._results['results']['exception'],
+ 'Remote Service detected error.',
base_test_result.ResultType.FAIL))
- else:
- output = self._results['results']['output'].splitlines()
- output = (l[len(self._INSTRUMENTATION_STREAM_LEADER):] for l in output
- if l.startswith(self._INSTRUMENTATION_STREAM_LEADER))
- results_list = self._test_instance.ParseGTestOutput(output)
- results.AddResults(results_list)
- if self._env.only_output_failures:
- logging.info('See logcat for more results information.')
- if not self._results['results']['pass']:
- results.AddResult(base_test_result.BaseTestResult(
- 'Remote Service detected error.',
- base_test_result.ResultType.FAIL))
- return results
+ return results
\ No newline at end of file
diff --git a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
index 709a30c..fe173a4 100644
--- a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
@@ -33,13 +33,6 @@
def _ParseTestResults(self):
logging.info('Parsing results from stdout.')
r = base_test_result.TestRunResults()
-
- if self._results['results']['exception']:
- r.AddResult(base_test_result.BaseTestResult(
- self._results['results']['exception'],
- base_test_result.ResultType.FAIL))
- return r
-
result_code, result_bundle, statuses = (
self._test_instance.ParseAmInstrumentRawOutput(
self._results['results']['output'].splitlines()))
diff --git a/build/android/pylib/remote/device/remote_device_test_run.py b/build/android/pylib/remote/device/remote_device_test_run.py
index a2d4a53..4a155ac 100644
--- a/build/android/pylib/remote/device/remote_device_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_test_run.py
@@ -99,6 +99,11 @@
timeout_counter += self.WAIT_TIME
heartbeat_counter += self.WAIT_TIME
self._DownloadTestResults(self._env.results_path)
+
+ if self._results['results']['exception']:
+ raise remote_device_helper.RemoteDeviceError(
+ self._results['results']['exception'], is_infra_error=True)
+
return self._ParseTestResults()
#override
diff --git a/build/android/tombstones.py b/build/android/tombstones.py
index 9b8a8b2..1a958ac 100755
--- a/build/android/tombstones.py
+++ b/build/android/tombstones.py
@@ -10,6 +10,8 @@
# Assumes tombstone file was created with current symbols.
import datetime
+import itertools
+import logging
import multiprocessing
import os
import re
@@ -20,6 +22,7 @@
from pylib import android_commands
from pylib.device import device_errors
from pylib.device import device_utils
+from pylib.utils import run_tests_helper
_TZ_UTC = {'TZ': 'UTC'}
@@ -33,15 +36,18 @@
Yields:
Tuples of (tombstone filename, date time of file on device).
"""
- lines = device.RunShellCommand(
- ['ls', '-a', '-l', '/data/tombstones'],
- as_root=True, check_return=True, env=_TZ_UTC, timeout=60)
- for line in lines:
- if 'tombstone' in line and not 'No such file or directory' in line:
- details = line.split()
- t = datetime.datetime.strptime(details[-3] + ' ' + details[-2],
- '%Y-%m-%d %H:%M')
- yield details[-1], t
+ try:
+ lines = device.RunShellCommand(
+ ['ls', '-a', '-l', '/data/tombstones'],
+ as_root=True, check_return=True, env=_TZ_UTC, timeout=60)
+ for line in lines:
+ if 'tombstone' in line and not 'No such file or directory' in line:
+ details = line.split()
+ t = datetime.datetime.strptime(details[-3] + ' ' + details[-2],
+ '%Y-%m-%d %H:%M')
+ yield details[-1], t
+ except device_errors.CommandFailedError:
+ logging.exception('Could not retrieve tombstones.')
def _GetDeviceDateTime(device):
@@ -133,8 +139,8 @@
', about this long ago: ' +
(str(tombstone['device_now'] - tombstone['time']) +
' Device: ' + tombstone['serial'])]
- print '\n'.join(lines)
- print 'Resolving...'
+ logging.info('\n'.join(lines))
+ logging.info('Resolving...')
lines += _ResolveSymbols(tombstone['data'], tombstone['stack'],
tombstone['device_abi'])
return lines
@@ -148,15 +154,15 @@
tombstones: a list of tombstones.
"""
if not tombstones:
- print 'No device attached? Or no tombstones?'
+ logging.warning('No tombstones to resolve.')
return
if len(tombstones) == 1:
data = _ResolveTombstone(tombstones[0])
else:
pool = multiprocessing.Pool(processes=jobs)
data = pool.map(_ResolveTombstone, tombstones)
- data = ['\n'.join(d) for d in data]
- print '\n'.join(data)
+ for d in data:
+ logging.info(d)
def _GetTombstonesForDevice(device, options):
@@ -169,7 +175,7 @@
ret = []
all_tombstones = list(_ListTombstones(device))
if not all_tombstones:
- print 'No device attached? Or no tombstones?'
+ logging.warning('No tombstones.')
return ret
# Sort the tombstones in date order, descending
@@ -192,7 +198,7 @@
for line in device.RunShellCommand(
['ls', '-a', '-l', '/data/tombstones'],
as_root=True, check_return=True, env=_TZ_UTC, timeout=60):
- print '%s: %s' % (str(device), line)
+ logging.info('%s: %s', str(device), line)
raise
# Erase all the tombstones if desired.
@@ -204,6 +210,11 @@
def main():
+ custom_handler = logging.StreamHandler(sys.stdout)
+ custom_handler.setFormatter(run_tests_helper.CustomFormatter())
+ logging.getLogger().addHandler(custom_handler)
+ logging.getLogger().setLevel(logging.INFO)
+
parser = optparse.OptionParser()
parser.add_option('--device',
help='The serial number of the device. If not specified '
@@ -226,6 +237,9 @@
else:
devices = android_commands.GetAttachedDevices()
+ # This must be done serially because strptime can hit a race condition if
+ # used for the first time in a multithreaded environment.
+ # http://bugs.python.org/issue7980
tombstones = []
for device_serial in devices:
device = device_utils.DeviceUtils(device_serial)
diff --git a/build/common.gypi b/build/common.gypi
index 61224ba..e900cc4 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -197,7 +197,7 @@
}],
# Set default value of toolkit_views based on OS.
- ['OS=="win" or chromeos==1 or use_aura==1', {
+ ['OS=="mac" or OS=="win" or chromeos==1 or use_aura==1', {
'toolkit_views%': 1,
}, {
'toolkit_views%': 0,
@@ -210,8 +210,8 @@
'toolkit_views%': 0,
}],
- # Enable HiDPI on Mac OS, Chrome OS and Windows.
- ['OS=="mac" or chromeos==1 or OS=="win"', {
+ # Enable HiDPI on Mac OS, Chrome OS, Windows and Linux.
+ ['OS=="mac" or chromeos==1 or OS=="win" or OS=="linux"', {
'enable_hidpi%': 1,
}],
@@ -438,7 +438,7 @@
# Track where uninitialized memory originates from. From fastest to
# slowest: 0 - no tracking, 1 - track only the initial allocation site, 2
# - track the chain of stores leading from allocation site to use site.
- 'msan_track_origins%': 1,
+ 'msan_track_origins%': 2,
# Enable building with UBSan (Clang's -fsanitize=undefined option).
# -fsanitize=undefined only works with clang, but ubsan=1 implies clang=1
@@ -450,10 +450,16 @@
# -fsanitize=vptr only works with clang, but ubsan_vptr=1 implies clang=1
'ubsan_vptr%': 0,
- # Use the dynamic libraries instrumented by one of the sanitizers
- # instead of the standard system libraries.
+ # Use dynamic libraries instrumented by one of the sanitizers
+ # instead of the standard system libraries. Set this flag to build the
+ # libraries from source.
'use_instrumented_libraries%': 0,
+ # Use dynamic libraries instrumented by one of the sanitizers
+ # instead of the standard system libraries. Set this flag to download
+ # prebuilt binaries from GCS.
+ 'use_prebuilt_instrumented_libraries%': 0,
+
# Use libc++ (third_party/libc++ and third_party/libc++abi) instead of
# stdlibc++ as standard library. This is intended to use for instrumented
# builds.
@@ -647,6 +653,9 @@
# See http://clang.llvm.org/docs/ControlFlowIntegrity.html
'cfi_vptr%': 0,
+ # Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
+ 'mac_views_browser%': 0,
+
'conditions': [
# A flag for POSIX platforms
['OS=="win"', {
@@ -1150,6 +1159,7 @@
'ubsan_blacklist%': '<(ubsan_blacklist)',
'ubsan_vptr%': '<(ubsan_vptr)',
'use_instrumented_libraries%': '<(use_instrumented_libraries)',
+ 'use_prebuilt_instrumented_libraries%': '<(use_prebuilt_instrumented_libraries)',
'use_custom_libcxx%': '<(use_custom_libcxx)',
'use_system_libcxx%': '<(use_system_libcxx)',
'clang_type_profiler%': '<(clang_type_profiler)',
@@ -1214,6 +1224,7 @@
'video_hole%': '<(video_hole)',
'v8_use_external_startup_data%': '<(v8_use_external_startup_data)',
'cfi_vptr%': '<(cfi_vptr)',
+ 'mac_views_browser%': '<(mac_views_browser)',
# Use system protobuf instead of bundled one.
'use_system_protobuf%': 0,
@@ -1469,10 +1480,6 @@
# Compile d8 for the host toolset.
'v8_toolset_for_d8': 'host',
- # Enable the V8 heap verification code. The verification itself is enabled
- # via a command line option.
- 'v8_enable_verify_heap%': 1,
-
# Use brlapi from brltty for braille display support.
'use_brlapi%': 0,
@@ -1503,9 +1510,6 @@
'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,
@@ -1951,9 +1955,7 @@
'win_use_allocator_shim%': 0,
}],
['syzyasan==1', {
- # Uncomment the following line to enable Kasko for
- # SyzyASAN-instrumented releases.
- # 'kasko%': 1,
+ 'kasko%': 1,
}],
['component=="shared_library" and "<(GENERATOR)"=="ninja"', {
# Only enabled by default for ninja because it's buggy in VS.
@@ -2078,6 +2080,11 @@
'-E', 'ANDROID_JAVA_TAGGED_ONLY=true',
'--no-output-all-resource-defines',
],
+ 'conditions': [
+ ['<(android_webview_build)==1', {
+ 'grit_defines': ['-D', 'is_android_webview_build'],
+ }],
+ ],
}],
['OS=="mac" or OS=="ios"', {
'grit_defines': ['-D', 'scale_factors=2x'],
@@ -2155,6 +2162,9 @@
['enable_wifi_bootstrapping==1', {
'grit_defines': ['-D', 'enable_wifi_bootstrapping'],
}],
+ ['mac_views_browser==1', {
+ 'grit_defines': ['-D', 'mac_views_browser'],
+ }],
['enable_resource_whitelist_generation==1 and OS!="win"', {
'grit_rc_header_format': ['-h', '#define {textual_id} _Pragma("whitelisted_resource_{numeric_id}") {numeric_id}'],
}],
@@ -2451,7 +2461,7 @@
'chromecast%': '<(chromecast)',
# See http://msdn.microsoft.com/en-us/library/aa652360(VS.71).aspx
- 'win_release_Optimization%': '2', # 2 = /Os
+ 'win_release_Optimization%': '2', # 2 = /O2
'win_debug_Optimization%': '0', # 0 = /Od
# See http://msdn.microsoft.com/en-us/library/2kxx5t2c(v=vs.80).aspx
@@ -3002,12 +3012,6 @@
['v8_use_external_startup_data==1', {
'defines': ['V8_USE_EXTERNAL_STARTUP_DATA'],
}],
- ['use_lto==1 and (target_arch=="ia32" or target_arch=="x64")', {
- # Required for third_party/zlib/crc_folding.c and various other code
- # that uses SSE. TODO(pcc): Remove this once we properly support
- # subtarget specific code generation in LLVM.
- 'ldflags': ['-Wl,-plugin-opt,mcpu=corei7-avx'],
- }],
], # conditions for 'target_defaults'
'target_conditions': [
['<(use_libpci)==1', {
@@ -3083,7 +3087,14 @@
'_CRT_NONSTDC_NO_DEPRECATE',
'_SCL_SECURE_NO_DEPRECATE',
],
- 'msvs_disabled_warnings': [4800],
+ 'msvs_disabled_warnings': [
+ # These are variable shadowing warnings that are new in VS2015.
+ # We should probably work through these at some point for
+ # non-chromium code, but for now, focus on chromium_code==1 code.
+ 4456, 4457, 4458, 4459,
+
+ 4800,
+ ],
'msvs_settings': {
'VCCLCompilerTool': {
'WarningLevel': '3',
@@ -3097,11 +3108,6 @@
'VCCLCompilerTool': { 'WarnAsError': 'false' },
}
}],
- ['clang==1', {
- 'msvs_settings': {
- 'VCCLCompilerTool': { 'WarnAsError': 'false' },
- }
- }],
[ 'component=="shared_library"', {
# TODO(darin): Unfortunately, some third_party code depends on base.
'msvs_disabled_warnings': [
@@ -3205,7 +3211,8 @@
# Suggested by Microsoft Devrel to avoid
# LINK : fatal error LNK1248: image size (80000000) exceeds maximum allowable size (80000000)
# which started happening more regularly after VS2013 Update 4.
- '/maxilksize:2147483647',
+ # Needs to be a bit lower for VS2015, or else errors out.
+ '/maxilksize:0x7ff00000',
],
},
},
@@ -4413,6 +4420,11 @@
'<(DEPTH)/third_party/instrumented_libraries/instrumented_libraries.gyp:instrumented_libraries',
],
}],
+ ['use_prebuilt_instrumented_libraries==1', {
+ 'dependencies': [
+ '<(DEPTH)/third_party/instrumented_libraries/instrumented_libraries.gyp:prebuilt_instrumented_libraries',
+ ],
+ }],
['use_custom_libcxx==1', {
'dependencies': [
'<(DEPTH)/buildtools/third_party/libc++/libc++.gyp:libcxx_proxy',
@@ -5475,6 +5487,11 @@
],
'msvs_cygwin_shell': 0,
'msvs_disabled_warnings': [
+ # C4091: 'typedef ': ignored on left of 'X' when no variable is
+ # declared.
+ # This happens in a number of Windows headers. Dumb.
+ 4091,
+
# C4127: conditional expression is constant
# This warning can in theory catch dead code and other problems, but
# triggers in far too many desirable cases where the conditional
@@ -5930,6 +5947,41 @@
],
},
}],
+ ['use_lto==1 and clang==1 and (target_arch=="ia32" or target_arch=="x64")', {
+ 'target_defaults': {
+ 'target_conditions': [
+ # Required for third_party/zlib/crc_folding.c and various other code
+ # that uses SSE. TODO(pcc): Remove this once we properly support
+ # subtarget specific code generation in LLVM.
+ ['_toolset=="target"', {
+ 'ldflags': [
+ '-Wl,-plugin-opt,mcpu=corei7-avx',
+ ],
+ }],
+ ['_toolset=="target" and _type!="static_library"', {
+ 'xcode_settings': {
+ 'OTHER_LDFLAGS': [
+ '-Wl,-mcpu,corei7-avx',
+ ],
+ },
+ }],
+ ],
+ },
+ }],
+ ['use_lto==1 and clang==1 and target_arch=="arm"', {
+ 'target_defaults': {
+ 'target_conditions': [
+ ['_toolset=="target"', {
+ # Without this flag, LTO produces a .text section that is larger
+ # than the maximum call displacement, preventing the linker from
+ # relocating calls (http://llvm.org/PR22999).
+ 'ldflags': [
+ '-Wl,-plugin-opt,-function-sections',
+ ],
+ }],
+ ],
+ },
+ }],
['(use_lto==1 or use_lto_o2==1) and clang==0', {
'target_defaults': {
'target_conditions': [
@@ -5962,6 +6014,18 @@
'ldflags': [
'-fsanitize=cfi-vptr',
],
+ 'xcode_settings': {
+ 'OTHER_CFLAGS': [
+ '-fsanitize=cfi-vptr',
+ ],
+ },
+ }],
+ ['_toolset=="target" and _type!="static_library"', {
+ 'xcode_settings': {
+ 'OTHER_LDFLAGS': [
+ '-fsanitize=cfi-vptr',
+ ],
+ },
}],
],
},
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 3afba89..8e30c4a 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -416,15 +416,8 @@
# Windows linker setup for EXEs and DLLs.
if (is_win) {
- if (is_debug) {
- _default_incremental_linking_config =
- "//build/config/win:incremental_linking"
- } else {
- _default_incremental_linking_config =
- "//build/config/win:no_incremental_linking"
- }
_windows_linker_configs = [
- _default_incremental_linking_config,
+ "//build/config/win:default_incremental_linking",
"//build/config/win:sdk_link",
"//build/config/win:common_linker_setup",
diff --git a/build/config/ui.gni b/build/config/ui.gni
index 46154a3..787e7ef 100644
--- a/build/config/ui.gni
+++ b/build/config/ui.gni
@@ -28,7 +28,10 @@
use_aura = is_win || is_linux
# True means the UI is built using the "views" framework.
- toolkit_views = is_win || is_chromeos || use_aura
+ toolkit_views = is_mac || is_win || is_chromeos || use_aura
+
+ # Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
+ mac_views_browser = false
# Whether we should use glib, a low level C utility library.
use_glib = is_linux && !use_ozone
@@ -59,4 +62,4 @@
use_clipboard_aurax11 = is_linux && use_aura && use_x11
-enable_hidpi = is_mac || is_chromeos || is_win
+enable_hidpi = is_mac || is_chromeos || is_win || is_linux
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 3e98c1a..4ca22f7 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -106,11 +106,42 @@
# Incremental linking ----------------------------------------------------------
+incremental_linking_on_switch = [ "/INCREMENTAL" ]
+incremental_linking_off_switch = [ "/INCREMENTAL:NO" ]
+
+# Applies incremental linking or not depending on the current configuration.
+config("default_incremental_linking") {
+ if (is_debug) {
+ ldflags = incremental_linking_on_switch
+ } else {
+ ldflags = incremental_linking_off_switch
+ }
+}
+
+# Explicitly on or off incremental linking
config("incremental_linking") {
- ldflags = [ "/INCREMENTAL" ]
+ ldflags = incremental_linking_on_switch
}
config("no_incremental_linking") {
- ldflags = [ "/INCREMENTAL:NO" ]
+ ldflags = incremental_linking_off_switch
+}
+
+# Some large modules can't handle incremental linking in some situations. This
+# config should be applied to large modules to turn off incremental linking
+# when it won't work.
+config("default_large_module_incremental_linking") {
+ if (!is_debug) {
+ # Default is always off in release build.
+ ldflags = incremental_linking_off_switch
+ } else if ((symbol_level == 0 || symbol_level == 1) &&
+ (current_cpu == "x86" || !is_component_build)) {
+ # When full symbols are on, don't do incremental linking for large modules
+ # on 32-bit or in non-component mode as the toolchain fails due to the size
+ # of the .ilk files.
+ ldflags = incremental_linking_off_switch
+ } else {
+ ldflags = incremental_linking_on_switch
+ }
}
# Character set ----------------------------------------------------------------
diff --git a/build/get_landmines.py b/build/get_landmines.py
index d7c98a5..8f5b878 100755
--- a/build/get_landmines.py
+++ b/build/get_landmines.py
@@ -24,6 +24,12 @@
"""
ALL LANDMINES ARE EMITTED FROM HERE.
"""
+ # DO NOT add landmines as part of a regular CL. Landmines are a last-effort
+ # bandaid fix if a CL that got landed has a build dependency bug and all bots
+ # need to be cleaned up. If you're writing a new CL that causes build
+ # dependency problems, fix the dependency problems instead of adding a
+ # landmine.
+
if (distributor() == 'goma' and platform() == 'win32' and
builder() == 'ninja'):
print 'Need to clobber winja goma due to backend cwd cache fix.'
diff --git a/build/install-build-deps.sh b/build/install-build-deps.sh
index 32dd744..53d9712 100755
--- a/build/install-build-deps.sh
+++ b/build/install-build-deps.sh
@@ -73,11 +73,11 @@
fi
lsb_release=$(lsb_release --codename --short)
-ubuntu_codenames="(precise|quantal|raring|saucy|trusty|utopic)"
+ubuntu_codenames="(precise|trusty|utopic)"
if [ 0 -eq "${do_unsupported-0}" ] && [ 0 -eq "${do_quick_check-0}" ] ; then
if [[ ! $lsb_release =~ $ubuntu_codenames ]]; then
- echo "ERROR: Only Ubuntu 12.04 (precise) through 14.10 (utopic) are"\
- "currently supported" >&2
+ echo "ERROR: Only Ubuntu 12.04 (precise), 14.04 (trusty) and " \
+ "14.10 (utopic) are currently supported" >&2
exit 1
fi
@@ -136,8 +136,16 @@
libpixman-1-0-dbg libsqlite3-0-dbg libx11-6-dbg libxau6-dbg
libxcb1-dbg libxcomposite1-dbg libxcursor1-dbg libxdamage1-dbg
libxdmcp6-dbg libxext6-dbg libxfixes3-dbg libxi6-dbg libxinerama1-dbg
- libxrandr2-dbg libxrender1-dbg libxtst6-dbg zlib1g-dbg
- libstdc++6-4.6-dbg"
+ libxrandr2-dbg libxrender1-dbg libxtst6-dbg zlib1g-dbg"
+
+# Find the proper version of libstdc++6-4.x-dbg.
+if [ "x$lsb_release" = "xprecise" ]; then
+ dbg_list="${dbg_list} libstdc++6-4.6-dbg"
+elif [ "x$lsb_release" = "xtrusty" ]; then
+ dbg_list="${dbg_list} libstdc++6-4.8-dbg"
+else
+ dbg_list="${dbg_list} libstdc++6-4.9-dbg"
+fi
# 32-bit libraries needed e.g. to compile V8 snapshot for Android or armhf
lib32_list="linux-libc-dev:i386"
@@ -163,8 +171,7 @@
# it depends on mesa, and only one version of mesa can exists on the system.
# Hence we must match the same version or this entire script will fail.
mesa_variant=""
-for variant in "-lts-quantal" "-lts-raring" "-lts-saucy" "-lts-trusty" \
- "-lts-utopic"; do
+for variant in "-lts-trusty" "-lts-utopic"; do
if $(dpkg-query -Wf'${Status}' libgl1-mesa-glx${variant} 2>/dev/null | \
grep -q " ok installed"); then
mesa_variant="${variant}"
@@ -349,7 +356,7 @@
fi
if test "$do_inst_lib32" = "1" || test "$do_inst_nacl" = "1"; then
- if [[ ! $lsb_release =~ (precise|quantal|raring) ]]; then
+ if [[ ! $lsb_release =~ (precise) ]]; then
sudo dpkg --add-architecture i386
fi
fi
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 43db731..76d2e1e 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -68,10 +68,6 @@
"race:thread_manager\n"
"race:v8::Locker::Initialize\n"
-// http://crbug.com/223352
-"race:uprv_malloc_54\n"
-"race:uprv_realloc_54\n"
-
// http://crbug.com/239359
"race:media::TestInputCallback::OnData\n"
diff --git a/build/secondary/third_party/icu/BUILD.gn b/build/secondary/third_party/icu/BUILD.gn
deleted file mode 100644
index 53818c9..0000000
--- a/build/secondary/third_party/icu/BUILD.gn
+++ /dev/null
@@ -1,554 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//third_party/icu/config.gni")
-
-# Meta target that includes both icuuc and icui18n. Most targets want both.
-# You can depend on the individually if you need to.
-group("icu") {
- deps = [
- ":icui18n",
- ":icuuc",
- ]
-}
-
-# Shared config used by ICU and all dependents.
-config("icu_config") {
- defines = [
- "U_USING_ICU_NAMESPACE=0",
- "U_ENABLE_DYLOAD=0",
- ]
-
- if (component_mode != "shared_library") {
- defines += [ "U_STATIC_IMPLEMENTATION" ]
- }
-
- include_dirs = [
- "source/common",
- "source/i18n",
- ]
-}
-
-# Config used only by ICU code.
-config("icu_code") {
- cflags = []
- if (is_win) {
- # Disable some compiler warnings.
- cflags += [
- "/wd4005", # Macro redefinition.
- "/wd4068", # Unknown pragmas.
- "/wd4267", # Conversion from size_t on 64-bits.
- "/wd4996", # Deprecated functions.
- ]
- } else if (is_linux) {
- cflags += [
- # Since ICU wants to internally use its own deprecated APIs, don't
- # complain about it.
- "-Wno-deprecated-declarations",
- "-Wno-unused-function",
- ]
- }
- if (is_clang) {
- cflags += [
- "-Wno-deprecated-declarations",
- "-Wno-logical-op-parentheses",
- "-Wno-tautological-compare",
- "-Wno-switch",
- ]
- }
-}
-
-component("icui18n") {
- sources = [
- "source/i18n/alphaindex.cpp",
- "source/i18n/anytrans.cpp",
- "source/i18n/astro.cpp",
- "source/i18n/basictz.cpp",
- "source/i18n/bocsu.cpp",
- "source/i18n/brktrans.cpp",
- "source/i18n/buddhcal.cpp",
- "source/i18n/calendar.cpp",
- "source/i18n/casetrn.cpp",
- "source/i18n/cecal.cpp",
- "source/i18n/chnsecal.cpp",
- "source/i18n/choicfmt.cpp",
- "source/i18n/coleitr.cpp",
- "source/i18n/collationbasedatabuilder.cpp",
- "source/i18n/collationbuilder.cpp",
- "source/i18n/collationcompare.cpp",
- "source/i18n/collation.cpp",
- "source/i18n/collationdatabuilder.cpp",
- "source/i18n/collationdata.cpp",
- "source/i18n/collationdatareader.cpp",
- "source/i18n/collationdatawriter.cpp",
- "source/i18n/collationfastlatinbuilder.cpp",
- "source/i18n/collationfastlatin.cpp",
- "source/i18n/collationfcd.cpp",
- "source/i18n/collationiterator.cpp",
- "source/i18n/collationkeys.cpp",
- "source/i18n/collationroot.cpp",
- "source/i18n/collationrootelements.cpp",
- "source/i18n/collationruleparser.cpp",
- "source/i18n/collationsets.cpp",
- "source/i18n/collationsettings.cpp",
- "source/i18n/collationtailoring.cpp",
- "source/i18n/collationweights.cpp",
- "source/i18n/coll.cpp",
- "source/i18n/compactdecimalformat.cpp",
- "source/i18n/coptccal.cpp",
- "source/i18n/cpdtrans.cpp",
- "source/i18n/csdetect.cpp",
- "source/i18n/csmatch.cpp",
- "source/i18n/csr2022.cpp",
- "source/i18n/csrecog.cpp",
- "source/i18n/csrmbcs.cpp",
- "source/i18n/csrsbcs.cpp",
- "source/i18n/csrucode.cpp",
- "source/i18n/csrutf8.cpp",
- "source/i18n/curramt.cpp",
- "source/i18n/currfmt.cpp",
- "source/i18n/currpinf.cpp",
- "source/i18n/currunit.cpp",
- "source/i18n/dangical.cpp",
- "source/i18n/datefmt.cpp",
- "source/i18n/dcfmtsym.cpp",
- "source/i18n/decContext.c",
- "source/i18n/decfmtst.cpp",
- "source/i18n/decimalformatpattern.cpp",
- "source/i18n/decimfmt.cpp",
- "source/i18n/decNumber.c",
- "source/i18n/digitlst.cpp",
- "source/i18n/dtfmtsym.cpp",
- "source/i18n/dtitvfmt.cpp",
- "source/i18n/dtitvinf.cpp",
- "source/i18n/dtptngen.cpp",
- "source/i18n/dtrule.cpp",
- "source/i18n/esctrn.cpp",
- "source/i18n/ethpccal.cpp",
- "source/i18n/filteredbrk.cpp",
- "source/i18n/fmtable_cnv.cpp",
- "source/i18n/fmtable.cpp",
- "source/i18n/format.cpp",
- "source/i18n/fphdlimp.cpp",
- "source/i18n/fpositer.cpp",
- "source/i18n/funcrepl.cpp",
- "source/i18n/gender.cpp",
- "source/i18n/gregocal.cpp",
- "source/i18n/gregoimp.cpp",
- "source/i18n/hebrwcal.cpp",
- "source/i18n/identifier_info.cpp",
- "source/i18n/indiancal.cpp",
- "source/i18n/inputext.cpp",
- "source/i18n/islamcal.cpp",
- "source/i18n/japancal.cpp",
- "source/i18n/locdspnm.cpp",
- "source/i18n/measfmt.cpp",
- "source/i18n/measunit.cpp",
- "source/i18n/measure.cpp",
- "source/i18n/msgfmt.cpp",
- "source/i18n/name2uni.cpp",
- "source/i18n/nfrs.cpp",
- "source/i18n/nfrule.cpp",
- "source/i18n/nfsubs.cpp",
- "source/i18n/nortrans.cpp",
- "source/i18n/nultrans.cpp",
- "source/i18n/numfmt.cpp",
- "source/i18n/numsys.cpp",
- "source/i18n/olsontz.cpp",
- "source/i18n/persncal.cpp",
- "source/i18n/plurfmt.cpp",
- "source/i18n/plurrule.cpp",
- "source/i18n/quant.cpp",
- "source/i18n/quantityformatter.cpp",
- "source/i18n/rbnf.cpp",
- "source/i18n/rbt.cpp",
- "source/i18n/rbt_data.cpp",
- "source/i18n/rbt_pars.cpp",
- "source/i18n/rbt_rule.cpp",
- "source/i18n/rbt_set.cpp",
- "source/i18n/rbtz.cpp",
- "source/i18n/regexcmp.cpp",
- "source/i18n/regeximp.cpp",
- "source/i18n/regexst.cpp",
- "source/i18n/regextxt.cpp",
- "source/i18n/region.cpp",
- "source/i18n/reldatefmt.cpp",
- "source/i18n/reldtfmt.cpp",
- "source/i18n/rematch.cpp",
- "source/i18n/remtrans.cpp",
- "source/i18n/repattrn.cpp",
- "source/i18n/rulebasedcollator.cpp",
- "source/i18n/scientificformathelper.cpp",
- "source/i18n/scriptset.cpp",
- "source/i18n/search.cpp",
- "source/i18n/selfmt.cpp",
- "source/i18n/sharedbreakiterator.cpp",
- "source/i18n/simpletz.cpp",
- "source/i18n/smpdtfmt.cpp",
- "source/i18n/smpdtfst.cpp",
- "source/i18n/sortkey.cpp",
- "source/i18n/strmatch.cpp",
- "source/i18n/strrepl.cpp",
- "source/i18n/stsearch.cpp",
- "source/i18n/taiwncal.cpp",
- "source/i18n/timezone.cpp",
- "source/i18n/titletrn.cpp",
- "source/i18n/tmunit.cpp",
- "source/i18n/tmutamt.cpp",
- "source/i18n/tmutfmt.cpp",
- "source/i18n/tolowtrn.cpp",
- "source/i18n/toupptrn.cpp",
- "source/i18n/translit.cpp",
- "source/i18n/transreg.cpp",
- "source/i18n/tridpars.cpp",
- "source/i18n/tzfmt.cpp",
- "source/i18n/tzgnames.cpp",
- "source/i18n/tznames.cpp",
- "source/i18n/tznames_impl.cpp",
- "source/i18n/tzrule.cpp",
- "source/i18n/tztrans.cpp",
- "source/i18n/ucal.cpp",
- "source/i18n/ucln_in.cpp",
- "source/i18n/ucol.cpp",
- "source/i18n/ucoleitr.cpp",
- "source/i18n/ucol_res.cpp",
- "source/i18n/ucol_sit.cpp",
- "source/i18n/ucsdet.cpp",
- "source/i18n/ucurr.cpp",
- "source/i18n/udat.cpp",
- "source/i18n/udateintervalformat.cpp",
- "source/i18n/udatpg.cpp",
- "source/i18n/uitercollationiterator.cpp",
- "source/i18n/ulocdata.c",
- "source/i18n/umsg.cpp",
- "source/i18n/unesctrn.cpp",
- "source/i18n/uni2name.cpp",
- "source/i18n/unum.cpp",
- "source/i18n/unumsys.cpp",
- "source/i18n/upluralrules.cpp",
- "source/i18n/uregexc.cpp",
- "source/i18n/uregex.cpp",
- "source/i18n/uregion.cpp",
- "source/i18n/usearch.cpp",
- "source/i18n/uspoof_build.cpp",
- "source/i18n/uspoof_conf.cpp",
- "source/i18n/uspoof.cpp",
- "source/i18n/uspoof_impl.cpp",
- "source/i18n/uspoof_wsconf.cpp",
- "source/i18n/utf16collationiterator.cpp",
- "source/i18n/utf8collationiterator.cpp",
- "source/i18n/utmscale.c",
- "source/i18n/utrans.cpp",
- "source/i18n/vtzone.cpp",
- "source/i18n/vzone.cpp",
- "source/i18n/windtfmt.cpp",
- "source/i18n/winnmfmt.cpp",
- "source/i18n/wintzimpl.cpp",
- "source/i18n/zonemeta.cpp",
- "source/i18n/zrule.cpp",
- "source/i18n/ztrans.cpp",
- ]
- defines = [ "U_I18N_IMPLEMENTATION" ]
- deps = [
- ":icuuc",
- ]
-
- # ICU uses RTTI, replace the default "no rtti" config.
- configs -= [
- "//build/config/compiler:no_rtti", # ICU uses RTTI.
- "//build/config/compiler:chromium_code",
- ]
- configs += [
- "//build/config/compiler:rtti",
- "//build/config/compiler:no_chromium_code",
- ]
-
- configs += [ ":icu_code" ]
- public_configs = [ ":icu_config" ]
-
- cflags = []
- if (is_android || is_linux) {
- cflags += [
- # ICU uses its own deprecated functions.
- "-Wno-deprecated-declarations",
- ]
- }
- if (is_clang) {
- # uspoof.h has a U_NAMESPACE_USE macro. That's a bug,
- # the header should use U_NAMESPACE_BEGIN instead.
- # http://bugs.icu-project.org/trac/ticket/9054
- configs -= [ "//build/config/clang:extra_warnings" ]
-
- cflags += [
- "-Wno-header-hygiene",
-
- # Looks like a real issue, see http://crbug.com/114660
- "-Wno-return-type-c-linkage",
- ]
- }
-}
-
-component("icuuc") {
- sources = [
- "source/common/appendable.cpp",
- "source/common/bmpset.cpp",
- "source/common/brkeng.cpp",
- "source/common/brkiter.cpp",
- "source/common/bytestream.cpp",
- "source/common/bytestriebuilder.cpp",
- "source/common/bytestrie.cpp",
- "source/common/bytestrieiterator.cpp",
- "source/common/caniter.cpp",
- "source/common/chariter.cpp",
- "source/common/charstr.cpp",
- "source/common/cmemory.c",
- "source/common/cstring.c",
- "source/common/cwchar.c",
- "source/common/dictbe.cpp",
- "source/common/dictionarydata.cpp",
- "source/common/dtintrv.cpp",
- "source/common/errorcode.cpp",
- "source/common/filterednormalizer2.cpp",
- "source/common/icudataver.c",
- "source/common/icuplug.cpp",
- "source/common/listformatter.cpp",
- "source/common/loadednormalizer2impl.cpp",
- "source/common/locavailable.cpp",
- "source/common/locbased.cpp",
- "source/common/locdispnames.cpp",
- "source/common/locid.cpp",
- "source/common/loclikely.cpp",
- "source/common/locmap.c",
- "source/common/locresdata.cpp",
- "source/common/locutil.cpp",
- "source/common/messagepattern.cpp",
- "source/common/normalizer2.cpp",
- "source/common/normalizer2impl.cpp",
- "source/common/normlzr.cpp",
- "source/common/parsepos.cpp",
- "source/common/patternprops.cpp",
- "source/common/propname.cpp",
- "source/common/propsvec.c",
- "source/common/punycode.cpp",
- "source/common/putil.cpp",
- "source/common/rbbi.cpp",
- "source/common/rbbidata.cpp",
- "source/common/rbbinode.cpp",
- "source/common/rbbirb.cpp",
- "source/common/rbbiscan.cpp",
- "source/common/rbbisetb.cpp",
- "source/common/rbbistbl.cpp",
- "source/common/rbbitblb.cpp",
- "source/common/resbund_cnv.cpp",
- "source/common/resbund.cpp",
- "source/common/ruleiter.cpp",
- "source/common/schriter.cpp",
- "source/common/serv.cpp",
- "source/common/servlk.cpp",
- "source/common/servlkf.cpp",
- "source/common/servls.cpp",
- "source/common/servnotf.cpp",
- "source/common/servrbf.cpp",
- "source/common/servslkf.cpp",
- "source/common/sharedobject.cpp",
- "source/common/simplepatternformatter.cpp",
- "source/common/stringpiece.cpp",
- "source/common/stringtriebuilder.cpp",
- "source/common/uarrsort.c",
- "source/common/ubidi.c",
- "source/common/ubidiln.c",
- "source/common/ubidi_props.c",
- "source/common/ubidiwrt.c",
- "source/common/ubrk.cpp",
- "source/common/ucase.cpp",
- "source/common/ucasemap.cpp",
- "source/common/ucasemap_titlecase_brkiter.cpp",
- "source/common/ucat.c",
- "source/common/uchar.c",
- "source/common/ucharstriebuilder.cpp",
- "source/common/ucharstrie.cpp",
- "source/common/ucharstrieiterator.cpp",
- "source/common/uchriter.cpp",
- "source/common/ucln_cmn.cpp",
- "source/common/ucmndata.c",
- "source/common/ucnv2022.cpp",
- "source/common/ucnv_bld.cpp",
- "source/common/ucnvbocu.cpp",
- "source/common/ucnv.c",
- "source/common/ucnv_cb.c",
- "source/common/ucnv_cnv.c",
- "source/common/ucnv_ct.c",
- "source/common/ucnvdisp.c",
- "source/common/ucnv_err.c",
- "source/common/ucnv_ext.cpp",
- "source/common/ucnvhz.c",
- "source/common/ucnv_io.cpp",
- "source/common/ucnvisci.c",
- "source/common/ucnvlat1.c",
- "source/common/ucnv_lmb.c",
- "source/common/ucnvmbcs.cpp",
- "source/common/ucnvscsu.c",
- "source/common/ucnvsel.cpp",
- "source/common/ucnv_set.c",
- "source/common/ucnv_u16.c",
- "source/common/ucnv_u32.c",
- "source/common/ucnv_u7.c",
- "source/common/ucnv_u8.c",
- "source/common/ucol_swp.cpp",
- "source/common/udata.cpp",
- "source/common/udatamem.c",
- "source/common/udataswp.c",
- "source/common/uenum.c",
- "source/common/uhash.c",
- "source/common/uhash_us.cpp",
- "source/common/uidna.cpp",
- "source/common/uinit.cpp",
- "source/common/uinvchar.c",
- "source/common/uiter.cpp",
- "source/common/ulist.c",
- "source/common/uloc.cpp",
- "source/common/uloc_keytype.cpp",
- "source/common/uloc_tag.c",
- "source/common/umapfile.c",
- "source/common/umath.c",
- "source/common/umutex.cpp",
- "source/common/unames.cpp",
- "source/common/unifiedcache.cpp",
- "source/common/unifilt.cpp",
- "source/common/unifunct.cpp",
- "source/common/uniset_closure.cpp",
- "source/common/uniset.cpp",
- "source/common/uniset_props.cpp",
- "source/common/unisetspan.cpp",
- "source/common/unistr_case.cpp",
- "source/common/unistr_case_locale.cpp",
- "source/common/unistr_cnv.cpp",
- "source/common/unistr.cpp",
- "source/common/unistr_props.cpp",
- "source/common/unistr_titlecase_brkiter.cpp",
- "source/common/unormcmp.cpp",
- "source/common/unorm.cpp",
- "source/common/uobject.cpp",
- "source/common/uprops.cpp",
- "source/common/uresbund.cpp",
- "source/common/ures_cnv.c",
- "source/common/uresdata.c",
- "source/common/usc_impl.c",
- "source/common/uscript.c",
- "source/common/uscript_props.cpp",
- "source/common/uset.cpp",
- "source/common/usetiter.cpp",
- "source/common/uset_props.cpp",
- "source/common/ushape.cpp",
- "source/common/usprep.cpp",
- "source/common/ustack.cpp",
- "source/common/ustrcase.cpp",
- "source/common/ustrcase_locale.cpp",
- "source/common/ustr_cnv.cpp",
- "source/common/ustrenum.cpp",
- "source/common/ustrfmt.c",
- "source/common/ustring.cpp",
- "source/common/ustr_titlecase_brkiter.cpp",
- "source/common/ustrtrns.cpp",
- "source/common/ustr_wcs.cpp",
- "source/common/utext.cpp",
- "source/common/utf_impl.c",
- "source/common/util.cpp",
- "source/common/util_props.cpp",
- "source/common/utrace.c",
- "source/common/utrie2_builder.cpp",
- "source/common/utrie2.cpp",
- "source/common/utrie.cpp",
- "source/common/uts46.cpp",
- "source/common/utypes.c",
- "source/common/uvector.cpp",
- "source/common/uvectr32.cpp",
- "source/common/uvectr64.cpp",
- "source/common/wintz.c",
- ]
- defines = [ "U_COMMON_IMPLEMENTATION" ]
- deps = [
- ":icudata",
- ]
- configs += [ ":icu_code" ]
-
- configs -= [
- "//build/config/compiler:no_rtti", # ICU uses RTTI.
- "//build/config/compiler:chromium_code",
- ]
- configs += [
- "//build/config/compiler:rtti",
- "//build/config/compiler:no_chromium_code",
- ]
-
- public_configs = [ ":icu_config" ]
-
- if (is_win || icu_use_data_file) {
- sources += [ "source/stubdata/stubdata.c" ]
- defines += [ "U_ICUDATAENTRY_IN_COMMON" ]
- }
-}
-
-# TODO(GYP) support use_system_icu.
-if (icu_use_data_file) {
- if (is_ios) {
- # TODO(GYP): Support mac resource bundle shown below.
- # 'link_settings': {
- # 'mac_bundle_resources': [
- # 'source/data/in/icudtl.dat',
- # ],
- # }
- } else {
- copy("icudata") {
- if (is_android) {
- sources = [
- "android/icudtl.dat",
- ]
- } else {
- sources = [
- "source/data/in/icudtl.dat",
- ]
- }
-
- outputs = [
- "$root_out_dir/icudtl.dat",
- ]
- }
- }
-} else {
- if (is_win) {
- # On Windows the target DLL is pre-built so just use a copy rule.
- copy("icudata") {
- sources = [
- "windows/icudt.dll",
- ]
- outputs = [
- "$root_out_dir/icudt.dll",
- ]
- }
- } else {
- source_set("icudata") {
- # These are hand-generated, but will do for now.
- #
- # TODO(GYP): Gyp has considerations here for QNX and for the host toolchain
- # that have not been ported over.
- if (is_linux) {
- sources = [
- "linux/icudtl_dat.S",
- ]
- } else if (is_mac) {
- sources = [
- "mac/icudtl_dat.S",
- ]
- } else if (is_android) {
- sources = [
- "android/icudtl_dat.S",
- ]
- } else {
- assert(false, "No icu data for this platform")
- }
- defines = [ "U_HIDE_DATA_SYMBOL" ]
- }
- }
-}
diff --git a/build/secondary/third_party/icu/config.gni b/build/secondary/third_party/icu/config.gni
deleted file mode 100644
index 9c389de..0000000
--- a/build/secondary/third_party/icu/config.gni
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-declare_args() {
- # Tells icu to load an external data file rather than rely on the icudata
- # being linked directly into the binary.
- #
- # This flag is a bit confusing. As of this writing, icu.gyp set the value to
- # 0 but common.gypi sets the value to 1 for most platforms (and the 1 takes
- # precedence).
- #
- # TODO(GYP) We'll probably need to enhance this logic to set the value to
- # true or false in similar circumstances.
- icu_use_data_file = true
-}
diff --git a/build/secondary/tools/grit/grit_rule.gni b/build/secondary/tools/grit/grit_rule.gni
index 777c3dc..5d3b1e4 100644
--- a/build/secondary/tools/grit/grit_rule.gni
+++ b/build/secondary/tools/grit/grit_rule.gni
@@ -285,6 +285,12 @@
"enable_service_discovery",
]
}
+if (mac_views_browser) {
+ grit_defines += [
+ "-D",
+ "mac_views_browser",
+ ]
+}
grit_resource_id_file = "//tools/gritsettings/resource_ids"
grit_info_script = "//tools/grit/grit_info.py"
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index ad33651..b4e5ffa 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -418,6 +418,10 @@
"resources/software_rasterizer.h",
"resources/task_graph_runner.cc",
"resources/task_graph_runner.h",
+ "resources/texture_compressor.cc",
+ "resources/texture_compressor.h",
+ "resources/texture_compressor_etc1.cc",
+ "resources/texture_compressor_etc1.h",
"resources/texture_mailbox.cc",
"resources/texture_mailbox.h",
"resources/texture_mailbox_deleter.cc",
@@ -655,6 +659,8 @@
"test/test_occlusion_tracker.h",
"test/test_shared_bitmap_manager.cc",
"test/test_shared_bitmap_manager.h",
+ "test/test_task_graph_runner.cc",
+ "test/test_task_graph_runner.h",
"test/test_texture.cc",
"test/test_texture.h",
"test/test_tile_priorities.cc",
@@ -860,6 +866,7 @@
"resources/picture_layer_tiling_perftest.cc",
"resources/picture_pile_impl_perftest.cc",
"resources/task_graph_runner_perftest.cc",
+ "resources/texture_compressor_perftest.cc",
"resources/tile_manager_perftest.cc",
"resources/tile_task_worker_pool_perftest.cc",
"test/cc_test_suite.cc",
diff --git a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
index f7a5878..6d2d3e8 100644
--- a/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_linear_fade_unittest.cc
@@ -9,6 +9,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,7 +21,7 @@
public ScrollbarAnimationControllerClient {
public:
ScrollbarAnimationControllerLinearFadeTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {}
void StartAnimatingScrollbarAnimationController(
ScrollbarAnimationController* controller) override {
@@ -75,6 +76,7 @@
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<ScrollbarAnimationControllerLinearFade> scrollbar_controller_;
scoped_ptr<LayerImpl> clip_layer_;
diff --git a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
index 01763c9..04f81d3 100644
--- a/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
+++ b/cc/animation/scrollbar_animation_controller_thinning_unittest.cc
@@ -9,6 +9,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -20,7 +21,7 @@
public ScrollbarAnimationControllerClient {
public:
ScrollbarAnimationControllerThinningTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {}
void StartAnimatingScrollbarAnimationController(
ScrollbarAnimationController* controller) override {
@@ -74,6 +75,7 @@
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<ScrollbarAnimationControllerThinning> scrollbar_controller_;
scoped_ptr<LayerImpl> clip_layer_;
diff --git a/cc/base/tiling_data.cc b/cc/base/tiling_data.cc
index 95fd68b..c9b2fd9 100644
--- a/cc/base/tiling_data.cc
+++ b/cc/base/tiling_data.cc
@@ -350,7 +350,11 @@
return *this;
}
-TilingData::DifferenceIterator::DifferenceIterator(
+TilingData::BaseDifferenceIterator::BaseDifferenceIterator() {
+ done();
+}
+
+TilingData::BaseDifferenceIterator::BaseDifferenceIterator(
const TilingData* tiling_data,
const gfx::Rect& consider_rect,
const gfx::Rect& ignore_rect)
@@ -369,9 +373,8 @@
gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
gfx::Rect consider(consider_rect);
- gfx::Rect ignore(ignore_rect);
consider.Intersect(tiling_bounds_rect);
- ignore.Intersect(tiling_bounds_rect);
+
if (consider.IsEmpty()) {
done();
return;
@@ -382,6 +385,9 @@
consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1);
consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1);
+ gfx::Rect ignore(ignore_rect);
+ ignore.Intersect(tiling_bounds_rect);
+
if (!ignore.IsEmpty()) {
ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x());
ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y());
@@ -393,10 +399,31 @@
ignore_top_ = std::max(ignore_top_, consider_top_);
ignore_right_ = std::min(ignore_right_, consider_right_);
ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
- }
- if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
- ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
+ ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ consider_left_ = consider_top_ = consider_right_ = consider_bottom_ = -1;
+ done();
+ return;
+ }
+ }
+}
+
+bool TilingData::BaseDifferenceIterator::HasConsiderRect() const {
+ // Consider indices are either all valid or all equal to -1.
+ DCHECK((0 <= consider_left_ && consider_left_ <= consider_right_ &&
+ 0 <= consider_top_ && consider_top_ <= consider_bottom_) ||
+ (consider_left_ == -1 && consider_top_ == -1 &&
+ consider_right_ == -1 && consider_bottom_ == -1));
+ return consider_left_ != -1;
+}
+
+TilingData::DifferenceIterator::DifferenceIterator(
+ const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect)
+ : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect) {
+ if (!HasConsiderRect()) {
done();
return;
}
@@ -446,82 +473,40 @@
const gfx::Rect& consider_rect,
const gfx::Rect& ignore_rect,
const gfx::Rect& center_rect)
- : consider_left_(-1),
- consider_top_(-1),
- consider_right_(-1),
- consider_bottom_(-1),
- ignore_left_(-1),
- ignore_top_(-1),
- ignore_right_(-1),
- ignore_bottom_(-1),
+ : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect),
direction_(RIGHT),
delta_x_(1),
delta_y_(0),
current_step_(0),
horizontal_step_count_(0),
vertical_step_count_(0) {
- if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
- done();
- return;
- }
-
- gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
- gfx::Rect consider(consider_rect);
- gfx::Rect ignore(ignore_rect);
- gfx::Rect center(center_rect);
- consider.Intersect(tiling_bounds_rect);
- ignore.Intersect(tiling_bounds_rect);
- if (consider.IsEmpty()) {
- done();
- return;
- }
-
- consider_left_ = tiling_data->TileXIndexFromSrcCoord(consider.x());
- consider_top_ = tiling_data->TileYIndexFromSrcCoord(consider.y());
- consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1);
- consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1);
-
- if (!ignore.IsEmpty()) {
- ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x());
- ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y());
- ignore_right_ = tiling_data->TileXIndexFromSrcCoord(ignore.right() - 1);
- ignore_bottom_ = tiling_data->TileYIndexFromSrcCoord(ignore.bottom() - 1);
-
- // Clamp ignore indices to consider indices.
- ignore_left_ = std::max(ignore_left_, consider_left_);
- ignore_top_ = std::max(ignore_top_, consider_top_);
- ignore_right_ = std::min(ignore_right_, consider_right_);
- ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
- }
-
- if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
- ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ if (!HasConsiderRect()) {
done();
return;
}
// Determine around left, such that it is between -1 and num_tiles_x.
int around_left = 0;
- if (center.x() < 0 || center.IsEmpty())
+ if (center_rect.x() < 0 || center_rect.IsEmpty())
around_left = -1;
- else if (center.x() >= tiling_data->tiling_size().width())
+ else if (center_rect.x() >= tiling_data->tiling_size().width())
around_left = tiling_data->num_tiles_x();
else
- around_left = tiling_data->TileXIndexFromSrcCoord(center.x());
+ around_left = tiling_data->TileXIndexFromSrcCoord(center_rect.x());
// Determine around top, such that it is between -1 and num_tiles_y.
int around_top = 0;
- if (center.y() < 0 || center.IsEmpty())
+ if (center_rect.y() < 0 || center_rect.IsEmpty())
around_top = -1;
- else if (center.y() >= tiling_data->tiling_size().height())
+ else if (center_rect.y() >= tiling_data->tiling_size().height())
around_top = tiling_data->num_tiles_y();
else
- around_top = tiling_data->TileYIndexFromSrcCoord(center.y());
+ around_top = tiling_data->TileYIndexFromSrcCoord(center_rect.y());
// Determine around right, such that it is between -1 and num_tiles_x.
- int right_src_coord = center.right() - 1;
+ int right_src_coord = center_rect.right() - 1;
int around_right = 0;
- if (right_src_coord < 0 || center.IsEmpty()) {
+ if (right_src_coord < 0 || center_rect.IsEmpty()) {
around_right = -1;
} else if (right_src_coord >= tiling_data->tiling_size().width()) {
around_right = tiling_data->num_tiles_x();
@@ -530,9 +515,9 @@
}
// Determine around bottom, such that it is between -1 and num_tiles_y.
- int bottom_src_coord = center.bottom() - 1;
+ int bottom_src_coord = center_rect.bottom() - 1;
int around_bottom = 0;
- if (bottom_src_coord < 0 || center.IsEmpty()) {
+ if (bottom_src_coord < 0 || center_rect.IsEmpty()) {
around_bottom = -1;
} else if (bottom_src_coord >= tiling_data->tiling_size().height()) {
around_bottom = tiling_data->num_tiles_y();
@@ -669,83 +654,41 @@
const gfx::Rect& consider_rect,
const gfx::Rect& ignore_rect,
const gfx::Rect& center_rect)
- : consider_left_(-1),
- consider_top_(-1),
- consider_right_(-1),
- consider_bottom_(-1),
+ : BaseDifferenceIterator(tiling_data, consider_rect, ignore_rect),
around_left_(-1),
around_top_(-1),
around_right_(-1),
around_bottom_(-1),
- ignore_left_(-1),
- ignore_top_(-1),
- ignore_right_(-1),
- ignore_bottom_(-1),
direction_(LEFT),
delta_x_(-1),
delta_y_(0),
current_step_(0),
horizontal_step_count_(0),
vertical_step_count_(0) {
- if (tiling_data->num_tiles_x() <= 0 || tiling_data->num_tiles_y() <= 0) {
- done();
- return;
- }
-
- gfx::Rect tiling_bounds_rect(tiling_data->tiling_size());
- gfx::Rect consider(consider_rect);
- gfx::Rect ignore(ignore_rect);
- gfx::Rect center(center_rect);
- consider.Intersect(tiling_bounds_rect);
- ignore.Intersect(tiling_bounds_rect);
- if (consider.IsEmpty()) {
- done();
- return;
- }
-
- consider_left_ = tiling_data->TileXIndexFromSrcCoord(consider.x());
- consider_top_ = tiling_data->TileYIndexFromSrcCoord(consider.y());
- consider_right_ = tiling_data->TileXIndexFromSrcCoord(consider.right() - 1);
- consider_bottom_ = tiling_data->TileYIndexFromSrcCoord(consider.bottom() - 1);
-
- if (!ignore.IsEmpty()) {
- ignore_left_ = tiling_data->TileXIndexFromSrcCoord(ignore.x());
- ignore_top_ = tiling_data->TileYIndexFromSrcCoord(ignore.y());
- ignore_right_ = tiling_data->TileXIndexFromSrcCoord(ignore.right() - 1);
- ignore_bottom_ = tiling_data->TileYIndexFromSrcCoord(ignore.bottom() - 1);
-
- // Clamp ignore indices to consider indices.
- ignore_left_ = std::max(ignore_left_, consider_left_);
- ignore_top_ = std::max(ignore_top_, consider_top_);
- ignore_right_ = std::min(ignore_right_, consider_right_);
- ignore_bottom_ = std::min(ignore_bottom_, consider_bottom_);
- }
-
- if (ignore_left_ == consider_left_ && ignore_right_ == consider_right_ &&
- ignore_top_ == consider_top_ && ignore_bottom_ == consider_bottom_) {
+ if (!HasConsiderRect()) {
done();
return;
}
// Determine around left, such that it is between -1 and num_tiles_x.
- if (center.x() < 0 || center.IsEmpty())
+ if (center_rect.x() < 0 || center_rect.IsEmpty())
around_left_ = -1;
- else if (center.x() >= tiling_data->tiling_size().width())
+ else if (center_rect.x() >= tiling_data->tiling_size().width())
around_left_ = tiling_data->num_tiles_x();
else
- around_left_ = tiling_data->TileXIndexFromSrcCoord(center.x());
+ around_left_ = tiling_data->TileXIndexFromSrcCoord(center_rect.x());
// Determine around top, such that it is between -1 and num_tiles_y.
- if (center.y() < 0 || center.IsEmpty())
+ if (center_rect.y() < 0 || center_rect.IsEmpty())
around_top_ = -1;
- else if (center.y() >= tiling_data->tiling_size().height())
+ else if (center_rect.y() >= tiling_data->tiling_size().height())
around_top_ = tiling_data->num_tiles_y();
else
- around_top_ = tiling_data->TileYIndexFromSrcCoord(center.y());
+ around_top_ = tiling_data->TileYIndexFromSrcCoord(center_rect.y());
// Determine around right, such that it is between -1 and num_tiles_x.
- int right_src_coord = center.right() - 1;
- if (right_src_coord < 0 || center.IsEmpty()) {
+ int right_src_coord = center_rect.right() - 1;
+ if (right_src_coord < 0 || center_rect.IsEmpty()) {
around_right_ = -1;
} else if (right_src_coord >= tiling_data->tiling_size().width()) {
around_right_ = tiling_data->num_tiles_x();
@@ -754,8 +697,8 @@
}
// Determine around bottom, such that it is between -1 and num_tiles_y.
- int bottom_src_coord = center.bottom() - 1;
- if (bottom_src_coord < 0 || center.IsEmpty()) {
+ int bottom_src_coord = center_rect.bottom() - 1;
+ if (bottom_src_coord < 0 || center_rect.IsEmpty()) {
around_bottom_ = -1;
} else if (bottom_src_coord >= tiling_data->tiling_size().height()) {
around_bottom_ = tiling_data->num_tiles_y();
diff --git a/cc/base/tiling_data.h b/cc/base/tiling_data.h
index 45b763e..a35be59 100644
--- a/cc/base/tiling_data.h
+++ b/cc/base/tiling_data.h
@@ -101,19 +101,21 @@
int bottom_;
};
- // Iterate through all indices whose bounds (not including borders) intersect
- // with |consider| but which also do not intersect with |ignore|.
- class CC_EXPORT DifferenceIterator : public BaseIterator {
- public:
- DifferenceIterator(const TilingData* tiling_data,
- const gfx::Rect& consider_rect,
- const gfx::Rect& ignore_rect);
- DifferenceIterator& operator++();
+ class CC_EXPORT BaseDifferenceIterator : public BaseIterator {
+ protected:
+ BaseDifferenceIterator();
+ BaseDifferenceIterator(const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect);
- private:
+ bool HasConsiderRect() const;
+ bool in_consider_rect() const {
+ return index_x_ >= consider_left_ && index_x_ <= consider_right_ &&
+ index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
+ }
bool in_ignore_rect() const {
- return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
- index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
+ return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
+ index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
}
int consider_left_;
@@ -126,10 +128,20 @@
int ignore_bottom_;
};
+ // Iterate through all indices whose bounds (not including borders) intersect
+ // with |consider| but which also do not intersect with |ignore|.
+ class CC_EXPORT DifferenceIterator : public BaseDifferenceIterator {
+ public:
+ DifferenceIterator(const TilingData* tiling_data,
+ const gfx::Rect& consider_rect,
+ const gfx::Rect& ignore_rect);
+ DifferenceIterator& operator++();
+ };
+
// Iterate through all indices whose bounds + border intersect with
// |consider| but which also do not intersect with |ignore|. The iterator
// order is a counterclockwise spiral around the given center.
- class CC_EXPORT SpiralDifferenceIterator : public BaseIterator {
+ class CC_EXPORT SpiralDifferenceIterator : public BaseDifferenceIterator {
public:
SpiralDifferenceIterator();
SpiralDifferenceIterator(const TilingData* tiling_data,
@@ -139,14 +151,6 @@
SpiralDifferenceIterator& operator++();
private:
- bool in_consider_rect() const {
- return index_x_ >= consider_left_ && index_x_ <= consider_right_ &&
- index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
- }
- bool in_ignore_rect() const {
- return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
- index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
- }
bool valid_column() const {
return index_x_ >= consider_left_ && index_x_ <= consider_right_;
}
@@ -162,15 +166,6 @@
bool needs_direction_switch() const;
void switch_direction();
- int consider_left_;
- int consider_top_;
- int consider_right_;
- int consider_bottom_;
- int ignore_left_;
- int ignore_top_;
- int ignore_right_;
- int ignore_bottom_;
-
enum Direction { UP, LEFT, DOWN, RIGHT };
Direction direction_;
@@ -181,7 +176,8 @@
int vertical_step_count_;
};
- class CC_EXPORT ReverseSpiralDifferenceIterator : public BaseIterator {
+ class CC_EXPORT ReverseSpiralDifferenceIterator
+ : public BaseDifferenceIterator {
public:
ReverseSpiralDifferenceIterator();
ReverseSpiralDifferenceIterator(const TilingData* tiling_data,
@@ -191,18 +187,10 @@
ReverseSpiralDifferenceIterator& operator++();
private:
- bool in_consider_rect() const {
- return index_x_ >= consider_left_ && index_x_ <= consider_right_ &&
- index_y_ >= consider_top_ && index_y_ <= consider_bottom_;
- }
bool in_around_rect() const {
return index_x_ >= around_left_ && index_x_ <= around_right_ &&
index_y_ >= around_top_ && index_y_ <= around_bottom_;
}
- bool in_ignore_rect() const {
- return index_x_ >= ignore_left_ && index_x_ <= ignore_right_ &&
- index_y_ >= ignore_top_ && index_y_ <= ignore_bottom_;
- }
bool valid_column() const {
return index_x_ >= consider_left_ && index_x_ <= consider_right_;
}
@@ -218,18 +206,10 @@
bool needs_direction_switch() const;
void switch_direction();
- int consider_left_;
- int consider_top_;
- int consider_right_;
- int consider_bottom_;
int around_left_;
int around_top_;
int around_right_;
int around_bottom_;
- int ignore_left_;
- int ignore_top_;
- int ignore_right_;
- int ignore_bottom_;
enum Direction { LEFT, UP, RIGHT, DOWN };
diff --git a/cc/cc.gyp b/cc/cc.gyp
index c796e7d..c5f2033 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -478,6 +478,10 @@
'resources/software_rasterizer.h',
'resources/task_graph_runner.cc',
'resources/task_graph_runner.h',
+ 'resources/texture_compressor.cc',
+ 'resources/texture_compressor.h',
+ 'resources/texture_compressor_etc1.cc',
+ 'resources/texture_compressor_etc1.h',
'resources/texture_mailbox.cc',
'resources/texture_mailbox.h',
'resources/texture_mailbox_deleter.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index bafd747..cb84033 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -260,6 +260,8 @@
'test/test_occlusion_tracker.h',
'test/test_shared_bitmap_manager.cc',
'test/test_shared_bitmap_manager.h',
+ 'test/test_task_graph_runner.cc',
+ 'test/test_task_graph_runner.h',
'test/test_texture.cc',
'test/test_texture.h',
'test/test_tile_priorities.cc',
@@ -351,6 +353,7 @@
'resources/picture_layer_tiling_perftest.cc',
'resources/picture_pile_impl_perftest.cc',
'resources/task_graph_runner_perftest.cc',
+ 'resources/texture_compressor_perftest.cc',
'resources/tile_manager_perftest.cc',
'resources/tile_task_worker_pool_perftest.cc',
'test/cc_test_suite.cc',
diff --git a/cc/cc_unittests.isolate b/cc/cc_unittests.isolate
index dc6c449..7c359d0 100644
--- a/cc/cc_unittests.isolate
+++ b/cc/cc_unittests.isolate
@@ -84,5 +84,6 @@
],
'includes': [
'../base/base.isolate',
+ '../third_party/angle/angle.isolate',
],
}
diff --git a/cc/debug/frame_viewer_instrumentation.cc b/cc/debug/frame_viewer_instrumentation.cc
index 53c1551..226cc88 100644
--- a/cc/debug/frame_viewer_instrumentation.cc
+++ b/cc/debug/frame_viewer_instrumentation.cc
@@ -6,6 +6,12 @@
namespace cc {
namespace frame_viewer_instrumentation {
+
+const char kCategoryLayerTree[] =
+ TRACE_DISABLED_BY_DEFAULT("cc.debug") ","
+ TRACE_DISABLED_BY_DEFAULT("cc.debug.quads") ","
+ TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers");
+
namespace {
const char kCategory[] = "cc," TRACE_DISABLED_BY_DEFAULT("devtools.timeline");
@@ -60,5 +66,11 @@
TRACE_EVENT_END0(kCategory, kRasterTask);
}
+bool IsTracingLayerTreeSnapshots() {
+ bool category_enabled;
+ TRACE_EVENT_CATEGORY_GROUP_ENABLED(kCategoryLayerTree, &category_enabled);
+ return category_enabled;
+}
+
} // namespace frame_viewer_instrumentation
} // namespace cc
diff --git a/cc/debug/frame_viewer_instrumentation.h b/cc/debug/frame_viewer_instrumentation.h
index 762d058..b6736be 100644
--- a/cc/debug/frame_viewer_instrumentation.h
+++ b/cc/debug/frame_viewer_instrumentation.h
@@ -11,6 +11,8 @@
namespace cc {
namespace frame_viewer_instrumentation {
+extern const char kCategoryLayerTree[];
+
class ScopedAnalyzeTask {
public:
ScopedAnalyzeTask(const void* tile_id,
@@ -35,6 +37,8 @@
DISALLOW_COPY_AND_ASSIGN(ScopedRasterTask);
};
+bool IsTracingLayerTreeSnapshots();
+
} // namespace frame_viewer_instrumentation
} // namespace cc
diff --git a/cc/debug/micro_benchmark_controller_unittest.cc b/cc/debug/micro_benchmark_controller_unittest.cc
index 31494ac..2a8dce4 100644
--- a/cc/debug/micro_benchmark_controller_unittest.cc
+++ b/cc/debug/micro_benchmark_controller_unittest.cc
@@ -25,7 +25,7 @@
impl_proxy_ = make_scoped_ptr(new FakeImplProxy);
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
layer_tree_host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(
- impl_proxy_.get(), shared_bitmap_manager_.get()));
+ impl_proxy_.get(), shared_bitmap_manager_.get(), nullptr));
layer_tree_host_ = FakeLayerTreeHost::Create(&layer_tree_host_client_);
layer_tree_host_->SetRootLayer(Layer::Create());
diff --git a/cc/debug/rasterize_and_record_benchmark.cc b/cc/debug/rasterize_and_record_benchmark.cc
index e46dcfe..73a0fa5 100644
--- a/cc/debug/rasterize_and_record_benchmark.cc
+++ b/cc/debug/rasterize_and_record_benchmark.cc
@@ -225,9 +225,11 @@
min_time = duration;
}
- record_results_.bytes_used += memory_used;
- record_results_.pixels_recorded +=
- visible_content_rect.width() * visible_content_rect.height();
+ if (mode_index == RecordingSource::RECORD_NORMALLY) {
+ record_results_.bytes_used += memory_used;
+ record_results_.pixels_recorded +=
+ visible_content_rect.width() * visible_content_rect.height();
+ }
record_results_.total_best_time[mode_index] += min_time;
}
}
diff --git a/cc/input/top_controls_manager_unittest.cc b/cc/input/top_controls_manager_unittest.cc
index 4145cac..52e46e6 100644
--- a/cc/input/top_controls_manager_unittest.cc
+++ b/cc/input/top_controls_manager_unittest.cc
@@ -15,6 +15,7 @@
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/frame_time.h"
@@ -28,7 +29,7 @@
MockTopControlsManagerClient(float top_controls_height,
float top_controls_show_threshold,
float top_controls_hide_threshold)
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
redraw_needed_(false),
update_draw_properties_needed_(false),
top_controls_shown_ratio_(1.f),
@@ -83,6 +84,7 @@
private:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerTreeImpl> active_tree_;
scoped_ptr<LayerImpl> root_scroll_layer_;
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index 87e559a..9e2d553 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -18,6 +18,7 @@
#include "cc/test/render_pass_test_common.h"
#include "cc/test/render_pass_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "cc/trees/layer_tree_impl.h"
@@ -37,8 +38,8 @@
LayerTreeSettings settings;
settings.minimum_occlusion_tracking_size = gfx::Size();
- host_impl_.reset(
- new FakeLayerTreeHostImpl(settings, &proxy_, &shared_bitmap_manager_));
+ host_impl_.reset(new FakeLayerTreeHostImpl(
+ settings, &proxy_, &shared_bitmap_manager_, &task_graph_runner_));
host_impl_->InitializeRenderer(FakeOutputSurface::Create3d());
host_impl_->SetViewportSize(gfx::Size(10, 10));
}
@@ -48,6 +49,7 @@
DebugScopedSetImplThreadAndMainThreadBlocked
always_impl_thread_and_main_thread_blocked_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
scoped_ptr<LayerTreeHostImpl> host_impl_;
};
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index e1a9daf..d2558c1 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -223,6 +223,10 @@
resources_.clear();
}
+gfx::Rect HeadsUpDisplayLayerImpl::GetEnclosingRectInTargetSpace() const {
+ return GetScaledEnclosingRectInTargetSpace(internal_contents_scale_);
+}
+
void HeadsUpDisplayLayerImpl::UpdateHudContents() {
const LayerTreeDebugState& debug_state = layer_tree_impl()->debug_state();
@@ -551,23 +555,23 @@
SkColor color = SK_ColorRED;
switch (layer_tree_impl()->GetGpuRasterizationStatus()) {
case GpuRasterizationStatus::ON:
- status = "GPU raster: on";
+ status = "on";
color = SK_ColorGREEN;
break;
case GpuRasterizationStatus::ON_FORCED:
- status = "GPU raster: on (forced)";
+ status = "on (forced)";
color = SK_ColorGREEN;
break;
case GpuRasterizationStatus::OFF_DEVICE:
- status = "GPU raster: off (device)";
+ status = "off (device)";
color = SK_ColorRED;
break;
case GpuRasterizationStatus::OFF_VIEWPORT:
- status = "GPU raster: off (viewport)";
+ status = "off (viewport)";
color = SK_ColorYELLOW;
break;
case GpuRasterizationStatus::OFF_CONTENT:
- status = "GPU raster: off (content)";
+ status = "off (content)";
color = SK_ColorYELLOW;
break;
}
@@ -578,17 +582,20 @@
const int kPadding = 4;
const int kFontHeight = 13;
- const int height = kFontHeight + 2 * kPadding;
+ const int height = 2 * kFontHeight + 3 * kPadding;
const int left = bounds().width() - width - right;
const SkRect area = SkRect::MakeXYWH(left, top, width, height);
SkPaint paint = CreatePaint();
DrawGraphBackground(canvas, &paint, area);
- SkPoint gpu_status_pos = SkPoint::Make(left + kPadding, top + kFontHeight);
+ SkPoint gpu_status_pos = SkPoint::Make(left + width - kPadding,
+ top + 2 * kFontHeight + 2 * kPadding);
paint.setColor(color);
- DrawText(canvas, &paint, status, SkPaint::kLeft_Align, kFontHeight,
+ DrawText(canvas, &paint, "GPU raster: ", SkPaint::kLeft_Align, kFontHeight,
+ left + kPadding, top + kFontHeight + kPadding);
+ DrawText(canvas, &paint, status, SkPaint::kRight_Align, kFontHeight,
gpu_status_pos);
return area;
@@ -600,7 +607,7 @@
int right,
int top) const {
const int kPadding = 4;
- const int kFontHeight = 15;
+ const int kFontHeight = 14;
const int kGraphWidth = paint_time_counter->HistorySize();
const int kGraphHeight = 40;
@@ -632,7 +639,7 @@
"%.1f-%.1f", paint_time_graph_.min, paint_time_graph_.max);
paint.setColor(DebugColors::PaintTimeDisplayTextAndGraphColor());
- DrawText(canvas, &paint, "Compositor frame time (ms)", SkPaint::kLeft_Align,
+ DrawText(canvas, &paint, "Compositor frame time(ms)", SkPaint::kLeft_Align,
kFontHeight, text_bounds.left(), text_bounds.bottom());
DrawText(canvas,
&paint,
diff --git a/cc/layers/heads_up_display_layer_impl.h b/cc/layers/heads_up_display_layer_impl.h
index 54bf153..750d991 100644
--- a/cc/layers/heads_up_display_layer_impl.h
+++ b/cc/layers/heads_up_display_layer_impl.h
@@ -45,6 +45,8 @@
void ReleaseResources() override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
+
bool IsAnimatingHUDContents() const { return fade_step_ > 0; }
private:
diff --git a/cc/layers/heads_up_display_layer_impl_unittest.cc b/cc/layers/heads_up_display_layer_impl_unittest.cc
index 4b07323..ab38fdd 100644
--- a/cc/layers/heads_up_display_layer_impl_unittest.cc
+++ b/cc/layers/heads_up_display_layer_impl_unittest.cc
@@ -32,7 +32,7 @@
TEST(HeadsUpDisplayLayerImplTest, ResourcelessSoftwareDrawAfterResourceLoss) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
host_impl.InitializeRenderer(FakeOutputSurface::Create3d());
scoped_ptr<HeadsUpDisplayLayerImpl> layer =
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 12773a1..1c677b6 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -18,6 +18,7 @@
#include "cc/animation/keyframed_animation_curve.h"
#include "cc/animation/layer_animation_controller.h"
#include "cc/base/simple_enclosed_region.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/layers/layer_client.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/scrollbar_layer_interface.h"
@@ -897,12 +898,7 @@
layer->SetContentBounds(content_bounds());
layer->SetContentsScale(contents_scale_x(), contents_scale_y());
- bool is_tracing;
- TRACE_EVENT_CATEGORY_GROUP_ENABLED(
- TRACE_DISABLED_BY_DEFAULT("cc.debug") "," TRACE_DISABLED_BY_DEFAULT(
- "devtools.timeline.layers"),
- &is_tracing);
- if (is_tracing)
+ if (frame_viewer_instrumentation::IsTracingLayerTreeSnapshots())
layer->SetDebugInfo(TakeDebugInfo());
layer->SetDoubleSided(double_sided_);
@@ -1320,6 +1316,22 @@
xform.FlattenTo2d();
xform.Translate(offset_to_transform_parent().x(),
offset_to_transform_parent().y());
+ // A fixed-position layer does not necessarily have the same render target
+ // as its transform node. In particular, its transform node may be an
+ // ancestor of its render target's transform node. For example, given layer
+ // tree R->S->F, suppose F is fixed and S owns a render surface (e.g., say S
+ // has opacity 0.9 and both S and F draw content). Then F's transform node
+ // is the root node, so the target space transform from that node is defined
+ // with respect to the root render surface. But F will render to S's
+ // surface, so must apply a change of basis transform to the target space
+ // transform from its transform node.
+ if (position_constraint_.is_fixed_position()) {
+ gfx::Transform tree_target_to_render_target;
+ tree.ComputeTransform(node->data.content_target_id,
+ render_target()->transform_tree_index(),
+ &tree_target_to_render_target);
+ xform.ConcatTransform(tree_target_to_render_target);
+ }
} else {
// Surfaces need to apply their sublayer scale.
xform.Scale(target_node->data.sublayer_scale.x(),
@@ -1354,4 +1366,12 @@
SetNeedsCommit();
}
+void Layer::DidBeginTracing() {
+ // We'll be dumping layer trees as part of trace, so make sure
+ // PushPropertiesTo() propagates layer debug info to the impl
+ // side -- otherwise this won't happen for the the layers that
+ // remain unchanged since tracing started.
+ SetNeedsPushProperties();
+}
+
} // namespace cc
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index e0288c7..4c03e31 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -526,6 +526,8 @@
// Sets new frame timing requests for this layer.
void SetFrameTimingRequests(const std::vector<FrameTimingRequest>& requests);
+ void DidBeginTracing();
+
protected:
friend class LayerImpl;
friend class TreeSynchronizer;
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 0353a78..a1a6161 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -1137,7 +1137,20 @@
gfx::ScrollOffset LayerImpl::PullDeltaForMainThread() {
RefreshFromScrollDelegate();
- return scroll_offset_->PullDeltaForMainThread();
+
+ // TODO(miletus): Remove all this temporary flooring machinery when
+ // Blink fully supports fractional scrolls.
+ gfx::ScrollOffset current_offset = CurrentScrollOffset();
+ gfx::Vector2dF current_delta = ScrollDelta();
+ gfx::Vector2dF floored_delta(floor(current_delta.x()),
+ floor(current_delta.y()));
+ gfx::Vector2dF diff_delta = floored_delta - current_delta;
+ gfx::ScrollOffset tmp_offset = ScrollOffsetWithDelta(current_offset,
+ diff_delta);
+ scroll_offset_->SetCurrent(tmp_offset);
+ gfx::ScrollOffset delta = scroll_offset_->PullDeltaForMainThread();
+ scroll_offset_->SetCurrent(current_offset);
+ return delta;
}
void LayerImpl::RefreshFromScrollDelegate() {
@@ -1426,7 +1439,8 @@
parent_->RemoveDependentNeedsPushProperties();
}
-void LayerImpl::GetAllTilesForTracing(std::set<const Tile*>* tiles) const {
+void LayerImpl::GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const {
}
void LayerImpl::AsValueInto(base::trace_event::TracedValue* state) const {
@@ -1594,4 +1608,20 @@
return Region(update_rect_);
}
+gfx::Rect LayerImpl::GetEnclosingRectInTargetSpace() const {
+ return MathUtil::MapEnclosingClippedRect(
+ draw_properties_.target_space_transform,
+ gfx::Rect(draw_properties_.content_bounds));
+}
+
+gfx::Rect LayerImpl::GetScaledEnclosingRectInTargetSpace(float scale) const {
+ gfx::Transform scaled_draw_transform =
+ draw_properties_.target_space_transform;
+ scaled_draw_transform.Scale(SK_MScalar1 / scale, SK_MScalar1 / scale);
+ gfx::Size scaled_content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(content_bounds(), scale));
+ return MathUtil::MapEnclosingClippedRect(scaled_draw_transform,
+ gfx::Rect(scaled_content_bounds));
+}
+
} // namespace cc
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 0357252..e0c42f0 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -5,6 +5,7 @@
#ifndef CC_LAYERS_LAYER_IMPL_H_
#define CC_LAYERS_LAYER_IMPL_H_
+#include <map>
#include <set>
#include <string>
#include <vector>
@@ -31,6 +32,7 @@
#include "cc/output/filter_operations.h"
#include "cc/quads/shared_quad_state.h"
#include "cc/resources/resource_provider.h"
+#include "cc/resources/tile_priority.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkColor.h"
#include "third_party/skia/include/core/SkImageFilter.h"
@@ -561,7 +563,8 @@
virtual scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl);
virtual void PushPropertiesTo(LayerImpl* layer);
- virtual void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
+ virtual void GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const;
virtual void AsValueInto(base::trace_event::TracedValue* dict) const;
virtual size_t GPUMemoryUsageInBytes() const;
@@ -600,6 +603,8 @@
// for layers that provide it.
virtual Region GetInvalidationRegion();
+ virtual gfx::Rect GetEnclosingRectInTargetSpace() const;
+
protected:
LayerImpl(LayerTreeImpl* layer_impl,
int id,
@@ -626,6 +631,8 @@
// Note carefully this does not affect the current layer.
void NoteLayerPropertyChangedForDescendants();
+ gfx::Rect GetScaledEnclosingRectInTargetSpace(float scale) const;
+
private:
void PushScrollOffset(const gfx::ScrollOffset* scroll_offset);
void DidUpdateScrollOffset();
diff --git a/cc/layers/layer_impl_unittest.cc b/cc/layers/layer_impl_unittest.cc
index 0dbf356..1cdbd59 100644
--- a/cc/layers/layer_impl_unittest.cc
+++ b/cc/layers/layer_impl_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_output_surface.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
#include "cc/trees/tree_synchronizer.h"
@@ -87,7 +88,7 @@
// Create a simple LayerImpl tree:
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d()));
scoped_ptr<LayerImpl> root_clip =
LayerImpl::Create(host_impl.active_tree(), 1);
@@ -250,7 +251,7 @@
TEST(LayerImplTest, VerifyNeedsUpdateDrawProperties) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d()));
host_impl.active_tree()->SetRootLayer(
LayerImpl::Create(host_impl.active_tree(), 1));
@@ -368,7 +369,7 @@
TEST(LayerImplTest, SafeOpaqueBackgroundColor) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
EXPECT_TRUE(host_impl.InitializeRenderer(FakeOutputSurface::Create3d()));
scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl.active_tree(), 1);
@@ -399,7 +400,7 @@
TEST(LayerImplTest, TransformInvertibility) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> layer = LayerImpl::Create(host_impl.active_tree(), 1);
EXPECT_TRUE(layer->transform().IsInvertible());
@@ -429,7 +430,11 @@
class LayerImplScrollTest : public testing::Test {
public:
LayerImplScrollTest()
- : host_impl_(settings(), &proxy_, &shared_bitmap_manager_), root_id_(7) {
+ : host_impl_(settings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
+ root_id_(7) {
host_impl_.active_tree()->SetRootLayer(
LayerImpl::Create(host_impl_.active_tree(), root_id_));
host_impl_.active_tree()->root_layer()->AddChild(
@@ -460,6 +465,7 @@
private:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
int root_id_;
};
@@ -771,7 +777,10 @@
};
LayerImplScrollbarSyncTest()
- : host_impl_(settings(), &proxy_, &shared_bitmap_manager_) {
+ : host_impl_(settings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_) {
host_impl_.CreatePendingTree();
CreateLayers(host_impl_.pending_tree());
@@ -836,6 +845,7 @@
private:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
};
diff --git a/cc/layers/layer_perftest.cc b/cc/layers/layer_perftest.cc
index 0b4c852..72b2e13 100644
--- a/cc/layers/layer_perftest.cc
+++ b/cc/layers/layer_perftest.cc
@@ -10,7 +10,7 @@
#include "cc/test/fake_layer_tree_host.h"
#include "cc/test/fake_layer_tree_host_client.h"
#include "cc/test/fake_layer_tree_host_impl.h"
-
+#include "cc/test/test_task_graph_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -30,7 +30,7 @@
class LayerPerfTest : public testing::Test {
public:
LayerPerfTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
fake_client_(FakeLayerTreeHostClient::DIRECT_3D),
timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
@@ -50,6 +50,7 @@
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
FakeLayerTreeHostClient fake_client_;
diff --git a/cc/layers/layer_position_constraint_unittest.cc b/cc/layers/layer_position_constraint_unittest.cc
index 1c0619b..1eea9c9 100644
--- a/cc/layers/layer_position_constraint_unittest.cc
+++ b/cc/layers/layer_position_constraint_unittest.cc
@@ -11,6 +11,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -63,7 +64,8 @@
class LayerPositionConstraintTest : public testing::Test {
public:
- LayerPositionConstraintTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {
+ LayerPositionConstraintTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {
root_ = CreateTreeForTest();
scroll_ = root_->children()[0];
fixed_to_top_left_.set_is_fixed_position(true);
@@ -127,6 +129,7 @@
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerImpl> root_;
LayerImpl* scroll_;
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 8a61510..10d774c 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -16,6 +16,7 @@
#include "cc/test/layer_test_common.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
@@ -41,7 +42,7 @@
class MockLayerTreeHost : public LayerTreeHost {
public:
explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
- : LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
+ : LayerTreeHost(client, nullptr, nullptr, nullptr, LayerTreeSettings()) {
InitializeSingleThreaded(client,
base::MessageLoopProxy::current(),
nullptr);
@@ -60,7 +61,7 @@
class LayerTest : public testing::Test {
public:
LayerTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
protected:
@@ -131,6 +132,7 @@
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
FakeLayerTreeHostClient fake_client_;
@@ -935,24 +937,16 @@
scoped_ptr<LayerTreeHost> Create() {
return LayerTreeHost::CreateSingleThreaded(
- &client_,
- &client_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- LayerTreeSettings(),
- base::MessageLoopProxy::current(),
- nullptr);
+ &client_, &client_, shared_bitmap_manager_.get(),
+ gpu_memory_buffer_manager_.get(), nullptr, LayerTreeSettings(),
+ base::MessageLoopProxy::current(), nullptr);
}
scoped_ptr<LayerTreeHost> Create(LayerTreeSettings settings) {
return LayerTreeHost::CreateSingleThreaded(
- &client_,
- &client_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- settings,
- base::MessageLoopProxy::current(),
- nullptr);
+ &client_, &client_, shared_bitmap_manager_.get(),
+ gpu_memory_buffer_manager_.get(), nullptr, settings,
+ base::MessageLoopProxy::current(), nullptr);
}
private:
diff --git a/cc/layers/layer_utils_unittest.cc b/cc/layers/layer_utils_unittest.cc
index 5764bc6..534a691 100644
--- a/cc/layers/layer_utils_unittest.cc
+++ b/cc/layers/layer_utils_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/box_f.h"
#include "ui/gfx/test/gfx_util.h"
@@ -24,7 +25,7 @@
class LayerUtilsGetAnimationBoundsTest : public testing::Test {
public:
LayerUtilsGetAnimationBoundsTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
root_(CreateThreeNodeTree(&host_impl_)),
parent_(root_->children()[0]),
child_(parent_->children()[0]) {}
@@ -45,6 +46,7 @@
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
scoped_ptr<LayerImpl> root_;
LayerImpl* parent_;
diff --git a/cc/layers/painted_scrollbar_layer_impl.cc b/cc/layers/painted_scrollbar_layer_impl.cc
index b05d51e..a085df5 100644
--- a/cc/layers/painted_scrollbar_layer_impl.cc
+++ b/cc/layers/painted_scrollbar_layer_impl.cc
@@ -131,6 +131,10 @@
}
}
+gfx::Rect PaintedScrollbarLayerImpl::GetEnclosingRectInTargetSpace() const {
+ return GetScaledEnclosingRectInTargetSpace(internal_contents_scale_);
+}
+
void PaintedScrollbarLayerImpl::SetThumbThickness(int thumb_thickness) {
if (thumb_thickness_ == thumb_thickness)
return;
diff --git a/cc/layers/painted_scrollbar_layer_impl.h b/cc/layers/painted_scrollbar_layer_impl.h
index 36a9be9..65d28ae 100644
--- a/cc/layers/painted_scrollbar_layer_impl.h
+++ b/cc/layers/painted_scrollbar_layer_impl.h
@@ -31,6 +31,7 @@
ResourceProvider* resource_provider) override;
void AppendQuads(RenderPass* render_pass,
AppendQuadsData* append_quads_data) override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
void SetThumbThickness(int thumb_thickness);
void SetThumbLength(int thumb_length);
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index 3d2d38e..87c4e58 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +38,8 @@
: proxy_(base::MessageLoopProxy::current()),
host_impl_(ImplSidePaintingSettings(),
&proxy_,
- &shared_bitmap_manager_) {
+ &shared_bitmap_manager_,
+ &task_graph_runner_) {
host_impl_.CreatePendingTree();
host_impl_.InitializeRenderer(FakeOutputSurface::Create3d());
}
@@ -82,8 +84,9 @@
protected:
FakeImplProxy proxy_;
- FakeLayerTreeHostImpl host_impl_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
+ FakeLayerTreeHostImpl host_impl_;
};
TEST_F(PictureImageLayerImplTest, CalculateContentsScale) {
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 672aab4..ad1d5a0 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -73,6 +73,8 @@
bool can_use_lcd_text = layer_impl->RasterSourceUsesLCDText();
scoped_refptr<RasterSource> raster_source =
recording_source_->CreateRasterSource(can_use_lcd_text);
+ layer_impl->set_gpu_raster_max_texture_size(
+ layer_tree_host()->device_viewport_size());
layer_impl->UpdateRasterSource(raster_source, &recording_invalidation_,
nullptr);
DCHECK(recording_invalidation_.IsEmpty());
@@ -95,6 +97,7 @@
recording_source_->DidMoveToNewCompositor();
recording_source_->SetSlowdownRasterScaleFactor(
host->debug_state().slow_down_raster_scale_factor);
+ recording_source_->SetGatherPixelRefs(host->settings().gather_pixel_refs);
DCHECK(host->settings().raster_enabled);
}
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 93d6581..e1b3724 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -130,6 +130,7 @@
DCHECK_LE(tilings_->num_tilings(),
layer_tree_impl()->create_low_res_tiling() ? 2u : 1u);
+ layer_impl->set_gpu_raster_max_texture_size(gpu_raster_max_texture_size_);
layer_impl->UpdateRasterSource(raster_source_, &invalidation_,
tilings_.get());
DCHECK(invalidation_.IsEmpty());
@@ -666,6 +667,10 @@
return layer_tree_impl()->RequiresHighResToDraw();
}
+gfx::Rect PictureLayerImpl::GetEnclosingRectInTargetSpace() const {
+ return GetScaledEnclosingRectInTargetSpace(MaximumTilingContentsScale());
+}
+
gfx::Size PictureLayerImpl::CalculateTileSize(
const gfx::Size& content_bounds) const {
int max_texture_size =
@@ -685,8 +690,8 @@
// For GPU rasterization, we pick an ideal tile size using the viewport
// so we don't need any settings. The current approach uses 4 tiles
// to cover the viewport vertically.
- int viewport_width = layer_tree_impl()->device_viewport_size().width();
- int viewport_height = layer_tree_impl()->device_viewport_size().height();
+ int viewport_width = gpu_raster_max_texture_size_.width();
+ int viewport_height = gpu_raster_max_texture_size_.height();
default_tile_width = viewport_width;
// Also, increase the height proportionally as the width decreases, and
// pad by our border texels to make the tiles exactly match the viewport.
@@ -1168,11 +1173,11 @@
*width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}
-void PictureLayerImpl::GetAllTilesForTracing(
- std::set<const Tile*>* tiles) const {
+void PictureLayerImpl::GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const {
if (!tilings_)
return;
- tilings_->GetAllTilesForTracing(tiles);
+ tilings_->GetAllTilesAndPrioritiesForTracing(tile_map);
}
void PictureLayerImpl::AsValueInto(
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 397cb62..bd13949 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -5,7 +5,7 @@
#ifndef CC_LAYERS_PICTURE_LAYER_IMPL_H_
#define CC_LAYERS_PICTURE_LAYER_IMPL_H_
-#include <set>
+#include <map>
#include <string>
#include <vector>
@@ -75,7 +75,11 @@
TilePriority::PriorityBin GetMaxTilePriorityBin() const override;
WhichTree GetTree() const override;
bool RequiresHighResToDraw() const override;
+ gfx::Rect GetEnclosingRectInTargetSpace() const override;
+ void set_gpu_raster_max_texture_size(gfx::Size gpu_raster_max_texture_size) {
+ gpu_raster_max_texture_size_ = gpu_raster_max_texture_size;
+ }
void UpdateRasterSource(scoped_refptr<RasterSource> raster_source,
Region* new_invalidation,
const PictureLayerTilingSet* pending_set);
@@ -131,7 +135,8 @@
bool ShouldAdjustRasterScaleDuringScaleAnimations() const;
void GetDebugBorderProperties(SkColor* color, float* width) const override;
- void GetAllTilesForTracing(std::set<const Tile*>* tiles) const override;
+ void GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const override;
void AsValueInto(base::trace_event::TracedValue* dict) const override;
virtual void UpdateIdealScales();
@@ -171,6 +176,8 @@
gfx::Rect visible_rect_for_tile_priority_;
gfx::Rect viewport_rect_for_tile_priority_in_content_space_;
+ gfx::Size gpu_raster_max_texture_size_;
+
// List of tilings that were used last time we appended quads. This can be
// used as an optimization not to remove tilings if they are still being
// drawn. Note that accessing this vector should only be done in the context
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index ea73cb2..47f49be 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -13,6 +13,7 @@
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/perf/perf_test.h"
@@ -41,7 +42,8 @@
: proxy_(base::MessageLoopProxy::current()),
host_impl_(ImplSidePaintingSettings(),
&proxy_,
- &shared_bitmap_manager_),
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
@@ -170,6 +172,7 @@
protected:
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeImplProxy proxy_;
FakeLayerTreeHostImpl host_impl_;
FakePictureLayerImpl* pending_layer_;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 26f3be5..1ed3287 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -27,6 +27,7 @@
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -71,7 +72,10 @@
public:
PictureLayerImplTest()
: proxy_(base::MessageLoopProxy::current()),
- host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_),
+ host_impl_(LowResTilingsSettings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
root_id_(6),
id_(7),
pending_layer_(nullptr),
@@ -82,7 +86,10 @@
explicit PictureLayerImplTest(const LayerTreeSettings& settings)
: proxy_(base::MessageLoopProxy::current()),
- host_impl_(settings, &proxy_, &shared_bitmap_manager_),
+ host_impl_(settings,
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
root_id_(6),
id_(7) {
host_impl_.SetViewportSize(gfx::Size(10000, 10000));
@@ -309,6 +316,7 @@
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
int root_id_;
int id_;
@@ -4942,6 +4950,8 @@
// The +2's below are for border texels.
host_impl_.SetUseGpuRasterization(true);
host_impl_.SetViewportSize(gfx::Size(2000, 2000));
+
+ layer->set_gpu_raster_max_texture_size(host_impl_.device_viewport_size());
result = layer->CalculateTileSize(gfx::Size(10000, 10000));
EXPECT_EQ(result.width(), 2000);
EXPECT_EQ(result.height(), 500 + 2);
@@ -4949,6 +4959,7 @@
// Clamp and round-up, when smaller than viewport.
// Tile-height doubles to 50% when width shrinks to <= 50%.
host_impl_.SetViewportSize(gfx::Size(1000, 1000));
+ layer->set_gpu_raster_max_texture_size(host_impl_.device_viewport_size());
result = layer->CalculateTileSize(gfx::Size(447, 10000));
EXPECT_EQ(result.width(), 448);
EXPECT_EQ(result.height(), 500 + 2);
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index ab06bb0..48d4abc 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -62,8 +62,8 @@
DebugScopedSetImplThread impl_thread(&proxy);
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(
- ImplSidePaintingSettings(), &proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(ImplSidePaintingSettings(), &proxy,
+ &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
scoped_ptr<FakePictureLayerImpl> layer_impl =
FakePictureLayerImpl::Create(host_impl.pending_tree(), 1);
@@ -130,12 +130,12 @@
scoped_ptr<LayerTreeHost> host1 = LayerTreeHost::CreateSingleThreaded(
&host_client1, &host_client1, shared_bitmap_manager.get(), nullptr,
- settings, base::MessageLoopProxy::current(), nullptr);
+ nullptr, settings, base::MessageLoopProxy::current(), nullptr);
host_client1.SetLayerTreeHost(host1.get());
scoped_ptr<LayerTreeHost> host2 = LayerTreeHost::CreateSingleThreaded(
&host_client2, &host_client2, shared_bitmap_manager.get(), nullptr,
- settings, base::MessageLoopProxy::current(), nullptr);
+ nullptr, settings, base::MessageLoopProxy::current(), nullptr);
host_client2.SetLayerTreeHost(host2.get());
// The PictureLayer is put in one LayerTreeHost.
diff --git a/cc/layers/render_surface_unittest.cc b/cc/layers/render_surface_unittest.cc
index 81b15ad..929407c 100644
--- a/cc/layers/render_surface_unittest.cc
+++ b/cc/layers/render_surface_unittest.cc
@@ -38,7 +38,7 @@
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> owning_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
owning_layer->SetHasRenderSurface(true);
@@ -83,7 +83,7 @@
TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectSharedQuadState) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
@@ -147,7 +147,7 @@
TEST(RenderSurfaceTest, SanityCheckSurfaceCreatesCorrectRenderPass) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root_layer =
LayerImpl::Create(host_impl.active_tree(), 1);
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 36c37e9..009ec3b 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -21,6 +21,7 @@
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_test.h"
#include "cc/test/mock_occlusion_tracker.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
@@ -516,8 +517,9 @@
public:
ScrollbarLayerSolidColorThumbTest() {
LayerTreeSettings layer_tree_settings;
- host_impl_.reset(new FakeLayerTreeHostImpl(
- layer_tree_settings, &proxy_, &shared_bitmap_manager_));
+ host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_));
const int kThumbThickness = 3;
const int kTrackStart = 0;
@@ -545,6 +547,7 @@
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
diff --git a/cc/layers/solid_color_layer_impl_unittest.cc b/cc/layers/solid_color_layer_impl_unittest.cc
index d10f35d..f35b82a 100644
--- a/cc/layers/solid_color_layer_impl_unittest.cc
+++ b/cc/layers/solid_color_layer_impl_unittest.cc
@@ -28,7 +28,7 @@
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -54,7 +54,7 @@
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -83,7 +83,7 @@
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->draw_properties().visible_content_rect = visible_content_rect;
@@ -112,7 +112,7 @@
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<SolidColorLayerImpl> layer =
SolidColorLayerImpl::Create(host_impl.active_tree(), 1);
layer->SetBounds(layer_size);
diff --git a/cc/layers/texture_layer_unittest.cc b/cc/layers/texture_layer_unittest.cc
index 6405db3..b088f6f 100644
--- a/cc/layers/texture_layer_unittest.cc
+++ b/cc/layers/texture_layer_unittest.cc
@@ -24,6 +24,7 @@
#include "cc/test/fake_output_surface.h"
#include "cc/test/layer_test_common.h"
#include "cc/test/layer_tree_test.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/blocking_task_runner.h"
#include "cc/trees/layer_tree_host.h"
@@ -51,7 +52,7 @@
class MockLayerTreeHost : public LayerTreeHost {
public:
explicit MockLayerTreeHost(FakeLayerTreeHostClient* client)
- : LayerTreeHost(client, nullptr, nullptr, LayerTreeSettings()) {
+ : LayerTreeHost(client, nullptr, nullptr, nullptr, LayerTreeSettings()) {
InitializeSingleThreaded(client,
base::MessageLoopProxy::current(),
nullptr);
@@ -172,7 +173,7 @@
TextureLayerTest()
: fake_client_(
FakeLayerTreeHostClient(FakeLayerTreeHostClient::DIRECT_3D)),
- host_impl_(&proxy_, &shared_bitmap_manager_),
+ host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
test_data_(&shared_bitmap_manager_) {}
protected:
@@ -195,6 +196,7 @@
FakeImplProxy proxy_;
FakeLayerTreeHostClient fake_client_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
CommonMailboxObjects test_data_;
};
diff --git a/cc/layers/tiled_layer_impl_unittest.cc b/cc/layers/tiled_layer_impl_unittest.cc
index e98fd09..7a47887 100644
--- a/cc/layers/tiled_layer_impl_unittest.cc
+++ b/cc/layers/tiled_layer_impl_unittest.cc
@@ -10,6 +10,7 @@
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/layer_test_common.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -19,7 +20,8 @@
class TiledLayerImplTest : public testing::Test {
public:
- TiledLayerImplTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ TiledLayerImplTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {}
scoped_ptr<TiledLayerImpl> CreateLayerNoTiles(
const gfx::Size& tile_size,
@@ -77,6 +79,7 @@
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
};
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 99cc0ca..511df0a 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -95,7 +95,7 @@
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
layer_tree_host_ = LayerTreeHost::CreateThreaded(
&synchonous_output_surface_client_, shared_bitmap_manager_.get(),
- nullptr, settings_, base::MessageLoopProxy::current(),
+ nullptr, nullptr, settings_, base::MessageLoopProxy::current(),
impl_thread_.message_loop_proxy(), nullptr);
synchonous_output_surface_client_.SetLayerTreeHost(layer_tree_host_.get());
proxy_ = layer_tree_host_->proxy();
@@ -116,8 +116,8 @@
0,
false,
1);
- host_impl_ = make_scoped_ptr(
- new FakeLayerTreeHostImpl(proxy_, shared_bitmap_manager_.get()));
+ host_impl_ = make_scoped_ptr(new FakeLayerTreeHostImpl(
+ proxy_, shared_bitmap_manager_.get(), nullptr));
}
~TiledLayerTest() override {
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 0ae4179..16034ea 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -278,27 +278,32 @@
return !frame->device_clip_rect.Contains(frame->device_viewport_rect);
}
-gfx::Rect DirectRenderer::DeviceClipRectInWindowSpace(const DrawingFrame* frame)
- const {
+gfx::Rect DirectRenderer::DeviceClipRectInDrawSpace(
+ const DrawingFrame* frame) const {
gfx::Rect device_clip_rect = frame->device_clip_rect;
- if (FlippedFramebuffer(frame))
- device_clip_rect.set_y(current_surface_size_.height() -
- device_clip_rect.bottom());
+ device_clip_rect -= current_viewport_rect_.OffsetFromOrigin();
+ device_clip_rect += current_draw_rect_.OffsetFromOrigin();
return device_clip_rect;
}
-void DirectRenderer::SetScissorStateForQuad(const DrawingFrame* frame,
- const DrawQuad& quad) {
- if (quad.isClipped()) {
- SetScissorTestRectInDrawSpace(frame, quad.clipRect());
- return;
- }
- if (NeedDeviceClip(frame)) {
- SetScissorTestRect(DeviceClipRectInWindowSpace(frame));
- return;
- }
+gfx::Rect DirectRenderer::DeviceViewportRectInDrawSpace(
+ const DrawingFrame* frame) const {
+ gfx::Rect device_viewport_rect = frame->device_viewport_rect;
+ device_viewport_rect -= current_viewport_rect_.OffsetFromOrigin();
+ device_viewport_rect += current_draw_rect_.OffsetFromOrigin();
+ return device_viewport_rect;
+}
- EnsureScissorTestDisabled();
+gfx::Rect DirectRenderer::OutputSurfaceRectInDrawSpace(
+ const DrawingFrame* frame) const {
+ if (frame->current_render_pass == frame->root_render_pass) {
+ gfx::Rect output_surface_rect(output_surface_->SurfaceSize());
+ output_surface_rect -= current_viewport_rect_.OffsetFromOrigin();
+ output_surface_rect += current_draw_rect_.OffsetFromOrigin();
+ return output_surface_rect;
+ } else {
+ return frame->current_render_pass->output_rect;
+ }
}
bool DirectRenderer::ShouldSkipQuad(const DrawQuad& quad,
@@ -315,14 +320,23 @@
return false;
}
-void DirectRenderer::SetScissorStateForQuadWithRenderPassScissor(
+void DirectRenderer::SetScissorStateForQuad(
const DrawingFrame* frame,
const DrawQuad& quad,
- const gfx::Rect& render_pass_scissor) {
- gfx::Rect quad_scissor_rect = render_pass_scissor;
- if (quad.isClipped())
- quad_scissor_rect.Intersect(quad.clipRect());
- SetScissorTestRectInDrawSpace(frame, quad_scissor_rect);
+ const gfx::Rect& render_pass_scissor,
+ bool use_render_pass_scissor) {
+ if (use_render_pass_scissor) {
+ gfx::Rect quad_scissor_rect = render_pass_scissor;
+ if (quad.isClipped())
+ quad_scissor_rect.Intersect(quad.clipRect());
+ SetScissorTestRectInDrawSpace(frame, quad_scissor_rect);
+ return;
+ } else if (quad.isClipped()) {
+ SetScissorTestRectInDrawSpace(frame, quad.clipRect());
+ return;
+ }
+
+ EnsureScissorTestDisabled();
}
void DirectRenderer::SetScissorTestRectInDrawSpace(
@@ -330,8 +344,6 @@
const gfx::Rect& draw_space_rect) {
gfx::Rect window_space_rect =
MoveFromDrawToWindowSpace(frame, draw_space_rect);
- if (NeedDeviceClip(frame))
- window_space_rect.Intersect(DeviceClipRectInWindowSpace(frame));
SetScissorTestRect(window_space_rect);
}
@@ -340,13 +352,9 @@
void DirectRenderer::DoDrawPolygon(const DrawPolygon& poly,
DrawingFrame* frame,
const gfx::Rect& render_pass_scissor,
- bool using_scissor_as_optimization) {
- if (using_scissor_as_optimization) {
- SetScissorStateForQuadWithRenderPassScissor(frame, *poly.original_ref(),
- render_pass_scissor);
- } else {
- SetScissorStateForQuad(frame, *poly.original_ref());
- }
+ bool use_render_pass_scissor) {
+ SetScissorStateForQuad(frame, *poly.original_ref(), render_pass_scissor,
+ use_render_pass_scissor);
// If the poly has not been split, then it is just a normal DrawQuad,
// and we should save any extra processing that would have to be done.
@@ -365,14 +373,14 @@
void DirectRenderer::FlushPolygons(ScopedPtrDeque<DrawPolygon>* poly_list,
DrawingFrame* frame,
const gfx::Rect& render_pass_scissor,
- bool using_scissor_as_optimization) {
+ bool use_render_pass_scissor) {
if (poly_list->empty()) {
return;
}
BspTree bsp_tree(poly_list);
BspWalkActionDrawPolygon action_handler(this, frame, render_pass_scissor,
- using_scissor_as_optimization);
+ use_render_pass_scissor);
bsp_tree.TraverseWithActionHandler(&action_handler);
DCHECK(poly_list->empty());
}
@@ -383,38 +391,53 @@
if (!UseRenderPass(frame, render_pass))
return;
- bool using_scissor_as_optimization = Capabilities().using_partial_swap;
- gfx::Rect render_pass_scissor;
- bool draw_rect_covers_full_surface = true;
- if (frame->current_render_pass == frame->root_render_pass &&
- !frame->device_viewport_rect.Contains(
- gfx::Rect(output_surface_->SurfaceSize())))
- draw_rect_covers_full_surface = false;
+ const gfx::Rect surface_rect_in_draw_space =
+ OutputSurfaceRectInDrawSpace(frame);
+ gfx::Rect render_pass_scissor_in_draw_space = surface_rect_in_draw_space;
- if (using_scissor_as_optimization) {
- render_pass_scissor = ComputeScissorRectForRenderPass(frame);
- SetScissorTestRectInDrawSpace(frame, render_pass_scissor);
- if (!render_pass_scissor.Contains(frame->current_render_pass->output_rect))
- draw_rect_covers_full_surface = false;
+ if (frame->current_render_pass == frame->root_render_pass) {
+ render_pass_scissor_in_draw_space.Intersect(
+ DeviceViewportRectInDrawSpace(frame));
}
- if (frame->current_render_pass != frame->root_render_pass ||
- settings_->should_clear_root_render_pass) {
- if (NeedDeviceClip(frame)) {
- SetScissorTestRect(DeviceClipRectInWindowSpace(frame));
- draw_rect_covers_full_surface = false;
- } else if (!using_scissor_as_optimization) {
- EnsureScissorTestDisabled();
- }
-
- bool has_external_stencil_test =
- output_surface_->HasExternalStencilTest() &&
- frame->current_render_pass == frame->root_render_pass;
-
- DiscardPixels(has_external_stencil_test, draw_rect_covers_full_surface);
- ClearFramebuffer(frame, has_external_stencil_test);
+ if (Capabilities().using_partial_swap) {
+ render_pass_scissor_in_draw_space.Intersect(
+ ComputeScissorRectForRenderPass(frame));
}
+ if (NeedDeviceClip(frame)) {
+ render_pass_scissor_in_draw_space.Intersect(
+ DeviceClipRectInDrawSpace(frame));
+ }
+
+ bool render_pass_is_clipped =
+ !render_pass_scissor_in_draw_space.Contains(surface_rect_in_draw_space);
+ bool is_root_render_pass =
+ frame->current_render_pass == frame->root_render_pass;
+ bool has_external_stencil_test =
+ is_root_render_pass && output_surface_->HasExternalStencilTest();
+ bool should_clear_surface =
+ !has_external_stencil_test &&
+ (!is_root_render_pass || settings_->should_clear_root_render_pass);
+
+ // If |has_external_stencil_test| we can't discard or clear. Make sure we
+ // don't need to.
+ DCHECK_IMPLIES(has_external_stencil_test,
+ !frame->current_render_pass->has_transparent_background);
+
+ SurfaceInitializationMode mode;
+ if (should_clear_surface && render_pass_is_clipped) {
+ mode = SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR;
+ } else if (should_clear_surface) {
+ mode = SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR;
+ } else {
+ mode = SURFACE_INITIALIZATION_MODE_PRESERVE;
+ }
+
+ PrepareSurfaceForPass(
+ frame, mode,
+ MoveFromDrawToWindowSpace(frame, render_pass_scissor_in_draw_space));
+
const QuadList& quad_list = render_pass->quad_list;
ScopedPtrDeque<DrawPolygon> poly_list;
@@ -425,15 +448,15 @@
const DrawQuad& quad = **it;
gfx::QuadF send_quad(quad.visible_rect);
- if (using_scissor_as_optimization &&
- ShouldSkipQuad(quad, render_pass_scissor)) {
+ if (render_pass_is_clipped &&
+ ShouldSkipQuad(quad, render_pass_scissor_in_draw_space)) {
continue;
}
if (last_sorting_context_id != quad.shared_quad_state->sorting_context_id) {
last_sorting_context_id = quad.shared_quad_state->sorting_context_id;
- FlushPolygons(&poly_list, frame, render_pass_scissor,
- using_scissor_as_optimization);
+ FlushPolygons(&poly_list, frame, render_pass_scissor_in_draw_space,
+ render_pass_is_clipped);
}
// This layer is in a 3D sorting context so we add it to the list of
@@ -448,17 +471,13 @@
}
// We are not in a 3d sorting context, so we should draw the quad normally.
- if (using_scissor_as_optimization) {
- SetScissorStateForQuadWithRenderPassScissor(frame, quad,
- render_pass_scissor);
- } else {
- SetScissorStateForQuad(frame, quad);
- }
+ SetScissorStateForQuad(frame, quad, render_pass_scissor_in_draw_space,
+ render_pass_is_clipped);
DoDrawQuad(frame, &quad, nullptr);
}
- FlushPolygons(&poly_list, frame, render_pass_scissor,
- using_scissor_as_optimization);
+ FlushPolygons(&poly_list, frame, render_pass_scissor_in_draw_space,
+ render_pass_is_clipped);
FinishDrawingQuadList();
}
@@ -487,7 +506,14 @@
size, ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER, RGBA_8888);
DCHECK(texture->id());
- return BindFramebufferToTexture(frame, texture, render_pass->output_rect);
+ if (BindFramebufferToTexture(frame, texture, render_pass->output_rect)) {
+ InitializeViewport(frame, render_pass->output_rect,
+ gfx::Rect(render_pass->output_rect.size()),
+ render_pass->output_rect.size());
+ return true;
+ }
+
+ return false;
}
bool DirectRenderer::HasAllocatedResourcesForTesting(RenderPassId id) const {
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index 3399491..dd3d13b 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -63,9 +63,15 @@
void DoDrawPolygon(const DrawPolygon& poly,
DrawingFrame* frame,
const gfx::Rect& render_pass_scissor,
- bool using_scissor_as_optimization);
+ bool use_render_pass_scissor);
protected:
+ enum SurfaceInitializationMode {
+ SURFACE_INITIALIZATION_MODE_PRESERVE,
+ SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR,
+ SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR,
+ };
+
DirectRenderer(RendererClient* client,
const RendererSettings* settings,
OutputSurface* output_surface,
@@ -83,15 +89,16 @@
const gfx::Rect& draw_rect) const;
bool NeedDeviceClip(const DrawingFrame* frame) const;
- gfx::Rect DeviceClipRectInWindowSpace(const DrawingFrame* frame) const;
+ gfx::Rect DeviceClipRectInDrawSpace(const DrawingFrame* frame) const;
+ gfx::Rect DeviceViewportRectInDrawSpace(const DrawingFrame* frame) const;
+ gfx::Rect OutputSurfaceRectInDrawSpace(const DrawingFrame* frame) const;
static gfx::Rect ComputeScissorRectForRenderPass(const DrawingFrame* frame);
- void SetScissorStateForQuad(const DrawingFrame* frame, const DrawQuad& quad);
+ void SetScissorStateForQuad(const DrawingFrame* frame,
+ const DrawQuad& quad,
+ const gfx::Rect& render_pass_scissor,
+ bool use_render_pass_scissor);
bool ShouldSkipQuad(const DrawQuad& quad,
const gfx::Rect& render_pass_scissor);
- void SetScissorStateForQuadWithRenderPassScissor(
- const DrawingFrame* frame,
- const DrawQuad& quad,
- const gfx::Rect& render_pass_scissor);
void SetScissorTestRectInDrawSpace(const DrawingFrame* frame,
const gfx::Rect& draw_space_rect);
@@ -100,7 +107,7 @@
void FlushPolygons(ScopedPtrDeque<DrawPolygon>* poly_list,
DrawingFrame* frame,
const gfx::Rect& render_pass_scissor,
- bool using_scissor_as_optimization);
+ bool use_render_pass_scissor);
void DrawRenderPass(DrawingFrame* frame, const RenderPass* render_pass);
bool UseRenderPass(DrawingFrame* frame, const RenderPass* render_pass);
@@ -110,10 +117,10 @@
const gfx::Rect& target_rect) = 0;
virtual void SetDrawViewport(const gfx::Rect& window_space_viewport) = 0;
virtual void SetScissorTestRect(const gfx::Rect& scissor_rect) = 0;
- virtual void DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) = 0;
- virtual void ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) = 0;
+ virtual void PrepareSurfaceForPass(
+ DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) = 0;
// clip_region is a (possibly null) pointer to a quad in the same
// space as the quad. When non-null only the area of the quad that overlaps
// with clip_region will be drawn.
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index b49ac8e..e614d8b 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -401,10 +401,8 @@
void GLRenderer::ReleaseRenderPassTextures() { render_pass_textures_.clear(); }
-void GLRenderer::DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) {
- if (has_external_stencil_test || !draw_rect_covers_full_surface ||
- !capabilities_.using_discard_framebuffer)
+void GLRenderer::DiscardPixels() {
+ if (!capabilities_.using_discard_framebuffer)
return;
bool using_default_framebuffer =
!current_framebuffer_lock_ &&
@@ -415,15 +413,27 @@
GL_FRAMEBUFFER, arraysize(attachments), attachments);
}
-void GLRenderer::ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) {
- // It's unsafe to clear when we have a stencil test because glClear ignores
- // stencil.
- if (has_external_stencil_test) {
- DCHECK(!frame->current_render_pass->has_transparent_background);
- return;
+void GLRenderer::PrepareSurfaceForPass(
+ DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) {
+ switch (initialization_mode) {
+ case SURFACE_INITIALIZATION_MODE_PRESERVE:
+ EnsureScissorTestDisabled();
+ return;
+ case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR:
+ EnsureScissorTestDisabled();
+ DiscardPixels();
+ ClearFramebuffer(frame);
+ break;
+ case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR:
+ SetScissorTestRect(render_pass_scissor);
+ ClearFramebuffer(frame);
+ break;
}
+}
+void GLRenderer::ClearFramebuffer(DrawingFrame* frame) {
// On DEBUG builds, opaque render passes are cleared to blue to easily see
// regions that were not drawn on the screen.
if (frame->current_render_pass->has_transparent_background)
@@ -2920,9 +2930,6 @@
DCHECK(gl_->CheckFramebufferStatus(GL_FRAMEBUFFER) ==
GL_FRAMEBUFFER_COMPLETE ||
IsContextLost());
-
- InitializeViewport(
- frame, target_rect, gfx::Rect(target_rect.size()), target_rect.size());
return true;
}
diff --git a/cc/output/gl_renderer.cc.rej b/cc/output/gl_renderer.cc.rej
deleted file mode 100644
index 3cf4e17..0000000
--- a/cc/output/gl_renderer.cc.rej
+++ /dev/null
@@ -1,9 +0,0 @@
-diff a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc (rejected hunks)
-@@ -18,7 +18,6 @@
- #include "build/build_config.h"
- #include "base/trace_event/trace_event.h"
- #include "cc/base/math_util.h"
--#include "cc/layers/video_layer_impl.h"
- #include "cc/output/compositor_frame.h"
- #include "cc/output/compositor_frame_metadata.h"
- #include "cc/output/context_provider.h"
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 27f2c42..ddc8791 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -110,10 +110,9 @@
const gfx::Rect& target_rect) override;
void SetDrawViewport(const gfx::Rect& window_space_viewport) override;
void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
- void DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) override;
- void ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) override;
+ void PrepareSurfaceForPass(DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) override;
void DoDrawQuad(DrawingFrame* frame,
const class DrawQuad*,
const gfx::QuadF* draw_region) override;
@@ -150,6 +149,9 @@
static void ToGLMatrix(float* gl_matrix, const gfx::Transform& transform);
+ void DiscardPixels();
+ void ClearFramebuffer(DrawingFrame* frame);
+
void DrawCheckerboardQuad(const DrawingFrame* frame,
const CheckerboardDrawQuad* quad,
const gfx::QuadF* clip_region);
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 62bff6f..7e0f8e0 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -97,25 +97,24 @@
// Explicitly named to be a friend in GLRenderer for shader access.
class GLRendererShaderPixelTest : public GLRendererPixelTest {
public:
- void TestShaders() {
+ void SetUp() override {
+ GLRendererPixelTest::SetUp();
ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TearDown() override {
+ GLRendererPixelTest::TearDown();
+ ASSERT_FALSE(renderer()->IsContextLost());
+ }
+
+ void TestBasicShaders() {
EXPECT_PROGRAM_VALID(renderer()->GetTileCheckerboardProgram());
EXPECT_PROGRAM_VALID(renderer()->GetDebugBorderProgram());
EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgram());
EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgramAA());
- TestShadersWithTexCoordPrecision(TEX_COORD_PRECISION_MEDIUM);
- TestShadersWithTexCoordPrecision(TEX_COORD_PRECISION_HIGH);
- ASSERT_FALSE(renderer()->IsContextLost());
}
- void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) {
- for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
- BlendMode blend_mode = static_cast<BlendMode>(i);
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassProgram(precision, blend_mode));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassProgramAA(precision, blend_mode));
- }
+ void TestShadersWithPrecision(TexCoordPrecision precision) {
EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision));
EXPECT_PROGRAM_VALID(
renderer()->GetNonPremultipliedTextureProgram(precision));
@@ -125,20 +124,28 @@
EXPECT_PROGRAM_VALID(renderer()->GetTextureIOSurfaceProgram(precision));
EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVProgram(precision));
EXPECT_PROGRAM_VALID(renderer()->GetVideoYUVAProgram(precision));
- // This is unlikely to be ever true in tests due to usage of osmesa.
if (renderer()->Capabilities().using_egl_image)
EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision));
else
EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision));
- TestShadersWithSamplerType(precision, SAMPLER_TYPE_2D);
- TestShadersWithSamplerType(precision, SAMPLER_TYPE_2D_RECT);
- // This is unlikely to be ever true in tests due to usage of osmesa.
- if (renderer()->Capabilities().using_egl_image)
- TestShadersWithSamplerType(precision, SAMPLER_TYPE_EXTERNAL_OES);
}
- void TestShadersWithSamplerType(TexCoordPrecision precision,
- SamplerType sampler) {
+ void TestShadersWithPrecisionAndBlend(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgramAA(precision, blend_mode));
+ }
+
+ void TestShadersWithPrecisionAndSampler(TexCoordPrecision precision,
+ SamplerType sampler) {
+ if (!renderer()->Capabilities().using_egl_image &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
+ }
+
EXPECT_PROGRAM_VALID(renderer()->GetTileProgram(precision, sampler));
EXPECT_PROGRAM_VALID(renderer()->GetTileProgramOpaque(precision, sampler));
EXPECT_PROGRAM_VALID(renderer()->GetTileProgramAA(precision, sampler));
@@ -147,30 +154,126 @@
renderer()->GetTileProgramSwizzleOpaque(precision, sampler));
EXPECT_PROGRAM_VALID(
renderer()->GetTileProgramSwizzleAA(precision, sampler));
- for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
- BlendMode blend_mode = static_cast<BlendMode>(i);
- for (int l = 0; l <= 1; ++l) {
- bool mask_for_background = (l == 1);
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassMaskProgram(precision,
- sampler,
- blend_mode,
- mask_for_background));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(
- precision, sampler, blend_mode, mask_for_background));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgramAA(
- precision, sampler, blend_mode, mask_for_background));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgram(
- precision, sampler, blend_mode, mask_for_background));
- }
+ }
+
+ void TestShadersWithMasks(TexCoordPrecision precision,
+ SamplerType sampler,
+ BlendMode blend_mode,
+ bool mask_for_background) {
+ if (!renderer()->Capabilities().using_egl_image &&
+ sampler == SAMPLER_TYPE_EXTERNAL_OES) {
+ // This will likely be hit in tests due to usage of osmesa.
+ return;
}
+
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgramAA(
+ precision, sampler, blend_mode, mask_for_background));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgram(
+ precision, sampler, blend_mode, mask_for_background));
}
};
namespace {
#if !defined(OS_ANDROID) && !defined(OS_WIN)
-TEST_F(GLRendererShaderPixelTest, AllShadersCompile) { TestShaders(); }
+static const TexCoordPrecision kPrecisionList[] = {TEX_COORD_PRECISION_MEDIUM,
+ TEX_COORD_PRECISION_HIGH};
+
+static const BlendMode kBlendModeList[LAST_BLEND_MODE + 1] = {
+ BLEND_MODE_NONE,
+ BLEND_MODE_NORMAL,
+ BLEND_MODE_SCREEN,
+ BLEND_MODE_OVERLAY,
+ BLEND_MODE_DARKEN,
+ BLEND_MODE_LIGHTEN,
+ BLEND_MODE_COLOR_DODGE,
+ BLEND_MODE_COLOR_BURN,
+ BLEND_MODE_HARD_LIGHT,
+ BLEND_MODE_SOFT_LIGHT,
+ BLEND_MODE_DIFFERENCE,
+ BLEND_MODE_EXCLUSION,
+ BLEND_MODE_MULTIPLY,
+ BLEND_MODE_HUE,
+ BLEND_MODE_SATURATION,
+ BLEND_MODE_COLOR,
+ BLEND_MODE_LUMINOSITY,
+};
+
+static const SamplerType kSamplerList[] = {
+ SAMPLER_TYPE_2D,
+ SAMPLER_TYPE_2D_RECT,
+ SAMPLER_TYPE_EXTERNAL_OES,
+};
+
+TEST_F(GLRendererShaderPixelTest, BasicShadersCompile) {
+ TestBasicShaders();
+}
+
+class PrecisionShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<TexCoordPrecision> {};
+
+TEST_P(PrecisionShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecision(GetParam());
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionShadersCompile,
+ PrecisionShaderPixelTest,
+ ::testing::ValuesIn(kPrecisionList));
+
+class PrecisionBlendShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, BlendMode>> {};
+
+TEST_P(PrecisionBlendShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndBlend(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(
+ PrecisionBlendShadersCompile,
+ PrecisionBlendShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kBlendModeList)));
+
+class PrecisionSamplerShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType>> {};
+
+TEST_P(PrecisionSamplerShaderPixelTest, ShadersCompile) {
+ TestShadersWithPrecisionAndSampler(std::tr1::get<0>(GetParam()),
+ std::tr1::get<1>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(PrecisionSamplerShadersCompile,
+ PrecisionSamplerShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList)));
+
+class MaskShaderPixelTest
+ : public GLRendererShaderPixelTest,
+ public ::testing::WithParamInterface<
+ std::tr1::tuple<TexCoordPrecision, SamplerType, BlendMode, bool>> {};
+
+TEST_P(MaskShaderPixelTest, ShadersCompile) {
+ TestShadersWithMasks(
+ std::tr1::get<0>(GetParam()), std::tr1::get<1>(GetParam()),
+ std::tr1::get<2>(GetParam()), std::tr1::get<3>(GetParam()));
+}
+
+INSTANTIATE_TEST_CASE_P(MaskShadersCompile,
+ MaskShaderPixelTest,
+ ::testing::Combine(::testing::ValuesIn(kPrecisionList),
+ ::testing::ValuesIn(kSamplerList),
+ ::testing::ValuesIn(kBlendModeList),
+ ::testing::Bool()));
+
#endif
class FakeRendererGL : public GLRenderer {
@@ -1309,32 +1412,8 @@
class FlippedScissorAndViewportContext : public TestWebGraphicsContext3D {
public:
- FlippedScissorAndViewportContext()
- : did_call_viewport_(false), did_call_scissor_(false) {}
- ~FlippedScissorAndViewportContext() override {
- EXPECT_TRUE(did_call_viewport_);
- EXPECT_TRUE(did_call_scissor_);
- }
-
- void viewport(GLint x, GLint y, GLsizei width, GLsizei height) override {
- EXPECT_EQ(10, x);
- EXPECT_EQ(390, y);
- EXPECT_EQ(100, width);
- EXPECT_EQ(100, height);
- did_call_viewport_ = true;
- }
-
- void scissor(GLint x, GLint y, GLsizei width, GLsizei height) override {
- EXPECT_EQ(30, x);
- EXPECT_EQ(450, y);
- EXPECT_EQ(20, width);
- EXPECT_EQ(20, height);
- did_call_scissor_ = true;
- }
-
- private:
- bool did_call_viewport_;
- bool did_call_scissor_;
+ MOCK_METHOD4(viewport, void(GLint x, GLint y, GLsizei width, GLsizei height));
+ MOCK_METHOD4(scissor, void(GLint x, GLint y, GLsizei width, GLsizei height));
};
TEST_F(GLRendererTest, ScissorAndViewportWithinNonreshapableSurface) {
@@ -1345,6 +1424,12 @@
scoped_ptr<FlippedScissorAndViewportContext> context_owned(
new FlippedScissorAndViewportContext);
+ // We expect exactly one call to viewport on this context and exactly two
+ // to scissor (one to scissor the clear, one to scissor the quad draw).
+ EXPECT_CALL(*context_owned, viewport(10, 390, 100, 100));
+ EXPECT_CALL(*context_owned, scissor(10, 390, 100, 100));
+ EXPECT_CALL(*context_owned, scissor(30, 450, 20, 20));
+
FakeOutputSurfaceClient output_surface_client;
scoped_ptr<OutputSurface> output_surface(
new NonReshapableOutputSurface(context_owned.Pass()));
diff --git a/cc/output/render_surface_filters.cc b/cc/output/render_surface_filters.cc
index fc2e88a..7cccb24 100644
--- a/cc/output/render_surface_filters.cc
+++ b/cc/output/render_surface_filters.cc
@@ -206,6 +206,7 @@
SkIntToScalar(op.amount()),
SkIntToScalar(op.amount()),
op.drop_shadow_color(),
+ SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode,
image_filter.get()));
break;
case FilterOperation::COLOR_MATRIX:
diff --git a/cc/output/renderer_pixeltest.cc.rej b/cc/output/renderer_pixeltest.cc.rej
deleted file mode 100644
index 13d6779..0000000
--- a/cc/output/renderer_pixeltest.cc.rej
+++ /dev/null
@@ -1,245 +0,0 @@
-diff a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc (rejected hunks)
-@@ -902,243 +901,6 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
- FuzzyPixelOffByOneComparator(true)));
- }
-
--class VideoGLRendererPixelTest : public GLRendererPixelTest {
-- protected:
-- void CreateEdgeBleedPass(media::VideoFrame::Format format,
-- RenderPassList* pass_list) {
-- gfx::Rect rect(200, 200);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- // Scale the video up so that bilinear filtering kicks in to sample more
-- // than just nearest neighbor would.
-- gfx::Transform scale_by_2;
-- scale_by_2.Scale(2.f, 2.f);
-- gfx::Rect half_rect(100, 100);
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(scale_by_2, half_rect, pass.get());
--
-- gfx::Size background_size(200, 200);
-- gfx::Rect green_rect(16, 20, 100, 100);
-- gfx::RectF tex_coord_rect(
-- static_cast<float>(green_rect.x()) / background_size.width(),
-- static_cast<float>(green_rect.y()) / background_size.height(),
-- static_cast<float>(green_rect.width()) / background_size.width(),
-- static_cast<float>(green_rect.height()) / background_size.height());
--
-- // YUV of (149,43,21) should be green (0,255,0) in RGB.
-- // Create a video frame that has a non-green background rect, with a
-- // green sub-rectangle that should be the only thing displayed in
-- // the final image. Bleeding will appear on all four sides of the video
-- // if the tex coords are not clamped.
-- CreateTestYUVVideoDrawQuad_TwoColor(
-- shared_state, format, false, tex_coord_rect, background_size, 0, 0, 0,
-- green_rect, 149, 43, 21, pass.get(), video_resource_updater_.get(),
-- resource_provider_.get());
-- pass_list->push_back(pass.Pass());
-- }
--
-- void SetUp() override {
-- GLRendererPixelTest::SetUp();
-- video_resource_updater_.reset(new VideoResourceUpdater(
-- output_surface_->context_provider(), resource_provider_.get()));
-- }
--
-- scoped_ptr<VideoResourceUpdater> video_resource_updater_;
--};
--
--TEST_F(VideoGLRendererPixelTest, SimpleYUVRect) {
-- gfx::Rect rect(this->device_viewport_size_);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
--
-- CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12,
-- false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
-- pass.get(), video_resource_updater_.get(),
-- rect, resource_provider_.get());
--
-- RenderPassList pass_list;
-- pass_list.push_back(pass.Pass());
--
-- EXPECT_TRUE(
-- this->RunPixelTest(&pass_list,
-- base::FilePath(FILE_PATH_LITERAL("yuv_stripes.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--TEST_F(VideoGLRendererPixelTest, OffsetYUVRect) {
-- gfx::Rect rect(this->device_viewport_size_);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
--
-- // Intentionally sets frame format to I420 for testing coverage.
-- CreateTestYUVVideoDrawQuad_Striped(
-- shared_state, media::VideoFrame::I420, false,
-- gfx::RectF(0.125f, 0.25f, 0.75f, 0.5f), pass.get(),
-- video_resource_updater_.get(), rect, resource_provider_.get());
--
-- RenderPassList pass_list;
-- pass_list.push_back(pass.Pass());
--
-- EXPECT_TRUE(this->RunPixelTest(
-- &pass_list,
-- base::FilePath(FILE_PATH_LITERAL("yuv_stripes_offset.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--TEST_F(VideoGLRendererPixelTest, SimpleYUVRectBlack) {
-- gfx::Rect rect(this->device_viewport_size_);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
--
-- // In MPEG color range YUV values of (15,128,128) should produce black.
-- CreateTestYUVVideoDrawQuad_Solid(
-- shared_state, media::VideoFrame::YV12, false,
-- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
-- video_resource_updater_.get(), rect, resource_provider_.get());
--
-- RenderPassList pass_list;
-- pass_list.push_back(pass.Pass());
--
-- // If we didn't get black out of the YUV values above, then we probably have a
-- // color range issue.
-- EXPECT_TRUE(this->RunPixelTest(&pass_list,
-- base::FilePath(FILE_PATH_LITERAL("black.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--TEST_F(VideoGLRendererPixelTest, SimpleYUVJRect) {
-- gfx::Rect rect(this->device_viewport_size_);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
--
-- // YUV of (149,43,21) should be green (0,255,0) in RGB.
-- CreateTestYUVVideoDrawQuad_Solid(
-- shared_state, media::VideoFrame::YV12J, false,
-- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 149, 43, 21, pass.get(),
-- video_resource_updater_.get(), rect, resource_provider_.get());
--
-- RenderPassList pass_list;
-- pass_list.push_back(pass.Pass());
--
-- EXPECT_TRUE(this->RunPixelTest(&pass_list,
-- base::FilePath(FILE_PATH_LITERAL("green.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--// Test that a YUV video doesn't bleed outside of its tex coords when the
--// tex coord rect is only a partial subrectangle of the coded contents.
--TEST_F(VideoGLRendererPixelTest, YUVEdgeBleed) {
-- RenderPassList pass_list;
-- CreateEdgeBleedPass(media::VideoFrame::YV12J, &pass_list);
-- EXPECT_TRUE(this->RunPixelTest(&pass_list,
-- base::FilePath(FILE_PATH_LITERAL("green.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--TEST_F(VideoGLRendererPixelTest, YUVAEdgeBleed) {
-- RenderPassList pass_list;
-- CreateEdgeBleedPass(media::VideoFrame::YV12A, &pass_list);
-- EXPECT_TRUE(this->RunPixelTest(&pass_list,
-- base::FilePath(FILE_PATH_LITERAL("green.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--TEST_F(VideoGLRendererPixelTest, SimpleYUVJRectGrey) {
-- gfx::Rect rect(this->device_viewport_size_);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
--
-- // Dark grey in JPEG color range (in MPEG, this is black).
-- CreateTestYUVVideoDrawQuad_Solid(
-- shared_state, media::VideoFrame::YV12J, false,
-- gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f), 15, 128, 128, pass.get(),
-- video_resource_updater_.get(), rect, resource_provider_.get());
--
-- RenderPassList pass_list;
-- pass_list.push_back(pass.Pass());
--
-- EXPECT_TRUE(
-- this->RunPixelTest(&pass_list,
-- base::FilePath(FILE_PATH_LITERAL("dark_grey.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--TEST_F(VideoGLRendererPixelTest, SimpleYUVARect) {
-- gfx::Rect rect(this->device_viewport_size_);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
--
-- CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A,
-- false, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
-- pass.get(), video_resource_updater_.get(),
-- rect, resource_provider_.get());
--
-- SolidColorDrawQuad* color_quad =
-- pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-- color_quad->SetNew(shared_state, rect, rect, SK_ColorWHITE, false);
--
-- RenderPassList pass_list;
-- pass_list.push_back(pass.Pass());
--
-- EXPECT_TRUE(this->RunPixelTest(
-- &pass_list,
-- base::FilePath(FILE_PATH_LITERAL("yuv_stripes_alpha.png")),
-- FuzzyPixelOffByOneComparator(true)));
--}
--
--TEST_F(VideoGLRendererPixelTest, FullyTransparentYUVARect) {
-- gfx::Rect rect(this->device_viewport_size_);
--
-- RenderPassId id(1, 1);
-- scoped_ptr<RenderPass> pass = CreateTestRootRenderPass(id, rect);
--
-- SharedQuadState* shared_state =
-- CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
--
-- CreateTestYUVVideoDrawQuad_Striped(shared_state, media::VideoFrame::YV12A,
-- true, gfx::RectF(0.0f, 0.0f, 1.0f, 1.0f),
-- pass.get(), video_resource_updater_.get(),
-- rect, resource_provider_.get());
--
-- SolidColorDrawQuad* color_quad =
-- pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-- color_quad->SetNew(shared_state, rect, rect, SK_ColorBLACK, false);
--
-- RenderPassList pass_list;
-- pass_list.push_back(pass.Pass());
--
-- EXPECT_TRUE(this->RunPixelTest(
-- &pass_list,
-- base::FilePath(FILE_PATH_LITERAL("black.png")),
-- ExactPixelComparator(true)));
--}
--
- TYPED_TEST(RendererPixelTest, FastPassColorFilterAlpha) {
- gfx::Rect viewport_rect(this->device_viewport_size_);
-
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index cecd633..bd99d0b 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -172,10 +172,6 @@
current_framebuffer_canvas_ =
skia::AdoptRef(new SkCanvas(current_framebuffer_lock_->sk_bitmap()));
current_canvas_ = current_framebuffer_canvas_.get();
- InitializeViewport(frame,
- target_rect,
- gfx::Rect(target_rect.size()),
- target_rect.size());
return true;
}
@@ -202,11 +198,7 @@
current_canvas_->clear(color);
}
-void SoftwareRenderer::DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) {}
-
-void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) {
+void SoftwareRenderer::ClearFramebuffer(DrawingFrame* frame) {
if (frame->current_render_pass->has_transparent_background) {
ClearCanvas(SkColorSetARGB(0, 0, 0, 0));
} else {
@@ -218,6 +210,25 @@
}
}
+void SoftwareRenderer::PrepareSurfaceForPass(
+ DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) {
+ switch (initialization_mode) {
+ case SURFACE_INITIALIZATION_MODE_PRESERVE:
+ EnsureScissorTestDisabled();
+ return;
+ case SURFACE_INITIALIZATION_MODE_FULL_SURFACE_CLEAR:
+ EnsureScissorTestDisabled();
+ ClearFramebuffer(frame);
+ break;
+ case SURFACE_INITIALIZATION_MODE_SCISSORED_CLEAR:
+ SetScissorTestRect(render_pass_scissor);
+ ClearFramebuffer(frame);
+ break;
+ }
+}
+
void SoftwareRenderer::SetDrawViewport(
const gfx::Rect& window_space_viewport) {}
diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h
index dc8e2fb..ae8beb4 100644
--- a/cc/output/software_renderer.h
+++ b/cc/output/software_renderer.h
@@ -48,10 +48,9 @@
const gfx::Rect& target_rect) override;
void SetDrawViewport(const gfx::Rect& window_space_viewport) override;
void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
- void DiscardPixels(bool has_external_stencil_test,
- bool draw_rect_covers_full_surface) override;
- void ClearFramebuffer(DrawingFrame* frame,
- bool has_external_stencil_test) override;
+ void PrepareSurfaceForPass(DrawingFrame* frame,
+ SurfaceInitializationMode initialization_mode,
+ const gfx::Rect& render_pass_scissor) override;
void DoDrawQuad(DrawingFrame* frame,
const DrawQuad* quad,
@@ -74,6 +73,7 @@
private:
void ClearCanvas(SkColor color);
+ void ClearFramebuffer(DrawingFrame* frame);
void SetClipRect(const gfx::Rect& rect);
bool IsSoftwareResource(ResourceProvider::ResourceId resource_id) const;
diff --git a/cc/quads/yuv_video_draw_quad.h.rej b/cc/quads/yuv_video_draw_quad.h.rej
deleted file mode 100644
index a838a4d..0000000
--- a/cc/quads/yuv_video_draw_quad.h.rej
+++ /dev/null
@@ -1,9 +0,0 @@
-diff a/cc/quads/yuv_video_draw_quad.h b/cc/quads/yuv_video_draw_quad.h (rejected hunks)
-@@ -8,7 +8,6 @@
- #include "base/basictypes.h"
- #include "base/memory/scoped_ptr.h"
- #include "cc/base/cc_export.h"
--#include "cc/layers/video_layer_impl.h"
- #include "cc/quads/draw_quad.h"
-
- namespace cc {
diff --git a/cc/resources/display_list_raster_source.cc b/cc/resources/display_list_raster_source.cc
index ab0292e..e35900a 100644
--- a/cc/resources/display_list_raster_source.cc
+++ b/cc/resources/display_list_raster_source.cc
@@ -87,13 +87,13 @@
SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const {
- RasterCommon(canvas, NULL, canvas_rect, contents_scale, false);
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
}
void DisplayListRasterSource::RasterForAnalysis(skia::AnalysisCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const {
- RasterCommon(canvas, canvas, canvas_rect, contents_scale, true);
+ RasterCommon(canvas, canvas, canvas_rect, contents_scale);
}
void DisplayListRasterSource::PlaybackToCanvas(SkCanvas* canvas,
@@ -103,14 +103,13 @@
canvas, canvas_rect, gfx::Rect(size_), contents_scale, background_color_,
clear_canvas_with_debug_color_, requires_clear_);
- RasterCommon(canvas, NULL, canvas_rect, contents_scale, false);
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
}
void DisplayListRasterSource::RasterCommon(SkCanvas* canvas,
SkDrawPictureCallback* callback,
const gfx::Rect& canvas_rect,
- float contents_scale,
- bool is_analysis) const {
+ float contents_scale) const {
canvas->translate(-canvas_rect.x(), -canvas_rect.y());
gfx::Rect content_rect =
gfx::ToEnclosingRect(gfx::ScaleRect(gfx::Rect(size_), contents_scale));
diff --git a/cc/resources/display_list_raster_source.h b/cc/resources/display_list_raster_source.h
index 44177fb..8c2ab91 100644
--- a/cc/resources/display_list_raster_source.h
+++ b/cc/resources/display_list_raster_source.h
@@ -88,8 +88,7 @@
void RasterCommon(SkCanvas* canvas,
SkDrawPictureCallback* callback,
const gfx::Rect& canvas_rect,
- float contents_scale,
- bool is_analysis) const;
+ float contents_scale) const;
DISALLOW_COPY_AND_ASSIGN(DisplayListRasterSource);
};
diff --git a/cc/resources/display_list_recording_source.cc b/cc/resources/display_list_recording_source.cc
index 367b23d..296036d 100644
--- a/cc/resources/display_list_recording_source.cc
+++ b/cc/resources/display_list_recording_source.cc
@@ -28,6 +28,7 @@
DisplayListRecordingSource::DisplayListRecordingSource()
: slow_down_raster_scale_factor_for_debug_(0),
+ gather_pixel_refs_(false),
requires_clear_(false),
is_solid_color_(false),
solid_color_(SK_ColorTRANSPARENT),
@@ -135,6 +136,10 @@
slow_down_raster_scale_factor_for_debug_ = factor;
}
+void DisplayListRecordingSource::SetGatherPixelRefs(bool gather_pixel_refs) {
+ gather_pixel_refs_ = gather_pixel_refs;
+}
+
void DisplayListRecordingSource::SetBackgroundColor(SkColor background_color) {
background_color_ = background_color;
}
diff --git a/cc/resources/display_list_recording_source.h b/cc/resources/display_list_recording_source.h
index e827d29..53d7fa5 100644
--- a/cc/resources/display_list_recording_source.h
+++ b/cc/resources/display_list_recording_source.h
@@ -30,6 +30,7 @@
gfx::Size GetSize() const final;
void SetEmptyBounds() override;
void SetSlowdownRasterScaleFactor(int factor) override;
+ void SetGatherPixelRefs(bool gather_pixel_refs) override;
void SetBackgroundColor(SkColor background_color) override;
void SetRequiresClear(bool requires_clear) override;
bool IsSuitableForGpuRasterization() const override;
@@ -42,6 +43,7 @@
gfx::Rect recorded_viewport_;
gfx::Size size_;
int slow_down_raster_scale_factor_for_debug_;
+ bool gather_pixel_refs_;
bool requires_clear_;
bool is_solid_color_;
SkColor solid_color_;
diff --git a/cc/resources/layer_quad.cc b/cc/resources/layer_quad.cc
index ba92314..ff336ba 100644
--- a/cc/resources/layer_quad.cc
+++ b/cc/resources/layer_quad.cc
@@ -22,6 +22,14 @@
scale(1.0f / tangent.Length());
}
+gfx::PointF LayerQuad::Edge::Intersect(const LayerQuad::Edge& e) const {
+ DCHECK(!degenerate());
+ DCHECK(!e.degenerate());
+
+ return gfx::PointF((y() * e.z() - e.y() * z()) / (x() * e.y() - e.x() * y()),
+ (x() * e.z() - e.x() * z()) / (e.x() * y() - x() * e.y()));
+}
+
LayerQuad::LayerQuad(const gfx::QuadF& quad) {
// Create edges.
left_ = Edge(quad.p4(), quad.p1());
@@ -46,6 +54,12 @@
bottom_(bottom) {}
gfx::QuadF LayerQuad::ToQuadF() const {
+ size_t num_degenerate_edges = left_.degenerate() + right_.degenerate() +
+ top_.degenerate() + bottom_.degenerate();
+ if (num_degenerate_edges > 1) {
+ return gfx::QuadF();
+ }
+
if (left_.degenerate()) {
return gfx::QuadF(top_.Intersect(bottom_), top_.Intersect(right_),
right_.Intersect(bottom_), bottom_.Intersect(top_));
diff --git a/cc/resources/layer_quad.h b/cc/resources/layer_quad.h
index 7433645..328f666 100644
--- a/cc/resources/layer_quad.h
+++ b/cc/resources/layer_quad.h
@@ -20,7 +20,7 @@
class CC_EXPORT LayerQuad {
public:
- class Edge {
+ class CC_EXPORT Edge {
public:
Edge() : x_(0), y_(0), z_(0), degenerate_(false) {}
Edge(const gfx::PointF& p, const gfx::PointF& q);
@@ -59,11 +59,7 @@
bool degenerate() const { return degenerate_; }
- gfx::PointF Intersect(const Edge& e) const {
- return gfx::PointF(
- (y() * e.z() - e.y() * z()) / (x() * e.y() - e.x() * y()),
- (x() * e.z() - e.x() * z()) / (e.x() * y() - x() * e.y()));
- }
+ gfx::PointF Intersect(const Edge& e) const;
private:
float x_;
diff --git a/cc/resources/layer_quad_unittest.cc b/cc/resources/layer_quad_unittest.cc
index 3560b8d..90f61be 100644
--- a/cc/resources/layer_quad_unittest.cc
+++ b/cc/resources/layer_quad_unittest.cc
@@ -38,5 +38,32 @@
EXPECT_EQ(layer_quad.ToQuadF(), quad);
}
+TEST(LayerQuadTest, Degenerate) {
+ gfx::QuadF quad;
+ gfx::PointF p1(1.0f, 1.0f);
+ gfx::PointF p2(0.0f, 1.0f);
+ gfx::PointF p3(1.0f, 0.0f);
+ gfx::QuadF triangle(p1, p2, p3, p1);
+
+ LayerQuad::Edge e1d(p1, p1);
+ LayerQuad::Edge e2d(p2, p2);
+ LayerQuad::Edge e2(p1, p2);
+ LayerQuad::Edge e3(p2, p3);
+ LayerQuad::Edge e4(p3, p1);
+ EXPECT_TRUE(e1d.degenerate());
+ EXPECT_TRUE(e2d.degenerate());
+ EXPECT_FALSE(e2.degenerate());
+ EXPECT_FALSE(e3.degenerate());
+ EXPECT_FALSE(e4.degenerate());
+
+ LayerQuad degenerate_quad(e1d, e2d, e2, e3);
+ // With more than one degenerate edge, we expect the quad to be zero.
+ EXPECT_EQ(quad, degenerate_quad.ToQuadF());
+
+ LayerQuad triangle_quad(e1d, e2, e3, e4);
+ // With only one degenerate edge, we expect the quad to be a triangle.
+ EXPECT_EQ(triangle, triangle_quad.ToQuadF());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc
index 867a86a..e88ff21 100644
--- a/cc/resources/picture.cc
+++ b/cc/resources/picture.cc
@@ -213,11 +213,7 @@
canvas->translate(SkFloatToScalar(-layer_rect_.x()),
SkFloatToScalar(-layer_rect_.y()));
- SkRect layer_skrect = SkRect::MakeXYWH(layer_rect_.x(),
- layer_rect_.y(),
- layer_rect_.width(),
- layer_rect_.height());
- canvas->clipRect(layer_skrect);
+ canvas->clipRect(gfx::RectToSkRect(layer_rect_));
painter->PaintContents(canvas.get(), layer_rect_, painting_control);
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 1e7281d..171a8cb 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -57,7 +57,6 @@
raster_source_(raster_source),
resolution_(NON_IDEAL_RESOLUTION),
tiling_data_(gfx::Size(), gfx::Size(), kBorderTexels),
- last_impl_frame_time_in_seconds_(0.0),
can_require_tiles_for_activation_(false),
current_content_to_screen_scale_(0.f),
has_visible_rect_tiles_(false),
@@ -530,21 +529,26 @@
double current_frame_time_in_seconds,
const gfx::Rect& visible_rect_in_content_space) const {
gfx::Rect skewport = visible_rect_in_content_space;
- if (last_impl_frame_time_in_seconds_ == 0.0)
+ if (skewport.IsEmpty())
return skewport;
- double time_delta =
- current_frame_time_in_seconds - last_impl_frame_time_in_seconds_;
+ if (visible_rect_history_[1].frame_time_in_seconds == 0.0)
+ return skewport;
+
+ double time_delta = current_frame_time_in_seconds -
+ visible_rect_history_[1].frame_time_in_seconds;
if (time_delta == 0.0)
return skewport;
double extrapolation_multiplier =
skewport_target_time_in_seconds_ / time_delta;
- int old_x = last_visible_rect_in_content_space_.x();
- int old_y = last_visible_rect_in_content_space_.y();
- int old_right = last_visible_rect_in_content_space_.right();
- int old_bottom = last_visible_rect_in_content_space_.bottom();
+ int old_x = visible_rect_history_[1].visible_rect_in_content_space.x();
+ int old_y = visible_rect_history_[1].visible_rect_in_content_space.y();
+ int old_right =
+ visible_rect_history_[1].visible_rect_in_content_space.right();
+ int old_bottom =
+ visible_rect_history_[1].visible_rect_in_content_space.bottom();
int new_x = visible_rect_in_content_space.x();
int new_y = visible_rect_in_content_space.y();
@@ -563,11 +567,13 @@
extrapolation_multiplier * (old_right - new_right),
extrapolation_multiplier * (old_bottom - new_bottom));
- // Clip the skewport to |max_skewport|.
+ // Ensure that visible rect is contained in the skewport.
+ skewport.Union(visible_rect_in_content_space);
+
+ // Clip the skewport to |max_skewport|. This needs to happen after the
+ // union in case intersecting would have left the empty rect.
skewport.Intersect(max_skewport);
- // Finally, ensure that visible rect is contained in the skewport.
- skewport.Union(visible_rect_in_content_space);
return skewport;
}
@@ -587,9 +593,9 @@
gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_);
if (tiling_size().IsEmpty()) {
- last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
+ UpdateVisibleRectHistory(current_frame_time_in_seconds,
+ visible_rect_in_content_space);
last_viewport_in_layer_space_ = viewport_in_layer_space;
- last_visible_rect_in_content_space_ = visible_rect_in_content_space;
return false;
}
@@ -621,9 +627,9 @@
content_to_screen_scale);
soon_border_rect.Inset(-border, -border, -border, -border);
- last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
+ UpdateVisibleRectHistory(current_frame_time_in_seconds,
+ visible_rect_in_content_space);
last_viewport_in_layer_space_ = viewport_in_layer_space;
- last_visible_rect_in_content_space_ = visible_rect_in_content_space;
SetLiveTilesRect(eventually_rect);
UpdateTilePriorityRects(
@@ -806,7 +812,8 @@
WhichTree tree = client_->GetTree();
WhichTree twin_tree = tree == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE;
- UpdateTilePriorityForTree(tile, tree);
+ tile->SetPriority(tree, ComputePriorityForTile(tile));
+ UpdateRequiredStateForTile(tile, tree);
const PictureLayerTiling* twin_tiling =
client_->GetPendingOrActiveTwinTiling(this);
@@ -820,24 +827,13 @@
return;
}
- twin_tiling->UpdateTilePriorityForTree(tile, twin_tree);
+ tile->SetPriority(twin_tree, twin_tiling->ComputePriorityForTile(tile));
+ twin_tiling->UpdateRequiredStateForTile(tile, twin_tree);
}
-void PictureLayerTiling::UpdateTilePriorityForTree(Tile* tile,
- WhichTree tree) const {
- // 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();
-
- 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 (max_tile_priority_bin <= TilePriority::NOW &&
- current_visible_rect_.Intersects(tile_bounds)) {
- tile->SetPriority(tree, TilePriority(resolution_, TilePriority::NOW, 0));
+void PictureLayerTiling::UpdateRequiredStateForTile(Tile* tile,
+ WhichTree tree) const {
+ if (tile->priority(tree).priority_bin == TilePriority::NOW) {
if (tree == PENDING_TREE) {
tile->set_required_for_activation(
IsTileRequiredForActivationIfVisible(tile));
@@ -848,11 +844,28 @@
return;
}
+ // Non-NOW bin tiles are not required or occluded.
if (tree == PENDING_TREE)
tile->set_required_for_activation(false);
else
tile->set_required_for_draw(false);
tile->set_is_occluded(tree, false);
+}
+
+TilePriority PictureLayerTiling::ComputePriorityForTile(
+ const Tile* tile) const {
+ // TODO(vmpstr): See if this can be moved to iterators.
+ TilePriority::PriorityBin max_tile_priority_bin =
+ client_->GetMaxTilePriorityBin();
+
+ 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 (max_tile_priority_bin <= TilePriority::NOW &&
+ current_visible_rect_.Intersects(tile_bounds)) {
+ return TilePriority(resolution_, TilePriority::NOW, 0);
+ }
DCHECK_GT(current_content_to_screen_scale_, 0.f);
float distance_to_visible =
@@ -862,27 +875,38 @@
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));
- return;
+ return TilePriority(resolution_, TilePriority::SOON, distance_to_visible);
}
- tile->SetPriority(
- tree,
- TilePriority(resolution_, TilePriority::EVENTUALLY, distance_to_visible));
+ return TilePriority(resolution_, TilePriority::EVENTUALLY,
+ distance_to_visible);
}
-void PictureLayerTiling::GetAllTilesForTracing(
- std::set<const Tile*>* tiles) const {
- for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
- tiles->insert(it->second.get());
+void PictureLayerTiling::GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const {
+ const PictureLayerTiling* twin_tiling =
+ client_->GetPendingOrActiveTwinTiling(this);
+ for (const auto& tile_pair : tiles_) {
+ const Tile* tile = tile_pair.second.get();
+ const TilePriority& priority = ComputePriorityForTile(tile);
+ const TilePriority& twin_priority =
+ twin_tiling ? twin_tiling->ComputePriorityForTile(tile)
+ : TilePriority();
+
+ // Store combined priority.
+ (*tile_map)[tile] = TilePriority(priority, twin_priority);
+ }
}
void PictureLayerTiling::AsValueInto(
base::trace_event::TracedValue* state) const {
state->SetInteger("num_tiles", tiles_.size());
state->SetDouble("content_scale", contents_scale_);
+ MathUtil::AddToTracedValue("visible_rect", current_visible_rect_, state);
+ MathUtil::AddToTracedValue("skewport_rect", current_skewport_rect_, state);
+ MathUtil::AddToTracedValue("soon_rect", current_soon_border_rect_, state);
+ MathUtil::AddToTracedValue("eventually_rect", current_eventually_rect_,
+ state);
MathUtil::AddToTracedValue("tiling_size", tiling_size(), state);
}
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index 65e7ee0..ea258a3 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -5,7 +5,7 @@
#ifndef CC_RESOURCES_PICTURE_LAYER_TILING_H_
#define CC_RESOURCES_PICTURE_LAYER_TILING_H_
-#include <set>
+#include <map>
#include <utility>
#include <vector>
@@ -140,6 +140,8 @@
bool IsTileRequiredForDrawIfVisible(const Tile* tile) const;
void UpdateTileAndTwinPriority(Tile* tile) const;
+ TilePriority ComputePriorityForTile(const Tile* tile) const;
+ void UpdateRequiredStateForTile(Tile* tile, WhichTree tree) const;
bool has_visible_rect_tiles() const { return has_visible_rect_tiles_; }
bool has_skewport_rect_tiles() const { return has_skewport_rect_tiles_; }
bool has_soon_border_rect_tiles() const {
@@ -211,7 +213,8 @@
double current_frame_time_in_seconds,
const Occlusion& occlusion_in_layer_space);
- void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
+ void GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const;
void AsValueInto(base::trace_event::TracedValue* array) const;
size_t GPUMemoryUsageInBytes() const;
@@ -232,7 +235,7 @@
RectExpansionCache* cache);
bool has_ever_been_updated() const {
- return last_impl_frame_time_in_seconds_ != 0.0;
+ return visible_rect_history_[0].frame_time_in_seconds != 0.0;
}
protected:
@@ -244,6 +247,11 @@
typedef std::pair<int, int> TileMapKey;
typedef base::hash_map<TileMapKey, scoped_refptr<Tile>> TileMap;
+ struct FrameVisibleRect {
+ gfx::Rect visible_rect_in_content_space;
+ double frame_time_in_seconds = 0.0;
+ };
+
PictureLayerTiling(float contents_scale,
scoped_refptr<RasterSource> raster_source,
PictureLayerTilingClient* client,
@@ -279,9 +287,21 @@
bool NeedsUpdateForFrameAtTimeAndViewport(
double frame_time_in_seconds,
const gfx::Rect& viewport_in_layer_space) {
- return frame_time_in_seconds != last_impl_frame_time_in_seconds_ ||
+ return frame_time_in_seconds !=
+ visible_rect_history_[0].frame_time_in_seconds ||
viewport_in_layer_space != last_viewport_in_layer_space_;
}
+ void UpdateVisibleRectHistory(
+ double frame_time_in_seconds,
+ const gfx::Rect& visible_rect_in_content_space) {
+ visible_rect_history_[1] = visible_rect_history_[0];
+ visible_rect_history_[0].frame_time_in_seconds = frame_time_in_seconds;
+ visible_rect_history_[0].visible_rect_in_content_space =
+ visible_rect_in_content_space;
+ // If we don't have a second history item, set it to the most recent one.
+ if (visible_rect_history_[1].frame_time_in_seconds == 0.0)
+ visible_rect_history_[1] = visible_rect_history_[0];
+ }
const size_t max_tiles_for_interest_area_;
const float skewport_target_time_in_seconds_;
@@ -298,10 +318,9 @@
TileMap tiles_; // It is not legal to have a NULL tile in the tiles_ map.
gfx::Rect live_tiles_rect_;
- // State saved for computing velocities based upon finite differences.
- double last_impl_frame_time_in_seconds_;
gfx::Rect last_viewport_in_layer_space_;
- gfx::Rect last_visible_rect_in_content_space_;
+ // State saved for computing velocities based upon finite differences.
+ FrameVisibleRect visible_rect_history_[2];
bool can_require_tiles_for_activation_;
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index bd150f4..e616ce2 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -328,10 +328,10 @@
return updated;
}
-void PictureLayerTilingSet::GetAllTilesForTracing(
- std::set<const Tile*>* tiles) const {
+void PictureLayerTilingSet::GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const {
for (auto* tiling : tilings_)
- tiling->GetAllTilesForTracing(tiles);
+ tiling->GetAllTilesAndPrioritiesForTracing(tile_map);
}
PictureLayerTilingSet::CoverageIterator::CoverageIterator(
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h
index a4c2fd8..24da44d 100644
--- a/cc/resources/picture_layer_tiling_set.h
+++ b/cc/resources/picture_layer_tiling_set.h
@@ -112,7 +112,8 @@
const Occlusion& occlusion_in_layer_space,
bool can_require_tiles_for_activation);
- void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
+ void GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const;
// For a given rect, iterates through tiles that can fill it. If no
// set of tiles with resources can fill the rect, then it will iterate
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index d4a8778..5999ecd 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -591,7 +591,7 @@
EXPECT_EQ(350, expand_skewport.height());
EXPECT_TRUE(expand_skewport.Contains(gfx::Rect(-50, -50, 200, 200)));
- // Expand the viewport past the limit.
+ // Expand the viewport past the limit in all directions.
gfx::Rect big_expand_skewport =
tiling->ComputeSkewport(1.5, gfx::Rect(-500, -500, 1500, 1500));
@@ -600,6 +600,23 @@
EXPECT_EQ(1650, big_expand_skewport.width());
EXPECT_EQ(1650, big_expand_skewport.height());
EXPECT_TRUE(big_expand_skewport.Contains(gfx::Rect(-500, -500, 1500, 1500)));
+
+ // Shrink the skewport in all directions.
+ gfx::Rect shrink_viewport =
+ tiling->ComputeSkewport(1.5, gfx::Rect(0, 0, 100, 100));
+ EXPECT_EQ(0, shrink_viewport.x());
+ EXPECT_EQ(0, shrink_viewport.y());
+ EXPECT_EQ(100, shrink_viewport.width());
+ EXPECT_EQ(100, shrink_viewport.height());
+
+ // Move the skewport really far in one direction.
+ gfx::Rect move_skewport_far =
+ tiling->ComputeSkewport(1.5, gfx::Rect(0, 5000, 100, 100));
+ EXPECT_EQ(0, move_skewport_far.x());
+ EXPECT_EQ(5000, move_skewport_far.y());
+ EXPECT_EQ(100, move_skewport_far.width());
+ EXPECT_EQ(175, move_skewport_far.height());
+ EXPECT_TRUE(move_skewport_far.Contains(gfx::Rect(0, 5000, 100, 100)));
}
TEST(PictureLayerTilingTest, ComputeSkewport) {
@@ -665,6 +682,75 @@
EXPECT_EQ(160, expanded_skewport.height());
}
+TEST(PictureLayerTilingTest, SkewportThroughUpdateTilePriorities) {
+ FakePictureLayerTilingClient client;
+
+ gfx::Rect viewport(0, 0, 100, 100);
+ gfx::Size layer_bounds(200, 200);
+
+ client.SetTileSize(gfx::Size(100, 100));
+ client.set_tree(ACTIVE_TREE);
+
+ scoped_refptr<FakePicturePileImpl> pile =
+ FakePicturePileImpl::CreateFilledPileWithDefaultTileSize(layer_bounds);
+ scoped_ptr<TestablePictureLayerTiling> tiling =
+ TestablePictureLayerTiling::Create(1.0f, pile, &client,
+ LayerTreeSettings());
+
+ tiling->ComputeTilePriorityRects(viewport, 1.f, 1.0, Occlusion());
+
+ // Move viewport down 50 pixels in 0.5 seconds.
+ gfx::Rect viewport_50 = gfx::Rect(0, 50, 100, 100);
+ gfx::Rect skewport_50 = tiling->ComputeSkewport(1.5, viewport_50);
+
+ EXPECT_EQ(gfx::Rect(0, 50, 100, 200), skewport_50);
+ tiling->ComputeTilePriorityRects(viewport_50, 1.f, 1.5, Occlusion());
+
+ gfx::Rect viewport_100 = gfx::Rect(0, 100, 100, 100);
+ gfx::Rect skewport_100 = tiling->ComputeSkewport(2.0, viewport_100);
+
+ EXPECT_EQ(gfx::Rect(0, 100, 100, 200), skewport_100);
+ tiling->ComputeTilePriorityRects(viewport_100, 1.f, 2.0, Occlusion());
+
+ // Advance time, but not the viewport.
+ gfx::Rect result = tiling->ComputeSkewport(2.5, viewport_100);
+ // Since the history did advance, we should still get a skewport but a smaller
+ // one.
+ EXPECT_EQ(gfx::Rect(0, 100, 100, 150), result);
+ tiling->ComputeTilePriorityRects(viewport_100, 1.f, 2.5, Occlusion());
+
+ // Advance time again.
+ result = tiling->ComputeSkewport(3.0, viewport_100);
+ EXPECT_EQ(viewport_100, result);
+ tiling->ComputeTilePriorityRects(viewport_100, 1.f, 3.0, Occlusion());
+
+ // Ensure we have a skewport.
+ gfx::Rect viewport_150 = gfx::Rect(0, 150, 100, 100);
+ gfx::Rect skewport_150 = tiling->ComputeSkewport(3.5, viewport_150);
+ EXPECT_EQ(gfx::Rect(0, 150, 100, 150), skewport_150);
+ tiling->ComputeTilePriorityRects(viewport_150, 1.f, 3.5, Occlusion());
+
+ // Advance the viewport, but not the time.
+ gfx::Rect viewport_200 = gfx::Rect(0, 200, 100, 100);
+ gfx::Rect skewport_200 = tiling->ComputeSkewport(3.5, viewport_200);
+ EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
+
+ // Ensure that continued calls with the same value, produce the same skewport.
+ tiling->ComputeTilePriorityRects(viewport_150, 1.f, 3.5, Occlusion());
+ EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
+ tiling->ComputeTilePriorityRects(viewport_150, 1.f, 3.5, Occlusion());
+ EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
+
+ tiling->ComputeTilePriorityRects(viewport_200, 1.f, 3.5, Occlusion());
+
+ // This should never happen, but advance the viewport yet again keeping the
+ // time the same.
+ gfx::Rect viewport_250 = gfx::Rect(0, 250, 100, 100);
+ gfx::Rect skewport_250 = tiling->ComputeSkewport(3.5, viewport_250);
+ EXPECT_EQ(viewport_250, skewport_250);
+ tiling->ComputeTilePriorityRects(viewport_250, 1.f, 3.5, Occlusion());
+}
+
TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
FakePictureLayerTilingClient client;
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index 04e0801..b5b9c79 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -10,7 +10,6 @@
#include "cc/base/region.h"
#include "cc/resources/picture_pile_impl.h"
-#include "cc/resources/tile_task_worker_pool.h"
#include "skia/ext/analysis_canvas.h"
namespace {
@@ -166,6 +165,7 @@
const gfx::Size& tile_grid_size)
: min_contents_scale_(0),
slow_down_raster_scale_factor_for_debug_(0),
+ gather_pixel_refs_(false),
has_any_recordings_(false),
clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
requires_clear_(true),
@@ -539,15 +539,9 @@
int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_);
scoped_refptr<Picture> picture;
- // Note: Currently, gathering of pixel refs when using a single
- // raster thread doesn't provide any benefit. This might change
- // in the future but we avoid it for now to reduce the cost of
- // Picture::Create.
- bool gather_pixel_refs = TileTaskWorkerPool::GetNumWorkerThreads() > 1;
-
for (int i = 0; i < repeat_count; i++) {
picture = Picture::Create(padded_record_rect, painter, tile_grid_size_,
- gather_pixel_refs, recording_mode);
+ gather_pixel_refs_, recording_mode);
// Note the '&&' with previous is-suitable state.
// This means that once a picture-pile becomes unsuitable for gpu
// rasterization due to some content, it will continue to be unsuitable
@@ -623,6 +617,10 @@
slow_down_raster_scale_factor_for_debug_ = factor;
}
+void PicturePile::SetGatherPixelRefs(bool gather_pixel_refs) {
+ gather_pixel_refs_ = gather_pixel_refs;
+}
+
void PicturePile::SetBackgroundColor(SkColor background_color) {
background_color_ = background_color;
}
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index bdba579..f3c9569 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -35,6 +35,7 @@
gfx::Size GetSize() const final;
void SetEmptyBounds() override;
void SetSlowdownRasterScaleFactor(int factor) override;
+ void SetGatherPixelRefs(bool gather_pixel_refs) override;
void SetBackgroundColor(SkColor background_color) override;
void SetRequiresClear(bool requires_clear) override;
bool IsSuitableForGpuRasterization() const override;
@@ -98,6 +99,7 @@
float min_contents_scale_;
gfx::Size tile_grid_size_;
int slow_down_raster_scale_factor_for_debug_;
+ bool gather_pixel_refs_;
// A hint about whether there are any recordings. This may be a false
// positive.
bool has_any_recordings_;
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index e5f217b..9c68137 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -80,17 +80,13 @@
void PicturePileImpl::PlaybackToSharedCanvas(SkCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const {
- RasterCommon(canvas,
- NULL,
- canvas_rect,
- contents_scale,
- false);
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
}
void PicturePileImpl::RasterForAnalysis(skia::AnalysisCanvas* canvas,
const gfx::Rect& canvas_rect,
float contents_scale) const {
- RasterCommon(canvas, canvas, canvas_rect, contents_scale, true);
+ RasterCommon(canvas, canvas, canvas_rect, contents_scale);
}
void PicturePileImpl::PlaybackToCanvas(SkCanvas* canvas,
@@ -99,11 +95,7 @@
RasterSourceHelper::PrepareForPlaybackToCanvas(
canvas, canvas_rect, gfx::Rect(tiling_.tiling_size()), contents_scale,
background_color_, clear_canvas_with_debug_color_, requires_clear_);
- RasterCommon(canvas,
- NULL,
- canvas_rect,
- contents_scale,
- false);
+ RasterCommon(canvas, NULL, canvas_rect, contents_scale);
}
void PicturePileImpl::CoalesceRasters(const gfx::Rect& canvas_rect,
@@ -201,12 +193,10 @@
}
}
-void PicturePileImpl::RasterCommon(
- SkCanvas* canvas,
- SkDrawPictureCallback* callback,
- const gfx::Rect& canvas_rect,
- float contents_scale,
- bool is_analysis) const {
+void PicturePileImpl::RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const {
DCHECK(contents_scale >= min_contents_scale_);
canvas->translate(-canvas_rect.x(), -canvas_rect.y());
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index b144a79..72f9a5c 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -140,12 +140,10 @@
float contents_scale,
PictureRegionMap* result) const;
- void RasterCommon(
- SkCanvas* canvas,
- SkDrawPictureCallback* callback,
- const gfx::Rect& canvas_rect,
- float contents_scale,
- bool is_analysis) const;
+ void RasterCommon(SkCanvas* canvas,
+ SkDrawPictureCallback* callback,
+ const gfx::Rect& canvas_rect,
+ float contents_scale) const;
// An internal CanRaster check that goes to the picture_map rather than
// using the recorded_viewport hint.
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
index a202e63..98e4e87 100644
--- a/cc/resources/recording_source.h
+++ b/cc/resources/recording_source.h
@@ -47,6 +47,7 @@
virtual gfx::Size GetSize() const = 0;
virtual void SetEmptyBounds() = 0;
virtual void SetSlowdownRasterScaleFactor(int factor) = 0;
+ virtual void SetGatherPixelRefs(bool gather_pixel_refs) = 0;
virtual void SetBackgroundColor(SkColor background_color) = 0;
virtual void SetRequiresClear(bool requires_clear) = 0;
virtual bool IsSuitableForGpuRasterization() const = 0;
diff --git a/cc/resources/texture_compressor.cc b/cc/resources/texture_compressor.cc
new file mode 100644
index 0000000..186a47d
--- /dev/null
+++ b/cc/resources/texture_compressor.cc
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/texture_compressor.h"
+
+#include "base/logging.h"
+#include "cc/resources/texture_compressor_etc1.h"
+
+namespace cc {
+
+scoped_ptr<TextureCompressor> TextureCompressor::Create(Format format) {
+ switch (format) {
+ case kFormatETC1:
+ return make_scoped_ptr(new TextureCompressorETC1());
+ }
+
+ NOTREACHED();
+ return nullptr;
+}
+
+} // namespace cc
diff --git a/cc/resources/texture_compressor.h b/cc/resources/texture_compressor.h
new file mode 100644
index 0000000..18faa40
--- /dev/null
+++ b/cc/resources/texture_compressor.h
@@ -0,0 +1,46 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_TEXTURE_COMPRESSOR_H_
+#define CC_RESOURCES_TEXTURE_COMPRESSOR_H_
+
+#include <stdint.h>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "cc/base/cc_export.h"
+
+namespace cc {
+
+class CC_EXPORT TextureCompressor {
+ public:
+ enum Format {
+ kFormatETC1,
+ };
+
+ enum Quality {
+ kQualityLow,
+ kQualityMedium,
+ kQualityHigh,
+ };
+
+ static scoped_ptr<TextureCompressor> Create(Format format);
+ virtual ~TextureCompressor() {}
+
+ virtual void Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) = 0;
+
+ protected:
+ TextureCompressor() {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureCompressor);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_TEXTURE_COMPRESSOR_H_
diff --git a/cc/resources/texture_compressor_etc1.cc b/cc/resources/texture_compressor_etc1.cc
new file mode 100644
index 0000000..61c4438
--- /dev/null
+++ b/cc/resources/texture_compressor_etc1.cc
@@ -0,0 +1,503 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// See the following specification for details on the ETC1 format:
+// https://www.khronos.org/registry/gles/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt
+
+#include "cc/resources/texture_compressor_etc1.h"
+
+#include <string.h>
+#include <limits>
+
+#include "base/logging.h"
+
+// Defining the following macro will cause the error metric function to weigh
+// each color channel differently depending on how the human eye can perceive
+// them. This can give a slight improvement in image quality at the cost of a
+// performance hit.
+// #define USE_PERCEIVED_ERROR_METRIC
+
+namespace {
+
+template <typename T>
+inline T clamp(T val, T min, T max) {
+ return val < min ? min : (val > max ? max : val);
+}
+
+inline uint8_t round_to_5_bits(float val) {
+ return clamp<uint8_t>(val * 31.0f / 255.0f + 0.5f, 0, 31);
+}
+
+inline uint8_t round_to_4_bits(float val) {
+ return clamp<uint8_t>(val * 15.0f / 255.0f + 0.5f, 0, 15);
+}
+
+union Color {
+ struct BgraColorType {
+ uint8_t b;
+ uint8_t g;
+ uint8_t r;
+ uint8_t a;
+ } channels;
+ uint8_t components[4];
+ uint32_t bits;
+};
+
+/*
+ * Codeword tables.
+ * See: Table 3.17.2
+ */
+static const int16_t g_codeword_tables[8][4] = {{-8, -2, 2, 8},
+ {-17, -5, 5, 17},
+ {-29, -9, 9, 29},
+ {-42, -13, 13, 42},
+ {-60, -18, 18, 60},
+ {-80, -24, 24, 80},
+ {-106, -33, 33, 106},
+ {-183, -47, 47, 183}};
+
+/*
+ * Maps modifier indices to pixel index values.
+ * See: Table 3.17.3
+ */
+static const uint8_t g_mod_to_pix[4] = {3, 2, 0, 1};
+
+/*
+ * The ETC1 specification index texels as follows:
+ *
+ * [a][e][i][m] [ 0][ 4][ 8][12]
+ * [b][f][j][n] <-> [ 1][ 5][ 9][13]
+ * [c][g][k][o] [ 2][ 6][10][14]
+ * [d][h][l][p] [ 3][ 7][11][15]
+ *
+ * However, when extracting sub blocks from BGRA data the natural array
+ * indexing order ends up different:
+ *
+ * vertical0: [a][e][b][f] horizontal0: [a][e][i][m]
+ * [c][g][d][h] [b][f][j][n]
+ * vertical1: [i][m][j][n] horizontal1: [c][g][k][o]
+ * [k][o][l][p] [d][h][l][p]
+ *
+ * In order to translate from the natural array indices in a sub block to the
+ * indices (number) used by specification and hardware we use this table.
+ */
+static const uint8_t g_idx_to_num[4][8] = {
+ {0, 4, 1, 5, 2, 6, 3, 7}, // Vertical block 0.
+ {8, 12, 9, 13, 10, 14, 11, 15}, // Vertical block 1.
+ {0, 4, 8, 12, 1, 5, 9, 13}, // Horizontal block 0.
+ {2, 6, 10, 14, 3, 7, 11, 15} // Horizontal block 1.
+};
+
+inline void WriteColors444(uint8_t* block,
+ const Color& color0,
+ const Color& color1) {
+ block[0] = (color0.channels.r & 0xf0) | (color1.channels.r >> 4);
+ block[1] = (color0.channels.g & 0xf0) | (color1.channels.g >> 4);
+ block[2] = (color0.channels.b & 0xf0) | (color1.channels.b >> 4);
+}
+
+inline void WriteColors555(uint8_t* block,
+ const Color& color0,
+ const Color& color1) {
+ // Table for conversion to 3-bit two complement format.
+ static const uint8_t two_compl_trans_table[8] = {
+ 4, // -4 (100b)
+ 5, // -3 (101b)
+ 6, // -2 (110b)
+ 7, // -1 (111b)
+ 0, // 0 (000b)
+ 1, // 1 (001b)
+ 2, // 2 (010b)
+ 3, // 3 (011b)
+ };
+
+ int16_t delta_r =
+ static_cast<int16_t>(color1.channels.r >> 3) - (color0.channels.r >> 3);
+ int16_t delta_g =
+ static_cast<int16_t>(color1.channels.g >> 3) - (color0.channels.g >> 3);
+ int16_t delta_b =
+ static_cast<int16_t>(color1.channels.b >> 3) - (color0.channels.b >> 3);
+ DCHECK(delta_r >= -4 && delta_r <= 3);
+ DCHECK(delta_g >= -4 && delta_g <= 3);
+ DCHECK(delta_b >= -4 && delta_b <= 3);
+
+ block[0] = (color0.channels.r & 0xf8) | two_compl_trans_table[delta_r + 4];
+ block[1] = (color0.channels.g & 0xf8) | two_compl_trans_table[delta_g + 4];
+ block[2] = (color0.channels.b & 0xf8) | two_compl_trans_table[delta_b + 4];
+}
+
+inline void WriteCodewordTable(uint8_t* block,
+ uint8_t sub_block_id,
+ uint8_t table) {
+ DCHECK_LT(sub_block_id, 2);
+ DCHECK_LT(table, 8);
+
+ uint8_t shift = (2 + (3 - sub_block_id * 3));
+ block[3] &= ~(0x07 << shift);
+ block[3] |= table << shift;
+}
+
+inline void WritePixelData(uint8_t* block, uint32_t pixel_data) {
+ block[4] |= pixel_data >> 24;
+ block[5] |= (pixel_data >> 16) & 0xff;
+ block[6] |= (pixel_data >> 8) & 0xff;
+ block[7] |= pixel_data & 0xff;
+}
+
+inline void WriteFlip(uint8_t* block, bool flip) {
+ block[3] &= ~0x01;
+ block[3] |= static_cast<uint8_t>(flip);
+}
+
+inline void WriteDiff(uint8_t* block, bool diff) {
+ block[3] &= ~0x02;
+ block[3] |= static_cast<uint8_t>(diff) << 1;
+}
+
+/**
+ * Compress and rounds BGR888 into BGR444. The resulting BGR444 color is
+ * expanded to BGR888 as it would be in hardware after decompression. The
+ * actual 444-bit data is available in the four most significant bits of each
+ * channel.
+ */
+inline Color MakeColor444(const float* bgr) {
+ uint8_t b4 = round_to_4_bits(bgr[0]);
+ uint8_t g4 = round_to_4_bits(bgr[1]);
+ uint8_t r4 = round_to_4_bits(bgr[2]);
+ Color bgr444;
+ bgr444.channels.b = (b4 << 4) | b4;
+ bgr444.channels.g = (g4 << 4) | g4;
+ bgr444.channels.r = (r4 << 4) | r4;
+ return bgr444;
+}
+
+/**
+ * Compress and rounds BGR888 into BGR555. The resulting BGR555 color is
+ * expanded to BGR888 as it would be in hardware after decompression. The
+ * actual 555-bit data is available in the five most significant bits of each
+ * channel.
+ */
+inline Color MakeColor555(const float* bgr) {
+ uint8_t b5 = round_to_5_bits(bgr[0]);
+ uint8_t g5 = round_to_5_bits(bgr[1]);
+ uint8_t r5 = round_to_5_bits(bgr[2]);
+ Color bgr555;
+ bgr555.channels.b = (b5 << 3) | (b5 >> 2);
+ bgr555.channels.g = (g5 << 3) | (g5 >> 2);
+ bgr555.channels.r = (r5 << 3) | (r5 >> 2);
+ return bgr555;
+}
+
+/**
+ * Constructs a color from a given base color and luminance value.
+ */
+inline Color MakeColor(const Color& base, int16_t lum) {
+ int b = static_cast<int>(base.channels.b) + lum;
+ int g = static_cast<int>(base.channels.g) + lum;
+ int r = static_cast<int>(base.channels.r) + lum;
+ Color color;
+ color.channels.b = static_cast<uint8_t>(clamp(b, 0, 255));
+ color.channels.g = static_cast<uint8_t>(clamp(g, 0, 255));
+ color.channels.r = static_cast<uint8_t>(clamp(r, 0, 255));
+ return color;
+}
+
+/**
+ * Calculates the error metric for two colors. A small error signals that the
+ * colors are similar to each other, a large error the signals the opposite.
+ */
+inline uint32_t GetColorError(const Color& u, const Color& v) {
+#ifdef USE_PERCEIVED_ERROR_METRIC
+ float delta_b = static_cast<float>(u.channels.b) - v.channels.b;
+ float delta_g = static_cast<float>(u.channels.g) - v.channels.g;
+ float delta_r = static_cast<float>(u.channels.r) - v.channels.r;
+ return static_cast<uint32_t>(0.299f * delta_b * delta_b +
+ 0.587f * delta_g * delta_g +
+ 0.114f * delta_r * delta_r);
+#else
+ int delta_b = static_cast<int>(u.channels.b) - v.channels.b;
+ int delta_g = static_cast<int>(u.channels.g) - v.channels.g;
+ int delta_r = static_cast<int>(u.channels.r) - v.channels.r;
+ return delta_b * delta_b + delta_g * delta_g + delta_r * delta_r;
+#endif
+}
+
+void GetAverageColor(const Color* src, float* avg_color) {
+ uint32_t sum_b = 0, sum_g = 0, sum_r = 0;
+
+ for (unsigned int i = 0; i < 8; ++i) {
+ sum_b += src[i].channels.b;
+ sum_g += src[i].channels.g;
+ sum_r += src[i].channels.r;
+ }
+
+ const float kInv8 = 1.0f / 8.0f;
+ avg_color[0] = static_cast<float>(sum_b) * kInv8;
+ avg_color[1] = static_cast<float>(sum_g) * kInv8;
+ avg_color[2] = static_cast<float>(sum_r) * kInv8;
+}
+
+void ComputeLuminance(uint8_t* block,
+ const Color* src,
+ const Color& base,
+ int sub_block_id,
+ const uint8_t* idx_to_num_tab) {
+ uint32_t best_tbl_err = std::numeric_limits<uint32_t>::max();
+ uint8_t best_tbl_idx = 0;
+ uint8_t best_mod_idx[8][8]; // [table][texel]
+
+ // Try all codeword tables to find the one giving the best results for this
+ // block.
+ for (unsigned int tbl_idx = 0; tbl_idx < 8; ++tbl_idx) {
+ // Pre-compute all the candidate colors; combinations of the base color and
+ // all available luminance values.
+ Color candidate_color[4]; // [modifier]
+ for (unsigned int mod_idx = 0; mod_idx < 4; ++mod_idx) {
+ int16_t lum = g_codeword_tables[tbl_idx][mod_idx];
+ candidate_color[mod_idx] = MakeColor(base, lum);
+ }
+
+ uint32_t tbl_err = 0;
+
+ for (unsigned int i = 0; i < 8; ++i) {
+ // Try all modifiers in the current table to find which one gives the
+ // smallest error.
+ uint32_t best_mod_err = std::numeric_limits<uint32_t>::max();
+ for (unsigned int mod_idx = 0; mod_idx < 4; ++mod_idx) {
+ const Color& color = candidate_color[mod_idx];
+
+ uint32_t mod_err = GetColorError(src[i], color);
+ if (mod_err < best_mod_err) {
+ best_mod_idx[tbl_idx][i] = mod_idx;
+ best_mod_err = mod_err;
+
+ if (mod_err == 0)
+ break; // We cannot do any better than this.
+ }
+ }
+
+ tbl_err += best_mod_err;
+ if (tbl_err > best_tbl_err)
+ break; // We're already doing worse than the best table so skip.
+ }
+
+ if (tbl_err < best_tbl_err) {
+ best_tbl_err = tbl_err;
+ best_tbl_idx = tbl_idx;
+
+ if (tbl_err == 0)
+ break; // We cannot do any better than this.
+ }
+ }
+
+ WriteCodewordTable(block, sub_block_id, best_tbl_idx);
+
+ uint32_t pix_data = 0;
+
+ for (unsigned int i = 0; i < 8; ++i) {
+ uint8_t mod_idx = best_mod_idx[best_tbl_idx][i];
+ uint8_t pix_idx = g_mod_to_pix[mod_idx];
+
+ uint32_t lsb = pix_idx & 0x1;
+ uint32_t msb = pix_idx >> 1;
+
+ // Obtain the texel number as specified in the standard.
+ int texel_num = idx_to_num_tab[i];
+ pix_data |= msb << (texel_num + 16);
+ pix_data |= lsb << (texel_num);
+ }
+
+ WritePixelData(block, pix_data);
+}
+
+/**
+ * Tries to compress the block under the assumption that it's a single color
+ * block. If it's not the function will bail out without writing anything to
+ * the destination buffer.
+ */
+bool TryCompressSolidBlock(uint8_t* dst, const Color* src) {
+ for (unsigned int i = 1; i < 16; ++i) {
+ if (src[i].bits != src[0].bits)
+ return false;
+ }
+
+ // Clear destination buffer so that we can "or" in the results.
+ memset(dst, 0, 8);
+
+ float src_color_float[3] = {static_cast<float>(src->channels.b),
+ static_cast<float>(src->channels.g),
+ static_cast<float>(src->channels.r)};
+ Color base = MakeColor555(src_color_float);
+
+ WriteDiff(dst, true);
+ WriteFlip(dst, false);
+ WriteColors555(dst, base, base);
+
+ uint8_t best_tbl_idx = 0;
+ uint8_t best_mod_idx = 0;
+ uint32_t best_mod_err = std::numeric_limits<uint32_t>::max();
+
+ // Try all codeword tables to find the one giving the best results for this
+ // block.
+ for (unsigned int tbl_idx = 0; tbl_idx < 8; ++tbl_idx) {
+ // Try all modifiers in the current table to find which one gives the
+ // smallest error.
+ for (unsigned int mod_idx = 0; mod_idx < 4; ++mod_idx) {
+ int16_t lum = g_codeword_tables[tbl_idx][mod_idx];
+ const Color& color = MakeColor(base, lum);
+
+ uint32_t mod_err = GetColorError(*src, color);
+ if (mod_err < best_mod_err) {
+ best_tbl_idx = tbl_idx;
+ best_mod_idx = mod_idx;
+ best_mod_err = mod_err;
+
+ if (mod_err == 0)
+ break; // We cannot do any better than this.
+ }
+ }
+
+ if (best_mod_err == 0)
+ break;
+ }
+
+ WriteCodewordTable(dst, 0, best_tbl_idx);
+ WriteCodewordTable(dst, 1, best_tbl_idx);
+
+ uint8_t pix_idx = g_mod_to_pix[best_mod_idx];
+ uint32_t lsb = pix_idx & 0x1;
+ uint32_t msb = pix_idx >> 1;
+
+ uint32_t pix_data = 0;
+ for (unsigned int i = 0; i < 2; ++i) {
+ for (unsigned int j = 0; j < 8; ++j) {
+ // Obtain the texel number as specified in the standard.
+ int texel_num = g_idx_to_num[i][j];
+ pix_data |= msb << (texel_num + 16);
+ pix_data |= lsb << (texel_num);
+ }
+ }
+
+ WritePixelData(dst, pix_data);
+ return true;
+}
+
+void CompressBlock(uint8_t* dst, const Color* ver_src, const Color* hor_src) {
+ if (TryCompressSolidBlock(dst, ver_src))
+ return;
+
+ const Color* sub_block_src[4] = {ver_src, ver_src + 8, hor_src, hor_src + 8};
+
+ Color sub_block_avg[4];
+ bool use_differential[2] = {true, true};
+
+ // Compute the average color for each sub block and determine if differential
+ // coding can be used.
+ for (unsigned int i = 0, j = 1; i < 4; i += 2, j += 2) {
+ float avg_color_0[3];
+ GetAverageColor(sub_block_src[i], avg_color_0);
+ Color avg_color_555_0 = MakeColor555(avg_color_0);
+
+ float avg_color_1[3];
+ GetAverageColor(sub_block_src[j], avg_color_1);
+ Color avg_color_555_1 = MakeColor555(avg_color_1);
+
+ for (unsigned int light_idx = 0; light_idx < 3; ++light_idx) {
+ int u = avg_color_555_0.components[light_idx] >> 3;
+ int v = avg_color_555_1.components[light_idx] >> 3;
+
+ int component_diff = v - u;
+ if (component_diff < -4 || component_diff > 3) {
+ use_differential[i / 2] = false;
+ sub_block_avg[i] = MakeColor444(avg_color_0);
+ sub_block_avg[j] = MakeColor444(avg_color_1);
+ } else {
+ sub_block_avg[i] = avg_color_555_0;
+ sub_block_avg[j] = avg_color_555_1;
+ }
+ }
+ }
+
+ // Compute the error of each sub block before adjusting for luminance. These
+ // error values are later used for determining if we should flip the sub
+ // block or not.
+ uint32_t sub_block_err[4] = {0};
+ for (unsigned int i = 0; i < 4; ++i) {
+ for (unsigned int j = 0; j < 8; ++j) {
+ sub_block_err[i] += GetColorError(sub_block_avg[i], sub_block_src[i][j]);
+ }
+ }
+
+ bool flip =
+ sub_block_err[2] + sub_block_err[3] < sub_block_err[0] + sub_block_err[1];
+
+ // Clear destination buffer so that we can "or" in the results.
+ memset(dst, 0, 8);
+
+ WriteDiff(dst, use_differential[!!flip]);
+ WriteFlip(dst, flip);
+
+ uint8_t sub_block_off_0 = flip ? 2 : 0;
+ uint8_t sub_block_off_1 = sub_block_off_0 + 1;
+
+ if (use_differential[!!flip]) {
+ WriteColors555(dst, sub_block_avg[sub_block_off_0],
+ sub_block_avg[sub_block_off_1]);
+ } else {
+ WriteColors444(dst, sub_block_avg[sub_block_off_0],
+ sub_block_avg[sub_block_off_1]);
+ }
+
+ // Compute luminance for the first sub block.
+ ComputeLuminance(dst, sub_block_src[sub_block_off_0],
+ sub_block_avg[sub_block_off_0], 0,
+ g_idx_to_num[sub_block_off_0]);
+ // Compute luminance for the second sub block.
+ ComputeLuminance(dst, sub_block_src[sub_block_off_1],
+ sub_block_avg[sub_block_off_1], 1,
+ g_idx_to_num[sub_block_off_1]);
+}
+
+} // namespace
+
+namespace cc {
+
+void TextureCompressorETC1::Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) {
+ DCHECK(width >= 4 && (width & 3) == 0);
+ DCHECK(height >= 4 && (height & 3) == 0);
+
+ Color ver_blocks[16];
+ Color hor_blocks[16];
+
+ for (int y = 0; y < height; y += 4, src += width * 4 * 4) {
+ for (int x = 0; x < width; x += 4, dst += 8) {
+ const Color* row0 = reinterpret_cast<const Color*>(src + x * 4);
+ const Color* row1 = row0 + width;
+ const Color* row2 = row1 + width;
+ const Color* row3 = row2 + width;
+
+ memcpy(ver_blocks, row0, 8);
+ memcpy(ver_blocks + 2, row1, 8);
+ memcpy(ver_blocks + 4, row2, 8);
+ memcpy(ver_blocks + 6, row3, 8);
+ memcpy(ver_blocks + 8, row0 + 2, 8);
+ memcpy(ver_blocks + 10, row1 + 2, 8);
+ memcpy(ver_blocks + 12, row2 + 2, 8);
+ memcpy(ver_blocks + 14, row3 + 2, 8);
+
+ memcpy(hor_blocks, row0, 16);
+ memcpy(hor_blocks + 4, row1, 16);
+ memcpy(hor_blocks + 8, row2, 16);
+ memcpy(hor_blocks + 12, row3, 16);
+
+ CompressBlock(dst, ver_blocks, hor_blocks);
+ }
+ }
+}
+
+} // namespace cc
diff --git a/cc/resources/texture_compressor_etc1.h b/cc/resources/texture_compressor_etc1.h
new file mode 100644
index 0000000..c457562
--- /dev/null
+++ b/cc/resources/texture_compressor_etc1.h
@@ -0,0 +1,31 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_RESOURCES_TEXTURE_COMPRESSOR_ETC1_H_
+#define CC_RESOURCES_TEXTURE_COMPRESSOR_ETC1_H_
+
+#include "cc/resources/texture_compressor.h"
+
+namespace cc {
+
+class CC_EXPORT TextureCompressorETC1 : public TextureCompressor {
+ public:
+ TextureCompressorETC1() {}
+
+ // Compress a texture using ETC1. Note that the |quality| parameter is
+ // ignored. The current implementation does not support different quality
+ // settings.
+ void Compress(const uint8_t* src,
+ uint8_t* dst,
+ int width,
+ int height,
+ Quality quality) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(TextureCompressorETC1);
+};
+
+} // namespace cc
+
+#endif // CC_RESOURCES_TEXTURE_COMPRESSOR_ETC1_H_
diff --git a/cc/resources/texture_compressor_perftest.cc b/cc/resources/texture_compressor_perftest.cc
new file mode 100644
index 0000000..7d68bd6
--- /dev/null
+++ b/cc/resources/texture_compressor_perftest.cc
@@ -0,0 +1,103 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/logging.h"
+#include "cc/debug/lap_timer.h"
+#include "cc/resources/texture_compressor.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/perf/perf_test.h"
+
+namespace cc {
+namespace {
+
+const int kTimeLimitMillis = 2000;
+const int kWarmupRuns = 5;
+const int kTimeCheckInterval = 10;
+
+const int kImageWidth = 256;
+const int kImageHeight = 256;
+const int kImageSizeInBytes = kImageWidth * kImageHeight * 4;
+
+const TextureCompressor::Quality kQualities[] = {
+ TextureCompressor::kQualityLow,
+ TextureCompressor::kQualityMedium,
+ TextureCompressor::kQualityHigh};
+
+std::string FormatName(TextureCompressor::Format format) {
+ switch (format) {
+ case TextureCompressor::kFormatETC1:
+ return "ETC1";
+ }
+
+ NOTREACHED();
+ return "";
+}
+
+std::string QualityName(TextureCompressor::Quality quality) {
+ switch (quality) {
+ case TextureCompressor::kQualityLow:
+ return "Low";
+ case TextureCompressor::kQualityMedium:
+ return "Medium";
+ case TextureCompressor::kQualityHigh:
+ return "High";
+ }
+
+ NOTREACHED();
+ return "";
+}
+
+class TextureCompressorPerfTest
+ : public testing::TestWithParam<TextureCompressor::Format> {
+ public:
+ TextureCompressorPerfTest()
+ : timer_(kWarmupRuns,
+ base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
+ kTimeCheckInterval) {}
+
+ void SetUp() override {
+ TextureCompressor::Format format = GetParam();
+ compressor_ = TextureCompressor::Create(format);
+ }
+
+ void RunTest(const std::string& name, TextureCompressor::Quality quality) {
+ timer_.Reset();
+ do {
+ compressor_->Compress(src_, dst_, kImageWidth, kImageHeight, quality);
+ timer_.NextLap();
+ } while (!timer_.HasTimeLimitExpired());
+
+ std::string str = FormatName(GetParam()) + " " + QualityName(quality);
+ perf_test::PrintResult("Compress256x256", name, str, timer_.MsPerLap(),
+ "us", true);
+ }
+
+ protected:
+ LapTimer timer_;
+ scoped_ptr<TextureCompressor> compressor_;
+ uint8_t src_[kImageSizeInBytes];
+ uint8_t dst_[kImageSizeInBytes];
+};
+
+TEST_P(TextureCompressorPerfTest, Compress256x256Image) {
+ for (int i = 0; i < kImageSizeInBytes; ++i)
+ src_[i] = i % 256;
+
+ for (auto& quality : kQualities)
+ RunTest("Image", quality);
+}
+
+TEST_P(TextureCompressorPerfTest, Compress256x256SolidImage) {
+ memset(src_, 0, kImageSizeInBytes);
+
+ for (auto& quality : kQualities)
+ RunTest("SolidImage", quality);
+}
+
+INSTANTIATE_TEST_CASE_P(TextureCompressorPerfTests,
+ TextureCompressorPerfTest,
+ ::testing::Values(TextureCompressor::kFormatETC1));
+
+} // namespace
+} // namespace cc
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index f86330e..45b4a30 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -48,7 +48,8 @@
"cc::Tile", this);
}
-void Tile::AsValueInto(base::trace_event::TracedValue* res) const {
+void Tile::AsValueWithPriorityInto(const TilePriority& priority,
+ base::trace_event::TracedValue* res) const {
TracedValue::MakeDictIntoImplicitSnapshotWithCategory(
TRACE_DISABLED_BY_DEFAULT("cc.debug"), res, "cc::Tile", this);
TracedValue::SetIDRef(raster_source_.get(), res, "picture_pile");
@@ -58,6 +59,8 @@
res->SetInteger("layer_id", layer_id_);
+ // TODO(vmpstr): Remove active and pending priority once tracing is using
+ // combined priority or at least can support both.
res->BeginDictionary("active_priority");
priority_[ACTIVE_TREE].AsValueInto(res);
res->EndDictionary();
@@ -66,6 +69,10 @@
priority_[PENDING_TREE].AsValueInto(res);
res->EndDictionary();
+ res->BeginDictionary("combined_priority");
+ priority.AsValueInto(res);
+ res->EndDictionary();
+
res->BeginDictionary("draw_info");
draw_info_.AsValueInto(res);
res->EndDictionary();
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index c3ca623..dcc8566 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -92,7 +92,8 @@
!draw_info_.IsReadyToDraw();
}
- void AsValueInto(base::trace_event::TracedValue* dict) const;
+ void AsValueWithPriorityInto(const TilePriority& priority,
+ base::trace_event::TracedValue* dict) const;
inline bool IsReadyToDraw() const { return draw_info_.IsReadyToDraw(); }
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 7ea86f0..71f2e83 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -366,15 +366,16 @@
scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
client_->BuildRasterQueue(global_state_.tree_priority,
RasterTilePriorityQueue::Type::ALL));
- // Inform the client that will likely require a draw if the top tile is
- // required for draw.
- client_->SetIsLikelyToRequireADraw(
- !raster_priority_queue->IsEmpty() &&
- raster_priority_queue->Top()->required_for_draw());
AssignGpuMemoryToTiles(raster_priority_queue.get(),
scheduled_raster_task_limit_,
&tiles_that_need_to_be_rasterized);
+ // Inform the client that will likely require a draw if the highest priority
+ // tile that will be rasterized is required for draw.
+ client_->SetIsLikelyToRequireADraw(
+ !tiles_that_need_to_be_rasterized.empty() &&
+ (*tiles_that_need_to_be_rasterized.begin())->required_for_draw());
+
// Schedule tile tasks.
ScheduleTasks(tiles_that_need_to_be_rasterized);
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 87d1837..236f918 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -18,6 +18,7 @@
#include "cc/test/fake_tile_manager_client.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_tile_priorities.h"
#include "cc/trees/layer_tree_impl.h"
@@ -90,7 +91,8 @@
proxy_(base::MessageLoopProxy::current()),
host_impl_(ImplSidePaintingSettings(10000),
&proxy_,
- &shared_bitmap_manager_),
+ &shared_bitmap_manager_,
+ &task_graph_runner_),
timer_(kWarmupRuns,
base::TimeDelta::FromMilliseconds(kTimeLimitMillis),
kTimeCheckInterval) {}
@@ -407,6 +409,7 @@
GlobalStateThatImpactsTilePriority global_state_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
TileMemoryLimitPolicy memory_limit_policy_;
int max_tiles_;
int id_;
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 19ccf24..e826f55 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -18,6 +18,7 @@
#include "cc/test/fake_tile_manager.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_tile_priorities.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -38,7 +39,10 @@
ready_to_activate_(false),
id_(7),
proxy_(base::MessageLoopProxy::current()),
- host_impl_(LowResTilingsSettings(), &proxy_, &shared_bitmap_manager_) {}
+ host_impl_(LowResTilingsSettings(),
+ &proxy_,
+ &shared_bitmap_manager_,
+ &task_graph_runner_) {}
void SetTreePriority(TreePriority tree_priority) {
GlobalStateThatImpactsTilePriority state;
@@ -137,6 +141,7 @@
GlobalStateThatImpactsTilePriority global_state_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
TileMemoryLimitPolicy memory_limit_policy_;
int max_tiles_;
bool ready_to_activate_;
@@ -1277,5 +1282,42 @@
EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
}
+TEST_F(TileManagerTilePriorityQueueTest, SetIsLikelyToRequireADraw) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ // Verify that the queue has a required for draw tile at Top.
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+ EXPECT_TRUE(queue->Top()->required_for_draw());
+
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+ host_impl_.tile_manager()->PrepareTiles(host_impl_.global_tile_state());
+ EXPECT_TRUE(host_impl_.is_likely_to_require_a_draw());
+}
+
+TEST_F(TileManagerTilePriorityQueueTest,
+ NoSetIsLikelyToRequireADrawOnZeroMemoryBudget) {
+ const gfx::Size layer_bounds(1000, 1000);
+ host_impl_.SetViewportSize(layer_bounds);
+ SetupDefaultTrees(layer_bounds);
+
+ // Verify that the queue has a required for draw tile at Top.
+ scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
+ SAME_PRIORITY_FOR_BOTH_TREES, RasterTilePriorityQueue::Type::ALL));
+ EXPECT_FALSE(queue->IsEmpty());
+ EXPECT_TRUE(queue->Top()->required_for_draw());
+
+ ManagedMemoryPolicy policy = host_impl_.ActualManagedMemoryPolicy();
+ policy.bytes_limit_when_visible = 0;
+ host_impl_.SetMemoryPolicy(policy);
+
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+ host_impl_.tile_manager()->PrepareTiles(host_impl_.global_tile_state());
+ EXPECT_FALSE(host_impl_.is_likely_to_require_a_draw());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/resources/tile_task_worker_pool.cc b/cc/resources/tile_task_worker_pool.cc
index 2775386..0fbc7be 100644
--- a/cc/resources/tile_task_worker_pool.cc
+++ b/cc/resources/tile_task_worker_pool.cc
@@ -6,11 +6,7 @@
#include <algorithm>
-#include "base/lazy_instance.h"
-#include "base/strings/stringprintf.h"
-#include "base/threading/simple_thread.h"
#include "base/trace_event/trace_event.h"
-#include "cc/base/scoped_ptr_deque.h"
#include "cc/resources/raster_source.h"
#include "skia/ext/refptr.h"
#include "third_party/skia/include/core/SkCanvas.h"
@@ -19,41 +15,6 @@
namespace cc {
namespace {
-base::ThreadPriority g_worker_thread_priority = base::kThreadPriority_Normal;
-
-class TileTaskGraphRunner : public TaskGraphRunner,
- public base::DelegateSimpleThread::Delegate {
- public:
- TileTaskGraphRunner() {
- size_t num_threads = TileTaskWorkerPool::GetNumWorkerThreads();
- while (workers_.size() < num_threads) {
- scoped_ptr<base::DelegateSimpleThread> worker =
- make_scoped_ptr(new base::DelegateSimpleThread(
- this, base::StringPrintf(
- "CompositorTileWorker%u",
- static_cast<unsigned>(workers_.size() + 1)).c_str()));
- worker->Start();
- worker->SetThreadPriority(g_worker_thread_priority);
- workers_.push_back(worker.Pass());
- }
- }
-
- ~TileTaskGraphRunner() override { NOTREACHED(); }
-
- private:
- // Overridden from base::DelegateSimpleThread::Delegate:
- void Run() override { TaskGraphRunner::Run(); }
-
- ScopedPtrDeque<base::DelegateSimpleThread> workers_;
-};
-
-base::LazyInstance<TileTaskGraphRunner>::Leaky g_task_graph_runner =
- LAZY_INSTANCE_INITIALIZER;
-
-const int kDefaultNumWorkerThreads = 1;
-
-int g_num_worker_threads = 0;
-
class TaskSetFinishedTaskImpl : public TileTask {
public:
explicit TaskSetFinishedTaskImpl(
@@ -107,33 +68,6 @@
}
// static
-void TileTaskWorkerPool::SetNumWorkerThreads(int num_threads) {
- DCHECK_LT(0, num_threads);
- DCHECK_EQ(0, g_num_worker_threads);
-
- g_num_worker_threads = num_threads;
-}
-
-// static
-int TileTaskWorkerPool::GetNumWorkerThreads() {
- if (!g_num_worker_threads)
- g_num_worker_threads = kDefaultNumWorkerThreads;
-
- return g_num_worker_threads;
-}
-
-// static
-void TileTaskWorkerPool::SetWorkerThreadPriority(
- base::ThreadPriority priority) {
- g_worker_thread_priority = priority;
-}
-
-// static
-TaskGraphRunner* TileTaskWorkerPool::GetTaskGraphRunner() {
- return g_task_graph_runner.Pointer();
-}
-
-// static
scoped_refptr<TileTask> TileTaskWorkerPool::CreateTaskSetFinishedTask(
base::SequencedTaskRunner* task_runner,
const base::Closure& on_task_set_finished_callback) {
diff --git a/cc/resources/tile_task_worker_pool.h b/cc/resources/tile_task_worker_pool.h
index 915a3fa..90adfd1 100644
--- a/cc/resources/tile_task_worker_pool.h
+++ b/cc/resources/tile_task_worker_pool.h
@@ -5,7 +5,6 @@
#ifndef CC_RESOURCES_TILE_TASK_WORKER_POOL_H_
#define CC_RESOURCES_TILE_TASK_WORKER_POOL_H_
-#include "base/threading/platform_thread.h"
#include "cc/resources/tile_task_runner.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/geometry/size.h"
@@ -27,20 +26,6 @@
TileTaskWorkerPool();
virtual ~TileTaskWorkerPool();
- // Set the number of threads to use for the global TaskGraphRunner instance.
- // This can only be called once and must be called prior to
- // GetNumWorkerThreads().
- static void SetNumWorkerThreads(int num_threads);
-
- // Returns the number of threads used for the global TaskGraphRunner instance.
- static int GetNumWorkerThreads();
-
- // Set the priority of worker threads.
- static void SetWorkerThreadPriority(base::ThreadPriority priority);
-
- // Returns a pointer to the global TaskGraphRunner instance.
- static TaskGraphRunner* GetTaskGraphRunner();
-
// Utility function that can be used to create a "Task set finished" task that
// posts |callback| to |task_runner| when run.
static scoped_refptr<TileTask> CreateTaskSetFinishedTask(
diff --git a/cc/resources/tile_task_worker_pool_unittest.cc b/cc/resources/tile_task_worker_pool_unittest.cc
index 72f9d20..3d74daf 100644
--- a/cc/resources/tile_task_worker_pool_unittest.cc
+++ b/cc/resources/tile_task_worker_pool_unittest.cc
@@ -27,6 +27,7 @@
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -142,39 +143,38 @@
case TILE_TASK_WORKER_POOL_TYPE_PIXEL_BUFFER:
Create3dOutputSurfaceAndResourceProvider();
tile_task_worker_pool_ = PixelBufferTileTaskWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- TileTaskWorkerPool::GetTaskGraphRunner(), context_provider_.get(),
- resource_provider_.get(), kMaxTransferBufferUsageBytes);
+ base::MessageLoopProxy::current().get(), &task_graph_runner_,
+ context_provider_.get(), resource_provider_.get(),
+ kMaxTransferBufferUsageBytes);
break;
case TILE_TASK_WORKER_POOL_TYPE_ZERO_COPY:
Create3dOutputSurfaceAndResourceProvider();
tile_task_worker_pool_ = ZeroCopyTileTaskWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- TileTaskWorkerPool::GetTaskGraphRunner(), resource_provider_.get());
+ base::MessageLoopProxy::current().get(), &task_graph_runner_,
+ resource_provider_.get());
break;
case TILE_TASK_WORKER_POOL_TYPE_ONE_COPY:
Create3dOutputSurfaceAndResourceProvider();
staging_resource_pool_ = ResourcePool::Create(resource_provider_.get(),
GL_TEXTURE_2D);
tile_task_worker_pool_ = OneCopyTileTaskWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- TileTaskWorkerPool::GetTaskGraphRunner(), context_provider_.get(),
- resource_provider_.get(), staging_resource_pool_.get());
+ base::MessageLoopProxy::current().get(), &task_graph_runner_,
+ context_provider_.get(), resource_provider_.get(),
+ staging_resource_pool_.get());
break;
case TILE_TASK_WORKER_POOL_TYPE_GPU:
Create3dOutputSurfaceAndResourceProvider();
rasterizer_ = GpuRasterizer::Create(
context_provider_.get(), resource_provider_.get(), false, false, 0);
tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- TileTaskWorkerPool::GetTaskGraphRunner(),
+ base::MessageLoopProxy::current().get(), &task_graph_runner_,
static_cast<GpuRasterizer*>(rasterizer_.get()));
break;
case TILE_TASK_WORKER_POOL_TYPE_BITMAP:
CreateSoftwareOutputSurfaceAndResourceProvider();
tile_task_worker_pool_ = BitmapTileTaskWorkerPool::Create(
- base::MessageLoopProxy::current().get(),
- TileTaskWorkerPool::GetTaskGraphRunner(), resource_provider_.get());
+ base::MessageLoopProxy::current().get(), &task_graph_runner_,
+ resource_provider_.get());
break;
}
@@ -331,6 +331,7 @@
scoped_ptr<TileTaskWorkerPool> tile_task_worker_pool_;
TestGpuMemoryBufferManager gpu_memory_buffer_manager_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
base::CancelableClosure timeout_;
UniqueNotifier all_tile_tasks_finished_;
int timeout_seconds_;
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index 3b20b79..68214cd 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -304,24 +304,21 @@
}
void Scheduler::SetupNextBeginFrameIfNeeded() {
- if (!task_runner_.get())
- return;
-
- if (state_machine_.ShouldSetNeedsBeginFrames(
- frame_source_->NeedsBeginFrames())) {
- frame_source_->SetNeedsBeginFrames(state_machine_.BeginFrameNeeded());
- if (!frame_source_->NeedsBeginFrames()) {
+ // Never call SetNeedsBeginFrames if the frame source already has the right
+ // value.
+ if (frame_source_->NeedsBeginFrames() != state_machine_.BeginFrameNeeded()) {
+ if (state_machine_.BeginFrameNeeded()) {
+ // Call SetNeedsBeginFrames(true) as soon as possible.
+ frame_source_->SetNeedsBeginFrames(true);
+ } else if (state_machine_.begin_impl_frame_state() ==
+ SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE) {
+ // Call SetNeedsBeginFrames(false) in between frames only.
+ frame_source_->SetNeedsBeginFrames(false);
client_->SendBeginMainFrameNotExpectedSoon();
}
}
- if (state_machine_.begin_impl_frame_state() ==
- SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE) {
- frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
- }
-
PostBeginRetroFrameIfNeeded();
- SetupPollingMechanisms();
}
// We may need to poll when we can't rely on BeginFrame to advance certain
@@ -537,7 +534,7 @@
state_machine_.SetSkipNextBeginMainFrameToReduceLatency();
}
- state_machine_.OnBeginImplFrame(begin_impl_frame_args_);
+ state_machine_.OnBeginImplFrame();
devtools_instrumentation::DidBeginFrame(layer_tree_host_id_);
client_->WillBeginImplFrame(begin_impl_frame_args_);
@@ -627,19 +624,11 @@
"461509 Scheduler::OnBeginImplFrameDeadline1"));
state_machine_.OnBeginImplFrameDeadline();
ProcessScheduledActions();
-
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
- tracked_objects::ScopedTracker tracking_profile2(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::OnBeginImplFrameDeadline2"));
state_machine_.OnBeginImplFrameIdle();
ProcessScheduledActions();
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
- tracked_objects::ScopedTracker tracking_profile3(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::OnBeginImplFrameDeadline3"));
client_->DidBeginImplFrameDeadline();
+ frame_source_->DidFinishFrame(begin_retro_frame_args_.size());
}
void Scheduler::PollForAnticipatedDrawTriggers() {
@@ -679,10 +668,6 @@
SchedulerStateMachine::Action action;
do {
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
- tracked_objects::ScopedTracker tracking_profile1(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions1"));
action = state_machine_.NextAction();
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug.scheduler"),
"SchedulerStateMachine",
@@ -697,24 +682,12 @@
switch (action) {
case SchedulerStateMachine::ACTION_NONE:
break;
- case SchedulerStateMachine::ACTION_ANIMATE: {
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile2(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions2"));
+ case SchedulerStateMachine::ACTION_ANIMATE:
client_->ScheduledActionAnimate();
break;
- }
- case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME: {
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile3(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions3"));
+ case SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME:
client_->ScheduledActionSendBeginMainFrame();
break;
- }
case SchedulerStateMachine::ACTION_COMMIT: {
// TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
// fixed.
@@ -724,15 +697,9 @@
client_->ScheduledActionCommit();
break;
}
- case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE: {
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile5(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions5"));
+ case SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE:
client_->ScheduledActionActivateSyncTree();
break;
- }
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE: {
// TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
// fixed.
@@ -742,52 +709,29 @@
DrawAndSwapIfPossible();
break;
}
- case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED: {
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile7(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions7"));
+ case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_FORCED:
client_->ScheduledActionDrawAndSwapForced();
break;
- }
case SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT:
// No action is actually performed, but this allows the state machine to
// advance out of its waiting to draw state without actually drawing.
break;
- case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION: {
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile8(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions8"));
+ case SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION:
client_->ScheduledActionBeginOutputSurfaceCreation();
break;
- }
- case SchedulerStateMachine::ACTION_PREPARE_TILES: {
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is
- // fixed.
- tracked_objects::ScopedTracker tracking_profile9(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions9"));
+ case SchedulerStateMachine::ACTION_PREPARE_TILES:
client_->ScheduledActionPrepareTiles();
break;
- }
}
} while (action != SchedulerStateMachine::ACTION_NONE);
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
- tracked_objects::ScopedTracker tracking_profile10(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions10"));
- SetupNextBeginFrameIfNeeded();
+ SetupPollingMechanisms();
+
client_->DidAnticipatedDrawTimeChange(AnticipatedDrawTime());
- // TODO(robliao): Remove ScopedTracker below once crbug.com/461509 is fixed.
- tracked_objects::ScopedTracker tracking_profile11(
- FROM_HERE_WITH_EXPLICIT_FUNCTION(
- "461509 Scheduler::ProcessScheduledActions11"));
RescheduleBeginImplFrameDeadlineIfNeeded();
+
+ SetupNextBeginFrameIfNeeded();
}
scoped_refptr<base::trace_event::ConvertableToTraceFormat> Scheduler::AsValue()
@@ -800,7 +744,7 @@
void Scheduler::AsValueInto(base::trace_event::TracedValue* state) const {
state->BeginDictionary("state_machine");
- state_machine_.AsValueInto(state, Now());
+ state_machine_.AsValueInto(state);
state->EndDictionary();
// Only trace frame sources when explicitly enabled - http://crbug.com/420607
@@ -834,6 +778,23 @@
begin_impl_frame_args_.AsValueInto(state);
state->EndDictionary();
+ base::TimeTicks now = Now();
+ base::TimeTicks frame_time = begin_impl_frame_args_.frame_time;
+ base::TimeTicks deadline = begin_impl_frame_args_.deadline;
+ base::TimeDelta interval = begin_impl_frame_args_.interval;
+ state->BeginDictionary("major_timestamps_in_ms");
+ state->SetDouble("0_interval", interval.InMillisecondsF());
+ state->SetDouble("1_now_to_deadline", (deadline - now).InMillisecondsF());
+ state->SetDouble("2_frame_time_to_now", (now - frame_time).InMillisecondsF());
+ state->SetDouble("3_frame_time_to_deadline",
+ (deadline - frame_time).InMillisecondsF());
+ state->SetDouble("4_now", (now - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble("5_frame_time",
+ (frame_time - base::TimeTicks()).InMillisecondsF());
+ state->SetDouble("6_deadline",
+ (deadline - base::TimeTicks()).InMillisecondsF());
+ state->EndDictionary();
+
state->EndDictionary();
state->BeginDictionary("client_state");
diff --git a/cc/scheduler/scheduler_settings.cc b/cc/scheduler/scheduler_settings.cc
index 39a98b4..c6c8e8e 100644
--- a/cc/scheduler/scheduler_settings.cc
+++ b/cc/scheduler/scheduler_settings.cc
@@ -5,7 +5,6 @@
#include "cc/scheduler/scheduler_settings.h"
#include "base/trace_event/trace_event_argument.h"
-#include "cc/trees/layer_tree_settings.h"
namespace cc {
@@ -21,23 +20,6 @@
background_frame_interval(base::TimeDelta::FromSeconds(1)) {
}
-SchedulerSettings::SchedulerSettings(const LayerTreeSettings& settings)
- : use_external_begin_frame_source(settings.use_external_begin_frame_source),
- main_frame_before_activation_enabled(
- settings.main_frame_before_activation_enabled),
- impl_side_painting(settings.impl_side_painting),
- timeout_and_draw_when_animation_checkerboards(
- settings.timeout_and_draw_when_animation_checkerboards),
- maximum_number_of_failed_draws_before_draw_is_forced_(
- settings.maximum_number_of_failed_draws_before_draw_is_forced_),
- using_synchronous_renderer_compositor(
- settings.using_synchronous_renderer_compositor),
- throttle_frame_production(settings.throttle_frame_production),
- main_thread_should_always_be_low_latency(false),
- background_frame_interval(base::TimeDelta::FromSecondsD(
- 1.0 / settings.background_animation_rate)) {
-}
-
SchedulerSettings::~SchedulerSettings() {}
scoped_refptr<base::trace_event::ConvertableToTraceFormat>
diff --git a/cc/scheduler/scheduler_settings.h b/cc/scheduler/scheduler_settings.h
index 85f64e1..421409a 100644
--- a/cc/scheduler/scheduler_settings.h
+++ b/cc/scheduler/scheduler_settings.h
@@ -17,12 +17,10 @@
}
namespace cc {
-class LayerTreeSettings;
class CC_EXPORT SchedulerSettings {
public:
SchedulerSettings();
- explicit SchedulerSettings(const LayerTreeSettings& settings);
~SchedulerSettings();
bool use_external_begin_frame_source;
diff --git a/cc/scheduler/scheduler_state_machine.cc b/cc/scheduler/scheduler_state_machine.cc
index 189387c..c512987 100644
--- a/cc/scheduler/scheduler_state_machine.cc
+++ b/cc/scheduler/scheduler_state_machine.cc
@@ -26,6 +26,10 @@
last_frame_number_swap_performed_(-1),
last_frame_number_swap_requested_(-1),
last_frame_number_begin_main_frame_sent_(-1),
+ animate_funnel_(false),
+ perform_swap_funnel_(false),
+ request_swap_funnel_(false),
+ send_begin_main_frame_funnel_(false),
prepare_tiles_funnel_(0),
consecutive_checkerboard_animations_(0),
max_pending_swaps_(1),
@@ -41,14 +45,14 @@
has_pending_tree_(false),
pending_tree_is_ready_for_activation_(false),
active_tree_needs_first_draw_(false),
- did_commit_after_animating_(false),
did_create_and_initialize_first_output_surface_(false),
impl_latency_takes_priority_(false),
skip_next_begin_main_frame_to_reduce_latency_(false),
skip_begin_main_frame_to_reduce_latency_(false),
continuous_painting_(false),
children_need_begin_frames_(false),
- defer_commits_(false) {
+ defer_commits_(false),
+ last_commit_had_no_updates_(false) {
}
const char* SchedulerStateMachine::OutputSurfaceStateToString(
@@ -151,12 +155,12 @@
SchedulerStateMachine::AsValue() const {
scoped_refptr<base::trace_event::TracedValue> state =
new base::trace_event::TracedValue();
- AsValueInto(state.get(), gfx::FrameTime::Now());
+ AsValueInto(state.get());
return state;
}
-void SchedulerStateMachine::AsValueInto(base::trace_event::TracedValue* state,
- base::TimeTicks now) const {
+void SchedulerStateMachine::AsValueInto(
+ base::trace_event::TracedValue* state) const {
state->BeginDictionary("major_state");
state->SetString("next_action", ActionToString(NextAction()));
state->SetString("begin_impl_frame_state",
@@ -168,35 +172,9 @@
ForcedRedrawOnTimeoutStateToString(forced_redraw_state_));
state->EndDictionary();
- state->BeginDictionary("major_timestamps_in_ms");
- state->SetDouble("0_interval",
- begin_impl_frame_args_.interval.InMicroseconds() / 1000.0L);
- state->SetDouble(
- "1_now_to_deadline",
- (begin_impl_frame_args_.deadline - now).InMicroseconds() / 1000.0L);
- state->SetDouble(
- "2_frame_time_to_now",
- (now - begin_impl_frame_args_.frame_time).InMicroseconds() / 1000.0L);
- state->SetDouble("3_frame_time_to_deadline",
- (begin_impl_frame_args_.deadline -
- begin_impl_frame_args_.frame_time).InMicroseconds() /
- 1000.0L);
- state->SetDouble("4_now",
- (now - base::TimeTicks()).InMicroseconds() / 1000.0L);
- state->SetDouble(
- "5_frame_time",
- (begin_impl_frame_args_.frame_time - base::TimeTicks()).InMicroseconds() /
- 1000.0L);
- state->SetDouble(
- "6_deadline",
- (begin_impl_frame_args_.deadline - base::TimeTicks()).InMicroseconds() /
- 1000.0L);
- state->EndDictionary();
-
state->BeginDictionary("minor_state");
state->SetInteger("commit_count", commit_count_);
state->SetInteger("current_frame_number", current_frame_number_);
-
state->SetInteger("last_frame_number_animate_performed",
last_frame_number_animate_performed_);
state->SetInteger("last_frame_number_swap_performed",
@@ -205,8 +183,12 @@
last_frame_number_swap_requested_);
state->SetInteger("last_frame_number_begin_main_frame_sent",
last_frame_number_begin_main_frame_sent_);
-
- state->SetInteger("prepare_tiles_funnel", prepare_tiles_funnel_);
+ state->SetBoolean("funnel: animate_funnel", animate_funnel_);
+ state->SetBoolean("funnel: perform_swap_funnel", perform_swap_funnel_);
+ state->SetBoolean("funnel: request_swap_funnel", request_swap_funnel_);
+ state->SetBoolean("funnel: send_begin_main_frame_funnel",
+ send_begin_main_frame_funnel_);
+ state->SetInteger("funnel: prepare_tiles_funnel", prepare_tiles_funnel_);
state->SetInteger("consecutive_checkerboard_animations",
consecutive_checkerboard_animations_);
state->SetInteger("max_pending_swaps_", max_pending_swaps_);
@@ -223,7 +205,6 @@
pending_tree_is_ready_for_activation_);
state->SetBoolean("active_tree_needs_first_draw",
active_tree_needs_first_draw_);
- state->SetBoolean("did_commit_after_animating", did_commit_after_animating_);
state->SetBoolean("did_create_and_initialize_first_output_surface",
did_create_and_initialize_first_output_surface_);
state->SetBoolean("impl_latency_takes_priority",
@@ -243,6 +224,11 @@
void SchedulerStateMachine::AdvanceCurrentFrameNumber() {
current_frame_number_++;
+ animate_funnel_ = false;
+ perform_swap_funnel_ = false;
+ request_swap_funnel_ = false;
+ send_begin_main_frame_funnel_ = false;
+
// "Drain" the PrepareTiles funnel.
if (prepare_tiles_funnel_ > 0)
prepare_tiles_funnel_--;
@@ -252,23 +238,6 @@
skip_next_begin_main_frame_to_reduce_latency_ = false;
}
-bool SchedulerStateMachine::HasAnimatedThisFrame() const {
- return last_frame_number_animate_performed_ == current_frame_number_;
-}
-
-bool SchedulerStateMachine::HasSentBeginMainFrameThisFrame() const {
- return current_frame_number_ ==
- last_frame_number_begin_main_frame_sent_;
-}
-
-bool SchedulerStateMachine::HasSwappedThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_performed_;
-}
-
-bool SchedulerStateMachine::HasRequestedSwapThisFrame() const {
- return current_frame_number_ == last_frame_number_swap_requested_;
-}
-
bool SchedulerStateMachine::PendingDrawsShouldBeAborted() const {
// These are all the cases where we normally cannot or do not want to draw
// but, if needs_redraw_ is true and we do not draw to make forward progress,
@@ -341,19 +310,16 @@
if (PendingDrawsShouldBeAborted())
return active_tree_needs_first_draw_;
+ // Do not draw too many times in a single frame. It's okay that we don't check
+ // this before checking for aborted draws because aborted draws do not request
+ // a swap.
+ if (request_swap_funnel_)
+ return false;
+
// Don't draw if we are waiting on the first commit after a surface.
if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false;
- // If a commit has occurred after the animate call, we need to call animate
- // again before we should draw.
- if (did_commit_after_animating_)
- return false;
-
- // After this line, we only want to send a swap request once per frame.
- if (HasRequestedSwapThisFrame())
- return false;
-
// Do not queue too many swaps.
if (pending_swaps_ >= max_pending_swaps_)
return false;
@@ -390,12 +356,12 @@
}
bool SchedulerStateMachine::ShouldAnimate() const {
- // Don't animate if we are waiting on the first commit after a surface.
- if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
+ // Do not animate too many times in a single frame.
+ if (animate_funnel_)
return false;
- // If a commit occurred after our last call, we need to do animation again.
- if (HasAnimatedThisFrame() && !did_commit_after_animating_)
+ // Don't animate if we are waiting on the first commit after a surface.
+ if (output_surface_state_ != OUTPUT_SURFACE_ACTIVE)
return false;
if (begin_impl_frame_state_ != BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING &&
@@ -406,6 +372,10 @@
}
bool SchedulerStateMachine::CouldSendBeginMainFrame() const {
+ // Do not send begin main frame too many times in a single frame.
+ if (send_begin_main_frame_funnel_)
+ return false;
+
if (!needs_commit_)
return false;
@@ -449,10 +419,6 @@
if (forced_redraw_state_ == FORCED_REDRAW_STATE_WAITING_FOR_COMMIT)
return true;
- // After this point, we only start a commit once per frame.
- if (HasSentBeginMainFrameThisFrame())
- return false;
-
// We shouldn't normally accept commits if there isn't an OutputSurface.
if (!HasInitializedOutputSurface())
return false;
@@ -461,7 +427,7 @@
// TODO(brianderson): Remove this restriction to improve throughput.
bool just_swapped_in_deadline =
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE &&
- HasSwappedThisFrame();
+ perform_swap_funnel_;
if (pending_swaps_ >= max_pending_swaps_ && !just_swapped_in_deadline)
return false;
@@ -538,9 +504,10 @@
return;
case ACTION_ANIMATE:
+ DCHECK(!animate_funnel_);
last_frame_number_animate_performed_ = current_frame_number_;
+ animate_funnel_ = true;
needs_animate_ = false;
- did_commit_after_animating_ = false;
// TODO(skyostil): Instead of assuming this, require the client to tell
// us.
SetNeedsRedraw();
@@ -550,8 +517,10 @@
DCHECK(!has_pending_tree_ ||
settings_.main_frame_before_activation_enabled);
DCHECK(visible_);
+ DCHECK(!send_begin_main_frame_funnel_);
commit_state_ = COMMIT_STATE_BEGIN_MAIN_FRAME_SENT;
needs_commit_ = false;
+ send_begin_main_frame_funnel_ = true;
last_frame_number_begin_main_frame_sent_ =
current_frame_number_;
return;
@@ -596,8 +565,8 @@
void SchedulerStateMachine::UpdateStateOnCommit(bool commit_has_no_updates) {
commit_count_++;
- if (!commit_has_no_updates && HasAnimatedThisFrame())
- did_commit_after_animating_ = true;
+ if (!commit_has_no_updates)
+ animate_funnel_ = false;
if (commit_has_no_updates || settings_.main_frame_before_activation_enabled) {
commit_state_ = COMMIT_STATE_IDLE;
@@ -645,6 +614,7 @@
if (continuous_painting_)
needs_commit_ = true;
+ last_commit_had_no_updates_ = commit_has_no_updates;
}
void SchedulerStateMachine::UpdateStateOnActivation() {
@@ -676,8 +646,11 @@
needs_redraw_ = false;
active_tree_needs_first_draw_ = false;
- if (did_request_swap)
+ if (did_request_swap) {
+ DCHECK(!request_swap_funnel_);
+ request_swap_funnel_ = true;
last_frame_number_swap_requested_ = current_frame_number_;
+ }
}
void SchedulerStateMachine::UpdateStateOnPrepareTiles() {
@@ -720,29 +693,6 @@
return BeginFrameNeededToAnimateOrDraw();
}
-bool SchedulerStateMachine::ShouldSetNeedsBeginFrames(
- bool frame_source_needs_begin_frames) const {
- bool needs_begin_frame = BeginFrameNeeded();
-
- // Never call SetNeedsBeginFrames if the frame source has the right value.
- if (needs_begin_frame == frame_source_needs_begin_frames)
- return false;
-
- // Always request the BeginFrame immediately if it's needed.
- if (needs_begin_frame)
- return true;
-
- // Stop requesting BeginFrames after a deadline.
- if (begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_DEADLINE)
- return true;
-
- // Stop requesting BeginFrames immediately when output surface is lost.
- if (!HasInitializedOutputSurface())
- return true;
-
- return false;
-}
-
bool SchedulerStateMachine::ShouldPollForAnticipatedDrawTriggers() const {
// ShouldPollForAnticipatedDrawTriggers is what we use in place of
// ProactiveBeginFrameWanted when we are using the synchronous
@@ -815,18 +765,23 @@
// SetNeedsBeginFrame requests, which may propagate to the BeginImplFrame
// provider and get sampled at an inopportune time, delaying the next
// BeginImplFrame.
- if (HasRequestedSwapThisFrame())
+ if (request_swap_funnel_)
+ return true;
+
+ // If the last commit was aborted because of early out (no updates), we should
+ // still want a begin frame in case there is a commit coming again.
+ if (last_commit_had_no_updates_)
return true;
return false;
}
-void SchedulerStateMachine::OnBeginImplFrame(const BeginFrameArgs& args) {
+void SchedulerStateMachine::OnBeginImplFrame() {
AdvanceCurrentFrameNumber();
- begin_impl_frame_args_ = args;
DCHECK_EQ(begin_impl_frame_state_, BEGIN_IMPL_FRAME_STATE_IDLE)
<< AsValue()->ToString();
begin_impl_frame_state_ = BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING;
+ last_commit_had_no_updates_ = false;
}
void SchedulerStateMachine::OnBeginImplFrameDeadlinePending() {
@@ -910,7 +865,7 @@
// If we just sent a BeginMainFrame and haven't hit the deadline yet, the main
// thread is in a low latency mode.
- if (HasSentBeginMainFrameThisFrame() &&
+ if (send_begin_main_frame_funnel_ &&
(begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING ||
begin_impl_frame_state_ == BEGIN_IMPL_FRAME_STATE_INSIDE_BEGIN_FRAME))
return false;
@@ -934,8 +889,8 @@
// Even if there's a new active tree to draw at the deadline or we've just
// swapped it, it may have been triggered by a previous BeginImplFrame, in
// which case the main thread is in a high latency mode.
- return (active_tree_needs_first_draw_ || HasSwappedThisFrame()) &&
- !HasSentBeginMainFrameThisFrame();
+ return (active_tree_needs_first_draw_ || perform_swap_funnel_) &&
+ !send_begin_main_frame_funnel_;
}
// If the active tree needs its first draw in any other state, we know the
@@ -976,7 +931,9 @@
void SchedulerStateMachine::DidSwapBuffers() {
pending_swaps_++;
DCHECK_LE(pending_swaps_, max_pending_swaps_);
+ DCHECK(!perform_swap_funnel_);
+ perform_swap_funnel_ = true;
last_frame_number_swap_performed_ = current_frame_number_;
}
diff --git a/cc/scheduler/scheduler_state_machine.h b/cc/scheduler/scheduler_state_machine.h
index a411022..3914039 100644
--- a/cc/scheduler/scheduler_state_machine.h
+++ b/cc/scheduler/scheduler_state_machine.h
@@ -9,7 +9,6 @@
#include "base/basictypes.h"
#include "base/memory/scoped_ptr.h"
-#include "base/time/time.h"
#include "cc/base/cc_export.h"
#include "cc/output/begin_frame_args.h"
#include "cc/scheduler/commit_earlyout_reason.h"
@@ -115,8 +114,7 @@
static const char* ActionToString(Action action);
scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const;
- void AsValueInto(base::trace_event::TracedValue* dict,
- base::TimeTicks now) const;
+ void AsValueInto(base::trace_event::TracedValue* dict) const;
Action NextAction() const;
void UpdateState(Action action);
@@ -125,10 +123,6 @@
// to make progress.
bool BeginFrameNeeded() const;
- // Indicates whether the scheduler should call
- // SetNeedsBeginFrames(BeginFrameNeeded()) on the frame source.
- bool ShouldSetNeedsBeginFrames(bool frame_source_needs_begin_frames) const;
-
// Indicates that we need to independently poll for new state and actions
// because we can't expect a BeginImplFrame. This is mostly used to avoid
// drawing repeat frames with the synchronous compositor without dropping
@@ -138,7 +132,7 @@
// Indicates that the system has entered and left a BeginImplFrame callback.
// The scheduler will not draw more than once in a given BeginImplFrame
// callback nor send more than one BeginMainFrame message.
- void OnBeginImplFrame(const BeginFrameArgs& args);
+ void OnBeginImplFrame();
void OnBeginImplFrameDeadlinePending();
void OnBeginImplFrameDeadline();
void OnBeginImplFrameIdle();
@@ -284,10 +278,6 @@
bool ShouldPrepareTiles() const;
void AdvanceCurrentFrameNumber();
- bool HasAnimatedThisFrame() const;
- bool HasSentBeginMainFrameThisFrame() const;
- bool HasRequestedSwapThisFrame() const;
- bool HasSwappedThisFrame() const;
void UpdateStateOnCommit(bool commit_had_no_updates);
void UpdateStateOnActivation();
@@ -301,8 +291,7 @@
CommitState commit_state_;
ForcedRedrawOnTimeoutState forced_redraw_state_;
- BeginFrameArgs begin_impl_frame_args_;
-
+ // These are used for tracing only.
int commit_count_;
int current_frame_number_;
int last_frame_number_animate_performed_;
@@ -310,11 +299,18 @@
int last_frame_number_swap_requested_;
int last_frame_number_begin_main_frame_sent_;
+ // These are used to ensure that an action only happens once per frame,
+ // deadline, etc.
+ bool animate_funnel_;
+ bool perform_swap_funnel_;
+ bool request_swap_funnel_;
+ bool send_begin_main_frame_funnel_;
// prepare_tiles_funnel_ is "filled" each time PrepareTiles is called
// and "drained" on each BeginImplFrame. If the funnel gets too full,
// we start throttling ACTION_PREPARE_TILES such that we average one
// PrepareTiles per BeginImplFrame.
int prepare_tiles_funnel_;
+
int consecutive_checkerboard_animations_;
int max_pending_swaps_;
int pending_swaps_;
@@ -329,7 +325,6 @@
bool has_pending_tree_;
bool pending_tree_is_ready_for_activation_;
bool active_tree_needs_first_draw_;
- bool did_commit_after_animating_;
bool did_create_and_initialize_first_output_surface_;
bool impl_latency_takes_priority_;
bool skip_next_begin_main_frame_to_reduce_latency_;
@@ -337,6 +332,7 @@
bool continuous_painting_;
bool children_need_begin_frames_;
bool defer_commits_;
+ bool last_commit_had_no_updates_;
private:
DISALLOW_COPY_AND_ASSIGN(SchedulerStateMachine);
diff --git a/cc/scheduler/scheduler_state_machine_unittest.cc b/cc/scheduler/scheduler_state_machine_unittest.cc
index 98d5b18..4c2c267 100644
--- a/cc/scheduler/scheduler_state_machine_unittest.cc
+++ b/cc/scheduler/scheduler_state_machine_unittest.cc
@@ -132,6 +132,8 @@
}
using SchedulerStateMachine::ShouldTriggerBeginImplFrameDeadlineImmediately;
+ using SchedulerStateMachine::ProactiveBeginFrameWanted;
+ using SchedulerStateMachine::UpdateStateOnCommit;
};
TEST(SchedulerStateMachineTest, TestNextActionBeginsMainFrameIfNeeded) {
@@ -152,8 +154,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -171,8 +172,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
}
@@ -190,8 +190,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -224,7 +223,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
// Commit to the pending tree.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -240,7 +239,7 @@
// Verify that the next commit starts while there is still a pending tree.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -277,7 +276,7 @@
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -294,7 +293,7 @@
// Failing the draw makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -310,7 +309,7 @@
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -324,7 +323,7 @@
// Missing high res content requires a commit (but not a redraw)
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_MISSING_HIGH_RES_CONTENT);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_FALSE(state.RedrawPending());
@@ -339,7 +338,7 @@
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.RedrawPending());
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -360,7 +359,7 @@
// Failing the draw for animation checkerboards makes us require a commit.
state.DidDrawIfPossibleCompleted(DRAW_ABORTED_CHECKERBOARD_ANIMATIONS);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -377,7 +376,7 @@
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -407,7 +406,7 @@
EXPECT_TRUE(state.RedrawPending());
// The redraw should be forced at the end of the next BeginImplFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -431,7 +430,7 @@
// Start a commit.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -484,7 +483,7 @@
// Start a draw.
state.SetNeedsRedraw(true);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -501,7 +500,7 @@
// We should not be trying to draw again now, but we have a commit pending.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -523,7 +522,7 @@
// Draw the first frame.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -542,7 +541,7 @@
// Move to another frame. This should now draw.
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -677,8 +676,7 @@
state.SetVisible(false);
state.SetNeedsRedraw(true);
if (j == 1)
- state.OnBeginImplFrame(
- CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
state.SetCanDraw(false);
EXPECT_NE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_IF_POSSIBLE,
@@ -700,7 +698,7 @@
state.SetNeedsRedraw(true);
state.SetVisible(true);
state.SetCanDraw(false);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_DRAW_AND_SWAP_ABORT);
EXPECT_ACTION_UPDATE_STATE(
@@ -724,7 +722,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_COMMIT_STATE(
@@ -758,7 +756,7 @@
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
EXPECT_ACTION(SchedulerStateMachine::ACTION_COMMIT);
@@ -791,7 +789,7 @@
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_COMMIT_STATE(
@@ -837,7 +835,7 @@
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_COMMIT_STATE(
@@ -867,7 +865,7 @@
// Haven't draw since last commit, do not begin new main frame.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -898,7 +896,7 @@
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_COMMIT_STATE(
@@ -929,7 +927,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Cannot BeginMainFrame yet since last commit is not yet activated and drawn.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_COMMIT_STATE(
SchedulerStateMachine::COMMIT_STATE_WAITING_FOR_ACTIVATION);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -950,7 +948,7 @@
state.DidSwapBuffersComplete();
// Haven't draw since last commit, do not begin new main frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -978,7 +976,7 @@
state.SetNeedsCommit();
// Begin the frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_COMMIT_STATE(
@@ -1018,7 +1016,7 @@
EXPECT_FALSE(state.needs_redraw());
// Next BeginImplFrame should initiate second commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1044,7 +1042,7 @@
state.SetNeedsCommit();
// Begin the frame while visible.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_COMMIT_STATE(
@@ -1078,7 +1076,7 @@
EXPECT_TRUE(state.NeedsCommit());
// Start a new frame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1100,7 +1098,7 @@
// Get into a begin frame / commit state.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_COMMIT_STATE(
@@ -1129,7 +1127,7 @@
EXPECT_FALSE(state.NeedsCommit());
EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1137,7 +1135,7 @@
// Verify another commit can start if requested, though.
state.SetNeedsCommit();
EXPECT_COMMIT_STATE(SchedulerStateMachine::COMMIT_STATE_IDLE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1154,14 +1152,14 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that the first init does not SetNeedsCommit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Check that a needs commit initiates a BeginMainFrame.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1185,7 +1183,7 @@
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
// When the context is recreated, we should begin a commit.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1209,14 +1207,14 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// Once context recreation begins, nothing should happen.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// While context is recreating, commits shouldn't begin.
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1232,7 +1230,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
// When the BeginFrame comes in we should begin a commit
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1258,7 +1256,7 @@
// Finishing the first commit after initializing an output surface should
// automatically cause a redraw.
EXPECT_TRUE(state.RedrawPending());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -1268,7 +1266,7 @@
EXPECT_FALSE(state.RedrawPending());
// Next frame as no work to do.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1276,7 +1274,7 @@
// Once the context is recreated, whether we draw should be based on
// SetCanDraw if waiting on first draw after activate.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
@@ -1292,7 +1290,7 @@
// SetCanDraw if waiting on first draw after activate.
state.SetNeedsRedraw(true);
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1326,7 +1324,7 @@
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1359,7 +1357,7 @@
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
@@ -1387,7 +1385,7 @@
// Set damage and expect a draw.
state.SetNeedsRedraw(true);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1420,7 +1418,7 @@
EXPECT_IMPL_FRAME_STATE(SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_IDLE);
EXPECT_ACTION(SchedulerStateMachine::ACTION_BEGIN_OUTPUT_SURFACE_CREATION);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_IMPL_FRAME_STATE(
SchedulerStateMachine::BEGIN_IMPL_FRAME_STATE_BEGIN_FRAME_STARTING);
EXPECT_ACTION(SchedulerStateMachine::ACTION_NONE);
@@ -1441,7 +1439,7 @@
// After we get a new output surface, the commit flow should start.
state.CreateAndInitializeOutputSurfaceWithActivatedCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1472,7 +1470,7 @@
state.DidCreateAndInitializeOutputSurface();
EXPECT_FALSE(state.RedrawPending());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION(SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
@@ -1586,7 +1584,7 @@
// This test mirrors what happens during the first frame of a scroll gesture.
// First we get the input event and a BeginFrame.
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
// As a response the compositor requests a redraw and a commit to tell the
// main thread about the new scroll offset.
@@ -1621,7 +1619,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ACTIVATE_SYNC_TREE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1642,7 +1640,7 @@
// in prefer impl latency mode.
state.SetNeedsRedraw(true);
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1679,7 +1677,7 @@
// and did not just swap.
state.SetNeedsCommit();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_FALSE(state.ShouldTriggerBeginImplFrameDeadlineImmediately());
state.OnBeginImplFrameDeadline();
@@ -1694,7 +1692,7 @@
state.SetNeedsCommit();
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
@@ -1717,7 +1715,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.OnBeginImplFrameDeadlinePending();
@@ -1739,7 +1737,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1763,7 +1761,7 @@
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
EXPECT_TRUE(state.BeginFrameNeeded());
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
@@ -1791,7 +1789,7 @@
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_ANIMATE);
state.SetNeedsAnimate();
@@ -1823,17 +1821,30 @@
EXPECT_TRUE(state.BeginFrameNeeded());
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.OnBeginImplFrameDeadline();
EXPECT_ACTION_UPDATE_STATE(SchedulerStateMachine::ACTION_NONE);
state.SetDeferCommits(false);
- state.OnBeginImplFrame(CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE));
+ state.OnBeginImplFrame();
EXPECT_ACTION_UPDATE_STATE(
SchedulerStateMachine::ACTION_SEND_BEGIN_MAIN_FRAME);
}
+TEST(SchedulerStateMachineTest, EarlyOutCommitWantsProactiveBeginFrame) {
+ SchedulerSettings settings;
+ StateMachine state(settings);
+ SET_UP_STATE(state);
+
+ EXPECT_FALSE(state.ProactiveBeginFrameWanted());
+ bool commit_has_no_updates = true;
+ state.UpdateStateOnCommit(commit_has_no_updates);
+ EXPECT_TRUE(state.ProactiveBeginFrameWanted());
+ state.OnBeginImplFrame();
+ EXPECT_FALSE(state.ProactiveBeginFrameWanted());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index 55f2164..b59359c 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -1752,9 +1752,8 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
- // Do nothing when impl frame is in deadine pending state.
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted();
@@ -1762,8 +1761,10 @@
EXPECT_ACTION("ScheduledActionCommit", client_, 0, 1);
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
void SchedulerTest::DidLoseOutputSurfaceAfterBeginFrameStartedWithHighLatency(
@@ -1785,19 +1786,20 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
// Do nothing when impl frame is in deadine pending state.
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_NO_ACTION(client_);
client_->Reset();
// Run posted deadline.
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
- // OnBeginImplFrameDeadline didn't schedule any actions because main frame is
- // not yet completed.
- EXPECT_NO_ACTION(client_);
+ // OnBeginImplFrameDeadline didn't schedule output surface creation because
+ // main frame is not yet completed.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
// BeginImplFrame is not started.
+ client_->Reset();
task_runner().RunUntilTime(now_src()->Now() +
base::TimeDelta::FromMilliseconds(10));
EXPECT_NO_ACTION(client_);
@@ -1851,19 +1853,19 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
if (impl_side_painting) {
// Sync tree should be forced to activate.
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 0, 3);
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+ EXPECT_SINGLE_ACTION("ScheduledActionActivateSyncTree", client_);
} else {
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_NO_ACTION(client_);
}
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
}
TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterReadyToCommit) {
@@ -1890,13 +1892,15 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 0, 2);
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 1, 2);
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionPrepareTiles", client_, 0, 4);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 1, 4);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 2, 4);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 3, 4);
}
TEST_F(SchedulerTest, DidLoseOutputSurfaceAfterBeginRetroFramePosted) {
@@ -2004,14 +2008,15 @@
client_->Reset();
EXPECT_FALSE(scheduler_->IsBeginRetroFrameArgsEmpty());
scheduler_->DidLoseOutputSurface();
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
- EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ EXPECT_NO_ACTION(client_);
EXPECT_TRUE(scheduler_->IsBeginRetroFrameArgsEmpty());
// BeginImplFrame deadline should abort drawing.
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
EXPECT_FALSE(client_->needs_begin_frames());
@@ -2021,8 +2026,7 @@
EXPECT_NO_ACTION(client_);
}
-TEST_F(SchedulerTest,
- StopBeginFrameAfterDidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
+TEST_F(SchedulerTest, DidLoseOutputSurfaceWithSyntheticBeginFrameSource) {
SetUpScheduler(true);
// SetNeedsCommit should begin the frame on the next BeginImplFrame.
@@ -2031,7 +2035,7 @@
EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted Tick.
+ AdvanceFrame();
EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
@@ -2046,15 +2050,49 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("SendBeginMainFrameNotExpectedSoon", client_);
- EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames());
+ // SetNeedsBeginFrames(false) is not called until the end of the frame.
+ EXPECT_NO_ACTION(client_);
+ EXPECT_TRUE(scheduler_->frame_source().NeedsBeginFrames());
client_->Reset();
- task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_);
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames());
}
+TEST_F(SchedulerTest, DidLoseOutputSurfaceWhenIdle) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // SetNeedsCommit should begin the frame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+
+ client_->Reset();
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 2);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+
+ client_->Reset();
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ EXPECT_SINGLE_ACTION("ScheduledActionCommit", client_);
+
+ client_->Reset();
+ task_runner().RunTasksWhile(client_->ImplFrameDeadlinePending(true));
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 0, 2);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 1, 2);
+
+ // Idle time between BeginFrames.
+ client_->Reset();
+ scheduler_->DidLoseOutputSurface();
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
+}
+
TEST_F(SchedulerTest, ScheduledActionActivateAfterBecomingInvisible) {
scheduler_settings_.impl_side_painting = true;
scheduler_settings_.use_external_begin_frame_source = true;
diff --git a/cc/surfaces/surface_display_output_surface.cc b/cc/surfaces/surface_display_output_surface.cc
index c07eece..0493724 100644
--- a/cc/surfaces/surface_display_output_surface.cc
+++ b/cc/surfaces/surface_display_output_surface.cc
@@ -25,6 +25,7 @@
allocator_(allocator) {
capabilities_.delegated_rendering = true;
capabilities_.max_frames_pending = 1;
+ capabilities_.adjust_deadline_for_parent = true;
capabilities_.can_force_reclaim_resources = true;
}
diff --git a/cc/test/fake_layer_tree_host.cc b/cc/test/fake_layer_tree_host.cc
index fe0351d..143d22e 100644
--- a/cc/test/fake_layer_tree_host.cc
+++ b/cc/test/fake_layer_tree_host.cc
@@ -7,9 +7,9 @@
namespace cc {
FakeLayerTreeHost::FakeLayerTreeHost(FakeLayerTreeHostClient* client,
const LayerTreeSettings& settings)
- : LayerTreeHost(client, NULL, NULL, settings),
+ : LayerTreeHost(client, NULL, NULL, NULL, settings),
client_(client),
- host_impl_(settings, &proxy_, &manager_),
+ host_impl_(settings, &proxy_, &manager_, nullptr),
needs_commit_(false) {
client_->SetLayerTreeHost(this);
}
diff --git a/cc/test/fake_layer_tree_host_impl.cc b/cc/test/fake_layer_tree_host_impl.cc
index ccfb203..d026120 100644
--- a/cc/test/fake_layer_tree_host_impl.cc
+++ b/cc/test/fake_layer_tree_host_impl.cc
@@ -10,13 +10,15 @@
namespace cc {
FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(Proxy* proxy,
- SharedBitmapManager* manager)
+ SharedBitmapManager* manager,
+ TaskGraphRunner* task_graph_runner)
: LayerTreeHostImpl(LayerTreeSettings(),
&client_,
proxy,
&stats_instrumentation_,
manager,
NULL,
+ task_graph_runner,
0) {
// Explicitly clear all debug settings.
SetDebugState(LayerTreeDebugState());
@@ -30,13 +32,15 @@
FakeLayerTreeHostImpl::FakeLayerTreeHostImpl(const LayerTreeSettings& settings,
Proxy* proxy,
- SharedBitmapManager* manager)
+ SharedBitmapManager* manager,
+ TaskGraphRunner* task_graph_runner)
: LayerTreeHostImpl(settings,
&client_,
proxy,
&stats_instrumentation_,
manager,
NULL,
+ task_graph_runner,
0) {
// Explicitly clear all debug settings.
SetDebugState(LayerTreeDebugState());
diff --git a/cc/test/fake_layer_tree_host_impl.h b/cc/test/fake_layer_tree_host_impl.h
index fe9bc4f..9c8f649 100644
--- a/cc/test/fake_layer_tree_host_impl.h
+++ b/cc/test/fake_layer_tree_host_impl.h
@@ -14,10 +14,13 @@
class FakeLayerTreeHostImpl : public LayerTreeHostImpl {
public:
- FakeLayerTreeHostImpl(Proxy* proxy, SharedBitmapManager* manager);
+ FakeLayerTreeHostImpl(Proxy* proxy,
+ SharedBitmapManager* manager,
+ TaskGraphRunner* task_graph_runner);
FakeLayerTreeHostImpl(const LayerTreeSettings& settings,
Proxy* proxy,
- SharedBitmapManager* manager);
+ SharedBitmapManager* manager,
+ TaskGraphRunner* task_graph_runner);
~FakeLayerTreeHostImpl() override;
void ForcePrepareToDraw() {
@@ -36,6 +39,7 @@
using LayerTreeHostImpl::ActivateSyncTree;
using LayerTreeHostImpl::prepare_tiles_needed;
+ using LayerTreeHostImpl::is_likely_to_require_a_draw;
private:
BeginFrameArgs current_begin_frame_args_;
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index 5ac6f69..75f7fda 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -132,6 +132,7 @@
DCHECK(layer_tree_impl()->IsPendingTree());
Region invalidation_temp = invalidation;
const PictureLayerTilingSet* pending_set = nullptr;
+ set_gpu_raster_max_texture_size(layer_tree_impl()->device_viewport_size());
UpdateRasterSource(raster_source, &invalidation_temp, pending_set);
}
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index 115fe55..ca29b9b 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -83,6 +83,10 @@
using PictureLayerImpl::UpdateIdealScales;
using PictureLayerImpl::MaximumTilingContentsScale;
+ void AddTilingUntilNextDraw(float scale) {
+ last_append_quads_tilings_.push_back(AddTiling(scale));
+ }
+
float raster_page_scale() const { return raster_page_scale_; }
void set_raster_page_scale(float scale) { raster_page_scale_ = scale; }
diff --git a/cc/test/fake_ui_resource_layer_tree_host_impl.cc b/cc/test/fake_ui_resource_layer_tree_host_impl.cc
index 9e7adde..43617a6 100644
--- a/cc/test/fake_ui_resource_layer_tree_host_impl.cc
+++ b/cc/test/fake_ui_resource_layer_tree_host_impl.cc
@@ -12,7 +12,9 @@
FakeUIResourceLayerTreeHostImpl::FakeUIResourceLayerTreeHostImpl(
Proxy* proxy,
SharedBitmapManager* manager)
- : FakeLayerTreeHostImpl(proxy, manager), fake_next_resource_id_(1) {}
+ : FakeLayerTreeHostImpl(proxy, manager, nullptr),
+ fake_next_resource_id_(1) {
+}
FakeUIResourceLayerTreeHostImpl::~FakeUIResourceLayerTreeHostImpl() {}
diff --git a/cc/test/layer_tree_json_parser_unittest.cc b/cc/test/layer_tree_json_parser_unittest.cc
index a11d545..8286a0f 100644
--- a/cc/test/layer_tree_json_parser_unittest.cc
+++ b/cc/test/layer_tree_json_parser_unittest.cc
@@ -65,7 +65,7 @@
TEST_F(LayerTreeJsonParserSanityCheck, Basic) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
LayerTreeImpl* tree = host_impl.active_tree();
scoped_ptr<LayerImpl> root_impl(LayerImpl::Create(tree, 1));
@@ -94,7 +94,7 @@
TEST_F(LayerTreeJsonParserSanityCheck, EventHandlerRegions) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
LayerTreeImpl* tree = host_impl.active_tree();
scoped_ptr<LayerImpl> root_impl(LayerImpl::Create(tree, 1));
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index 6b6c00b..2e12953 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -171,8 +171,7 @@
draw_texture_target_);
*tile_task_worker_pool = BitmapTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
- resource_provider);
+ task_runner, task_graph_runner(), resource_provider);
break;
case GPU_TILE_TASK_WORKER_POOL:
EXPECT_TRUE(context_provider);
@@ -182,7 +181,7 @@
draw_texture_target_);
*tile_task_worker_pool = GpuTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
+ task_runner, task_graph_runner(),
static_cast<GpuRasterizer*>(host_impl->rasterizer()));
break;
case ZERO_COPY_TILE_TASK_WORKER_POOL:
@@ -193,8 +192,7 @@
ResourcePool::Create(resource_provider, draw_texture_target_);
*tile_task_worker_pool = ZeroCopyTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
- resource_provider);
+ task_runner, task_graph_runner(), resource_provider);
break;
case ONE_COPY_TILE_TASK_WORKER_POOL:
EXPECT_TRUE(context_provider);
@@ -207,8 +205,8 @@
ResourcePool::Create(resource_provider, draw_texture_target_);
*tile_task_worker_pool = OneCopyTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
- context_provider, resource_provider, staging_resource_pool->get());
+ task_runner, task_graph_runner(), context_provider, resource_provider,
+ staging_resource_pool->get());
break;
case PIXEL_BUFFER_TILE_TASK_WORKER_POOL:
EXPECT_TRUE(context_provider);
@@ -217,8 +215,8 @@
resource_provider, draw_texture_target_);
*tile_task_worker_pool = PixelBufferTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
- context_provider, resource_provider, max_transfer_buffer_usage_bytes);
+ task_runner, task_graph_runner(), context_provider, resource_provider,
+ max_transfer_buffer_usage_bytes);
break;
}
}
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 3c6ff57..2fff95f 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -22,6 +22,7 @@
#include "cc/test/test_context_provider.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/tiled_layer_test_common.h"
#include "cc/trees/layer_tree_host_client.h"
#include "cc/trees/layer_tree_host_impl.h"
@@ -209,15 +210,11 @@
Proxy* proxy,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
RenderingStatsInstrumentation* stats_instrumentation) {
- return make_scoped_ptr(
- new LayerTreeHostImplForTesting(test_hooks,
- settings,
- host_impl_client,
- proxy,
- shared_bitmap_manager,
- gpu_memory_buffer_manager,
- stats_instrumentation));
+ return make_scoped_ptr(new LayerTreeHostImplForTesting(
+ test_hooks, settings, host_impl_client, proxy, shared_bitmap_manager,
+ gpu_memory_buffer_manager, task_graph_runner, stats_instrumentation));
}
protected:
@@ -228,6 +225,7 @@
Proxy* proxy,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
RenderingStatsInstrumentation* stats_instrumentation)
: LayerTreeHostImpl(settings,
host_impl_client,
@@ -235,6 +233,7 @@
stats_instrumentation,
shared_bitmap_manager,
gpu_memory_buffer_manager,
+ task_graph_runner,
0),
test_hooks_(test_hooks),
block_notify_ready_to_activate_for_testing_(false),
@@ -455,12 +454,17 @@
static scoped_ptr<LayerTreeHostForTesting> Create(
TestHooks* test_hooks,
LayerTreeHostClientForTesting* client,
+ SharedBitmapManager* shared_bitmap_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_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));
+ new LayerTreeHostForTesting(test_hooks, client, shared_bitmap_manager,
+ gpu_memory_buffer_manager,
+ task_graph_runner, settings));
if (impl_task_runner.get()) {
layer_tree_host->InitializeForTesting(
ThreadProxyForTest::Create(test_hooks,
@@ -483,12 +487,8 @@
scoped_ptr<LayerTreeHostImpl> CreateLayerTreeHostImpl(
LayerTreeHostImplClient* host_impl_client) override {
return LayerTreeHostImplForTesting::Create(
- test_hooks_,
- settings(),
- host_impl_client,
- proxy(),
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
+ test_hooks_, settings(), host_impl_client, proxy(),
+ shared_bitmap_manager_, gpu_memory_buffer_manager_, task_graph_runner_,
rendering_stats_instrumentation());
}
@@ -501,17 +501,23 @@
void set_test_started(bool started) { test_started_ = started; }
private:
- LayerTreeHostForTesting(TestHooks* test_hooks,
- LayerTreeHostClient* client,
- const LayerTreeSettings& settings)
- : LayerTreeHost(client, NULL, NULL, settings),
- shared_bitmap_manager_(new TestSharedBitmapManager),
- gpu_memory_buffer_manager_(new TestGpuMemoryBufferManager),
+ LayerTreeHostForTesting(
+ TestHooks* test_hooks,
+ LayerTreeHostClient* client,
+ SharedBitmapManager* shared_bitmap_manager,
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
+ const LayerTreeSettings& settings)
+ : LayerTreeHost(client, NULL, NULL, NULL, settings),
+ shared_bitmap_manager_(shared_bitmap_manager),
+ gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ task_graph_runner_(task_graph_runner),
test_hooks_(test_hooks),
test_started_(false) {}
- scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
- scoped_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ SharedBitmapManager* shared_bitmap_manager_;
+ gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ TaskGraphRunner* task_graph_runner_;
TestHooks* test_hooks_;
bool test_started_;
};
@@ -663,9 +669,8 @@
DCHECK(!impl_thread_ || impl_thread_->message_loop_proxy().get());
layer_tree_host_ = LayerTreeHostForTesting::Create(
- this,
- client_.get(),
- settings_,
+ this, client_.get(), shared_bitmap_manager_.get(),
+ gpu_memory_buffer_manager_.get(), task_graph_runner_.get(), settings_,
base::MessageLoopProxy::current(),
impl_thread_ ? impl_thread_->message_loop_proxy() : NULL,
external_begin_frame_source.Pass());
@@ -793,6 +798,10 @@
main_task_runner_ = base::MessageLoopProxy::current();
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager);
+ gpu_memory_buffer_manager_.reset(new TestGpuMemoryBufferManager);
+ task_graph_runner_.reset(new TestTaskGraphRunner);
+
delegating_renderer_ = delegating_renderer;
// Spend less time waiting for BeginFrame because the output is
@@ -878,4 +887,13 @@
layer_tree_host_ = nullptr;
}
+LayerTreeHost* LayerTreeTest::layer_tree_host() {
+ // We check for a null proxy here as we sometimes ask for the layer tree host
+ // when the proxy does not exist, often for checking settings after a test has
+ // completed. For example, LTHPixelResourceTest::RunPixelResourceTest. See
+ // elsewhere in this file for other examples.
+ DCHECK(!proxy() || proxy()->IsMainThread() || proxy()->IsMainThreadBlocked());
+ return layer_tree_host_.get();
+}
+
} // namespace cc
diff --git a/cc/test/layer_tree_test.h b/cc/test/layer_tree_test.h
index c2b18b1..35a3546 100644
--- a/cc/test/layer_tree_test.h
+++ b/cc/test/layer_tree_test.h
@@ -21,6 +21,7 @@
class LayerTreeHostClient;
class LayerTreeHostImpl;
class TestContextProvider;
+class TestGpuMemoryBufferManager;
class TestWebGraphicsContext3D;
// Used by test stubs to notify the test when something interesting happens.
@@ -195,10 +196,13 @@
Proxy* proxy() const {
return layer_tree_host_ ? layer_tree_host_->proxy() : NULL;
}
+ TaskGraphRunner* task_graph_runner() const {
+ return task_graph_runner_.get();
+ }
bool TestEnded() const { return ended_; }
- LayerTreeHost* layer_tree_host() { return layer_tree_host_.get(); }
+ LayerTreeHost* layer_tree_host();
bool delegating_renderer() const { return delegating_renderer_; }
FakeOutputSurface* output_surface() { return output_surface_; }
int LastCommittedSourceFrameNumber(LayerTreeHostImpl* impl) const;
@@ -234,6 +238,9 @@
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner_;
scoped_ptr<base::Thread> impl_thread_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ scoped_ptr<TaskGraphRunner> task_graph_runner_;
base::CancelableClosure timeout_;
scoped_refptr<TestContextProvider> compositor_contexts_;
base::WeakPtr<LayerTreeTest> main_thread_weak_ptr_;
diff --git a/cc/test/ordered_simple_task_runner.cc b/cc/test/ordered_simple_task_runner.cc
index e337909..9fc22ad 100644
--- a/cc/test/ordered_simple_task_runner.cc
+++ b/cc/test/ordered_simple_task_runner.cc
@@ -127,6 +127,10 @@
return true;
}
+size_t OrderedSimpleTaskRunner::NumPendingTasks() const {
+ return pending_tasks_.size();
+}
+
bool OrderedSimpleTaskRunner::HasPendingTasks() const {
return pending_tasks_.size() > 0;
}
diff --git a/cc/test/ordered_simple_task_runner.h b/cc/test/ordered_simple_task_runner.h
index 54b1db4..6848303 100644
--- a/cc/test/ordered_simple_task_runner.h
+++ b/cc/test/ordered_simple_task_runner.h
@@ -73,6 +73,7 @@
advance_now_ = advance_now;
}
+ size_t NumPendingTasks() const;
bool HasPendingTasks() const;
base::TimeTicks NextTaskTime();
base::TimeDelta DelayToNextTaskTime();
diff --git a/cc/test/test_now_source.cc b/cc/test/test_now_source.cc
index 0576d06..e1a633f 100644
--- a/cc/test/test_now_source.cc
+++ b/cc/test/test_now_source.cc
@@ -23,17 +23,21 @@
}
TestNowSource::TestNowSource()
- : initial_(base::TimeTicks::FromInternalValue(10000)), now_() {
+ : initial_(base::TimeTicks::FromInternalValue(10000)),
+ now_(),
+ num_now_calls_(0) {
Reset();
}
TestNowSource::TestNowSource(base::TimeTicks initial)
- : initial_(initial), now_() {
+ : initial_(initial), now_(), num_now_calls_(0) {
Reset();
}
TestNowSource::TestNowSource(int64_t initial)
- : initial_(base::TimeTicks::FromInternalValue(initial)), now_() {
+ : initial_(base::TimeTicks::FromInternalValue(initial)),
+ now_(),
+ num_now_calls_(0) {
Reset();
}
@@ -53,6 +57,7 @@
}
base::TimeTicks TestNowSource::Now() const {
+ num_now_calls_++;
return now_;
}
diff --git a/cc/test/test_now_source.h b/cc/test/test_now_source.h
index 54e5a28..9b46bbe 100644
--- a/cc/test/test_now_source.h
+++ b/cc/test/test_now_source.h
@@ -37,6 +37,8 @@
void AsValueInto(base::trace_event::TracedValue* state) const;
std::string ToString() const;
+ int NumNowCalls() const { return num_now_calls_; }
+
protected:
TestNowSource();
explicit TestNowSource(int64_t initial);
@@ -44,6 +46,7 @@
base::TimeTicks initial_;
base::TimeTicks now_;
+ mutable int num_now_calls_;
private:
friend class base::RefCounted<TestNowSource>;
diff --git a/cc/test/test_task_graph_runner.cc b/cc/test/test_task_graph_runner.cc
new file mode 100644
index 0000000..fe9734e
--- /dev/null
+++ b/cc/test/test_task_graph_runner.cc
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/test/test_task_graph_runner.h"
+
+namespace cc {
+
+TestTaskGraphRunner::TestTaskGraphRunner()
+ : worker_thread_(this, "CompositorWorker") {
+ worker_thread_.Start();
+}
+
+TestTaskGraphRunner::~TestTaskGraphRunner() {
+ TaskGraphRunner::Shutdown();
+ worker_thread_.Join();
+}
+
+void TestTaskGraphRunner::Run() {
+ TaskGraphRunner::Run();
+}
+
+} // namespace cc
diff --git a/cc/test/test_task_graph_runner.h b/cc/test/test_task_graph_runner.h
new file mode 100644
index 0000000..8314e11
--- /dev/null
+++ b/cc/test/test_task_graph_runner.h
@@ -0,0 +1,30 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_TEST_TEST_TASK_GRAPH_RUNNER_H_
+#define CC_TEST_TEST_TASK_GRAPH_RUNNER_H_
+
+#include "base/threading/simple_thread.h"
+#include "cc/resources/task_graph_runner.h"
+
+namespace cc {
+
+class TestTaskGraphRunner : public TaskGraphRunner,
+ public base::DelegateSimpleThread::Delegate {
+ public:
+ TestTaskGraphRunner();
+ ~TestTaskGraphRunner() override;
+
+ // Overridden from base::DelegateSimpleThread::Delegate:
+ void Run() override;
+
+ private:
+ base::DelegateSimpleThread worker_thread_;
+
+ DISALLOW_COPY_AND_ASSIGN(TestTaskGraphRunner);
+};
+
+} // namespace cc
+
+#endif // CC_TEST_TEST_TASK_GRAPH_RUNNER_H_
diff --git a/cc/trees/damage_tracker.cc b/cc/trees/damage_tracker.cc
index 866f09d..235dfcf 100644
--- a/cc/trees/damage_tracker.cc
+++ b/cc/trees/damage_tracker.cc
@@ -283,8 +283,7 @@
RectMapData& data = RectDataForLayer(layer->id(), &layer_is_new);
gfx::Rect old_rect_in_target_space = data.rect_;
- gfx::Rect rect_in_target_space = MathUtil::MapEnclosingClippedRect(
- layer->draw_transform(), gfx::Rect(layer->content_bounds()));
+ gfx::Rect rect_in_target_space = layer->GetEnclosingRectInTargetSpace();
data.Update(rect_in_target_space, mailboxId_);
gfx::RectF damage_rect =
diff --git a/cc/trees/damage_tracker_unittest.cc b/cc/trees/damage_tracker_unittest.cc
index 95609d3..2df71dd 100644
--- a/cc/trees/damage_tracker_unittest.cc
+++ b/cc/trees/damage_tracker_unittest.cc
@@ -12,6 +12,7 @@
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_common.h"
#include "cc/trees/single_thread_proxy.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -74,7 +75,8 @@
class DamageTrackerTest : public testing::Test {
public:
- DamageTrackerTest() : host_impl_(&proxy_, &shared_bitmap_manager_) {}
+ DamageTrackerTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_) {}
scoped_ptr<LayerImpl> CreateTestTreeWithOneSurface() {
scoped_ptr<LayerImpl> root =
@@ -176,6 +178,7 @@
protected:
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
};
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index 8a3e644..9d2be10 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -21,6 +21,7 @@
#include "cc/animation/layer_animation_controller.h"
#include "cc/base/math_util.h"
#include "cc/debug/devtools_instrumentation.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/input/layer_selection_bound.h"
#include "cc/input/page_scale_animation.h"
@@ -55,6 +56,7 @@
LayerTreeHostClient* client,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
@@ -62,7 +64,8 @@
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));
+ client, shared_bitmap_manager, gpu_memory_buffer_manager,
+ task_graph_runner, settings));
layer_tree_host->InitializeThreaded(main_task_runner,
impl_task_runner,
external_begin_frame_source.Pass());
@@ -74,11 +77,13 @@
LayerTreeHostSingleThreadClient* single_thread_client,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
const LayerTreeSettings& settings,
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));
+ client, shared_bitmap_manager, gpu_memory_buffer_manager,
+ task_graph_runner, settings));
layer_tree_host->InitializeSingleThreaded(single_thread_client,
main_task_runner,
external_begin_frame_source.Pass());
@@ -89,6 +94,7 @@
LayerTreeHostClient* client,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
const LayerTreeSettings& settings)
: micro_benchmark_controller_(this),
next_ui_resource_id_(1),
@@ -120,6 +126,7 @@
next_commit_forces_redraw_(false),
shared_bitmap_manager_(shared_bitmap_manager),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ task_graph_runner_(task_graph_runner),
surface_id_namespace_(0u),
next_surface_sequence_(1u) {
if (settings_.accelerated_animation_enabled)
@@ -268,6 +275,15 @@
contents_texture_manager_->ReduceMemory(host_impl->resource_provider());
}
+ bool is_new_trace;
+ TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
+ if (is_new_trace &&
+ frame_viewer_instrumentation::IsTracingLayerTreeSnapshots() &&
+ root_layer()) {
+ LayerTreeHostCommon::CallFunctionForSubtree(
+ root_layer(), [](Layer* layer) { layer->DidBeginTracing(); });
+ }
+
LayerTreeImpl* sync_tree = host_impl->sync_tree();
if (next_commit_forces_redraw_) {
@@ -420,17 +436,14 @@
scoped_ptr<LayerTreeHostImpl> LayerTreeHost::CreateLayerTreeHostImpl(
LayerTreeHostImplClient* client) {
DCHECK(proxy_->IsImplThread());
- scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings_,
- client,
- proxy_.get(),
- rendering_stats_instrumentation_.get(),
- shared_bitmap_manager_,
- gpu_memory_buffer_manager_,
- id_);
+ scoped_ptr<LayerTreeHostImpl> host_impl = LayerTreeHostImpl::Create(
+ settings_, client, proxy_.get(), rendering_stats_instrumentation_.get(),
+ shared_bitmap_manager_, gpu_memory_buffer_manager_, task_graph_runner_,
+ id_);
host_impl->SetUseGpuRasterization(UseGpuRasterization());
shared_bitmap_manager_ = NULL;
gpu_memory_buffer_manager_ = NULL;
+ task_graph_runner_ = NULL;
top_controls_manager_weak_ptr_ =
host_impl->top_controls_manager()->AsWeakPtr();
input_handler_weak_ptr_ = host_impl->AsWeakPtr();
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index 1379d08..e1bcad5 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -61,6 +61,7 @@
class ResourceProvider;
class ResourceUpdateQueue;
class SharedBitmapManager;
+class TaskGraphRunner;
class TopControlsManager;
class UIResourceRequest;
struct PendingPageScaleAnimation;
@@ -75,6 +76,7 @@
LayerTreeHostClient* client,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_refptr<base::SingleThreadTaskRunner> impl_task_runner,
@@ -85,6 +87,7 @@
LayerTreeHostSingleThreadClient* single_thread_client,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
const LayerTreeSettings& settings,
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
scoped_ptr<BeginFrameSource> external_begin_frame_source);
@@ -307,6 +310,7 @@
LayerTreeHost(LayerTreeHostClient* client,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
const LayerTreeSettings& settings);
void InitializeThreaded(
scoped_refptr<base::SingleThreadTaskRunner> main_task_runner,
@@ -440,6 +444,7 @@
SharedBitmapManager* shared_bitmap_manager_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ TaskGraphRunner* task_graph_runner_;
ScopedPtrVector<SwapPromise> swap_promise_list_;
std::set<SwapPromiseMonitor*> swap_promise_monitor_;
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h
index 88197da..404f407 100644
--- a/cc/trees/layer_tree_host_common.h
+++ b/cc/trees/layer_tree_host_common.h
@@ -150,7 +150,9 @@
struct ScrollUpdateInfo {
int layer_id;
- gfx::Vector2dF scroll_delta;
+ // TODO(miletus): Use ScrollOffset once LayerTreeHost/Blink fully supports
+ // franctional scroll offset.
+ gfx::Vector2d scroll_delta;
};
};
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index dd797d5..082d14f 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -28,6 +28,7 @@
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_host_common_test.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/proxy.h"
#include "cc/trees/single_thread_proxy.h"
@@ -315,7 +316,7 @@
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> sublayer_scoped_ptr(
@@ -5721,7 +5722,7 @@
TEST_F(LayerTreeHostCommonTest, OpacityAnimatingOnPendingTree) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.pending_tree(), 1);
@@ -5763,7 +5764,7 @@
public testing::TestWithParam<LCDTextTestParam> {
public:
LCDTextTest()
- : host_impl_(&proxy_, &shared_bitmap_manager_),
+ : host_impl_(&proxy_, &shared_bitmap_manager_, &task_graph_runner_),
root_(nullptr),
child_(nullptr),
grand_child_(nullptr) {}
@@ -5810,6 +5811,7 @@
FakeImplProxy proxy_;
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeLayerTreeHostImpl host_impl_;
LayerImpl* root_;
@@ -5947,7 +5949,7 @@
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayer) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6005,7 +6007,7 @@
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayerImpl) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6050,7 +6052,7 @@
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayers) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6107,7 +6109,7 @@
TEST_F(LayerTreeHostCommonTest, SubtreeHidden_TwoLayersImpl) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6152,7 +6154,7 @@
TEST_F(LayerTreeHostCommonTest, SubtreeHiddenWithCopyRequest) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6299,7 +6301,7 @@
TEST_F(LayerTreeHostCommonTest, ClippedOutCopyRequest) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6374,7 +6376,7 @@
TEST_F(LayerTreeHostCommonTest, VisibleContentRectInsideSurface) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
const gfx::Transform identity_matrix;
@@ -6985,7 +6987,7 @@
TEST_F(LayerTreeHostCommonTest, CanRenderToSeparateSurface) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root =
LayerImpl::Create(host_impl.active_tree(), 12345);
scoped_ptr<LayerImpl> child1 =
@@ -7646,6 +7648,55 @@
EXPECT_TRUE(render_surface_layer_list.at(2)->render_surface());
}
+TEST_F(LayerTreeHostCommonTest, FixedPositionWithInterveningRenderSurface) {
+ // Ensures that when we have a render surface between a fixed position layer
+ // and its container, we compute the fixed position layer's draw transform
+ // with respect to that intervening render surface, not with respect to its
+ // container's render target.
+ //
+ // + root
+ // + render_surface
+ // + fixed
+ //
+ scoped_refptr<Layer> root = Layer::Create();
+ scoped_refptr<LayerWithForcedDrawsContent> render_surface =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ scoped_refptr<LayerWithForcedDrawsContent> fixed =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+
+ root->AddChild(render_surface);
+ render_surface->AddChild(fixed);
+
+ root->SetIsContainerForFixedPositionLayers(true);
+ render_surface->SetForceRenderSurface(true);
+
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ fixed->SetPositionConstraint(constraint);
+
+ SetLayerPropertiesForTesting(root.get(), gfx::Transform(), gfx::Point3F(),
+ gfx::PointF(), gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(render_surface.get(), gfx::Transform(),
+ gfx::Point3F(), gfx::PointF(7.f, 9.f),
+ gfx::Size(50, 50), true, false);
+ SetLayerPropertiesForTesting(fixed.get(), gfx::Transform(), gfx::Point3F(),
+ gfx::PointF(10.f, 15.f), gfx::Size(50, 50), true,
+ false);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ gfx::Transform expected_draw_transform;
+ expected_draw_transform.Translate(10.f, 15.f);
+ EXPECT_EQ(expected_draw_transform, fixed->draw_transform());
+
+ gfx::Transform expected_screen_space_transform;
+ expected_screen_space_transform.Translate(17.f, 24.f);
+ EXPECT_EQ(expected_screen_space_transform, fixed->screen_space_transform());
+}
+
TEST_F(LayerTreeHostCommonTest, ScrollCompensationWithRounding) {
// This test verifies that a scrolling layer that gets snapped to
// integer coordinates doesn't move a fixed position child.
@@ -7657,7 +7708,7 @@
//
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> container =
@@ -7801,7 +7852,7 @@
//
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
host_impl.CreatePendingTree();
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
scoped_ptr<LayerImpl> container =
@@ -7895,7 +7946,7 @@
TEST_F(LayerTreeHostCommonTest, MaximumAnimationScaleFactor) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
gfx::Transform identity_matrix;
scoped_ptr<AnimationScaleFactorTrackingLayerImpl> grand_parent =
AnimationScaleFactorTrackingLayerImpl::Create(host_impl.active_tree(), 1);
@@ -8112,7 +8163,7 @@
TEST_F(LayerTreeHostCommonTest, RenderSurfaceLayerListMembership) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
gfx::Transform identity_matrix;
scoped_ptr<LayerImpl> grand_parent =
@@ -8355,7 +8406,7 @@
TEST_F(LayerTreeHostCommonTest, DrawPropertyScales) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl.active_tree(), 1);
LayerImpl* root_layer = root.get();
@@ -8635,7 +8686,7 @@
TEST_F(LayerTreeHostCommonTest, BoundsDeltaAffectVisibleContentRect) {
FakeImplProxy proxy;
TestSharedBitmapManager shared_bitmap_manager;
- FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
+ FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager, nullptr);
// Set two layers: the root layer clips it's child,
// the child draws its content.
@@ -8854,5 +8905,43 @@
ExecuteCalculateDrawProperties(root.get());
}
+TEST_F(LayerTreeHostCommonTest, OnlyApplyFixedPositioningOnce) {
+ gfx::Transform identity;
+ gfx::Transform translate_z;
+ translate_z.Translate3d(0, 0, 10);
+
+ scoped_refptr<Layer> root = Layer::Create();
+ SetLayerPropertiesForTesting(root.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(800, 800), true, false);
+ root->SetIsContainerForFixedPositionLayers(true);
+
+ scoped_refptr<Layer> frame_clip = Layer::Create();
+ SetLayerPropertiesForTesting(frame_clip.get(), translate_z, gfx::Point3F(),
+ gfx::PointF(500, 100), gfx::Size(100, 100), true,
+ false);
+ frame_clip->SetMasksToBounds(true);
+
+ scoped_refptr<LayerWithForcedDrawsContent> fixed =
+ make_scoped_refptr(new LayerWithForcedDrawsContent());
+ SetLayerPropertiesForTesting(fixed.get(), identity, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1000, 1000), true,
+ false);
+
+ LayerPositionConstraint constraint;
+ constraint.set_is_fixed_position(true);
+ fixed->SetPositionConstraint(constraint);
+
+ root->AddChild(frame_clip);
+ frame_clip->AddChild(fixed);
+
+ scoped_ptr<FakeLayerTreeHost> host(CreateFakeLayerTreeHost());
+ host->SetRootLayer(root);
+
+ ExecuteCalculateDrawProperties(root.get());
+
+ gfx::Rect expected(0, 0, 100, 100);
+ EXPECT_EQ(expected, fixed->visible_rect_from_property_trees());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index a8d4294..2c13fcb 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -6,6 +6,7 @@
#include <algorithm>
#include <limits>
+#include <map>
#include "base/basictypes.h"
#include "base/containers/hash_tables.h"
@@ -24,6 +25,7 @@
#include "cc/debug/debug_rect_history.h"
#include "cc/debug/devtools_instrumentation.h"
#include "cc/debug/frame_rate_counter.h"
+#include "cc/debug/frame_viewer_instrumentation.h"
#include "cc/debug/paint_time_counter.h"
#include "cc/debug/rendering_stats_instrumentation.h"
#include "cc/debug/traced_value.h"
@@ -168,14 +170,11 @@
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id) {
- return make_scoped_ptr(new LayerTreeHostImpl(settings,
- client,
- proxy,
- rendering_stats_instrumentation,
- shared_bitmap_manager,
- gpu_memory_buffer_manager,
- id));
+ return make_scoped_ptr(new LayerTreeHostImpl(
+ settings, client, proxy, rendering_stats_instrumentation,
+ shared_bitmap_manager, gpu_memory_buffer_manager, task_graph_runner, id));
}
LayerTreeHostImpl::LayerTreeHostImpl(
@@ -185,6 +184,7 @@
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id)
: client_(client),
proxy_(proxy),
@@ -223,6 +223,7 @@
micro_benchmark_controller_(this),
shared_bitmap_manager_(shared_bitmap_manager),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
+ task_graph_runner_(task_graph_runner),
id_(id),
requires_high_res_to_draw_(false),
is_likely_to_require_a_draw_(false),
@@ -1528,12 +1529,8 @@
{
TRACE_EVENT0("cc", "DrawLayers.FrameViewerTracing");
TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID(
- TRACE_DISABLED_BY_DEFAULT("cc.debug") ","
- TRACE_DISABLED_BY_DEFAULT("cc.debug.quads") ","
- TRACE_DISABLED_BY_DEFAULT("devtools.timeline.layers"),
- "cc::LayerTreeHostImpl",
- id_,
- AsValueWithFrame(frame));
+ frame_viewer_instrumentation::kCategoryLayerTree,
+ "cc::LayerTreeHostImpl", id_, AsValueWithFrame(frame));
}
const DrawMode draw_mode = GetDrawMode();
@@ -2034,8 +2031,7 @@
ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D);
*tile_task_worker_pool = BitmapTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
- resource_provider_.get());
+ task_runner, task_graph_runner_, resource_provider_.get());
return;
}
@@ -2044,7 +2040,7 @@
ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D);
*tile_task_worker_pool = GpuTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
+ task_runner, task_graph_runner_,
static_cast<GpuRasterizer*>(rasterizer_.get()));
return;
}
@@ -2068,7 +2064,7 @@
single_thread_synchronous_task_graph_runner_.reset(new TaskGraphRunner);
task_graph_runner = single_thread_synchronous_task_graph_runner_.get();
} else {
- task_graph_runner = TileTaskWorkerPool::GetTaskGraphRunner();
+ task_graph_runner = task_graph_runner_;
}
*tile_task_worker_pool = ZeroCopyTileTaskWorkerPool::Create(
@@ -2084,9 +2080,8 @@
ResourcePool::Create(resource_provider_.get(), GL_TEXTURE_2D);
*tile_task_worker_pool = OneCopyTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(),
- context_provider, resource_provider_.get(),
- staging_resource_pool_.get());
+ task_runner, task_graph_runner_, context_provider,
+ resource_provider_.get(), staging_resource_pool_.get());
return;
}
}
@@ -2100,7 +2095,7 @@
resource_provider_.get(), GL_TEXTURE_2D);
*tile_task_worker_pool = PixelBufferTileTaskWorkerPool::Create(
- task_runner, TileTaskWorkerPool::GetTaskGraphRunner(), context_provider,
+ task_runner, task_graph_runner_, context_provider,
resource_provider_.get(),
GetMaxTransferBufferUsageBytes(context_provider->ContextCapabilities(),
settings_.renderer_settings.refresh_rate));
@@ -3013,7 +3008,7 @@
if (!scroll_delta.IsZero()) {
LayerTreeHostCommon::ScrollUpdateInfo scroll;
scroll.layer_id = layer_impl->id();
- scroll.scroll_delta = gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
+ scroll.scroll_delta = gfx::Vector2d(scroll_delta.x(), scroll_delta.y());
scroll_info->scrolls.push_back(scroll);
}
@@ -3247,19 +3242,18 @@
MathUtil::AddToTracedValue("device_viewport_size", device_viewport_size_,
state);
- std::set<const Tile*> tiles;
- active_tree_->GetAllTilesForTracing(&tiles);
+ std::map<const Tile*, TilePriority> tile_map;
+ active_tree_->GetAllTilesAndPrioritiesForTracing(&tile_map);
if (pending_tree_)
- pending_tree_->GetAllTilesForTracing(&tiles);
+ pending_tree_->GetAllTilesAndPrioritiesForTracing(&tile_map);
state->BeginArray("active_tiles");
- for (std::set<const Tile*>::const_iterator it = tiles.begin();
- it != tiles.end();
- ++it) {
- const Tile* tile = *it;
+ for (const auto& pair : tile_map) {
+ const Tile* tile = pair.first;
+ const TilePriority& priority = pair.second;
state->BeginDictionary();
- tile->AsValueInto(state);
+ tile->AsValueWithPriorityInto(priority, state);
state->EndDictionary();
}
state->EndArray();
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index defe796..2efe2da 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -142,6 +142,7 @@
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id);
~LayerTreeHostImpl() override;
@@ -531,12 +532,16 @@
RenderingStatsInstrumentation* rendering_stats_instrumentation,
SharedBitmapManager* shared_bitmap_manager,
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager,
+ TaskGraphRunner* task_graph_runner,
int id);
-
// Virtual for testing.
virtual void AnimateLayers(base::TimeTicks monotonic_time);
+ bool is_likely_to_require_a_draw() const {
+ return is_likely_to_require_a_draw_;
+ }
+
LayerTreeHostImplClient* client_;
Proxy* proxy_;
@@ -731,6 +736,7 @@
SharedBitmapManager* shared_bitmap_manager_;
gpu::GpuMemoryBufferManager* gpu_memory_buffer_manager_;
+ TaskGraphRunner* task_graph_runner_;
int id_;
std::set<SwapPromiseMonitor*> swap_promise_monitor_;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index e8471e2..284cae0 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -52,6 +52,7 @@
#include "cc/test/render_pass_test_common.h"
#include "cc/test/test_gpu_memory_buffer_manager.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/test/test_web_graphics_context_3d.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/single_thread_proxy.h"
@@ -82,6 +83,7 @@
always_main_thread_blocked_(&proxy_),
shared_bitmap_manager_(new TestSharedBitmapManager),
gpu_memory_buffer_manager_(new TestGpuMemoryBufferManager),
+ task_graph_runner_(new TestTaskGraphRunner),
on_can_draw_state_changed_called_(false),
did_notify_ready_to_activate_(false),
did_request_commit_(false),
@@ -162,13 +164,10 @@
virtual bool CreateHostImpl(const LayerTreeSettings& settings,
scoped_ptr<OutputSurface> output_surface) {
- host_impl_ = LayerTreeHostImpl::Create(settings,
- this,
- &proxy_,
- &stats_instrumentation_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- 0);
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_,
+ shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(),
+ task_graph_runner_.get(), 0);
bool init = host_impl_->InitializeRenderer(output_surface.Pass());
host_impl_->SetViewportSize(gfx::Size(10, 10));
return init;
@@ -192,14 +191,13 @@
static void ExpectContains(const ScrollAndScaleSet& scroll_info,
int id,
- const gfx::Vector2dF& scroll_delta) {
+ const gfx::Vector2d& scroll_delta) {
int times_encountered = 0;
for (size_t i = 0; i < scroll_info.scrolls.size(); ++i) {
if (scroll_info.scrolls[i].layer_id != id)
continue;
- EXPECT_VECTOR2DF_NEAR(scroll_delta, scroll_info.scrolls[i].scroll_delta,
- 1.0e-10);
+ EXPECT_VECTOR_EQ(scroll_delta, scroll_info.scrolls[i].scroll_delta);
times_encountered++;
}
@@ -391,6 +389,7 @@
scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
scoped_ptr<TestGpuMemoryBufferManager> gpu_memory_buffer_manager_;
+ scoped_ptr<TestTaskGraphRunner> task_graph_runner_;
scoped_ptr<LayerTreeHostImpl> host_impl_;
FakeRenderingStatsInstrumentation stats_instrumentation_;
bool on_can_draw_state_changed_called_;
@@ -1543,6 +1542,7 @@
rendering_stats_instrumentation,
manager,
NULL,
+ NULL,
0) {}
BeginFrameArgs CurrentBeginFrameArgs() const override {
@@ -3714,7 +3714,7 @@
// The layer should have scrolled down in its local coordinates.
scoped_ptr<ScrollAndScaleSet> scroll_info = host_impl_->ProcessScrollDeltas();
ExpectContains(*scroll_info.get(), scroll_layer->id(),
- gfx::Vector2dF(0, gesture_scroll_delta.x()));
+ gfx::Vector2d(0, gesture_scroll_delta.x()));
// Reset and scroll down with the wheel.
scroll_layer->SetScrollDelta(gfx::Vector2dF());
@@ -3773,7 +3773,7 @@
// The child layer should have scrolled down in its local coordinates an
// amount proportional to the angle between it and the input scroll delta.
- gfx::Vector2dF expected_scroll_delta(
+ gfx::Vector2d expected_scroll_delta(
0, gesture_scroll_delta.y() *
std::cos(MathUtil::Deg2Rad(child_layer_angle)));
scoped_ptr<ScrollAndScaleSet> scroll_info =
@@ -3795,7 +3795,7 @@
// The child layer should have scrolled down in its local coordinates an
// amount proportional to the angle between it and the input scroll delta.
- gfx::Vector2dF expected_scroll_delta(
+ gfx::Vector2d expected_scroll_delta(
0, -gesture_scroll_delta.x() *
std::sin(MathUtil::Deg2Rad(child_layer_angle)));
scoped_ptr<ScrollAndScaleSet> scroll_info =
@@ -3804,7 +3804,7 @@
// The root scroll layer should have scrolled more, since the input scroll
// delta was mostly orthogonal to the child layer's vertical scroll axis.
- gfx::Vector2dF expected_root_scroll_delta(
+ gfx::Vector2d expected_root_scroll_delta(
gesture_scroll_delta.x() *
std::pow(std::cos(MathUtil::Deg2Rad(child_layer_angle)), 2),
0);
@@ -5042,16 +5042,10 @@
// that we can force partial swap enabled.
LayerTreeSettings settings;
settings.renderer_settings.partial_swap_enabled = true;
- scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
- new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> layer_tree_host_impl =
- LayerTreeHostImpl::Create(settings,
- this,
- &proxy_,
- &stats_instrumentation_,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_,
+ shared_bitmap_manager_.get(), NULL, task_graph_runner_.get(), 0);
layer_tree_host_impl->InitializeRenderer(output_surface.Pass());
layer_tree_host_impl->SetViewportSize(gfx::Size(500, 500));
@@ -5297,8 +5291,8 @@
CreateHostImpl(settings, FakeOutputSurface::Create3d(context_owned.Pass()));
SetupRootLayerImpl(FakeLayerWithQuads::Create(host_impl_->active_tree(), 1));
- // The first frame is not a partially-swapped one.
- harness.MustSetScissor(0, 0, 10, 10);
+ // The first frame is not a partially-swapped one. No scissor should be set.
+ harness.MustSetNoScissor();
harness.MustDrawSolidQuad();
{
LayerTreeHostImpl::FrameData frame;
@@ -5339,7 +5333,7 @@
LayerTreeSettings settings;
settings.renderer_settings.partial_swap_enabled = partial_swap;
scoped_ptr<LayerTreeHostImpl> my_host_impl = LayerTreeHostImpl::Create(
- settings, client, proxy, stats_instrumentation, manager, NULL, 0);
+ settings, client, proxy, stats_instrumentation, manager, NULL, NULL, 0);
my_host_impl->InitializeRenderer(output_surface.Pass());
my_host_impl->SetViewportSize(gfx::Size(100, 100));
@@ -6643,13 +6637,10 @@
// doesn't support memory management extensions.
TEST_F(LayerTreeHostImplTest, DefaultMemoryAllocation) {
LayerTreeSettings settings;
- host_impl_ = LayerTreeHostImpl::Create(settings,
- this,
- &proxy_,
- &stats_instrumentation_,
- shared_bitmap_manager_.get(),
- gpu_memory_buffer_manager_.get(),
- 0);
+ host_impl_ = LayerTreeHostImpl::Create(
+ settings, this, &proxy_, &stats_instrumentation_,
+ shared_bitmap_manager_.get(), gpu_memory_buffer_manager_.get(),
+ task_graph_runner_.get(), 0);
scoped_ptr<OutputSurface> output_surface(
FakeOutputSurface::Create3d(TestWebGraphicsContext3D::Create()));
@@ -6690,7 +6681,7 @@
LayerTreeSettings settings;
settings.gpu_rasterization_enabled = true;
host_impl_ = LayerTreeHostImpl::Create(
- settings, this, &proxy_, &stats_instrumentation_, NULL, NULL, 0);
+ settings, this, &proxy_, &stats_instrumentation_, NULL, NULL, NULL, 0);
host_impl_->SetUseGpuRasterization(true);
host_impl_->SetVisible(true);
host_impl_->SetMemoryPolicy(policy1);
@@ -6753,8 +6744,9 @@
LayerTreeSettings settings;
settings.impl_side_painting = true;
- fake_host_impl_ = new FakeLayerTreeHostImpl(
- settings, &proxy_, shared_bitmap_manager_.get());
+ fake_host_impl_ = new FakeLayerTreeHostImpl(settings, &proxy_,
+ shared_bitmap_manager_.get(),
+ task_graph_runner_.get());
host_impl_.reset(fake_host_impl_);
host_impl_->InitializeRenderer(CreateOutputSurface());
host_impl_->SetViewportSize(gfx::Size(10, 10));
@@ -8128,7 +8120,10 @@
gfx::Size(10, 10), gfx::Size(10, 10)));
Region empty_invalidation;
const PictureLayerTilingSet* null_tiling_set = nullptr;
+ layer->set_gpu_raster_max_texture_size(host_impl_->device_viewport_size());
layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
+ nondraw_layer->set_gpu_raster_max_texture_size(
+ host_impl_->device_viewport_size());
nondraw_layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
layer->AddChild(nondraw_layer.Pass());
@@ -8246,7 +8241,10 @@
gfx::Size(10, 10), gfx::Size(10, 10)));
Region empty_invalidation;
const PictureLayerTilingSet* null_tiling_set = nullptr;
+ layer->set_gpu_raster_max_texture_size(host_impl_->device_viewport_size());
layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
+ nondraw_layer->set_gpu_raster_max_texture_size(
+ host_impl_->device_viewport_size());
nondraw_layer->UpdateRasterSource(pile, &empty_invalidation, null_tiling_set);
layer->AddChild(nondraw_layer.Pass());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index 9416474..201af9a 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -68,7 +68,17 @@
namespace cc {
namespace {
-class LayerTreeHostTest : public LayerTreeTest {};
+class LayerTreeHostTest : public LayerTreeTest {
+ public:
+ LayerTreeHostTest() : contents_texture_manager_(nullptr) {}
+
+ void DidInitializeOutputSurface() override {
+ contents_texture_manager_ = layer_tree_host()->contents_texture_manager();
+ }
+
+ protected:
+ PrioritizedResourceManager* contents_texture_manager_;
+};
// Test if the LTHI receives ReadyToActivate notifications from the TileManager
// when no raster tasks get scheduled.
@@ -473,6 +483,86 @@
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestSetNeedsRedrawRect);
+// Ensure the texture size of the pending and active trees are identical when a
+// layer is not in the viewport and a resize happens on the viewport
+class LayerTreeHostTestGpuRasterDeviceSizeChanged : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestGpuRasterDeviceSizeChanged()
+ : num_draws_(0), bounds_(500, 64), invalid_rect_(10, 10, 20, 20) {}
+
+ void BeginTest() override {
+ client_.set_fill_with_nonsolid_color(true);
+ root_layer_ = FakePictureLayer::Create(&client_);
+ root_layer_->SetIsDrawable(true);
+ gfx::Transform transform;
+ // Translate the layer out of the viewport to force it to not update its
+ // tile size via PushProperties.
+ transform.Translate(10000.0, 10000.0);
+ root_layer_->SetTransform(transform);
+ root_layer_->SetBounds(bounds_);
+ layer_tree_host()->SetRootLayer(root_layer_);
+ layer_tree_host()->SetViewportSize(bounds_);
+
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->gpu_rasterization_enabled = true;
+ settings->gpu_rasterization_forced = true;
+ }
+
+ void DrawLayersOnThread(LayerTreeHostImpl* impl) override {
+ // Perform 2 commits.
+ if (!num_draws_) {
+ PostSetNeedsRedrawRectToMainThread(invalid_rect_);
+ } else {
+ EndTest();
+ }
+ num_draws_++;
+ }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ if (num_draws_ == 2) {
+ auto pending_tree = host_impl->pending_tree();
+ auto pending_layer_impl =
+ static_cast<FakePictureLayerImpl*>(pending_tree->root_layer());
+ EXPECT_NE(pending_layer_impl, nullptr);
+
+ auto active_tree = host_impl->pending_tree();
+ auto active_layer_impl =
+ static_cast<FakePictureLayerImpl*>(active_tree->root_layer());
+ EXPECT_NE(pending_layer_impl, nullptr);
+
+ auto active_tiling_set = active_layer_impl->picture_layer_tiling_set();
+ auto active_tiling = active_tiling_set->tiling_at(0);
+ auto pending_tiling_set = pending_layer_impl->picture_layer_tiling_set();
+ auto pending_tiling = pending_tiling_set->tiling_at(0);
+ EXPECT_EQ(
+ pending_tiling->TilingDataForTesting().max_texture_size().width(),
+ active_tiling->TilingDataForTesting().max_texture_size().width());
+ }
+ }
+
+ void DidCommitAndDrawFrame() override {
+ // On the second commit, resize the viewport.
+ if (num_draws_ == 1) {
+ layer_tree_host()->SetViewportSize(gfx::Size(400, 64));
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ int num_draws_;
+ const gfx::Size bounds_;
+ const gfx::Rect invalid_rect_;
+ FakeContentLayerClient client_;
+ scoped_refptr<FakePictureLayer> root_layer_;
+};
+
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(
+ LayerTreeHostTestGpuRasterDeviceSizeChanged);
+
class LayerTreeHostTestNoExtraCommitFromInvalidate : public LayerTreeHostTest {
public:
void InitializeSettings(LayerTreeSettings* settings) override {
@@ -692,6 +782,13 @@
public:
LayerTreeHostTestUndrawnLayersDamageLater() {}
+ void InitializeSettings(LayerTreeSettings* settings) override {
+ // If we don't set the minimum contents scale, it's harder to verify whether
+ // the damage we get is correct. For other scale amounts, please see
+ // LayerTreeHostTestDamageWithScale.
+ settings->minimum_contents_scale = 1.f;
+ }
+
void SetupTree() override {
if (layer_tree_host()->settings().impl_side_painting)
root_layer_ = FakePictureLayer::Create(&client_);
@@ -786,6 +883,114 @@
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestUndrawnLayersDamageLater);
+// Tests that if a layer is not drawn because of some reason in the parent then
+// its damage is preserved until the next time it is drawn.
+class LayerTreeHostTestDamageWithScale : public LayerTreeHostTest {
+ public:
+ LayerTreeHostTestDamageWithScale() {}
+
+ void SetupTree() override {
+ client_.set_fill_with_nonsolid_color(true);
+
+ scoped_ptr<FakePicturePile> pile(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ root_layer_ =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ root_layer_->SetBounds(gfx::Size(50, 50));
+
+ pile.reset(
+ new FakePicturePile(ImplSidePaintingSettings().minimum_contents_scale,
+ ImplSidePaintingSettings().default_tile_grid_size));
+ child_layer_ =
+ FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
+ child_layer_->SetBounds(gfx::Size(25, 25));
+ child_layer_->SetIsDrawable(true);
+ child_layer_->SetContentsOpaque(true);
+ root_layer_->AddChild(child_layer_);
+
+ layer_tree_host()->SetRootLayer(root_layer_);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ // Force the layer to have a tiling at 1.3f scale. Note that if we simply
+ // add tiling, it will be gone by the time we draw because of aggressive
+ // cleanup. AddTilingUntilNextDraw ensures that it remains there during
+ // damage calculation.
+ FakePictureLayerImpl* child_layer_impl = static_cast<FakePictureLayerImpl*>(
+ host_impl->active_tree()->LayerById(child_layer_->id()));
+ child_layer_impl->AddTilingUntilNextDraw(1.3f);
+ }
+
+ void BeginTest() override { PostSetNeedsCommitToMainThread(); }
+
+ DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
+ LayerTreeHostImpl::FrameData* frame_data,
+ DrawResult draw_result) override {
+ EXPECT_EQ(DRAW_SUCCESS, draw_result);
+
+ gfx::RectF root_damage_rect;
+ if (!frame_data->render_passes.empty())
+ root_damage_rect = frame_data->render_passes.back()->damage_rect;
+
+ // The first time, the whole view needs be drawn.
+ // Afterwards, just the opacity of surface_layer1 is changed a few times,
+ // and each damage should be the bounding box of it and its child. If this
+ // was working improperly, the damage might not include its childs bounding
+ // box.
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_EQ(gfx::Rect(root_layer_->bounds()), root_damage_rect);
+ break;
+ case 1: {
+ FakePictureLayerImpl* child_layer_impl =
+ static_cast<FakePictureLayerImpl*>(
+ host_impl->active_tree()->LayerById(child_layer_->id()));
+ // We remove tilings pretty aggressively if they are not ideal. Add this
+ // back in so that we can compare
+ // child_layer_impl->GetEnclosingRectInTargetSpace to the damage.
+ child_layer_impl->AddTilingUntilNextDraw(1.3f);
+
+ EXPECT_EQ(gfx::Rect(26, 26), root_damage_rect);
+ EXPECT_EQ(child_layer_impl->GetEnclosingRectInTargetSpace(),
+ root_damage_rect);
+ EXPECT_TRUE(child_layer_impl->GetEnclosingRectInTargetSpace().Contains(
+ gfx::Rect(child_layer_->bounds())));
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+
+ return draw_result;
+ }
+
+ void DidCommitAndDrawFrame() override {
+ switch (layer_tree_host()->source_frame_number()) {
+ case 1: {
+ // Test not owning the surface.
+ child_layer_->SetOpacity(0.5f);
+ break;
+ }
+ case 2:
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ FakeContentLayerClient client_;
+ scoped_refptr<Layer> root_layer_;
+ scoped_refptr<Layer> child_layer_;
+};
+
+MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestDamageWithScale);
+
// Tests that if a layer is not drawn because of some reason in the parent,
// causing its content bounds to not be computed, then when it is later drawn,
// its content bounds get pushed.
@@ -1346,7 +1551,7 @@
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
+ ASSERT_EQ(0u, impl->settings().max_partial_texture_updates);
TestWebGraphicsContext3D* context = TestContext();
@@ -1425,7 +1630,7 @@
: public LayerTreeHostTestDirectRendererAtomicCommit {
public:
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- ASSERT_EQ(0u, layer_tree_host()->settings().max_partial_texture_updates);
+ ASSERT_EQ(0u, impl->settings().max_partial_texture_updates);
TestWebGraphicsContext3D* context = TestContext();
@@ -1542,7 +1747,7 @@
}
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
- ASSERT_EQ(1u, layer_tree_host()->settings().max_partial_texture_updates);
+ ASSERT_EQ(1u, impl->settings().max_partial_texture_updates);
TestWebGraphicsContext3D* context = TestContext();
@@ -2082,7 +2287,7 @@
LayerTreeHostWithProxy(FakeLayerTreeHostClient* client,
const LayerTreeSettings& settings,
scoped_ptr<FakeProxy> proxy)
- : LayerTreeHost(client, NULL, NULL, settings) {
+ : LayerTreeHost(client, NULL, NULL, NULL, settings) {
proxy->SetLayerTreeHost(this);
client->SetLayerTreeHost(this);
InitializeForTesting(proxy.Pass());
@@ -2154,14 +2359,9 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current(),
- nullptr);
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings,
+ base::MessageLoopProxy::current(), nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2178,14 +2378,9 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current(),
- nullptr);
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings,
+ base::MessageLoopProxy::current(), nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2202,14 +2397,9 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current(),
- nullptr);
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings,
+ base::MessageLoopProxy::current(), nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2227,14 +2417,9 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
- scoped_ptr<LayerTreeHost> host =
- LayerTreeHost::CreateSingleThreaded(&client,
- &client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current(),
- nullptr);
+ scoped_ptr<LayerTreeHost> host = LayerTreeHost::CreateSingleThreaded(
+ &client, &client, shared_bitmap_manager.get(), NULL, NULL, settings,
+ base::MessageLoopProxy::current(), nullptr);
client.SetLayerTreeHost(host.get());
host->Composite(base::TimeTicks::Now());
@@ -2266,12 +2451,10 @@
bool visible) override {
if (visible) {
// One backing should remain unevicted.
- EXPECT_EQ(
- 100u * 100u * 4u * 1u,
- layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(100u * 100u * 4u * 1u,
+ contents_texture_manager_->MemoryUseBytes());
} else {
- EXPECT_EQ(
- 0u, layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(0u, contents_texture_manager_->MemoryUseBytes());
}
// Make sure that contents textures are marked as having been
@@ -2286,9 +2469,9 @@
switch (num_commits_) {
case 1:
// All three backings should have memory.
- EXPECT_EQ(
- 100u * 100u * 4u * 3u,
- layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(100u * 100u * 4u * 3u,
+ contents_texture_manager_->MemoryUseBytes());
+
// Set a new policy that will kick out 1 of the 3 resources.
// Because a resource was evicted, a commit will be kicked off.
host_impl->SetMemoryPolicy(
@@ -2298,9 +2481,8 @@
break;
case 2:
// Only two backings should have memory.
- EXPECT_EQ(
- 100u * 100u * 4u * 2u,
- layer_tree_host()->contents_texture_manager()->MemoryUseBytes());
+ EXPECT_EQ(100u * 100u * 4u * 2u,
+ contents_texture_manager_->MemoryUseBytes());
// Become backgrounded, which will cause 1 more resource to be
// evicted.
PostSetVisibleToMainThread(false);
@@ -3129,12 +3311,12 @@
}
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
- if (!layer_tree_host()->settings().impl_side_painting)
+ if (!impl->settings().impl_side_painting)
PerformTest(impl);
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- if (layer_tree_host()->settings().impl_side_painting)
+ if (impl->settings().impl_side_painting)
PerformTest(impl);
}
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index cc536f4..48e6530 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -103,7 +103,7 @@
// Only valid for single-threaded impl-side painting, which activates
// immediately and will try to draw again when content has finished.
DCHECK(!host_impl->proxy()->HasImplThread());
- DCHECK(layer_tree_host()->settings().impl_side_painting);
+ DCHECK(host_impl->settings().impl_side_painting);
return draw_result;
}
EXPECT_EQ(DRAW_SUCCESS, draw_result);
@@ -876,7 +876,7 @@
FakeContentLayerImpl* child_content = NULL;
FakeContentLayerImpl* grandchild_content = NULL;
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (host_impl->settings().impl_side_painting) {
root_picture = static_cast<FakePictureLayerImpl*>(
host_impl->active_tree()->root_layer());
child_picture =
@@ -896,7 +896,7 @@
++num_commits_;
switch (num_commits_) {
case 1:
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (host_impl->settings().impl_side_painting) {
EXPECT_EQ(0u, root_picture->release_resources_count());
EXPECT_EQ(0u, child_picture->release_resources_count());
EXPECT_EQ(0u, grandchild_picture->release_resources_count());
@@ -911,7 +911,7 @@
times_to_fail_create_ = 1;
break;
case 2:
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (host_impl->settings().impl_side_painting) {
EXPECT_TRUE(root_picture->release_resources_count());
EXPECT_TRUE(child_picture->release_resources_count());
EXPECT_TRUE(grandchild_picture->release_resources_count());
@@ -1269,7 +1269,7 @@
virtual void StepCompleteOnImplThread(LayerTreeHostImpl* impl) = 0;
void CommitCompleteOnThread(LayerTreeHostImpl* impl) override {
- if (!layer_tree_host()->settings().impl_side_painting) {
+ if (!impl->settings().impl_side_painting) {
StepCompleteOnImplThread(impl);
PostStepCompleteToMainThread();
++time_step_;
@@ -1277,7 +1277,7 @@
}
void DidActivateTreeOnThread(LayerTreeHostImpl* impl) override {
- if (layer_tree_host()->settings().impl_side_painting) {
+ if (impl->settings().impl_side_painting) {
StepCompleteOnImplThread(impl);
PostStepCompleteToMainThread();
++time_step_;
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 622143d..3abc4dc 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -106,7 +106,7 @@
settings.verify_property_trees = true;
settings.raster_enabled = false;
layer_tree_host_ = LayerTreeHost::CreateSingleThreaded(
- this, this, nullptr, nullptr, settings, nullptr, nullptr);
+ this, this, nullptr, 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_picture.cc b/cc/trees/layer_tree_host_unittest_picture.cc
index 5ce47cd..7d3d525 100644
--- a/cc/trees/layer_tree_host_unittest_picture.cc
+++ b/cc/trees/layer_tree_host_unittest_picture.cc
@@ -565,7 +565,8 @@
// Multi-thread only because in single thread you can't pinch zoom on the
// compositor thread.
-MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale);
+// Disabled due to flakiness. See http://crbug.com/460581
+// MULTI_THREAD_IMPL_TEST_F(LayerTreeHostPictureTestRSLLMembershipWithScale);
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index 547ece7..be972e9 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -429,14 +429,19 @@
PostSetNeedsCommitToMainThread();
break;
case 1:
- EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(), scroll_amount_);
- EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2dF());
+ EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(),
+ gfx::ToFlooredVector2d(scroll_amount_));
+ EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(),
+ gfx::Vector2dF(fmod(scroll_amount_.x(), 1.0f), 0.0f));
PostSetNeedsCommitToMainThread();
break;
case 2:
- EXPECT_VECTOR_EQ(scroll_layer->BaseScrollOffset(),
- (scroll_amount_ + scroll_amount_));
- EXPECT_VECTOR_EQ(scroll_layer->ScrollDelta(), gfx::Vector2dF());
+ EXPECT_VECTOR_EQ(
+ scroll_layer->BaseScrollOffset(),
+ gfx::ToFlooredVector2d(scroll_amount_ + scroll_amount_));
+ EXPECT_VECTOR_EQ(
+ scroll_layer->ScrollDelta(),
+ gfx::Vector2dF(fmod(2.0f * scroll_amount_.x(), 1.0f), 0.0f));
EndTest();
break;
}
@@ -1121,14 +1126,10 @@
ASSERT_TRUE(impl_thread.message_loop_proxy().get());
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
- scoped_ptr<LayerTreeHost> layer_tree_host =
- LayerTreeHost::CreateThreaded(&client,
- shared_bitmap_manager.get(),
- NULL,
- settings,
- base::MessageLoopProxy::current(),
- impl_thread.message_loop_proxy(),
- nullptr);
+ scoped_ptr<LayerTreeHost> layer_tree_host = LayerTreeHost::CreateThreaded(
+ &client, shared_bitmap_manager.get(), NULL, NULL, settings,
+ base::MessageLoopProxy::current(), impl_thread.message_loop_proxy(),
+ nullptr);
impl_thread.message_loop_proxy()
->PostTask(FROM_HERE,
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index a27630e..b5f8aed 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -982,7 +982,8 @@
return layer_tree_host_impl_->animation_registrar();
}
-void LayerTreeImpl::GetAllTilesForTracing(std::set<const Tile*>* tiles) const {
+void LayerTreeImpl::GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const {
typedef LayerIterator<LayerImpl> LayerIteratorType;
LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list_);
for (LayerIteratorType it =
@@ -992,7 +993,7 @@
if (!it.represents_itself())
continue;
LayerImpl* layer_impl = *it;
- layer_impl->GetAllTilesForTracing(tiles);
+ layer_impl->GetAllTilesAndPrioritiesForTracing(tile_map);
}
}
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 15e0f0c..a8c58d1 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -116,7 +116,8 @@
// Tracing methods.
// ---------------------------------------------------------------------------
- void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
+ void GetAllTilesAndPrioritiesForTracing(
+ std::map<const Tile*, TilePriority>* tile_map) const;
void AsValueInto(base::trace_event::TracedValue* dict) const;
// Other public methods
diff --git a/cc/trees/layer_tree_impl_unittest.cc b/cc/trees/layer_tree_impl_unittest.cc
index 06df3c2..c4abd52 100644
--- a/cc/trees/layer_tree_impl_unittest.cc
+++ b/cc/trees/layer_tree_impl_unittest.cc
@@ -13,6 +13,7 @@
#include "cc/test/geometry_test_utils.h"
#include "cc/test/layer_tree_host_common_test.h"
#include "cc/test/test_shared_bitmap_manager.h"
+#include "cc/test/test_task_graph_runner.h"
#include "cc/trees/layer_tree_host_impl.h"
#include "ui/gfx/geometry/size_conversions.h"
@@ -25,8 +26,8 @@
LayerTreeSettings settings;
settings.layer_transforms_should_scale_layer_contents = true;
settings.scrollbar_show_scale_threshold = 1.1f;
- host_impl_.reset(
- new FakeLayerTreeHostImpl(settings, &proxy_, &shared_bitmap_manager_));
+ host_impl_.reset(new FakeLayerTreeHostImpl(
+ settings, &proxy_, &shared_bitmap_manager_, &task_graph_runner_));
EXPECT_TRUE(host_impl_->InitializeRenderer(FakeOutputSurface::Create3d()));
}
@@ -40,6 +41,7 @@
private:
TestSharedBitmapManager shared_bitmap_manager_;
+ TestTaskGraphRunner task_graph_runner_;
FakeImplProxy proxy_;
scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
};
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 96c9d16..09314ad 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -70,9 +70,30 @@
use_occlusion_for_tile_prioritization(false),
record_full_layer(false),
use_display_lists(false),
- verify_property_trees(false) {
+ verify_property_trees(false),
+ gather_pixel_refs(false) {
}
LayerTreeSettings::~LayerTreeSettings() {}
+SchedulerSettings LayerTreeSettings::ToSchedulerSettings() const {
+ SchedulerSettings scheduler_settings;
+ scheduler_settings.use_external_begin_frame_source =
+ use_external_begin_frame_source;
+ scheduler_settings.main_frame_before_activation_enabled =
+ main_frame_before_activation_enabled;
+ scheduler_settings.impl_side_painting = impl_side_painting;
+ scheduler_settings.timeout_and_draw_when_animation_checkerboards =
+ timeout_and_draw_when_animation_checkerboards;
+ scheduler_settings.maximum_number_of_failed_draws_before_draw_is_forced_ =
+ maximum_number_of_failed_draws_before_draw_is_forced_;
+ scheduler_settings.using_synchronous_renderer_compositor =
+ using_synchronous_renderer_compositor;
+ scheduler_settings.throttle_frame_production = throttle_frame_production;
+ scheduler_settings.main_thread_should_always_be_low_latency = false;
+ scheduler_settings.background_frame_interval =
+ base::TimeDelta::FromSecondsD(1.0 / background_animation_rate);
+ return scheduler_settings;
+}
+
} // namespace cc
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 4554362..1f61f89 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -9,6 +9,7 @@
#include "cc/base/cc_export.h"
#include "cc/debug/layer_tree_debug_state.h"
#include "cc/output/renderer_settings.h"
+#include "cc/scheduler/scheduler_settings.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/geometry/size.h"
@@ -82,8 +83,11 @@
bool record_full_layer;
bool use_display_lists;
bool verify_property_trees;
+ bool gather_pixel_refs;
LayerTreeDebugState initial_debug_state;
+
+ SchedulerSettings ToSchedulerSettings() const;
};
} // namespace cc
diff --git a/cc/trees/occlusion_tracker_perftest.cc b/cc/trees/occlusion_tracker_perftest.cc
index e53a05f..854dacd 100644
--- a/cc/trees/occlusion_tracker_perftest.cc
+++ b/cc/trees/occlusion_tracker_perftest.cc
@@ -36,13 +36,9 @@
void CreateHost() {
LayerTreeSettings settings;
shared_bitmap_manager_.reset(new TestSharedBitmapManager());
- host_impl_ = LayerTreeHostImpl::Create(settings,
- &client_,
- &proxy_,
- &stats_,
- shared_bitmap_manager_.get(),
- NULL,
- 1);
+ host_impl_ =
+ LayerTreeHostImpl::Create(settings, &client_, &proxy_, &stats_,
+ shared_bitmap_manager_.get(), NULL, NULL, 1);
host_impl_->InitializeRenderer(FakeOutputSurface::Create3d());
scoped_ptr<LayerImpl> root_layer = LayerImpl::Create(active_tree(), 1);
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index 0db2ad7..3da729e 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -27,8 +27,6 @@
Layer* render_target;
int clip_tree_parent;
int opacity_tree_parent;
- gfx::Vector2dF offset_to_transform_tree_parent;
- gfx::Vector2dF offset_to_transform_fixed_parent;
const Layer* page_scale_layer;
float page_scale_factor;
float device_scale_factor;
@@ -131,11 +129,17 @@
Layer* transform_parent = GetTransformParent(data_from_ancestor, layer);
- // May be non-zero if layer is fixed or has a scroll parent.
gfx::Vector2dF parent_offset;
if (transform_parent) {
- // TODO(vollick): This is to mimic existing bugs (crbug.com/441447).
- if (!is_fixed) {
+ if (layer->scroll_parent()) {
+ gfx::Transform to_parent;
+ Layer* source = layer->parent();
+ parent_offset += source->offset_to_transform_parent();
+ data_from_ancestor.transform_tree->ComputeTransform(
+ source->transform_tree_index(),
+ transform_parent->transform_tree_index(), &to_parent);
+ parent_offset += to_parent.To2dTranslation();
+ } else if (!is_fixed) {
parent_offset = transform_parent->offset_to_transform_parent();
} else if (data_from_ancestor.transform_tree_parent !=
data_from_ancestor.transform_fixed_parent) {
@@ -150,18 +154,6 @@
fixed_offset += parent_to_parent.To2dTranslation();
parent_offset += fixed_offset;
}
-
- gfx::Transform to_parent;
- Layer* source = data_from_ancestor.transform_tree_parent;
- if (layer->scroll_parent()) {
- source = layer->parent();
- parent_offset += layer->parent()->offset_to_transform_parent();
- }
- data_from_ancestor.transform_tree->ComputeTransform(
- source->transform_tree_index(),
- transform_parent->transform_tree_index(), &to_parent);
-
- parent_offset += to_parent.To2dTranslation();
}
if (layer->IsContainerForFixedPositionLayers() || is_root)
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 1ecce4d..b6084bc 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -5,6 +5,7 @@
#include "cc/trees/single_thread_proxy.h"
#include "base/auto_reset.h"
+#include "base/profiler/scoped_tracker.h"
#include "base/trace_event/trace_event.h"
#include "cc/debug/benchmark_instrumentation.h"
#include "cc/debug/devtools_instrumentation.h"
@@ -96,7 +97,8 @@
DebugScopedSetImplThread impl(this);
if (layer_tree_host_->settings().single_thread_proxy_scheduler &&
!scheduler_on_impl_thread_) {
- SchedulerSettings scheduler_settings(layer_tree_host_->settings());
+ SchedulerSettings scheduler_settings(
+ layer_tree_host_->settings().ToSchedulerSettings());
// SingleThreadProxy should run in main thread low latency mode.
scheduler_settings.main_thread_should_always_be_low_latency = true;
scheduler_on_impl_thread_ =
@@ -208,6 +210,10 @@
TRACE_EVENT0("cc", "SingleThreadProxy::DoCommit");
DCHECK(Proxy::IsMainThread());
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION("461509 SingleThreadProxy::DoCommit1"));
commit_requested_ = false;
layer_tree_host_->WillCommit();
devtools_instrumentation::ScopedCommitTrace commit_task(
@@ -215,6 +221,11 @@
// Commit immediately.
{
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit2"));
DebugScopedSetMainThreadBlocked main_thread_blocked(this);
DebugScopedSetImplThread impl(this);
@@ -228,21 +239,47 @@
if (PrioritizedResourceManager* contents_texture_manager =
layer_tree_host_->contents_texture_manager()) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit3"));
contents_texture_manager->PushTexturePrioritiesToBackings();
}
layer_tree_host_->BeginCommitOnImplThread(layer_tree_host_impl_.get());
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit4"));
scoped_ptr<ResourceUpdateController> update_controller =
ResourceUpdateController::Create(
NULL,
MainThreadTaskRunner(),
queue_for_commit_.Pass(),
layer_tree_host_impl_->resource_provider());
+
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile5(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit5"));
update_controller->Finalize();
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile6(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit6"));
if (layer_tree_host_impl_->EvictedUIResourcesExist())
layer_tree_host_->RecreateUIResources();
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile7(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit7"));
layer_tree_host_->FinishCommitOnImplThread(layer_tree_host_impl_.get());
#if DCHECK_IS_ON()
@@ -255,6 +292,11 @@
#endif
if (layer_tree_host_->settings().impl_side_painting) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile8(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit8"));
// Commit goes directly to the active tree, but we need to synchronously
// "activate" the tree still during commit to satisfy any potential
// SetNextCommitWaitsForActivation calls. Unfortunately, the tree
@@ -262,6 +304,11 @@
// the flag to force the tree to not draw until textures are ready.
NotifyReadyToActivate();
} else {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile9(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoCommit9"));
CommitComplete();
}
}
@@ -596,6 +643,12 @@
DebugScopedSetImplThread impl(this);
base::AutoReset<bool> mark_inside(&inside_draw_, true);
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile1(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite1"));
+
// We guard PrepareToDraw() with CanDraw() because it always returns a valid
// frame, so can only be used when such a frame is possible. Since
// DrawLayers() depends on the result of PrepareToDraw(), it is guarded on
@@ -606,16 +659,47 @@
timing_history_.DidStartDrawing();
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile2(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite2"));
draw_result = layer_tree_host_impl_->PrepareToDraw(frame);
draw_frame = draw_result == DRAW_SUCCESS;
- if (draw_frame)
+ if (draw_frame) {
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile3(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite3"));
layer_tree_host_impl_->DrawLayers(frame, frame_begin_time);
+ }
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile4(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite4"));
layer_tree_host_impl_->DidDrawAllLayers(*frame);
bool start_ready_animations = draw_frame;
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile5(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite5"));
layer_tree_host_impl_->UpdateAnimationState(start_ready_animations);
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile6(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite6"));
layer_tree_host_impl_->ResetCurrentBeginFrameArgsForNextFrame();
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile7(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite7"));
timing_history_.DidFinishDrawing();
}
@@ -634,8 +718,18 @@
BlockingTaskRunner::CapturePostTasks blocked(
blocking_main_thread_task_runner());
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509
+ // is fixed.
+ tracked_objects::ScopedTracker tracking_profile8(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite8"));
layer_tree_host_impl_->SwapBuffers(*frame);
}
+ // TODO(robliao): Remove ScopedTracker below once https://crbug.com/461509 is
+ // fixed.
+ tracked_objects::ScopedTracker tracking_profile9(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "461509 SingleThreadProxy::DoComposite9"));
DidCommitAndDrawFrame();
return draw_result;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 6e1a0d9..ff2ca46 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -1165,7 +1165,8 @@
DCHECK(IsImplThread());
impl().layer_tree_host_impl =
layer_tree_host()->CreateLayerTreeHostImpl(this);
- SchedulerSettings scheduler_settings(layer_tree_host()->settings());
+ SchedulerSettings scheduler_settings(
+ layer_tree_host()->settings().ToSchedulerSettings());
impl().scheduler = Scheduler::Create(
this,
scheduler_settings,
diff --git a/cc/trees/tree_synchronizer_unittest.cc b/cc/trees/tree_synchronizer_unittest.cc
index d48f821..a17bec8 100644
--- a/cc/trees/tree_synchronizer_unittest.cc
+++ b/cc/trees/tree_synchronizer_unittest.cc
@@ -556,13 +556,8 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings,
- NULL,
- &proxy,
- &stats_instrumentation,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(settings, NULL, &proxy, &stats_instrumentation,
+ shared_bitmap_manager.get(), NULL, NULL, 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
host_->SetRootLayer(layer_tree_root);
@@ -595,13 +590,8 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings,
- NULL,
- &proxy,
- &stats_instrumentation,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(settings, NULL, &proxy, &stats_instrumentation,
+ shared_bitmap_manager.get(), NULL, NULL, 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> scroll_parent = Layer::Create();
@@ -668,13 +658,8 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
scoped_ptr<LayerTreeHostImpl> host_impl =
- LayerTreeHostImpl::Create(settings,
- NULL,
- &proxy,
- &stats_instrumentation,
- shared_bitmap_manager.get(),
- NULL,
- 0);
+ LayerTreeHostImpl::Create(settings, NULL, &proxy, &stats_instrumentation,
+ shared_bitmap_manager.get(), NULL, NULL, 0);
scoped_refptr<Layer> layer_tree_root = Layer::Create();
scoped_refptr<Layer> clip_parent = Layer::Create();
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index d5b799e..af23813 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -82,6 +82,7 @@
{'name': 'scissor_test'},
{'name': 'stencil_test',
'state_flag': 'framebuffer_state_.clear_state_dirty'},
+ {'name': 'rasterizer_discard', 'es3': True},
]
_STATES = {
@@ -898,7 +899,10 @@
},
'Capability': {
'type': 'GLenum',
- 'valid': ["GL_%s" % cap['name'].upper() for cap in _CAPABILITY_FLAGS],
+ 'valid': ["GL_%s" % cap['name'].upper() for cap in _CAPABILITY_FLAGS
+ if 'es3' not in cap or cap['es3'] != True],
+ 'valid_es3': ["GL_%s" % cap['name'].upper() for cap in _CAPABILITY_FLAGS
+ if 'es3' in cap and cap['es3'] == True],
'invalid': [
'GL_CLIP_PLANE0',
'GL_POINT_SPRITE',
@@ -2676,7 +2680,7 @@
},
'MapTexSubImage2DCHROMIUM': {
'gen_cmd': False,
- 'extension': True,
+ 'extension': "CHROMIUM_sub_image",
'chromium': True,
'client_test': False,
'pepper_interface': 'ChromiumMapSub',
@@ -3082,7 +3086,7 @@
},
'UnmapTexSubImage2DCHROMIUM': {
'gen_cmd': False,
- 'extension': True,
+ 'extension': "CHROMIUM_sub_image",
'chromium': True,
'client_test': False,
'pepper_interface': 'ChromiumMapSub',
@@ -3265,6 +3269,7 @@
'unit_test': False,
'pepper_interface': 'Query',
'not_shared': 'True',
+ 'extension': "occlusion_query_EXT",
},
'DeleteQueriesEXT': {
'type': 'DELn',
@@ -3273,11 +3278,13 @@
'resource_types': 'Queries',
'unit_test': False,
'pepper_interface': 'Query',
+ 'extension': "occlusion_query_EXT",
},
'IsQueryEXT': {
'gen_cmd': False,
'client_test': False,
'pepper_interface': 'Query',
+ 'extension': "occlusion_query_EXT",
},
'BeginQueryEXT': {
'type': 'Manual',
@@ -3285,6 +3292,7 @@
'data_transfer_methods': ['shm'],
'gl_test_func': 'glBeginQuery',
'pepper_interface': 'Query',
+ 'extension': "occlusion_query_EXT",
},
'BeginTransformFeedback': {
'unsafe': True,
@@ -3295,6 +3303,7 @@
'gl_test_func': 'glEndnQuery',
'client_test': False,
'pepper_interface': 'Query',
+ 'extension': "occlusion_query_EXT",
},
'EndTransformFeedback': {
'unsafe': True,
@@ -3304,12 +3313,14 @@
'client_test': False,
'gl_test_func': 'glGetQueryiv',
'pepper_interface': 'Query',
+ 'extension': "occlusion_query_EXT",
},
'GetQueryObjectuivEXT': {
'gen_cmd': False,
'client_test': False,
'gl_test_func': 'glGetQueryObjectuiv',
'pepper_interface': 'Query',
+ 'extension': "occlusion_query_EXT",
},
'BindUniformLocationCHROMIUM': {
'type': 'GLchar',
@@ -3396,7 +3407,7 @@
'ShallowFlushCHROMIUM': {
'impl_func': False,
'gen_cmd': False,
- 'extension': True,
+ 'extension': "CHROMIUM_miscellaneous",
'chromium': True,
'client_test': False,
},
@@ -4198,6 +4209,46 @@
(func.return_type, func.original_name,
func.MakeTypedOriginalArgString("")))
+ def WriteMojoGLES2ImplHeader(self, func, file):
+ """Writes the Mojo GLES2 implementation header."""
+ file.Write("%s %s(%s) override;\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+
+ def WriteMojoGLES2Impl(self, func, file):
+ """Writes the Mojo GLES2 implementation."""
+ file.Write("%s MojoGLES2Impl::%s(%s) {\n" %
+ (func.return_type, func.original_name,
+ func.MakeTypedOriginalArgString("")))
+ # TODO(alhaad): Add Mojo C thunk for each of the following methods and
+ # remove this.
+ func_list = ["GenQueriesEXT", "BeginQueryEXT", "MapTexSubImage2DCHROMIUM",
+ "UnmapTexSubImage2DCHROMIUM", "DeleteQueriesEXT",
+ "EndQueryEXT", "GetQueryObjectuivEXT", "ShallowFlushCHROMIUM"]
+ if func.original_name in func_list:
+ file.Write("return static_cast<gpu::gles2::GLES2Interface*>"
+ "(MojoGLES2GetGLES2Interface(context_))->" +
+ func.original_name + "(" + func.MakeOriginalArgString("") +
+ ");")
+ file.Write("}")
+ return
+
+ extensions = ["CHROMIUM_sync_point", "CHROMIUM_texture_mailbox"]
+ if func.IsCoreGLFunction() or func.GetInfo("extension") in extensions:
+ file.Write("MojoGLES2MakeCurrent(context_);");
+ func_return = "gl" + func.original_name + "(" + \
+ func.MakeOriginalArgString("") + ");"
+ if func.return_type == "void":
+ file.Write(func_return);
+ else:
+ file.Write("return " + func_return);
+ else:
+ file.Write("NOTREACHED() << \"Unimplemented %s.\";\n" %
+ func.original_name);
+ if func.return_type != "void":
+ file.Write("return 0;")
+ file.Write("}")
+
def WriteGLES2InterfaceStub(self, func, file):
"""Writes the GLES2 Interface stub declaration."""
file.Write("%s %s(%s) override;\n" %
@@ -8907,6 +8958,14 @@
"""Writes the GLES2 Interface declaration."""
self.type_handler.WriteGLES2InterfaceHeader(self, file)
+ def WriteMojoGLES2ImplHeader(self, file):
+ """Writes the Mojo GLES2 implementation header declaration."""
+ self.type_handler.WriteMojoGLES2ImplHeader(self, file)
+
+ def WriteMojoGLES2Impl(self, file):
+ """Writes the Mojo GLES2 implementation declaration."""
+ self.type_handler.WriteMojoGLES2Impl(self, file)
+
def WriteGLES2InterfaceStub(self, file):
"""Writes the GLES2 Interface Stub declaration."""
self.type_handler.WriteGLES2InterfaceStub(self, file)
@@ -9534,20 +9593,31 @@
file.Write("""
void ContextState::InitCapabilities(const ContextState* prev_state) const {
""")
- def WriteCapabilities(test_prev):
+ def WriteCapabilities(test_prev, es3_caps):
for capability in _CAPABILITY_FLAGS:
capability_name = capability['name']
+ capability_es3 = 'es3' in capability and capability['es3'] == True
+ if capability_es3 and not es3_caps or not capability_es3 and es3_caps:
+ continue
if test_prev:
file.Write(""" if (prev_state->enable_flags.cached_%s !=
- enable_flags.cached_%s)\n""" %
+ enable_flags.cached_%s) {\n""" %
(capability_name, capability_name))
file.Write(" EnableDisable(GL_%s, enable_flags.cached_%s);\n" %
(capability_name.upper(), capability_name))
+ if test_prev:
+ file.Write(" }")
file.Write(" if (prev_state) {")
- WriteCapabilities(True)
+ WriteCapabilities(True, False)
+ file.Write(" if (feature_info_->IsES3Capable()) {\n")
+ WriteCapabilities(True, True)
+ file.Write(" }\n")
file.Write(" } else {")
- WriteCapabilities(False)
+ WriteCapabilities(False, False)
+ file.Write(" if (feature_info_->IsES3Capable()) {\n")
+ WriteCapabilities(False, True)
+ file.Write(" }\n")
file.Write(" }")
file.Write("""}
@@ -9783,13 +9853,24 @@
filename % 0,
"// It is included by gles2_cmd_decoder_unittest_base.cc\n")
file.Write(
-"""void GLES2DecoderTestBase::SetupInitCapabilitiesExpectations() {
-""")
+"""void GLES2DecoderTestBase::SetupInitCapabilitiesExpectations(
+ bool es3_capable) {""")
for capability in _CAPABILITY_FLAGS:
- file.Write(" ExpectEnableDisable(GL_%s, %s);\n" %
- (capability['name'].upper(),
- ('false', 'true')['default' in capability]))
- file.Write("""}
+ capability_es3 = 'es3' in capability and capability['es3'] == True
+ if not capability_es3:
+ file.Write(" ExpectEnableDisable(GL_%s, %s);\n" %
+ (capability['name'].upper(),
+ ('false', 'true')['default' in capability]))
+
+ file.Write(" if (es3_capable) {")
+ for capability in _CAPABILITY_FLAGS:
+ capability_es3 = 'es3' in capability and capability['es3'] == True
+ if capability_es3:
+ file.Write(" ExpectEnableDisable(GL_%s, %s);\n" %
+ (capability['name'].upper(),
+ ('false', 'true')['default' in capability]))
+ file.Write(""" }
+}
void GLES2DecoderTestBase::SetupInitStateExpectations() {
""")
@@ -9930,6 +10011,68 @@
file.Close()
self.generated_cpp_filenames.append(file.filename)
+ def WriteMojoGLES2ImplHeader(self, filename):
+ """Writes the Mojo GLES2 implementation header."""
+ file = CHeaderWriter(
+ filename,
+ "// This file is included by gles2_interface.h to declare the\n"
+ "// GL api functions.\n")
+
+ code = """
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "third_party/mojo/src/mojo/public/c/gles2/gles2.h"
+
+namespace mojo {
+
+class MojoGLES2Impl : public gpu::gles2::GLES2Interface {
+ public:
+ explicit MojoGLES2Impl(MojoGLES2Context context) {
+ context_ = context;
+ }
+ ~MojoGLES2Impl() override {}
+ """
+ file.Write(code);
+ for func in self.original_functions:
+ func.WriteMojoGLES2ImplHeader(file)
+ code = """
+ private:
+ MojoGLES2Context context_;
+};
+
+} // namespace mojo
+ """
+ file.Write(code);
+ file.Close()
+ self.generated_cpp_filenames.append(file.filename)
+
+ def WriteMojoGLES2Impl(self, filename):
+ """Writes the Mojo GLES2 implementation."""
+ file = CWriter(filename)
+ file.Write(_LICENSE)
+ file.Write(_DO_NOT_EDIT_WARNING)
+
+ code = """
+#include "mojo/gpu/mojo_gles2_impl_autogen.h"
+
+#include "base/logging.h"
+#include "third_party/mojo/src/mojo/public/c/gles2/chromium_sync_point.h"
+#include "third_party/mojo/src/mojo/public/c/gles2/chromium_texture_mailbox.h"
+#include "third_party/mojo/src/mojo/public/c/gles2/gles2.h"
+
+namespace mojo {
+
+ """
+ file.Write(code);
+ for func in self.original_functions:
+ func.WriteMojoGLES2Impl(file)
+ code = """
+
+} // namespace mojo
+ """
+ file.Write(code);
+ file.Close()
+ self.generated_cpp_filenames.append(file.filename)
+
def WriteGLES2InterfaceStub(self, filename):
"""Writes the GLES2 interface stub header."""
file = CHeaderWriter(
@@ -10448,6 +10591,10 @@
"gpu/command_buffer/common/gles2_cmd_format_test_autogen.h")
gen.WriteGLES2InterfaceHeader(
"gpu/command_buffer/client/gles2_interface_autogen.h")
+ gen.WriteMojoGLES2ImplHeader(
+ "mojo/gpu/mojo_gles2_impl_autogen.h")
+ gen.WriteMojoGLES2Impl(
+ "mojo/gpu/mojo_gles2_impl_autogen.cc")
gen.WriteGLES2InterfaceStub(
"gpu/command_buffer/client/gles2_interface_stub_autogen.h")
gen.WriteGLES2InterfaceStubImpl(
@@ -10500,6 +10647,15 @@
gen.WriteMojoGLCallVisitorForExtension(
mojo_gles2_prefix + "_chromium_sync_point_autogen.h",
"CHROMIUM_sync_point")
+ gen.WriteMojoGLCallVisitorForExtension(
+ mojo_gles2_prefix + "_chromium_sub_image_autogen.h",
+ "CHROMIUM_sub_image")
+ gen.WriteMojoGLCallVisitorForExtension(
+ mojo_gles2_prefix + "_chromium_miscellaneous_autogen.h",
+ "CHROMIUM_miscellaneous")
+ gen.WriteMojoGLCallVisitorForExtension(
+ mojo_gles2_prefix + "_occlusion_query_ext_autogen.h",
+ "occlusion_query_EXT")
Format(gen.generated_cpp_filenames)
diff --git a/gpu/command_buffer/client/client_context_state.h b/gpu/command_buffer/client/client_context_state.h
index f5a93a6..a92c04a 100644
--- a/gpu/command_buffer/client/client_context_state.h
+++ b/gpu/command_buffer/client/client_context_state.h
@@ -7,7 +7,7 @@
#ifndef GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_H_
#define GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_H_
-#include <GLES2/gl2.h>
+#include <GLES3/gl3.h>
#include <vector>
#include "gles2_impl_export.h"
diff --git a/gpu/command_buffer/client/client_context_state_autogen.h b/gpu/command_buffer/client/client_context_state_autogen.h
index 72a4f72..aa4b8fd 100644
--- a/gpu/command_buffer/client/client_context_state_autogen.h
+++ b/gpu/command_buffer/client/client_context_state_autogen.h
@@ -23,6 +23,7 @@
bool sample_coverage;
bool scissor_test;
bool stencil_test;
+ bool rasterizer_discard;
};
#endif // GPU_COMMAND_BUFFER_CLIENT_CLIENT_CONTEXT_STATE_AUTOGEN_H_
diff --git a/gpu/command_buffer/client/client_context_state_impl_autogen.h b/gpu/command_buffer/client/client_context_state_impl_autogen.h
index cff14f7..d0ce722 100644
--- a/gpu/command_buffer/client/client_context_state_impl_autogen.h
+++ b/gpu/command_buffer/client/client_context_state_impl_autogen.h
@@ -21,7 +21,8 @@
sample_alpha_to_coverage(false),
sample_coverage(false),
scissor_test(false),
- stencil_test(false) {
+ stencil_test(false),
+ rasterizer_discard(false) {
}
bool ClientContextState::SetCapabilityState(GLenum cap,
@@ -83,6 +84,12 @@
enable_flags.stencil_test = enabled;
}
return true;
+ case GL_RASTERIZER_DISCARD:
+ if (enable_flags.rasterizer_discard != enabled) {
+ *changed = true;
+ enable_flags.rasterizer_discard = enabled;
+ }
+ return true;
default:
return false;
}
@@ -116,6 +123,9 @@
case GL_STENCIL_TEST:
*enabled = enable_flags.stencil_test;
return true;
+ case GL_RASTERIZER_DISCARD:
+ *enabled = enable_flags.rasterizer_discard;
+ return true;
default:
return false;
}
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index fe59c2a..139dc65 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -4975,7 +4975,7 @@
SetGLError(GL_INVALID_VALUE, func, "size < 0");
return false;
}
- if (!FitInt32NonNegative<GLsizeiptr>(size)) {
+ if (!base::IsValueInRangeForNumericType<int32_t>(size)) {
SetGLError(GL_INVALID_OPERATION, func, "size more than 32-bit");
return false;
}
@@ -4987,7 +4987,7 @@
SetGLError(GL_INVALID_VALUE, func, "offset < 0");
return false;
}
- if (!FitInt32NonNegative<GLintptr>(offset)) {
+ if (!base::IsValueInRangeForNumericType<int32_t>(offset)) {
SetGLError(GL_INVALID_OPERATION, func, "offset more than 32-bit");
return false;
}
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 22f826f..caf30af 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -404,13 +404,14 @@
// Return the number of bytes per element, based on the element type.
int BytesPerElement(int type) {
switch (type) {
+ case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
+ return 8;
case GL_FLOAT:
case GL_UNSIGNED_INT_24_8_OES:
case GL_UNSIGNED_INT:
case GL_UNSIGNED_INT_2_10_10_10_REV:
case GL_UNSIGNED_INT_10F_11F_11F_REV:
case GL_UNSIGNED_INT_5_9_9_9_REV:
- case GL_FLOAT_32_UNSIGNED_INT_24_8_REV:
return 4;
case GL_HALF_FLOAT_OES:
case GL_UNSIGNED_SHORT:
@@ -430,12 +431,18 @@
} // anonymous namespace
uint32 GLES2Util::ComputeImageGroupSize(int format, int type) {
- return BytesPerElement(type) * ElementsPerGroup(format, type);
+ int bytes_per_element = BytesPerElement(type);
+ DCHECK_GE(8, bytes_per_element);
+ int elements_per_group = ElementsPerGroup(format, type);
+ DCHECK_GE(4, elements_per_group);
+ return bytes_per_element * elements_per_group;
}
bool GLES2Util::ComputeImagePaddedRowSize(
int width, int format, int type, int unpack_alignment,
uint32* padded_row_size) {
+ DCHECK(unpack_alignment == 1 || unpack_alignment == 2 ||
+ unpack_alignment == 4 || unpack_alignment == 8);
uint32 bytes_per_group = ComputeImageGroupSize(format, type);
uint32 unpadded_row_size;
if (!SafeMultiplyUint32(width, bytes_per_group, &unpadded_row_size)) {
@@ -454,6 +461,8 @@
int width, int height, int depth, int format, int type,
int unpack_alignment, uint32* size, uint32* ret_unpadded_row_size,
uint32* ret_padded_row_size) {
+ DCHECK(unpack_alignment == 1 || unpack_alignment == 2 ||
+ unpack_alignment == 4 || unpack_alignment == 8);
uint32 bytes_per_group = ComputeImageGroupSize(format, type);
uint32 row_size;
if (!SafeMultiplyUint32(width, bytes_per_group, &row_size)) {
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 1661247..e6b8bf0 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -14,6 +14,7 @@
#include <string>
#include <vector>
+#include "base/numerics/safe_math.h"
#include "gpu/command_buffer/common/gles2_utils_export.h"
namespace gpu {
@@ -25,44 +26,29 @@
// Multiplies 2 32 bit unsigned numbers checking for overflow.
// If there was no overflow returns true.
inline bool SafeMultiplyUint32(uint32_t a, uint32_t b, uint32_t* dst) {
- if (b == 0) {
- *dst = 0;
- return true;
- }
- uint32_t v = a * b;
- if (v / b != a) {
- *dst = 0;
- return false;
- }
- *dst = v;
- return true;
+ DCHECK(dst);
+ base::CheckedNumeric<uint32_t> checked = a;
+ checked *= b;
+ *dst = checked.ValueOrDefault(0);
+ return checked.IsValid();
}
// Does an add checking for overflow. If there was no overflow returns true.
inline bool SafeAddUint32(uint32_t a, uint32_t b, uint32_t* dst) {
- if (a + b < a) {
- *dst = 0;
- return false;
- }
- *dst = a + b;
- return true;
+ DCHECK(dst);
+ base::CheckedNumeric<uint32_t> checked = a;
+ checked += b;
+ *dst = checked.ValueOrDefault(0);
+ return checked.IsValid();
}
// Does an add checking for overflow. If there was no overflow returns true.
inline bool SafeAddInt32(int32_t a, int32_t b, int32_t* dst) {
- int64_t sum64 = static_cast<int64_t>(a) + b;
- int32_t sum32 = static_cast<int32_t>(sum64);
- bool safe = sum64 == static_cast<int64_t>(sum32);
- *dst = safe ? sum32 : 0;
- return safe;
-}
-
-// Return false if |value| is more than a 32 bit integer can represent.
-template<typename T>
-inline bool FitInt32NonNegative(T value) {
- const int32_t max = std::numeric_limits<int32_t>::max();
- return (std::numeric_limits<T>::max() <= max ||
- value <= static_cast<T>(max));
+ DCHECK(dst);
+ base::CheckedNumeric<int32_t> checked = a;
+ checked += b;
+ *dst = checked.ValueOrDefault(0);
+ return checked.IsValid();
}
// Utilties for GLES2 support.
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 fade8fa..42da99f 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -4560,6 +4560,7 @@
{GL_SAMPLE_COVERAGE, "GL_SAMPLE_COVERAGE"},
{GL_SCISSOR_TEST, "GL_SCISSOR_TEST"},
{GL_STENCIL_TEST, "GL_STENCIL_TEST"},
+ {GL_RASTERIZER_DISCARD, "GL_RASTERIZER_DISCARD"},
};
return GLES2Util::GetQualifiedEnumString(string_table,
arraysize(string_table), value);
@@ -4768,6 +4769,7 @@
{GL_SAMPLE_COVERAGE, "GL_SAMPLE_COVERAGE"},
{GL_SCISSOR_TEST, "GL_SCISSOR_TEST"},
{GL_STENCIL_TEST, "GL_STENCIL_TEST"},
+ {GL_RASTERIZER_DISCARD, "GL_RASTERIZER_DISCARD"},
};
return GLES2Util::GetQualifiedEnumString(string_table,
arraysize(string_table), value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc b/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
index 58a6c38..8f7f94f 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils_unittest.cc
@@ -232,8 +232,8 @@
EXPECT_TRUE(GLES2Util::ComputeImageDataSizes(
kWidth, kHeight, 1, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV,
1, &size, &unpadded_row_size, &padded_row_size));
- EXPECT_EQ(kWidth * kHeight * 4, size);
- EXPECT_EQ(kWidth * 4, padded_row_size);
+ EXPECT_EQ(kWidth * kHeight * 8, size);
+ EXPECT_EQ(kWidth * 8, padded_row_size);
EXPECT_EQ(padded_row_size, unpadded_row_size);
}
diff --git a/gpu/command_buffer/service/context_state_autogen.h b/gpu/command_buffer/service/context_state_autogen.h
index fcae244..405addd 100644
--- a/gpu/command_buffer/service/context_state_autogen.h
+++ b/gpu/command_buffer/service/context_state_autogen.h
@@ -32,6 +32,8 @@
bool cached_scissor_test;
bool stencil_test;
bool cached_stencil_test;
+ bool rasterizer_discard;
+ bool cached_rasterizer_discard;
};
GLfloat blend_color_red;
@@ -150,6 +152,12 @@
return;
enable_flags.cached_stencil_test = enable;
break;
+ case GL_RASTERIZER_DISCARD:
+ if (enable_flags.cached_rasterizer_discard == enable &&
+ !ignore_cached_state)
+ return;
+ enable_flags.cached_rasterizer_discard = enable;
+ break;
default:
NOTREACHED();
return;
diff --git a/gpu/command_buffer/service/context_state_impl_autogen.h b/gpu/command_buffer/service/context_state_impl_autogen.h
index 037ac6c..467f1ce 100644
--- a/gpu/command_buffer/service/context_state_impl_autogen.h
+++ b/gpu/command_buffer/service/context_state_impl_autogen.h
@@ -30,7 +30,9 @@
scissor_test(false),
cached_scissor_test(false),
stencil_test(false),
- cached_stencil_test(false) {
+ cached_stencil_test(false),
+ rasterizer_discard(false),
+ cached_rasterizer_discard(false) {
}
void ContextState::Initialize() {
@@ -134,33 +136,49 @@
void ContextState::InitCapabilities(const ContextState* prev_state) const {
if (prev_state) {
- if (prev_state->enable_flags.cached_blend != enable_flags.cached_blend)
+ if (prev_state->enable_flags.cached_blend != enable_flags.cached_blend) {
EnableDisable(GL_BLEND, enable_flags.cached_blend);
+ }
if (prev_state->enable_flags.cached_cull_face !=
- enable_flags.cached_cull_face)
+ enable_flags.cached_cull_face) {
EnableDisable(GL_CULL_FACE, enable_flags.cached_cull_face);
+ }
if (prev_state->enable_flags.cached_depth_test !=
- enable_flags.cached_depth_test)
+ enable_flags.cached_depth_test) {
EnableDisable(GL_DEPTH_TEST, enable_flags.cached_depth_test);
- if (prev_state->enable_flags.cached_dither != enable_flags.cached_dither)
+ }
+ if (prev_state->enable_flags.cached_dither != enable_flags.cached_dither) {
EnableDisable(GL_DITHER, enable_flags.cached_dither);
+ }
if (prev_state->enable_flags.cached_polygon_offset_fill !=
- enable_flags.cached_polygon_offset_fill)
+ enable_flags.cached_polygon_offset_fill) {
EnableDisable(GL_POLYGON_OFFSET_FILL,
enable_flags.cached_polygon_offset_fill);
+ }
if (prev_state->enable_flags.cached_sample_alpha_to_coverage !=
- enable_flags.cached_sample_alpha_to_coverage)
+ enable_flags.cached_sample_alpha_to_coverage) {
EnableDisable(GL_SAMPLE_ALPHA_TO_COVERAGE,
enable_flags.cached_sample_alpha_to_coverage);
+ }
if (prev_state->enable_flags.cached_sample_coverage !=
- enable_flags.cached_sample_coverage)
+ enable_flags.cached_sample_coverage) {
EnableDisable(GL_SAMPLE_COVERAGE, enable_flags.cached_sample_coverage);
+ }
if (prev_state->enable_flags.cached_scissor_test !=
- enable_flags.cached_scissor_test)
+ enable_flags.cached_scissor_test) {
EnableDisable(GL_SCISSOR_TEST, enable_flags.cached_scissor_test);
+ }
if (prev_state->enable_flags.cached_stencil_test !=
- enable_flags.cached_stencil_test)
+ enable_flags.cached_stencil_test) {
EnableDisable(GL_STENCIL_TEST, enable_flags.cached_stencil_test);
+ }
+ if (feature_info_->IsES3Capable()) {
+ if (prev_state->enable_flags.cached_rasterizer_discard !=
+ enable_flags.cached_rasterizer_discard) {
+ EnableDisable(GL_RASTERIZER_DISCARD,
+ enable_flags.cached_rasterizer_discard);
+ }
+ }
} else {
EnableDisable(GL_BLEND, enable_flags.cached_blend);
EnableDisable(GL_CULL_FACE, enable_flags.cached_cull_face);
@@ -173,6 +191,10 @@
EnableDisable(GL_SAMPLE_COVERAGE, enable_flags.cached_sample_coverage);
EnableDisable(GL_SCISSOR_TEST, enable_flags.cached_scissor_test);
EnableDisable(GL_STENCIL_TEST, enable_flags.cached_stencil_test);
+ if (feature_info_->IsES3Capable()) {
+ EnableDisable(GL_RASTERIZER_DISCARD,
+ enable_flags.cached_rasterizer_discard);
+ }
}
}
@@ -358,6 +380,8 @@
return enable_flags.scissor_test;
case GL_STENCIL_TEST:
return enable_flags.stencil_test;
+ case GL_RASTERIZER_DISCARD:
+ return enable_flags.rasterizer_discard;
default:
NOTREACHED();
return false;
@@ -700,6 +724,12 @@
params[0] = static_cast<GLint>(enable_flags.stencil_test);
}
return true;
+ case GL_RASTERIZER_DISCARD:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLint>(enable_flags.rasterizer_discard);
+ }
+ return true;
default:
return false;
}
@@ -1037,6 +1067,12 @@
params[0] = static_cast<GLfloat>(enable_flags.stencil_test);
}
return true;
+ case GL_RASTERIZER_DISCARD:
+ *num_written = 1;
+ if (params) {
+ params[0] = static_cast<GLfloat>(enable_flags.rasterizer_discard);
+ }
+ return true;
default:
return false;
}
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 319e37d..0886768 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1641,11 +1641,16 @@
// Validates the program and location for a glGetUniform call and returns
// a SizeResult setup to receive the result. Returns true if glGetUniform
// should be called.
- bool GetUniformSetup(
- GLuint program, GLint fake_location,
- uint32 shm_id, uint32 shm_offset,
- error::Error* error, GLint* real_location, GLuint* service_id,
- void** result, GLenum* result_type);
+ bool GetUniformSetup(GLuint program,
+ GLint fake_location,
+ uint32 shm_id,
+ uint32 shm_offset,
+ error::Error* error,
+ GLint* real_location,
+ GLuint* service_id,
+ void** result,
+ GLenum* result_type,
+ GLsizei* result_size);
void MaybeExitOnContextLost();
bool WasContextLost() override;
@@ -9602,11 +9607,16 @@
return error::kNoError;
}
-bool GLES2DecoderImpl::GetUniformSetup(
- GLuint program_id, GLint fake_location,
- uint32 shm_id, uint32 shm_offset,
- error::Error* error, GLint* real_location,
- GLuint* service_id, void** result_pointer, GLenum* result_type) {
+bool GLES2DecoderImpl::GetUniformSetup(GLuint program_id,
+ GLint fake_location,
+ uint32 shm_id,
+ uint32 shm_offset,
+ error::Error* error,
+ GLint* real_location,
+ GLuint* service_id,
+ void** result_pointer,
+ GLenum* result_type,
+ GLsizei* result_size) {
DCHECK(error);
DCHECK(service_id);
DCHECK(result_pointer);
@@ -9658,6 +9668,7 @@
return false;
}
result->size = size;
+ *result_size = size;
*result_type = type;
return true;
}
@@ -9670,12 +9681,13 @@
GLint fake_location = c.location;
GLuint service_id;
GLenum result_type;
+ GLsizei result_size;
GLint real_location = -1;
Error error;
void* result;
- if (GetUniformSetup(
- program, fake_location, c.params_shm_id, c.params_shm_offset,
- &error, &real_location, &service_id, &result, &result_type)) {
+ if (GetUniformSetup(program, fake_location, c.params_shm_id,
+ c.params_shm_offset, &error, &real_location, &service_id,
+ &result, &result_type, &result_size)) {
glGetUniformiv(
service_id, real_location,
static_cast<cmds::GetUniformiv::Result*>(result)->GetData());
@@ -9695,13 +9707,14 @@
typedef cmds::GetUniformfv::Result Result;
Result* result;
GLenum result_type;
- if (GetUniformSetup(
- program, fake_location, c.params_shm_id, c.params_shm_offset,
- &error, &real_location, &service_id,
- reinterpret_cast<void**>(&result), &result_type)) {
+ GLsizei result_size;
+ if (GetUniformSetup(program, fake_location, c.params_shm_id,
+ c.params_shm_offset, &error, &real_location, &service_id,
+ reinterpret_cast<void**>(&result), &result_type,
+ &result_size)) {
if (result_type == GL_BOOL || result_type == GL_BOOL_VEC2 ||
result_type == GL_BOOL_VEC3 || result_type == GL_BOOL_VEC4) {
- GLsizei num_values = result->GetNumResults();
+ GLsizei num_values = result_size / sizeof(Result::Type);
scoped_ptr<GLint[]> temp(new GLint[num_values]);
glGetUniformiv(service_id, real_location, temp.get());
GLfloat* dst = result->GetData();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
index 3c353c4..9a27c2f 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_autogen.h
@@ -4871,6 +4871,14 @@
framebuffer_state_.clear_state_dirty = true;
}
return false;
+ case GL_RASTERIZER_DISCARD:
+ state_.enable_flags.rasterizer_discard = enabled;
+ if (state_.enable_flags.cached_rasterizer_discard != enabled ||
+ state_.ignore_cached_state) {
+ state_.enable_flags.cached_rasterizer_discard = enabled;
+ return true;
+ }
+ return false;
default:
NOTREACHED();
return false;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
index 0aca4df..b76e7bf 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_0_autogen.h
@@ -12,7 +12,7 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_0_AUTOGEN_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_0_AUTOGEN_H_
-void GLES2DecoderTestBase::SetupInitCapabilitiesExpectations() {
+void GLES2DecoderTestBase::SetupInitCapabilitiesExpectations(bool es3_capable) {
ExpectEnableDisable(GL_BLEND, false);
ExpectEnableDisable(GL_CULL_FACE, false);
ExpectEnableDisable(GL_DEPTH_TEST, false);
@@ -22,6 +22,9 @@
ExpectEnableDisable(GL_SAMPLE_COVERAGE, false);
ExpectEnableDisable(GL_SCISSOR_TEST, false);
ExpectEnableDisable(GL_STENCIL_TEST, false);
+ if (es3_capable) {
+ ExpectEnableDisable(GL_RASTERIZER_DISCARD, false);
+ }
}
void GLES2DecoderTestBase::SetupInitStateExpectations() {
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 c75d7f5..119096b 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.cc
@@ -338,7 +338,7 @@
max_viewport_dims, max_viewport_dims + arraysize(max_viewport_dims)))
.RetiresOnSaturation();
- SetupInitCapabilitiesExpectations();
+ SetupInitCapabilitiesExpectations(group_->feature_info()->IsES3Capable());
SetupInitStateExpectations();
EXPECT_CALL(*gl_, ActiveTexture(GL_TEXTURE0))
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 18e7422..0ca537a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_base.h
@@ -229,7 +229,7 @@
GLuint vertex_shader_client_id, GLuint vertex_shader_service_id,
GLuint fragment_shader_client_id, GLuint fragment_shader_service_id);
- void SetupInitCapabilitiesExpectations();
+ void SetupInitCapabilitiesExpectations(bool es3_capable);
void SetupInitStateExpectations();
void ExpectEnableDisable(GLenum cap, bool enable);
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 ee63b3a..22c5be7 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -88,6 +88,10 @@
GL_STENCIL_TEST,
};
+static const GLenum valid_capability_table_es3[] = {
+ GL_RASTERIZER_DISCARD,
+};
+
static const GLenum valid_cmp_function_table[] = {
GL_NEVER,
GL_LESS,
@@ -246,6 +250,7 @@
GL_SAMPLE_COVERAGE,
GL_SCISSOR_TEST,
GL_STENCIL_TEST,
+ GL_RASTERIZER_DISCARD,
};
static const GLenum valid_get_max_index_type_table[] = {
@@ -936,6 +941,8 @@
void Validators::UpdateValuesES3() {
buffer_target.AddValues(valid_buffer_target_table_es3,
arraysize(valid_buffer_target_table_es3));
+ capability.AddValues(valid_capability_table_es3,
+ arraysize(valid_capability_table_es3));
pixel_type.AddValues(valid_pixel_type_table_es3,
arraysize(valid_pixel_type_table_es3));
texture_bind_target.AddValues(valid_texture_bind_target_table_es3,
diff --git a/gpu/config/BUILD.gn b/gpu/config/BUILD.gn
index 6139153..9304695 100644
--- a/gpu/config/BUILD.gn
+++ b/gpu/config/BUILD.gn
@@ -35,7 +35,6 @@
"gpu_info_collector_ozone.cc",
"gpu_info_collector_win.cc",
"gpu_info_collector_x11.cc",
- "gpu_performance_stats.h",
"gpu_test_config.cc",
"gpu_test_config.h",
"gpu_test_expectations_parser.cc",
diff --git a/gpu/config/gpu_blacklist_unittest.cc b/gpu/config/gpu_blacklist_unittest.cc
index c9fa415..1a3deb6 100644
--- a/gpu/config/gpu_blacklist_unittest.cc
+++ b/gpu/config/gpu_blacklist_unittest.cc
@@ -65,9 +65,6 @@
gpu_info_.machine_model_version = "7.1";
gpu_info_.gl_vendor = "NVIDIA Corporation";
gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
- gpu_info_.performance_stats.graphics = 5.0;
- gpu_info_.performance_stats.gaming = 5.0;
- gpu_info_.performance_stats.overall = 5.0;
}
void TearDown() override {}
diff --git a/gpu/config/gpu_control_list.cc b/gpu/config/gpu_control_list.cc
index c95ef9f..3dd1d92 100644
--- a/gpu/config/gpu_control_list.cc
+++ b/gpu/config/gpu_control_list.cc
@@ -1204,18 +1204,6 @@
!gl_reset_notification_strategy_info_->Contains(
gpu_info.gl_reset_notification_strategy))
return false;
- if (perf_graphics_info_.get() != NULL &&
- (gpu_info.performance_stats.graphics == 0.0 ||
- !perf_graphics_info_->Contains(gpu_info.performance_stats.graphics)))
- return false;
- if (perf_gaming_info_.get() != NULL &&
- (gpu_info.performance_stats.gaming == 0.0 ||
- !perf_gaming_info_->Contains(gpu_info.performance_stats.gaming)))
- return false;
- if (perf_overall_info_.get() != NULL &&
- (gpu_info.performance_stats.overall == 0.0 ||
- !perf_overall_info_->Contains(gpu_info.performance_stats.overall)))
- return false;
if (!machine_model_name_list_.empty()) {
if (gpu_info.machine_model_name.empty())
return false;
diff --git a/gpu/config/gpu_control_list_entry_unittest.cc b/gpu/config/gpu_control_list_entry_unittest.cc
index 5587446..0c31e20 100644
--- a/gpu/config/gpu_control_list_entry_unittest.cc
+++ b/gpu/config/gpu_control_list_entry_unittest.cc
@@ -59,9 +59,6 @@
gpu_info_.gl_version = "2.1 NVIDIA-8.24.11 310.90.9b01";
gpu_info_.gl_vendor = "NVIDIA Corporation";
gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
- gpu_info_.performance_stats.graphics = 5.0;
- gpu_info_.performance_stats.gaming = 5.0;
- gpu_info_.performance_stats.overall = 5.0;
}
protected:
@@ -610,61 +607,6 @@
GpuControlList::kOsMacosx, "10.9", gpu_info));
}
-TEST_F(GpuControlListEntryTest, PerfGraphicsEntry) {
- const std::string json = LONG_STRING_CONST(
- {
- "id": 1,
- "perf_graphics": {
- "op": "<",
- "value": "6.0"
- },
- "features": [
- "test_feature_0"
- ]
- }
- );
- ScopedEntry entry(GetEntryFromString(json));
- EXPECT_TRUE(entry.get() != NULL);
- EXPECT_TRUE(entry->Contains(GpuControlList::kOsWin, "10.6", gpu_info()));
-}
-
-TEST_F(GpuControlListEntryTest, PerfGamingEntry) {
- const std::string json = LONG_STRING_CONST(
- {
- "id": 1,
- "perf_graphics": {
- "op": "<=",
- "value": "4.0"
- },
- "features": [
- "test_feature_0"
- ]
- }
- );
- ScopedEntry entry(GetEntryFromString(json));
- EXPECT_TRUE(entry.get() != NULL);
- EXPECT_FALSE(entry->Contains(GpuControlList::kOsWin, "10.6", gpu_info()));
-}
-
-TEST_F(GpuControlListEntryTest, PerfOverallEntry) {
- const std::string json = LONG_STRING_CONST(
- {
- "id": 1,
- "perf_overall": {
- "op": "between",
- "value": "1.0",
- "value2": "9.0"
- },
- "features": [
- "test_feature_0"
- ]
- }
- );
- ScopedEntry entry(GetEntryFromString(json));
- EXPECT_TRUE(entry.get() != NULL);
- EXPECT_TRUE(entry->Contains(GpuControlList::kOsWin, "10.6", gpu_info()));
-}
-
TEST_F(GpuControlListEntryTest, DisabledEntry) {
const std::string json = LONG_STRING_CONST(
{
diff --git a/gpu/config/gpu_control_list_format.txt b/gpu/config/gpu_control_list_format.txt
index c897cb6..88c6f29 100644
--- a/gpu/config/gpu_control_list_format.txt
+++ b/gpu/config/gpu_control_list_format.txt
@@ -44,24 +44,21 @@
// 12. "gl_vendor" is a string pattern.
// 13. "gl_renderer" is a string pattern.
// 14. "gl_extensions" is a string pattern.
-// 15. "perf_graphics" is a FLOAT structure (defined below).
-// 16. "perf_gaming" is a FLOAT structure (defined below).
-// 17. "perf_overall" is a FLOAT structure (defined below).
-// 18. "machine_model_name" is an array of string patterns.
-// 19. "machine_model_version" is a VERSION structure (defined below).
-// 20. "gpu_count" is a INT structure (defined below).
-// 21 "cpu_info" is a string pattern.
-// 22. "exceptions" is a list of entries.
-// 23. "features" is a list of gpu control list options, which can be
+// 15. "machine_model_name" is an array of string patterns.
+// 16. "machine_model_version" is a VERSION structure (defined below).
+// 17. "gpu_count" is a INT structure (defined below).
+// 18. "cpu_info" is a string pattern.
+// 19. "exceptions" is a list of entries.
+// 20. "features" is a list of gpu control list options, which can be
// configured by a specific list. See its *_json.cc file for a list of
// supported features. This field is mandatory.
-// 24. "description" has the description of the entry.
-// 25. "webkit_bugs" is an array of associated webkit bug numbers.
-// 26. "cr_bugs" is an array of associated webkit bug numbers.
-// 27. "disabled" is a boolean. If it is present, the entry will be skipped.
+// 21. "description" has the description of the entry.
+// 22. "webkit_bugs" is an array of associated webkit bug numbers.
+// 23. "cr_bugs" is an array of associated webkit bug numbers.
+// 24. "disabled" is a boolean. If it is present, the entry will be skipped.
// This can not be used in exceptions.
-// 28. "direct_rendering" is a boolean. If present, this will filter on whether
-// the GL contexts are direct or indirect based on the value.
+// 25. "direct_rendering" is a boolean. If present, this will filter on whether
+// the GL contexts are direct or indirect based on the value.
//
// VERSION includes "op", "style", "value", and "value2". "op" can be any of
// the following values: "=", "<", "<=", ">", ">=", "any", "between". "style"
diff --git a/gpu/config/gpu_control_list_unittest.cc b/gpu/config/gpu_control_list_unittest.cc
index f968183..716722c 100644
--- a/gpu/config/gpu_control_list_unittest.cc
+++ b/gpu/config/gpu_control_list_unittest.cc
@@ -57,9 +57,6 @@
gpu_info_.machine_model_version = "7.1";
gpu_info_.gl_vendor = "NVIDIA Corporation";
gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
- gpu_info_.performance_stats.graphics = 5.0;
- gpu_info_.performance_stats.gaming = 5.0;
- gpu_info_.performance_stats.overall = 5.0;
}
void TearDown() override {}
diff --git a/gpu/config/gpu_driver_bug_list_unittest.cc b/gpu/config/gpu_driver_bug_list_unittest.cc
index 33e09a1..4d62c39 100644
--- a/gpu/config/gpu_driver_bug_list_unittest.cc
+++ b/gpu/config/gpu_driver_bug_list_unittest.cc
@@ -36,9 +36,6 @@
gpu_info_.machine_model_version = "7.1";
gpu_info_.gl_vendor = "NVIDIA Corporation";
gpu_info_.gl_renderer = "NVIDIA GeForce GT 120 OpenGL Engine";
- gpu_info_.performance_stats.graphics = 5.0;
- gpu_info_.performance_stats.gaming = 5.0;
- gpu_info_.performance_stats.overall = 5.0;
}
void TearDown() override {}
diff --git a/gpu/config/gpu_info.cc b/gpu/config/gpu_info.cc
index 6ceb7fc..2cba5d8 100644
--- a/gpu/config/gpu_info.cc
+++ b/gpu/config/gpu_info.cc
@@ -90,7 +90,6 @@
std::string gl_ws_extensions;
uint32 gl_reset_notification_strategy;
bool can_lose_context;
- GpuPerformanceStats performance_stats;
bool software_rendering;
bool direct_rendering;
bool sandboxed;
diff --git a/gpu/config/gpu_info.h b/gpu/config/gpu_info.h
index 7c92d3a..e5bef23 100644
--- a/gpu/config/gpu_info.h
+++ b/gpu/config/gpu_info.h
@@ -16,7 +16,6 @@
#include "base/version.h"
#include "build/build_config.h"
#include "gpu/config/dx_diag_node.h"
-#include "gpu/config/gpu_performance_stats.h"
#include "gpu/gpu_export.h"
#include "ui/gfx/geometry/size.h"
@@ -180,9 +179,6 @@
// semantics are available.
bool can_lose_context;
- // By default all values are 0.
- GpuPerformanceStats performance_stats;
-
bool software_rendering;
// Whether the driver uses direct rendering. True on most platforms, false on
diff --git a/gpu/config/gpu_info_collector_win.cc b/gpu/config/gpu_info_collector_win.cc
index e8c8f2f..cc935ea 100644
--- a/gpu/config/gpu_info_collector_win.cc
+++ b/gpu/config/gpu_info_collector_win.cc
@@ -63,116 +63,6 @@
return static_cast<float>(score);
}
-GpuPerformanceStats RetrieveGpuPerformanceStats() {
- TRACE_EVENT0("gpu", "RetrieveGpuPerformanceStats");
-
- // If the user re-runs the assessment without restarting, the COM API
- // returns WINSAT_ASSESSMENT_STATE_NOT_AVAILABLE. Because of that and
- // http://crbug.com/124325, read the assessment result files directly.
- GpuPerformanceStats stats;
-
- // Get path to WinSAT results files.
- wchar_t winsat_results_path[MAX_PATH];
- DWORD size = ExpandEnvironmentStrings(
- L"%WinDir%\\Performance\\WinSAT\\DataStore\\",
- winsat_results_path, MAX_PATH);
- if (size == 0 || size > MAX_PATH) {
- LOG(ERROR) << "The path to the WinSAT results is too long: "
- << size << " chars.";
- return stats;
- }
-
- // Find most recent formal assessment results.
- base::FileEnumerator file_enumerator(
- base::FilePath(winsat_results_path),
- false, // not recursive
- base::FileEnumerator::FILES,
- FILE_PATH_LITERAL("* * Formal.Assessment (*).WinSAT.xml"));
-
- base::FilePath current_results;
- for (base::FilePath results = file_enumerator.Next(); !results.empty();
- results = file_enumerator.Next()) {
- // The filenames start with the date and time as yyyy-mm-dd hh.mm.ss.xxx,
- // so the greatest file lexicographically is also the most recent file.
- if (base::FilePath::CompareLessIgnoreCase(current_results.value(),
- results.value()))
- current_results = results;
- }
-
- std::string current_results_string = current_results.MaybeAsASCII();
- if (current_results_string.empty())
- return stats;
-
- // Get relevant scores from results file. XML schema at:
- // http://msdn.microsoft.com/en-us/library/windows/desktop/aa969210.aspx
- XmlReader reader;
- if (!reader.LoadFile(current_results_string)) {
- LOG(ERROR) << "Could not open WinSAT results file.";
- return stats;
- }
- // Descend into <WinSAT> root element.
- if (!reader.SkipToElement() || !reader.Read()) {
- LOG(ERROR) << "Could not read WinSAT results file.";
- return stats;
- }
-
- // Search for <WinSPR> element containing the results.
- do {
- if (reader.NodeName() == "WinSPR")
- break;
- } while (reader.Next());
- // Descend into <WinSPR> element.
- if (!reader.Read()) {
- LOG(ERROR) << "Could not find WinSPR element in results file.";
- return stats;
- }
-
- // Read scores.
- for (int depth = reader.Depth(); reader.Depth() == depth; reader.Next()) {
- std::string node_name = reader.NodeName();
- if (node_name == "SystemScore")
- stats.overall = ReadXMLFloatValue(&reader);
- else if (node_name == "GraphicsScore")
- stats.graphics = ReadXMLFloatValue(&reader);
- else if (node_name == "GamingScore")
- stats.gaming = ReadXMLFloatValue(&reader);
- }
-
- if (stats.overall == 0.0)
- LOG(ERROR) << "Could not read overall score from assessment results.";
- if (stats.graphics == 0.0)
- LOG(ERROR) << "Could not read graphics score from assessment results.";
- if (stats.gaming == 0.0)
- LOG(ERROR) << "Could not read gaming score from assessment results.";
-
- return stats;
-}
-
-GpuPerformanceStats RetrieveGpuPerformanceStatsWithHistograms() {
- base::TimeTicks start_time = base::TimeTicks::Now();
-
- GpuPerformanceStats stats = RetrieveGpuPerformanceStats();
-
- UMA_HISTOGRAM_TIMES("GPU.WinSAT.ReadResultsFileTime",
- base::TimeTicks::Now() - start_time);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "GPU.WinSAT.OverallScore2",
- static_cast<base::HistogramBase::Sample>(stats.overall * 10), 10, 200,
- 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "GPU.WinSAT.GraphicsScore2",
- static_cast<base::HistogramBase::Sample>(stats.graphics * 10), 10, 200,
- 50);
- UMA_HISTOGRAM_CUSTOM_COUNTS(
- "GPU.WinSAT.GamingScore2",
- static_cast<base::HistogramBase::Sample>(stats.gaming * 10), 10, 200, 50);
- UMA_HISTOGRAM_BOOLEAN(
- "GPU.WinSAT.HasResults",
- stats.overall != 0.0 && stats.graphics != 0.0 && stats.gaming != 0.0);
-
- return stats;
-}
-
// Returns the display link driver version or an invalid version if it is
// not installed.
Version DisplayLinkVersion() {
@@ -505,8 +395,6 @@
DCHECK(gpu_info);
- gpu_info->performance_stats = RetrieveGpuPerformanceStatsWithHistograms();
-
// nvd3d9wrap.dll is loaded into all processes when Optimus is enabled.
HMODULE nvd3d9wrap = GetModuleHandleW(L"nvd3d9wrap.dll");
gpu_info->optimus = nvd3d9wrap != NULL;
@@ -618,6 +506,8 @@
MergeGPUInfoGL(basic_gpu_info, context_gpu_info);
+ basic_gpu_info->dx_diagnostics_info_state =
+ context_gpu_info.dx_diagnostics_info_state;
basic_gpu_info->dx_diagnostics = context_gpu_info.dx_diagnostics;
}
diff --git a/gpu/config/gpu_performance_stats.h b/gpu/config/gpu_performance_stats.h
deleted file mode 100644
index 2ade8bf..0000000
--- a/gpu/config/gpu_performance_stats.h
+++ /dev/null
@@ -1,23 +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 GPU_CONFIG_GPU_PERFORMANCE_STATS_H_
-#define GPU_CONFIG_GPU_PERFORMANCE_STATS_H_
-
-#include "gpu/gpu_export.h"
-
-namespace gpu {
-
-struct GPU_EXPORT GpuPerformanceStats {
- GpuPerformanceStats() : graphics(0.f), gaming(0.f), overall(0.f) {}
-
- float graphics;
- float gaming;
- float overall;
-};
-
-} // namespace gpu
-
-#endif // GPU_CONFIG_GPU_PERFORMANCE_STATS_H_
-
diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc
index 95d828d..bd846a6 100644
--- a/gpu/config/software_rendering_list_json.cc
+++ b/gpu/config/software_rendering_list_json.cc
@@ -18,7 +18,7 @@
{
"name": "software rendering list",
// Please update the version number whenever you change this file.
- "version": "9.19",
+ "version": "10.0",
"entries": [
{
"id": 1,
@@ -336,32 +336,6 @@
]
},
{
- "id": 32,
- "description": "Accelerated 2d canvas is disabled on Windows systems with low perf stats",
- "cr_bugs": [116350, 151500],
- "os": {
- "type": "win"
- },
- "perf_overall": {
- "op": "<",
- "value": "3.5"
- },
- "exceptions": [
- {
- "perf_gaming": {
- "op": ">",
- "value": "3.5"
- }
- },
- {
- "cpu_info": "(?i).*Atom.*"
- }
- ],
- "features": [
- "accelerated_2d_canvas"
- ]
- },
- {
"id": 34,
"description": "S3 Trio (used in Virtual PC) is not compatible",
"cr_bugs": [119948],
diff --git a/gpu/gpu_config.gypi b/gpu/gpu_config.gypi
index f1915f3..2b94403 100644
--- a/gpu/gpu_config.gypi
+++ b/gpu/gpu_config.gypi
@@ -36,7 +36,6 @@
'config/gpu_info_collector_ozone.cc',
'config/gpu_info_collector_win.cc',
'config/gpu_info_collector_x11.cc',
- 'config/gpu_performance_stats.h',
'config/gpu_test_config.cc',
'config/gpu_test_config.h',
'config/gpu_test_expectations_parser.cc',
diff --git a/gpu/gpu_unittests.isolate b/gpu/gpu_unittests.isolate
index b12c5cb..7ad1b79 100644
--- a/gpu/gpu_unittests.isolate
+++ b/gpu/gpu_unittests.isolate
@@ -59,5 +59,6 @@
],
'includes': [
'../base/base.isolate',
+ '../third_party/angle/angle.isolate',
],
}
diff --git a/gpu/perftests/texture_upload_perftest.cc b/gpu/perftests/texture_upload_perftest.cc
index 89e901a..c14a151 100644
--- a/gpu/perftests/texture_upload_perftest.cc
+++ b/gpu/perftests/texture_upload_perftest.cc
@@ -20,14 +20,15 @@
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_enums.h"
#include "ui/gl/gl_surface.h"
+#include "ui/gl/gl_version_info.h"
#include "ui/gl/gpu_timing.h"
#include "ui/gl/scoped_make_current.h"
namespace gpu {
namespace {
-const int kUploadPerfWarmupRuns = 10;
-const int kUploadPerfTestRuns = 100;
+const int kUploadPerfWarmupRuns = 5;
+const int kUploadPerfTestRuns = 30;
#define SHADER(Src) #Src
@@ -44,9 +45,12 @@
v_texCoord = a_texCoord;
}
);
-const char kFragmentShader[] =
+const char kShaderDefaultFloatPrecision[] =
SHADER(
precision mediump float;
+);
+const char kFragmentShader[] =
+SHADER(
uniform sampler2D a_texture;
varying vec2 v_texCoord;
void main() {
@@ -55,8 +59,8 @@
);
// clang-format on
-void CheckNoGlError() {
- CHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+void CheckNoGlError(const std::string& msg) {
+ CHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()) << " " << msg;
}
// Utility function to compile a shader from a string.
@@ -87,6 +91,24 @@
return format == GL_RGBA ? 4 : 1;
}
+GLenum GLFormatToInternalFormat(GLenum format) {
+ return format == GL_RED ? GL_R8 : format;
+}
+
+GLenum GLFormatToStorageFormat(GLenum format) {
+ switch (format) {
+ case GL_RGBA:
+ return GL_RGBA8;
+ case GL_LUMINANCE:
+ return GL_LUMINANCE8;
+ case GL_RED:
+ return GL_R8;
+ default:
+ NOTREACHED();
+ }
+ return 0;
+}
+
void GenerateTextureData(const gfx::Size& size,
int bytes_per_pixel,
const int seed,
@@ -123,7 +145,7 @@
case GL_LUMINANCE: // (L_t, L_t, L_t, 1)
expected[1] = pixels[pixels_index];
expected[2] = pixels[pixels_index];
- case GL_RED_EXT: // (R_t, 0, 0, 1)n
+ case GL_RED: // (R_t, 0, 0, 1)
expected[0] = pixels[pixels_index];
expected[3] = 255;
break;
@@ -187,7 +209,12 @@
// Prepare a simple program and a vertex buffer that will be
// used to draw a quad on the offscreen surface.
vertex_shader_ = LoadShader(GL_VERTEX_SHADER, kVertexShader);
- fragment_shader_ = LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
+
+ bool is_gles = gfx::GetGLImplementation() == gfx::kGLImplementationEGLGLES2;
+ fragment_shader_ = LoadShader(
+ GL_FRAGMENT_SHADER,
+ base::StringPrintf("%s%s", is_gles ? kShaderDefaultFloatPrecision : "",
+ kFragmentShader).c_str());
program_object_ = glCreateProgram();
CHECK_NE(0u, program_object_);
@@ -219,7 +246,12 @@
reinterpret_cast<void*>(sizeof(GLfloat) * 2));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
- CheckNoGlError();
+ CheckNoGlError("glEnableVertexAttribArray");
+
+ has_texture_storage_ =
+ gl_context_->GetVersionInfo()->is_es3 ||
+ gl_context_->HasExtension("GL_EXT_texture_storage") ||
+ gl_context_->HasExtension("GL_ARB_texture_storage");
}
void GenerateVertexBuffer(const gfx::Size& size) {
@@ -241,7 +273,7 @@
right, top, 1.f, 1.f};
// clang-format on
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
- CheckNoGlError();
+ CheckNoGlError("glBufferData");
}
void TearDown() override {
@@ -254,7 +286,7 @@
glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
glDeleteFramebuffersEXT(1, &framebuffer_object_);
glDeleteTextures(1, &color_texture_);
- CheckNoGlError();
+ CheckNoGlError("glDeleteTextures");
gpu_timing_client_ = nullptr;
gl_context_ = nullptr;
@@ -262,36 +294,59 @@
}
protected:
- GLuint CreateGLTexture() {
+ GLuint CreateGLTexture(const GLenum format,
+ const gfx::Size& size,
+ const bool specify_storage) {
GLuint texture_id = 0;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texture_id);
glBindTexture(GL_TEXTURE_2D, texture_id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ if (specify_storage) {
+ if (has_texture_storage_) {
+ glTexStorage2DEXT(GL_TEXTURE_2D, 1, GLFormatToStorageFormat(format),
+ size.width(), size.height());
+ CheckNoGlError("glTexStorage2DEXT");
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GLFormatToInternalFormat(format),
+ size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE,
+ nullptr);
+ CheckNoGlError("glTexImage2D");
+ }
+ }
return texture_id;
}
void UploadTexture(GLuint texture_id,
const gfx::Size& size,
const std::vector<uint8>& pixels,
- GLenum format) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, size.width(), size.height(), 0,
- format, GL_UNSIGNED_BYTE, &pixels[0]);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- CheckNoGlError();
+ GLenum format,
+ const bool subimage) {
+ if (subimage) {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(),
+ format, GL_UNSIGNED_BYTE, &pixels[0]);
+ CheckNoGlError("glTexSubImage2D");
+ } else {
+ glTexImage2D(GL_TEXTURE_2D, 0, GLFormatToInternalFormat(format),
+ size.width(), size.height(), 0, format, GL_UNSIGNED_BYTE,
+ &pixels[0]);
+ CheckNoGlError("glTexImage2D");
+ }
}
// Upload and draw on the offscren surface.
// Return a list of pair. Each pair describe a gl operation and the wall
// time elapsed in milliseconds.
- std::vector<Measurement> UploadAndDraw(const gfx::Size& size,
+ std::vector<Measurement> UploadAndDraw(GLuint texture_id,
+ const gfx::Size& size,
const std::vector<uint8>& pixels,
- const GLenum format) {
- GLuint texture_id = CreateGLTexture();
+ const GLenum format,
+ const bool subimage) {
MeasurementTimers tex_timers(gpu_timing_client_.get());
- UploadTexture(texture_id, size, pixels, format);
+ UploadTexture(texture_id, size, pixels, format, subimage);
tex_timers.Record();
MeasurementTimers draw_timers(gpu_timing_client_.get());
@@ -301,15 +356,13 @@
MeasurementTimers finish_timers(gpu_timing_client_.get());
glFinish();
- CheckNoGlError();
+ CheckNoGlError("glFinish");
finish_timers.Record();
- glDeleteTextures(1, &texture_id);
-
std::vector<uint8> pixels_rendered(size.GetArea() * 4);
glReadPixels(0, 0, size.width(), size.height(), GL_RGBA, GL_UNSIGNED_BYTE,
&pixels_rendered[0]);
- CheckNoGlError();
+ CheckNoGlError("glReadPixels");
EXPECT_TRUE(
CompareBufferToRGBABuffer(format, size, pixels, pixels_rendered))
<< "Format is: " << gfx::GLEnums::GetStringEnum(format);
@@ -319,7 +372,8 @@
gpu_timing_client_->IsAvailable() &&
gpu_timing_client_->CheckAndResetTimerErrors();
if (!gpu_timer_errors) {
- measurements.push_back(tex_timers.GetAsMeasurement("teximage2d"));
+ measurements.push_back(tex_timers.GetAsMeasurement(
+ subimage ? "texsubimage2d" : "teximage2d"));
measurements.push_back(draw_timers.GetAsMeasurement("drawarrays"));
measurements.push_back(finish_timers.GetAsMeasurement("finish"));
}
@@ -327,14 +381,16 @@
}
void RunUploadAndDrawMultipleTimes(const gfx::Size& size,
- const GLenum format) {
+ const GLenum format,
+ const bool subimage) {
std::vector<uint8> pixels;
base::SmallMap<std::map<std::string, Measurement>>
aggregates; // indexed by name
int successful_runs = 0;
+ GLuint texture_id = CreateGLTexture(format, size, subimage);
for (int i = 0; i < kUploadPerfWarmupRuns + kUploadPerfTestRuns; ++i) {
GenerateTextureData(size, GLFormatBytePerPixel(format), i + 1, &pixels);
- auto run = UploadAndDraw(size, pixels, format);
+ auto run = UploadAndDraw(texture_id, size, pixels, format, subimage);
if (i < kUploadPerfWarmupRuns || !run.size()) {
continue;
}
@@ -345,8 +401,14 @@
aggregate.Increment(measurement);
}
}
+ glDeleteTextures(1, &texture_id);
+
std::string graph_name = base::StringPrintf(
"%d_%s", size.width(), gfx::GLEnums::GetStringEnum(format).c_str());
+ if (subimage) {
+ graph_name += "_sub";
+ }
+
if (successful_runs) {
for (const auto& entry : aggregates) {
const auto m = entry.second.Divide(successful_runs);
@@ -370,33 +432,41 @@
GLint sampler_location_ = -1;
GLint translation_location_ = -1;
GLuint vertex_buffer_ = 0;
+
+ bool has_texture_storage_ = false;
};
// Perf test that generates, uploads and draws a texture on a surface repeatedly
// and prints out aggregated measurements for all the runs.
-TEST_F(TextureUploadPerfTest, glTexImage2d) {
+TEST_F(TextureUploadPerfTest, upload) {
int sizes[] = {21, 128, 256, 512, 1024};
std::vector<GLenum> formats;
formats.push_back(GL_RGBA);
- // Used by default for ResourceProvider::yuv_resource_format_.
- formats.push_back(GL_LUMINANCE);
+
+ if (!gl_context_->GetVersionInfo()->is_es3) {
+ // Used by default for ResourceProvider::yuv_resource_format_.
+ formats.push_back(GL_LUMINANCE);
+ }
ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
- bool has_texture_rg = gl_context_->HasExtension("GL_EXT_texture_rg") ||
- gl_context_->HasExtension("GL_ARB_texture_rg");
+ const bool has_texture_rg = gl_context_->GetVersionInfo()->is_es3 ||
+ gl_context_->HasExtension("GL_EXT_texture_rg") ||
+ gl_context_->HasExtension("GL_ARB_texture_rg");
if (has_texture_rg) {
// Used as ResourceProvider::yuv_resource_format_ if
// {ARB,EXT}_texture_rg are available.
- formats.push_back(GL_RED_EXT);
+ formats.push_back(GL_RED);
}
+
for (int side : sizes) {
ASSERT_GE(fbo_size_.width(), side);
ASSERT_GE(fbo_size_.height(), side);
gfx::Size size(side, side);
GenerateVertexBuffer(size);
for (GLenum format : formats) {
- RunUploadAndDrawMultipleTimes(size, format);
+ RunUploadAndDrawMultipleTimes(size, format, true); // use glTexSubImage2D
+ RunUploadAndDrawMultipleTimes(size, format, false); // use glTexImage2D
}
}
}
@@ -425,12 +495,12 @@
gfx::Vector2dF(1.f, 0.f),
gfx::Vector2dF(0.f, 1.f),
gfx::Vector2dF(1.f, 1.f)};
- GLuint texture_id = CreateGLTexture();
+ GLuint texture_id = CreateGLTexture(GL_RGBA, texture_size, true);
MeasurementTimers upload_and_draw_timers(gpu_timing_client_.get());
for (int i = 0; i < 4; ++i) {
- UploadTexture(texture_id, texture_size, pixels[i % 4], GL_RGBA);
+ UploadTexture(texture_id, texture_size, pixels[i % 4], GL_RGBA, true);
DCHECK_NE(-1, translation_location_);
glUniform2f(translation_location_, positions[i % 4].x(),
positions[i % 4].y());
@@ -444,7 +514,7 @@
upload_and_draw_timers.Record();
MeasurementTimers finish_timers(gpu_timing_client_.get());
glFinish();
- CheckNoGlError();
+ CheckNoGlError("glFinish");
finish_timers.Record();
glDeleteTextures(1, &texture_id);
@@ -455,7 +525,7 @@
texture_size.height() * positions[i].y(), texture_size.width(),
texture_size.height(), GL_RGBA, GL_UNSIGNED_BYTE,
&pixels_rendered[0]);
- CheckNoGlError();
+ CheckNoGlError("glReadPixels");
ASSERT_EQ(pixels[i].size(), pixels_rendered.size());
EXPECT_EQ(pixels[i], pixels_rendered);
}
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 2357a7f..14b91ef 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -8,6 +8,9 @@
if (current_cpu == "arm") {
import("//build/config/arm.gni")
}
+if (current_cpu == "mipsel" || current_cpu == "mips64el") {
+ import("//build/config/mips.gni")
+}
skia_support_gpu = !is_ios
skia_support_pdf = !is_ios && (enable_basic_printing || enable_print_preview)
@@ -36,26 +39,30 @@
[ "//third_party/skia/gyp/core.gypi" ])
# The list of Skia gpu sources that are to be set for chromium.
-gypi_skia_gpu =
- exec_script("//build/gypi_to_gn.py",
- [
- rebase_path("//third_party/skia/gyp/gpu.gypi"),
- "--replace=<(skia_include_path)=//third_party/skia/include",
- "--replace=<(skia_src_path)=//third_party/skia/src",
- ],
- "scope",
- [ "//third_party/skia/gyp/gpu.gypi" ])
+if (skia_support_gpu) {
+ gypi_skia_gpu =
+ exec_script("//build/gypi_to_gn.py",
+ [
+ rebase_path("//third_party/skia/gyp/gpu.gypi"),
+ "--replace=<(skia_include_path)=//third_party/skia/include",
+ "--replace=<(skia_src_path)=//third_party/skia/src",
+ ],
+ "scope",
+ [ "//third_party/skia/gyp/gpu.gypi" ])
+}
# The list of Skia pdf sources that are to be set for chromium.
-gypi_skia_pdf =
- exec_script("//build/gypi_to_gn.py",
- [
- rebase_path("//third_party/skia/gyp/pdf.gypi"),
- "--replace=<(skia_include_path)=//third_party/skia/include",
- "--replace=<(skia_src_path)=//third_party/skia/src",
- ],
- "scope",
- [ "//third_party/skia/gyp/pdf.gypi" ])
+if (skia_support_pdf) {
+ gypi_skia_pdf =
+ exec_script("//build/gypi_to_gn.py",
+ [
+ rebase_path("//third_party/skia/gyp/pdf.gypi"),
+ "--replace=<(skia_include_path)=//third_party/skia/include",
+ "--replace=<(skia_src_path)=//third_party/skia/src",
+ ],
+ "scope",
+ [ "//third_party/skia/gyp/pdf.gypi" ])
+}
# The list of Skia effects that are to be set for chromium.
gypi_skia_effects =
@@ -537,6 +544,7 @@
[
# Chrome-specific.
"ext/convolver_SSE2.cc",
+ "ext/convolver_SSE2.h",
]
if (is_linux || is_mac) {
@@ -564,7 +572,19 @@
}
} else if (current_cpu == "mipsel") {
cflags += [ "-fomit-frame-pointer" ]
- sources = gypi_skia_opts.none_sources
+
+ if (mips_dsp_rev >= 1) {
+ sources = gypi_skia_opts.mips_dsp_sources
+ if (mips_dsp_rev >= 2) {
+ sources += [
+ # Chrome-specific.
+ "ext/convolver_mips_dspr2.cc",
+ "ext/convolver_mips_dspr2.h",
+ ]
+ }
+ } else {
+ sources = gypi_skia_opts.none_sources
+ }
} else {
assert(false, "Need to port cpu specific stuff from skia_library_opts.gyp")
}
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 6db5919..e9990e6 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -261,10 +261,18 @@
# define SK_IGNORE_ETC1_SUPPORT
#endif
+#ifndef SK_SUPPORT_LEGACY_BOOL_ONGETINFO
+# define SK_SUPPORT_LEGACY_BOOL_ONGETINFO
+#endif
+
#ifndef SK_IGNORE_GPU_DITHER
# define SK_IGNORE_GPU_DITHER
#endif
+#ifndef SK_SUPPORT_LEGACY_INT_COLORMATRIX
+# define SK_SUPPORT_LEGACY_INT_COLORMATRIX
+#endif
+
#ifndef SK_LEGACY_STROKE_CURVES
# define SK_LEGACY_STROKE_CURVES
#endif
diff --git a/skia/ext/SkDiscardableMemory_chrome.cc b/skia/ext/SkDiscardableMemory_chrome.cc
index 50e7f2e..5bb6928 100644
--- a/skia/ext/SkDiscardableMemory_chrome.cc
+++ b/skia/ext/SkDiscardableMemory_chrome.cc
@@ -4,6 +4,9 @@
#include "SkDiscardableMemory_chrome.h"
+#include "base/memory/discardable_memory.h"
+#include "base/memory/discardable_memory_allocator.h"
+
SkDiscardableMemoryChrome::~SkDiscardableMemoryChrome() {}
bool SkDiscardableMemoryChrome::lock() {
@@ -25,5 +28,6 @@
SkDiscardableMemory* SkDiscardableMemory::Create(size_t bytes) {
return new SkDiscardableMemoryChrome(
- base::DiscardableMemory::CreateLockedMemory(bytes));
+ base::DiscardableMemoryAllocator::GetInstance()
+ ->AllocateLockedDiscardableMemory(bytes));
}
diff --git a/skia/ext/SkDiscardableMemory_chrome.h b/skia/ext/SkDiscardableMemory_chrome.h
index 50946e6..1be4516 100644
--- a/skia/ext/SkDiscardableMemory_chrome.h
+++ b/skia/ext/SkDiscardableMemory_chrome.h
@@ -5,10 +5,13 @@
#ifndef SKIA_EXT_SK_DISCARDABLE_MEMORY_CHROME_H_
#define SKIA_EXT_SK_DISCARDABLE_MEMORY_CHROME_H_
-#include "base/memory/discardable_memory.h"
#include "base/memory/scoped_ptr.h"
#include "third_party/skia/src/core/SkDiscardableMemory.h"
+namespace base {
+class DiscardableMemory;
+}
+
// This class implements the SkDiscardableMemory interface using
// base::DiscardableMemory.
class SK_API SkDiscardableMemoryChrome : public SkDiscardableMemory {
diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc
index 194f382..fb6f7ad 100644
--- a/skia/ext/benchmarking_canvas.cc
+++ b/skia/ext/benchmarking_canvas.cc
@@ -249,7 +249,7 @@
"None", "Low", "Medium", "High"};
DCHECK_LT(static_cast<size_t>(paint.getFilterQuality()),
SK_ARRAY_COUNT(gFilterQualityStrings));
- val->SetString("FilterQuality",
+ val->SetString("FilterLevel",
gFilterQualityStrings[paint.getFilterQuality()]);
}
diff --git a/skia/skia.gyp b/skia/skia.gyp
index 16e03a2..109adff 100644
--- a/skia/skia.gyp
+++ b/skia/skia.gyp
@@ -107,14 +107,13 @@
target_arch != "arm64" and target_arch != "mips64el"', {
'sources': [
'ext/convolver_SSE2.cc',
+ 'ext/convolver_SSE2.h',
],
}],
- [ 'target_arch == "mipsel"',{
- 'cflags': [
- '-fomit-frame-pointer',
- ],
+ [ 'target_arch == "mipsel" and mips_dsp_rev >= 2',{
'sources': [
'ext/convolver_mips_dspr2.cc',
+ 'ext/convolver_mips_dspr2.h',
],
}],
],
diff --git a/skia/skia_library_opts.gyp b/skia/skia_library_opts.gyp
index cde0e0b..58f036f 100644
--- a/skia/skia_library_opts.gyp
+++ b/skia/skia_library_opts.gyp
@@ -64,11 +64,16 @@
}],
[ 'target_arch == "arm"', {
'conditions': [
+ [ 'arm_version >= 7', {
+ 'sources': [ '<@(armv7_sources)' ],
+ }, { # arm_version < 7
+ 'sources': [ '<@(none_sources)' ],
+ }],
[ 'arm_version >= 7 and (arm_neon == 1 or arm_neon_optional == 1)', {
'dependencies': [
'skia_opts_neon',
]
- }],
+ }],
],
# The assembly uses the frame pointer register (r7 in Thumb/r11 in
# ARM), the compiler doesn't like that. Explicitly remove the
@@ -83,13 +88,17 @@
'-fomit-frame-pointer',
],
}],
- [ 'target_arch == "arm" and arm_version < 7', {
- 'sources': [ '<@(none_sources)' ],
+ [ 'target_arch == "mipsel"',{
+ 'cflags': [ '-fomit-frame-pointer' ],
+ 'conditions': [
+ [ 'mips_dsp_rev >= 1', {
+ 'sources': [ '<@(mips_dsp_sources)' ],
+ }, { # mips_dsp_rev == 0
+ 'sources': [ '<@(none_sources)' ],
+ }],
+ ],
}],
- [ 'target_arch == "arm" and arm_version >= 7', {
- 'sources': [ '<@(armv7_sources)' ],
- }],
- [ 'target_arch == "mipsel" or target_arch == "mips64el"',{
+ [ 'target_arch == "mips64el"',{
'cflags': [ '-fomit-frame-pointer' ],
'sources': [ '<@(none_sources)' ],
}],
diff --git a/sky/engine/platform/fonts/opentype/OpenTypeSanitizer.cpp b/sky/engine/platform/fonts/opentype/OpenTypeSanitizer.cpp
index 3d628ff..003869e 100644
--- a/sky/engine/platform/fonts/opentype/OpenTypeSanitizer.cpp
+++ b/sky/engine/platform/fonts/opentype/OpenTypeSanitizer.cpp
@@ -48,9 +48,6 @@
if (m_buffer->size() > maxWebFontSize)
return nullptr;
- if (RuntimeEnabledFeatures::woff2Enabled())
- ots::EnableWOFF2();
-
// A transcoded font is usually smaller than an original font.
// However, it can be slightly bigger than the original one due to
// name table replacement and/or padding for glyf table.
diff --git a/sky/engine/platform/graphics/GraphicsContext.cpp b/sky/engine/platform/graphics/GraphicsContext.cpp
index 92d3f5c..5a8458b 100644
--- a/sky/engine/platform/graphics/GraphicsContext.cpp
+++ b/sky/engine/platform/graphics/GraphicsContext.cpp
@@ -45,6 +45,7 @@
#include "third_party/skia/include/core/SkColorFilter.h"
#include "third_party/skia/include/core/SkData.h"
#include "third_party/skia/include/core/SkDevice.h"
+#include "third_party/skia/include/core/SkMatrixImageFilter.h"
#include "third_party/skia/include/core/SkPicture.h"
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkRefCnt.h"
@@ -52,7 +53,6 @@
#include "third_party/skia/include/effects/SkBlurMaskFilter.h"
#include "third_party/skia/include/effects/SkCornerPathEffect.h"
#include "third_party/skia/include/effects/SkLumaColorFilter.h"
-#include "third_party/skia/include/effects/SkMatrixImageFilter.h"
#include "third_party/skia/include/effects/SkPictureImageFilter.h"
#include "third_party/skia/include/gpu/GrRenderTarget.h"
#include "third_party/skia/include/gpu/GrTexture.h"
diff --git a/sky/engine/platform/graphics/filters/FEDropShadow.cpp b/sky/engine/platform/graphics/filters/FEDropShadow.cpp
index dcee91a..5c3dede 100644
--- a/sky/engine/platform/graphics/filters/FEDropShadow.cpp
+++ b/sky/engine/platform/graphics/filters/FEDropShadow.cpp
@@ -111,7 +111,7 @@
float stdY = filter()->applyVerticalScale(m_stdY);
Color color = adaptColorToOperatingColorSpace(m_shadowColor.combineWithAlpha(m_shadowOpacity));
SkImageFilter::CropRect cropRect = getCropRect(builder->cropOffset());
- return adoptRef(SkDropShadowImageFilter::Create(SkFloatToScalar(dx), SkFloatToScalar(dy), SkFloatToScalar(stdX), SkFloatToScalar(stdY), color.rgb(), input.get(), &cropRect));
+ return adoptRef(SkDropShadowImageFilter::Create(SkFloatToScalar(dx), SkFloatToScalar(dy), SkFloatToScalar(stdX), SkFloatToScalar(stdY), color.rgb(), SkDropShadowImageFilter::kDrawShadowAndForeground_ShadowMode, input.get(), &cropRect));
}
diff --git a/sky/engine/platform/graphics/filters/SkiaImageFilterBuilder.cpp b/sky/engine/platform/graphics/filters/SkiaImageFilterBuilder.cpp
index 3dec62a..b973855 100644
--- a/sky/engine/platform/graphics/filters/SkiaImageFilterBuilder.cpp
+++ b/sky/engine/platform/graphics/filters/SkiaImageFilterBuilder.cpp
@@ -32,11 +32,11 @@
#include "sky/engine/platform/graphics/filters/SourceGraphic.h"
#include "sky/engine/platform/graphics/skia/SkiaUtils.h"
#include "sky/engine/public/platform/WebPoint.h"
+#include "third_party/skia/include/core/SkMatrixImageFilter.h"
#include "third_party/skia/include/effects/SkBlurImageFilter.h"
#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
-#include "third_party/skia/include/effects/SkMatrixImageFilter.h"
#include "third_party/skia/include/effects/SkTableColorFilter.h"
namespace blink {
diff --git a/testing/android/junit/BUILD.gn b/testing/android/junit/BUILD.gn
index e4cd871..f80d0b5 100644
--- a/testing/android/junit/BUILD.gn
+++ b/testing/android/junit/BUILD.gn
@@ -12,6 +12,7 @@
deps = [
"//third_party/junit",
"//third_party/mockito:mockito_java",
+ "//third_party/robolectric:robolectric_java",
]
}
diff --git a/testing/android/junit/java/src/org/chromium/testing/local/LocalRobolectricTestRunner.java b/testing/android/junit/java/src/org/chromium/testing/local/LocalRobolectricTestRunner.java
new file mode 100644
index 0000000..293525e
--- /dev/null
+++ b/testing/android/junit/java/src/org/chromium/testing/local/LocalRobolectricTestRunner.java
@@ -0,0 +1,58 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.testing.local;
+
+import org.junit.runners.model.InitializationError;
+
+import org.robolectric.AndroidManifest;
+import org.robolectric.DependencyResolver;
+import org.robolectric.LocalDependencyResolver;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.SdkConfig;
+import org.robolectric.annotation.Config;
+
+import java.io.File;
+
+/**
+ * A custom Robolectric Junit4 Test Runner. This test runner will load the
+ * "real" android jars from a local directory rather than use Maven to fetch
+ * them from the Maven Central repository. Additionally, it will ignore the
+ * API level written in the AndroidManifest as that can cause issues if
+ * robolectric does not support that API level.
+ */
+public class LocalRobolectricTestRunner extends RobolectricTestRunner {
+
+ private static final int ANDROID_API_LEVEL = 18;
+
+ public LocalRobolectricTestRunner(Class<?> testClass) throws InitializationError {
+ super(testClass);
+ }
+
+ @Override
+ protected final DependencyResolver getJarResolver() {
+ String dependencyDir = System.getProperty("robolectric.dependency.dir");
+ if (dependencyDir == null) {
+ throw new IllegalStateException("robolectric.dependency.dir not specified. Make sure"
+ + " you are setting the robolectric.dependency.dir system property to the"
+ + " directory containing Robolectric's runtime dependency jars.");
+ }
+ return new LocalDependencyResolver(new File(dependencyDir));
+ }
+
+ @Override
+ protected SdkConfig pickSdkVersion(AndroidManifest appManifest, Config config) {
+ // Pulling from the manifest is dangerous as the apk might target a version of
+ // android that robolectric does not yet support. We still allow the API level to
+ // be overridden with the Config annotation.
+ return config.emulateSdk() < 0
+ ? new SdkConfig(ANDROID_API_LEVEL) : super.pickSdkVersion(null, config);
+ }
+
+ @Override
+ protected int pickReportedSdkVersion(Config config, AndroidManifest appManifest) {
+ return config.reportSdk() < 0
+ ? ANDROID_API_LEVEL : super.pickReportedSdkVersion(config, appManifest);
+ }
+}
\ No newline at end of file
diff --git a/testing/android/junit/junit_test.gyp b/testing/android/junit/junit_test.gyp
index f0f8b8c..16e0048 100644
--- a/testing/android/junit/junit_test.gyp
+++ b/testing/android/junit/junit_test.gyp
@@ -11,6 +11,7 @@
'dependencies': [
'../../../third_party/junit/junit.gyp:junit_jar',
'../../../third_party/mockito/mockito.gyp:mockito_jar',
+ '../../../third_party/robolectric/robolectric.gyp:robolectric_jar'
],
'variables': {
'src_paths': [
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index a8730fb..8a47be4 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -1128,5 +1128,25 @@
},
"url_unittests"
]
+ },
+ "Cast Linux": {
+ "gtest_tests": [
+ "base_unittests",
+ "cacheinvalidation_unittests",
+ "cast_media_unittests",
+ "cast_shell_browser_test",
+ "content_unittests",
+ "crypto_unittests",
+ "gpu_unittests",
+ "ipc_tests",
+ "jingle_unittests",
+ "media_unittests",
+ "net_unittests",
+ "sandbox_linux_unittests",
+ "sql_unittests",
+ "sync_unit_tests",
+ "ui_base_unittests",
+ "url_unittests"
+ ]
}
}
diff --git a/testing/buildbot/chromium.perf.json b/testing/buildbot/chromium.perf.json
index 2fd07bd..ec70b5b 100644
--- a/testing/buildbot/chromium.perf.json
+++ b/testing/buildbot/chromium.perf.json
@@ -18,6 +18,11 @@
"name": "gpu_perftests",
"script": "gtest_perf_test.py",
"args": ["gpu_perftests"]
+ },
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests"]
}
]
},
@@ -31,15 +36,20 @@
"name": "gpu_perftests",
"script": "gtest_perf_test.py",
"args": ["gpu_perftests"]
+ },
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests"]
}
]
},
"Android Nexus6 Perf": {
"scripts": [
{
- "name": "gpu_perftests",
+ "name": "cc_perftests",
"script": "gtest_perf_test.py",
- "args": ["gpu_perftests"]
+ "args": ["cc_perftests"]
}
]
},
@@ -53,6 +63,11 @@
"name": "gpu_perftests",
"script": "gtest_perf_test.py",
"args": ["gpu_perftests"]
+ },
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests"]
}
]
},
@@ -62,6 +77,11 @@
"name": "gpu_perftests",
"script": "gtest_perf_test.py",
"args": ["gpu_perftests"]
+ },
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests"]
}
]
},
@@ -75,6 +95,11 @@
"name": "gpu_perftests",
"script": "gtest_perf_test.py",
"args": ["gpu_perftests"]
+ },
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests"]
}
]
},
@@ -92,15 +117,48 @@
"name": "gpu_perftests",
"script": "gtest_perf_test.py",
"args": ["gpu_perftests"]
+ },
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests"]
}
]
},
"Mac 10.8 Perf (1)": {
"scripts": [
+ {
+ "name": "gpu_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["gpu_perftests", "--test-launcher-print-test-stdio=always"]
+ }
+ ]
+ },
+ "Mac 10.8 Perf (3)": {
+ "scripts": [
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests", "--test-launcher-print-test-stdio=always"]
+ }
]
},
"Mac 10.9 Perf (1)": {
"scripts": [
+ {
+ "name": "gpu_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["gpu_perftests", "--test-launcher-print-test-stdio=always"]
+ }
+ ]
+ },
+ "Mac 10.9 Perf (3)": {
+ "scripts": [
+ {
+ "name": "cc_perftests",
+ "script": "gtest_perf_test.py",
+ "args": ["cc_perftests", "--test-launcher-print-test-stdio=always"]
+ }
]
}
}
diff --git a/testing/chromoting/integration_tests.gyp b/testing/chromoting/integration_tests.gyp
index 2588d24..b50c3c6 100644
--- a/testing/chromoting/integration_tests.gyp
+++ b/testing/chromoting/integration_tests.gyp
@@ -2,6 +2,9 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+# TODO: Factor out all of the common items across the test targets into a
+# single .gypi file that can be included by each test target.
+
{
'conditions': [
['archive_chromoting_tests==1', {
@@ -24,10 +27,34 @@
['OS=="linux"', {
'dependencies': [
'../../remoting/remoting.gyp:remoting_me2me_host_archive',
+ '../../remoting/webapp/app_remoting/internal/app_remoting_all.gyp:app_remoting_all_apps',
],
}], # OS=="linux"
],
- },
+ }, # target_name: 'chromoting_integration_tests_run'
+ {
+ 'target_name': 'chromoting_multi_machine_example_test',
+ 'type': 'none',
+ 'dependencies': [
+ '../../chrome/chrome.gyp:browser_tests',
+ '../../remoting/remoting.gyp:remoting_webapp_v1',
+ '../../remoting/remoting.gyp:remoting_webapp_v2',
+ ],
+ 'includes': [
+ '../../build/isolate.gypi',
+ ],
+ 'sources': [
+ 'multi_machine_example/example_test_controller.isolate',
+ 'multi_machine_example/example_task.isolate',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'dependencies': [
+ '../../remoting/remoting.gyp:remoting_me2me_host_archive',
+ ],
+ }], # OS=="linux"
+ ],
+ }, # target_name: 'chromoting_multi_machine_example_test'
],
}],
],
diff --git a/testing/chromoting/multi_machine_example/example_task.isolate b/testing/chromoting/multi_machine_example/example_task.isolate
new file mode 100644
index 0000000..710e6da
--- /dev/null
+++ b/testing/chromoting/multi_machine_example/example_task.isolate
@@ -0,0 +1,18 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../chromoting_integration_tests.isolate',
+ '../../legion/legion.isolate',
+ '../../../chrome/chrome.isolate',
+ '../../../remoting/tools/remote_test_helper/remote_test_helper.isolate',
+ ],
+ 'variables': {
+ 'command': [
+ 'python',
+ '../../legion/run_task.py',
+ ],
+ },
+}
diff --git a/testing/chromoting/multi_machine_example/example_test_controller.isolate b/testing/chromoting/multi_machine_example/example_test_controller.isolate
new file mode 100644
index 0000000..957cae4
--- /dev/null
+++ b/testing/chromoting/multi_machine_example/example_test_controller.isolate
@@ -0,0 +1,31 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'includes': [
+ '../../legion/legion.isolate',
+ ],
+ 'variables': {
+ 'command': [
+ 'python',
+ 'example_test_controller.py',
+ '--commands_file',
+ '../browser_test_commands_linux.txt',
+ '--prod_dir',
+ '<(PRODUCT_DIR)',
+ '--cfg_file',
+ '../../../remoting/tools/internal/test-account-host-config.json',
+ '--me2me_manifest_file',
+ '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_desktop.json',
+ '--it2me_manifest_file',
+ '<(PRODUCT_DIR)/remoting/com.google.chrome.remote_assistance.json',
+ '--user_profile_dir',
+ '/tmp/chromoting_test_profile',
+ ],
+ 'files': [
+ 'example_test_controller.py',
+ '../../../tools/swarming_client/',
+ ],
+ },
+}
diff --git a/testing/chromoting/multi_machine_example/example_test_controller.py b/testing/chromoting/multi_machine_example/example_test_controller.py
new file mode 100755
index 0000000..2ba2024
--- /dev/null
+++ b/testing/chromoting/multi_machine_example/example_test_controller.py
@@ -0,0 +1,143 @@
+#!/usr/bin/env python
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""The test controller for the chromoting localhost browser_tests.
+
+This test uses the legion framework to setup this controller which will run
+the chromoting_integration_tests on a task machine. This is intended to be an
+example Legion-based test for the chromoting team.
+
+The controller will start a task machine to run browser_tests_launcher on. The
+output of these tests are streamed back to the test controller to be output
+on the controller's stdout and stderr channels. The final test output is then
+read and becomes the final output of the controller, mirroring the test's
+pass/fail result.
+"""
+
+import argparse
+import logging
+import os
+import sys
+import time
+
+# Map the legion directory so we can import the host controller.
+SRC_DIR = os.path.join('..', '..', '..')
+sys.path.append(os.path.join(SRC_DIR, 'testing'))
+from legion import test_controller
+
+
+class ExampleController(test_controller.TestController):
+ """The test controller for the Chromoting browser_tests."""
+
+ def __init__(self):
+ super(ExampleController, self).__init__()
+ self.task = None
+ self.args = None
+
+ def RunTest(self):
+ """Main method to run the test code."""
+ self.ParseArgs()
+ self.CreateTask()
+ self.TestIntegrationTests()
+
+ def CreateBrowserTestsLauncherCommand(self):
+ return [
+ 'python',
+ self.TaskAbsPath('../browser_tests_launcher.py'),
+ '--commands_file', self.TaskAbsPath(self.args.commands_file),
+ '--prod_dir', self.TaskAbsPath(self.args.prod_dir),
+ '--cfg_file', self.TaskAbsPath(self.args.cfg_file),
+ '--me2me_manifest_file', self.TaskAbsPath(
+ self.args.me2me_manifest_file),
+ '--it2me_manifest_file', self.TaskAbsPath(
+ self.args.it2me_manifest_file),
+ '--user_profile_dir', self.args.user_profile_dir,
+ ]
+
+ def TaskAbsPath(self, path):
+ """Returns the absolute path to the resource on the task machine.
+
+ Args:
+ path: The relative path to the resource.
+
+ Since the test controller and the task machines run in different tmp dirs
+ on different machines the absolute path cannot be calculated correctly on
+ this machine. This function maps the relative path (from this directory)
+ to an absolute path on the task machine.
+ """
+ return self.task.rpc.AbsPath(path)
+
+ def CreateTask(self):
+ """Creates a task object and sets the proper values."""
+ self.task = self.CreateNewTask(
+ isolated_hash=self.args.task_machine,
+ dimensions={'os': 'Ubuntu-14.04', 'pool': 'Chromoting'})
+ self.task.Create()
+ self.task.WaitForConnection()
+
+ def ParseArgs(self):
+ """Gets the command line args."""
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--task_machine',
+ help='isolated hash of the task machine.')
+ # The rest of the args are taken from
+ # testing/chromoting/browser_tests_launcher.py.
+ parser.add_argument('-f', '--commands_file',
+ help='path to file listing commands to be launched.')
+ parser.add_argument('-p', '--prod_dir',
+ help='path to folder having product and test binaries.')
+ parser.add_argument('-c', '--cfg_file',
+ help='path to test host config file.')
+ parser.add_argument('--me2me_manifest_file',
+ help='path to me2me host manifest file.')
+ parser.add_argument('--it2me_manifest_file',
+ help='path to it2me host manifest file.')
+ parser.add_argument(
+ '-u', '--user_profile_dir',
+ help='path to user-profile-dir, used by connect-to-host tests.')
+ self.args, _ = parser.parse_known_args()
+
+ def TestIntegrationTests(self):
+ """Runs the integration tests via browser_tests_launcher.py."""
+ # Create a process object, configure it, and start it.
+ # All interactions with the process are based on this "proc" key.
+ proc = self.task.rpc.subprocess.Process(
+ self.CreateBrowserTestsLauncherCommand())
+ # Set the cwd to browser_tests_launcher relative to this directory.
+ # This allows browser_test_launcher to use relative paths.
+ self.task.rpc.subprocess.SetCwd(proc, '../')
+ # Set the task verbosity to true to allow stdout/stderr to be echo'ed to
+ # run_task's stdout/stderr on the task machine. This can assist in
+ # debugging.
+ self.task.rpc.subprocess.SetVerbose(proc)
+ # Set the process as detached to create it in a new process group.
+ self.task.rpc.subprocess.SetDetached(proc)
+ # Start the actual process on the task machine.
+ self.task.rpc.subprocess.Start(proc)
+
+ # Collect the stdout/stderr and emit it from this controller while the
+ # process is running.
+ while self.task.rpc.subprocess.Poll(proc) is None:
+ # Output the test's stdout and stderr in semi-realtime.
+ # This is not true realtime due to the RPC calls and the 1s sleep.
+ stdout, stderr = self.task.rpc.subprocess.ReadOutput(proc)
+ if stdout:
+ sys.stdout.write(stdout)
+ if stderr:
+ sys.stderr.write(stderr)
+ time.sleep(1)
+
+ # Get the return code, clean up the process object.
+ returncode = self.task.rpc.subprocess.GetReturncode(proc)
+ self.task.rpc.subprocess.Delete(proc)
+
+ # Pass or fail depending on the return code from the browser_tests_launcher.
+ if returncode != 0:
+ raise AssertionError('browser_tests_launcher failed with return code '
+ '%i' % returncode)
+
+
+if __name__ == '__main__':
+ ExampleController().RunController()
diff --git a/testing/commit_queue/config.json b/testing/commit_queue/config.json
index 6ca3384..8c0a2e7 100644
--- a/testing/commit_queue/config.json
+++ b/testing/commit_queue/config.json
@@ -1,93 +1,185 @@
{
- "experimental_tryjobs": {
- "10 percent experiment": {
- "percentage": 0.10,
- "trybots": {
- "launched": {
- "tryserver.chromium.linux": {
- "android_amp_rel_tests_recipe": ["defaulttests"],
- "android_n5_rel_tests_recipe": ["defaulttests"],
- "cast_shell": ["defaulttests"],
- "cast_shell_apk": ["defaulttests"],
- "linux_arm_compile": ["defaulttests"],
- "linux_chromium_asan_rel_ng": ["defaulttests"],
- "linux_chromium_chromeos_ozone_rel_ng": ["defaulttests"]
- },
- "tryserver.chromium.mac": {
- "mac_chromium_gn_rel": ["defaulttests"]
- },
- "tryserver.chromium.win": {
- "win8_chromium_ng": ["defaulttests"],
- "win8_chromium_gn_rel": ["defaulttests"]
+ "commit_burst_delay": 60,
+ "commit_user": "commit-bot@chromium.org",
+ "committer_project": "chromium",
+ "cq_status_url": "https://chromium-cq-status.appspot.com",
+ "git_repo_url": "https://chromium.googlesource.com/chromium/src",
+ "hide_ref_in_committed_msg": true,
+ "max_commit_burst": 2,
+ "project_bases": [
+ ".*"
+ ],
+ "project_bases_legacy": [
+ "^svn\\:\\/\\/svn\\.chromium\\.org\\/chrome/trunk/src(|/.*)$",
+ "^svn\\:\\/\\/chrome\\-svn\\/chrome/trunk/src(|/.*)$",
+ "^svn\\:\\/\\/chrome\\-svn\\.corp\\/chrome/trunk/src(|/.*)$",
+ "^svn\\:\\/\\/chrome\\-svn\\.corp\\.google\\.com\\/chrome/trunk/src(|/.*)$",
+ "^http\\:\\/\\/src\\.chromium\\.org\\/svn/trunk/src(|/.*)$",
+ "^https\\:\\/\\/src\\.chromium\\.org\\/svn/trunk/src(|/.*)$",
+ "^http\\:\\/\\/src\\.chromium\\.org\\/chrome/trunk/src(|/.*)$",
+ "^https\\:\\/\\/src\\.chromium\\.org\\/chrome/trunk/src(|/.*)$"
+ ],
+ "project_bases_legacy_from_git_repo_url": true,
+ "remote_branch": "refs/pending/heads/master",
+ "rietveld_url": "https://codereview.chromium.org",
+ "rietveld_user": "commit-bot@chromium.org",
+ "skip_throttle_users": [
+ "commit-bot@chromium.org"
+ ],
+ "tree_status_url": "https://chromium-status.appspot.com",
+ "tryserver_url": "http://build.chromium.org/p/tryserver.chromium/",
+ "use_buildbucket_for_tryjobs": true,
+ "verifiers_no_patch": {
+ "experimental_try_job_verifier": {
+ "10 percent experiment": {
+ "percentage": 0.1,
+ "trybots": {
+ "launched": {
+ "tryserver.chromium.linux": {
+ "android_amp_rel_tests_recipe": [
+ "defaulttests"
+ ],
+ "cast_shell": [
+ "defaulttests"
+ ],
+ "cast_shell_apk": [
+ "defaulttests"
+ ],
+ "linux_arm_compile": [
+ "defaulttests"
+ ],
+ "linux_chromium_asan_rel_ng": [
+ "defaulttests"
+ ]
+ },
+ "tryserver.chromium.mac": {
+ "mac_chromium_gn_rel": [
+ "defaulttests"
+ ]
+ },
+ "tryserver.chromium.win": {
+ "win8_chromium_gn_rel": [
+ "defaulttests"
+ ],
+ "win8_chromium_ng": [
+ "defaulttests"
+ ]
+ }
}
}
- }
- },
- "50 percent experiment": {
- "percentage": 0.50,
- "trybots": {
- "launched": {
- "tryserver.chromium.linux": {
- }
- }
- }
- },
- "75 percent experiment": {
- "percentage": 0.75,
- "trybots": {
- "launched": {
- "tryserver.chromium.linux": {
- }
- }
- }
- },
- "100 percent experiment": {
- "percentage": 1.00,
- "trybots": {
- "launched": {
- "tryserver.chromium.linux": {
- },
- "tryserver.chromium.mac": {
- }
- }
- }
- }
- },
- "trybots": {
- "launched": {
- "tryserver.chromium.linux": {
- "android_chromium_gn_compile_dbg": ["defaulttests"],
- "android_chromium_gn_compile_rel": ["defaulttests"],
- "android_compile_rel": ["defaulttests"],
- "chromium_presubmit": ["defaulttests"],
- "linux_android_rel_ng": ["defaulttests"],
- "linux_chromium_asan_rel": ["defaulttests"],
- "linux_chromium_chromeos_compile_dbg_ng": ["defaulttests"],
- "linux_chromium_chromeos_rel_ng": ["defaulttests"],
- "linux_chromium_clobber_rel_ng": ["defaulttests"],
- "linux_chromium_gn_chromeos_rel": ["defaulttests"],
- "linux_chromium_gn_dbg": ["defaulttests"],
- "linux_chromium_gn_rel": ["defaulttests"],
- "linux_chromium_rel_ng": ["defaulttests"],
- "android_arm64_dbg_recipe": ["defaulttests"],
- "android_clang_dbg_recipe": ["defaulttests"],
- "android_aosp": ["compile"],
- "linux_chromium_compile_dbg_32_ng": ["compile"]
},
- "tryserver.chromium.mac": {
- "ios_dbg_simulator_ninja": ["defaulttests"],
- "ios_rel_device_ninja": ["defaulttests"],
- "mac_chromium_compile_dbg_ng": ["defaulttests"],
- "mac_chromium_rel_ng": ["defaulttests"]
+ "100 percent experiment": {
+ "percentage": 1.0,
+ "trybots": {
+ "launched": {
+ "tryserver.chromium.linux": {},
+ "tryserver.chromium.mac": {}
+ }
+ }
},
- "tryserver.chromium.win": {
- "win8_chromium_rel": ["defaulttests"],
- "win_chromium_compile_dbg_ng": ["defaulttests"],
- "win_chromium_rel_ng": ["defaulttests"],
- "win_chromium_x64_rel_ng": ["defaulttests"]
+ "50 percent experiment": {
+ "percentage": 0.5,
+ "trybots": {
+ "launched": {
+ "tryserver.chromium.linux": {}
+ }
+ }
+ },
+ "75 percent experiment": {
+ "percentage": 0.75,
+ "trybots": {
+ "launched": {
+ "tryserver.chromium.linux": {}
+ }
+ }
}
},
- "triggered": {
+ "reviewer_lgtm_verifier": {},
+ "tree_status_verifier": {},
+ "try_job_verifier": {
+ "launched": {
+ "tryserver.chromium.linux": {
+ "android_arm64_dbg_recipe": [
+ "defaulttests"
+ ],
+ "android_chromium_gn_compile_dbg": [
+ "defaulttests"
+ ],
+ "android_chromium_gn_compile_rel": [
+ "defaulttests"
+ ],
+ "android_clang_dbg_recipe": [
+ "defaulttests"
+ ],
+ "android_compile_rel": [
+ "defaulttests"
+ ],
+ "chromium_presubmit": [
+ "defaulttests"
+ ],
+ "linux_android_rel_ng": [
+ "defaulttests"
+ ],
+ "linux_chromium_asan_rel": [
+ "defaulttests"
+ ],
+ "linux_chromium_chromeos_compile_dbg_ng": [
+ "defaulttests"
+ ],
+ "linux_chromium_chromeos_ozone_rel_ng": [
+ "defaulttests"
+ ],
+ "linux_chromium_chromeos_rel_ng": [
+ "defaulttests"
+ ],
+ "linux_chromium_clobber_rel_ng": [
+ "defaulttests"
+ ],
+ "linux_chromium_compile_dbg_32_ng": [
+ "compile"
+ ],
+ "linux_chromium_gn_chromeos_rel": [
+ "defaulttests"
+ ],
+ "linux_chromium_gn_dbg": [
+ "defaulttests"
+ ],
+ "linux_chromium_gn_rel": [
+ "defaulttests"
+ ],
+ "linux_chromium_rel_ng": [
+ "defaulttests"
+ ]
+ },
+ "tryserver.chromium.mac": {
+ "ios_dbg_simulator_ninja": [
+ "defaulttests"
+ ],
+ "ios_rel_device_ninja": [
+ "defaulttests"
+ ],
+ "mac_chromium_compile_dbg_ng": [
+ "defaulttests"
+ ],
+ "mac_chromium_rel_ng": [
+ "defaulttests"
+ ]
+ },
+ "tryserver.chromium.win": {
+ "win8_chromium_rel": [
+ "defaulttests"
+ ],
+ "win_chromium_compile_dbg_ng": [
+ "defaulttests"
+ ],
+ "win_chromium_rel_ng": [
+ "defaulttests"
+ ],
+ "win_chromium_x64_rel_ng": [
+ "defaulttests"
+ ]
+ }
+ }
}
}
}
diff --git a/testing/iossim/iossim.gyp b/testing/iossim/iossim.gyp
index 6a1fb02..0fdd8b1 100644
--- a/testing/iossim/iossim.gyp
+++ b/testing/iossim/iossim.gyp
@@ -4,7 +4,7 @@
{
'conditions': [
- ['OS!="ios" or "<(GENERATOR)"=="ninja"', {
+ ['OS!="ios" or "<(GENERATOR)"!="xcode" or "<(GENERATOR_FLAVOR)"=="ninja"', {
'targets': [
{
'target_name': 'iossim',
@@ -126,7 +126,7 @@
},
},
],
- }, { # else, OS=="ios" and "<(GENERATOR)"!="ninja"
+ }, { # else, OS=="ios" and "<(GENERATOR)"=="xcode" and "<(GENERATOR_FLAVOR)"!="ninja"
'variables': {
'ninja_output_dir': 'ninja-iossim',
'ninja_product_dir':
diff --git a/third_party/boringssl/boringssl_unittest.cc b/third_party/boringssl/boringssl_unittest.cc
index 4cc0804..d568e33 100644
--- a/third_party/boringssl/boringssl_unittest.cc
+++ b/third_party/boringssl/boringssl_unittest.cc
@@ -116,6 +116,10 @@
FILE_PATH_LITERAL("aes_256_cbc_sha1_ssl3_tests.txt")},
{FILE_PATH_LITERAL("des-ede3-cbc-sha1-ssl3"),
FILE_PATH_LITERAL("des_ede3_cbc_sha1_ssl3_tests.txt")},
+ {FILE_PATH_LITERAL("aes-128-ctr-hmac-sha256"),
+ FILE_PATH_LITERAL("aes_128_ctr_hmac_sha256.txt")},
+ {FILE_PATH_LITERAL("aes-256-ctr-hmac-sha256"),
+ FILE_PATH_LITERAL("aes_256_ctr_hmac_sha256.txt")},
};
TEST(BoringSSL, AEADs) {
diff --git a/third_party/boringssl/err_data.c b/third_party/boringssl/err_data.c
index 65bc34f..fe8e3d4 100644
--- a/third_party/boringssl/err_data.c
+++ b/third_party/boringssl/err_data.c
@@ -79,192 +79,194 @@
0xc3d0679,
0xc3d8681,
0xc3e068c,
- 0x10321744,
- 0x1032975b,
- 0x10331774,
- 0x1033978a,
- 0x1034179a,
- 0x103497ad,
- 0x103517bb,
- 0x103597ca,
- 0x103617ea,
- 0x10369809,
- 0x10371826,
- 0x10379843,
- 0x10381858,
- 0x1038987a,
- 0x10391899,
- 0x103998b8,
- 0x103a18cf,
- 0x103a98e6,
- 0x103b18ef,
- 0x103b98fa,
- 0x103c1914,
- 0x103c991c,
- 0x103d1924,
- 0x103d992b,
- 0x103e193e,
- 0x103e9950,
- 0x103f1963,
- 0x103f996c,
- 0x143209cb,
- 0x143289d9,
- 0x143309e5,
- 0x143389f2,
- 0x1832100b,
- 0x18329023,
- 0x18331045,
- 0x18339057,
- 0x18341068,
- 0x18349081,
- 0x18351092,
- 0x183590a8,
- 0x183610b8,
- 0x183690cd,
- 0x183710e6,
- 0x183790f7,
- 0x1838110d,
- 0x1838911e,
- 0x18391130,
- 0x18399145,
- 0x183a1157,
- 0x183a9167,
- 0x183b117c,
- 0x183b9189,
- 0x183c119b,
- 0x183c91a9,
- 0x183d11bc,
- 0x183d91cc,
- 0x183e11e1,
- 0x183e91f2,
- 0x183f1205,
- 0x183f9214,
- 0x18401224,
- 0x18409231,
- 0x18411240,
- 0x18419251,
- 0x18421264,
- 0x18429276,
- 0x18431288,
- 0x18439299,
- 0x184412aa,
- 0x184492bb,
- 0x184512cc,
- 0x184592d9,
- 0x184612e7,
- 0x184692fa,
- 0x1847130e,
- 0x1847931b,
- 0x1848132a,
- 0x18489339,
- 0x1849134a,
- 0x18499357,
- 0x184a1365,
- 0x184a9376,
- 0x184b1387,
- 0x184b9395,
- 0x184c13a5,
- 0x184c93cb,
- 0x184d13da,
- 0x184d93ea,
- 0x184e13fa,
- 0x184e9409,
+ 0x103217ce,
+ 0x103297e5,
+ 0x103317fe,
+ 0x10339814,
+ 0x10341824,
+ 0x10349837,
+ 0x10351845,
+ 0x10359854,
+ 0x10361874,
+ 0x10369893,
+ 0x103718b0,
+ 0x103798cd,
+ 0x103818e2,
+ 0x10389904,
+ 0x10391923,
+ 0x10399942,
+ 0x103a1959,
+ 0x103a9970,
+ 0x103b1979,
+ 0x103b9984,
+ 0x103c199e,
+ 0x103c99a6,
+ 0x103d19ae,
+ 0x103d99b5,
+ 0x103e19c8,
+ 0x103e99da,
+ 0x103f19ed,
+ 0x103f99f6,
+ 0x14320a25,
+ 0x14328a33,
+ 0x14330a3f,
+ 0x14338a4c,
+ 0x18321065,
+ 0x1832907d,
+ 0x1833109f,
+ 0x183390b1,
+ 0x183410e3,
+ 0x183490fc,
+ 0x1835110d,
+ 0x18359123,
+ 0x18361133,
+ 0x18369148,
+ 0x18371161,
+ 0x18379172,
+ 0x18381188,
+ 0x18389199,
+ 0x183911ab,
+ 0x183991c0,
+ 0x183a11d2,
+ 0x183a91e2,
+ 0x183b11f7,
+ 0x183b9204,
+ 0x183c1216,
+ 0x183c9224,
+ 0x183d1237,
+ 0x183d9247,
+ 0x183e125c,
+ 0x183e926d,
+ 0x183f1280,
+ 0x183f928f,
+ 0x1840129f,
+ 0x184092ac,
+ 0x184112bb,
+ 0x184192cc,
+ 0x184212df,
+ 0x184292f1,
+ 0x18431303,
+ 0x18439314,
+ 0x18441325,
+ 0x18449336,
+ 0x18451347,
+ 0x18459354,
+ 0x18461362,
+ 0x18469375,
+ 0x18471389,
+ 0x18479396,
+ 0x184813a5,
+ 0x184893b4,
+ 0x184913c5,
+ 0x184993e1,
+ 0x184a13ef,
+ 0x184a9400,
+ 0x184b1411,
+ 0x184b941f,
+ 0x184c142f,
+ 0x184c9455,
+ 0x184d1464,
+ 0x184d9474,
+ 0x184e1484,
+ 0x184e9493,
+ 0x184f13d2,
+ 0x184f90c2,
0x1c320699,
0x1c3286a5,
0x1c3306b0,
0x1c3386bc,
- 0x2032141d,
- 0x20329428,
- 0x20331430,
- 0x2033943c,
- 0x24321448,
- 0x24329456,
- 0x24331468,
- 0x24339477,
- 0x2434148a,
- 0x2434949d,
- 0x243514b4,
- 0x243594cc,
- 0x243614da,
- 0x243694f2,
- 0x243714fb,
- 0x2437950d,
- 0x24381521,
- 0x2438952e,
- 0x24391544,
- 0x2439955c,
- 0x243a1574,
- 0x243a957e,
- 0x243b1593,
- 0x243b95a1,
- 0x243c15b9,
- 0x243c95d0,
- 0x243d15db,
- 0x243d95e9,
- 0x28320a2b,
- 0x28328a3a,
- 0x28330a45,
- 0x28338a4a,
- 0x28340a55,
- 0x2c322850,
- 0x2c32a85c,
- 0x2c33286f,
- 0x2c33a880,
- 0x2c342899,
- 0x2c34a8c1,
- 0x2c3528d8,
- 0x2c35a8f5,
- 0x2c362912,
- 0x2c36a92f,
- 0x2c372948,
- 0x2c37a961,
- 0x2c382977,
- 0x2c38a985,
- 0x2c392997,
- 0x2c39a9b4,
- 0x2c3a29d1,
- 0x2c3aa9df,
- 0x2c3b29fd,
- 0x2c3baa1b,
- 0x2c3c2a36,
- 0x2c3caa4a,
- 0x2c3d2a5c,
- 0x2c3daa6c,
- 0x2c3e2a7a,
- 0x2c3eaa8a,
- 0x2c3f2a9a,
- 0x2c3faab5,
- 0x2c402ac6,
- 0x2c40aae1,
- 0x2c412af5,
- 0x2c41ab08,
- 0x2c422b27,
- 0x2c42ab3b,
- 0x2c432b4e,
- 0x2c43ab5d,
- 0x2c442b6c,
- 0x2c44ab83,
- 0x2c452b9e,
- 0x2c45abb6,
- 0x2c462bca,
- 0x2c46abdd,
- 0x2c472bee,
- 0x2c47abff,
- 0x2c482c10,
- 0x2c48ac21,
- 0x2c492c30,
- 0x2c49ac3d,
- 0x2c4a2c4a,
- 0x2c4aac57,
- 0x2c4b2c60,
- 0x2c4bac74,
- 0x2c4c2c83,
- 0x2c4cac91,
- 0x2c4d2cb3,
- 0x2c4dacc4,
- 0x2c4e2cd5,
- 0x2c4eaca0,
- 0x2c4f28b2,
+ 0x203214a7,
+ 0x203294b2,
+ 0x203314ba,
+ 0x203394c6,
+ 0x243214d2,
+ 0x243294e0,
+ 0x243314f2,
+ 0x24339501,
+ 0x24341514,
+ 0x24349527,
+ 0x2435153e,
+ 0x24359556,
+ 0x24361564,
+ 0x2436957c,
+ 0x24371585,
+ 0x24379597,
+ 0x243815ab,
+ 0x243895b8,
+ 0x243915ce,
+ 0x243995e6,
+ 0x243a15fe,
+ 0x243a9608,
+ 0x243b161d,
+ 0x243b962b,
+ 0x243c1643,
+ 0x243c965a,
+ 0x243d1665,
+ 0x243d9673,
+ 0x28320a85,
+ 0x28328a94,
+ 0x28330a9f,
+ 0x28338aa4,
+ 0x28340aaf,
+ 0x2c3228da,
+ 0x2c32a8e6,
+ 0x2c3328f9,
+ 0x2c33a90a,
+ 0x2c342923,
+ 0x2c34a94b,
+ 0x2c352962,
+ 0x2c35a97f,
+ 0x2c36299c,
+ 0x2c36a9b9,
+ 0x2c3729d2,
+ 0x2c37a9eb,
+ 0x2c382a01,
+ 0x2c38aa0f,
+ 0x2c392a21,
+ 0x2c39aa3e,
+ 0x2c3a2a5b,
+ 0x2c3aaa69,
+ 0x2c3b2a87,
+ 0x2c3baaa5,
+ 0x2c3c2ac0,
+ 0x2c3caad4,
+ 0x2c3d2ae6,
+ 0x2c3daaf6,
+ 0x2c3e2b04,
+ 0x2c3eab14,
+ 0x2c3f2b24,
+ 0x2c3fab3f,
+ 0x2c402b50,
+ 0x2c40ab6b,
+ 0x2c412b7f,
+ 0x2c41ab92,
+ 0x2c422bb1,
+ 0x2c42abc5,
+ 0x2c432bd8,
+ 0x2c43abe7,
+ 0x2c442bf6,
+ 0x2c44ac0d,
+ 0x2c452c28,
+ 0x2c45ac40,
+ 0x2c462c54,
+ 0x2c46ac67,
+ 0x2c472c78,
+ 0x2c47ac89,
+ 0x2c482c9a,
+ 0x2c48acab,
+ 0x2c492cba,
+ 0x2c49acc7,
+ 0x2c4a2cd4,
+ 0x2c4aace1,
+ 0x2c4b2cea,
+ 0x2c4bacfe,
+ 0x2c4c2d0d,
+ 0x2c4cad1b,
+ 0x2c4d2d3d,
+ 0x2c4dad4e,
+ 0x2c4e2d5f,
+ 0x2c4ead2a,
+ 0x2c4f293c,
0x30320000,
0x30328018,
0x3033002c,
@@ -329,239 +331,239 @@
0x30508404,
0x30510413,
0x3051841c,
- 0x3432095d,
- 0x3432896d,
- 0x34330978,
- 0x34338985,
- 0x3832098e,
- 0x383289a1,
- 0x383309ab,
- 0x383389bd,
- 0x3c320a5c,
- 0x3c328a6a,
- 0x3c330a81,
- 0x3c338a95,
- 0x3c340ab0,
- 0x3c348ac1,
- 0x3c350acd,
- 0x3c358ae1,
- 0x3c360af3,
- 0x3c368b1c,
- 0x3c370b29,
- 0x3c378b36,
- 0x3c380b44,
- 0x3c388b51,
- 0x3c390b5e,
- 0x3c398b82,
- 0x3c3a0b92,
- 0x3c3a8baa,
- 0x3c3b0bbf,
- 0x3c3b8bd4,
- 0x3c3c0be1,
- 0x3c3c8bf4,
- 0x3c3d0c07,
- 0x3c3d8c2b,
- 0x3c3e0c53,
- 0x3c3e8c6c,
- 0x3c3f0c82,
- 0x3c3f8c8f,
- 0x3c400ca2,
- 0x3c408cb3,
- 0x3c410cc4,
- 0x3c418cdd,
- 0x3c420cf6,
- 0x3c428d0c,
- 0x3c430d29,
- 0x3c438d3f,
- 0x3c440d5b,
- 0x3c448d82,
- 0x3c450da0,
- 0x3c458dba,
- 0x3c460dd2,
- 0x3c468dea,
- 0x3c470e15,
- 0x3c478e40,
- 0x3c480e61,
- 0x3c488e8a,
- 0x3c490ea5,
- 0x3c498ec0,
- 0x3c4a0ecd,
- 0x3c4a8ee4,
- 0x3c4b0efb,
- 0x3c4b8f24,
- 0x3c4c0f34,
- 0x3c4c8f40,
- 0x3c4d0f58,
- 0x3c4d8f6b,
- 0x3c4e0f7c,
- 0x3c4e8f8d,
- 0x3c4f0f9d,
- 0x40321977,
- 0x40329991,
- 0x4033199d,
- 0x403399b5,
- 0x403419d3,
- 0x403499f2,
- 0x40351a09,
- 0x40359a25,
- 0x40361a41,
- 0x40369a5b,
- 0x40371a7a,
- 0x40379a99,
- 0x40381ab1,
- 0x40389ace,
- 0x40391af1,
- 0x40399b0e,
- 0x403a1b2c,
- 0x403a9b3c,
- 0x403b1b51,
- 0x403b9b6d,
- 0x403c1b87,
- 0x403c9b92,
- 0x403d1bb5,
- 0x403d9bd9,
- 0x403e1bef,
- 0x403e9bf9,
- 0x403f1c05,
- 0x403f9c16,
- 0x40401c2e,
- 0x40409c36,
- 0x40411c3f,
- 0x40419c48,
- 0x40421c58,
- 0x40429c6c,
- 0x40431c77,
- 0x40439c83,
- 0x40441c9e,
- 0x40449caa,
- 0x40451cb7,
- 0x40459cca,
- 0x40461ce2,
- 0x40469cfa,
- 0x40471d10,
- 0x40479d2b,
- 0x40481d46,
- 0x40489d5a,
- 0x40491d73,
- 0x40499d8c,
- 0x404a1da6,
- 0x404a9db0,
- 0x404b1dc0,
- 0x404b9de1,
- 0x404c1dfc,
- 0x404c9e0a,
- 0x404d1e17,
- 0x404d9e2b,
- 0x404e1e43,
- 0x404e9e51,
- 0x404f1e7b,
- 0x404f9e92,
- 0x40501ea4,
- 0x40509ed5,
- 0x40511f06,
- 0x40519f1b,
- 0x40521f2c,
- 0x40529f4c,
- 0x40531f67,
- 0x40539f77,
- 0x40541f83,
- 0x40549f96,
- 0x40551fac,
- 0x40559fca,
- 0x40561fd7,
- 0x40569fe1,
- 0x40571fef,
- 0x4057a00a,
- 0x40582025,
- 0x4058a044,
- 0x40592059,
- 0x4059a06e,
- 0x405a208b,
- 0x405aa09f,
- 0x405b20bb,
- 0x405ba0d1,
- 0x405c20ee,
- 0x405ca100,
- 0x405d2117,
- 0x405da128,
- 0x405e2144,
- 0x405ea158,
- 0x405f2168,
- 0x405fa184,
- 0x40602199,
- 0x4060a1af,
- 0x406121cc,
- 0x4061a1e5,
- 0x406221f8,
- 0x4062a201,
- 0x40632211,
- 0x4063a21d,
- 0x40642233,
- 0x4064a251,
- 0x40652266,
- 0x4065a283,
- 0x4066229a,
- 0x4066a2b8,
- 0x406722d5,
- 0x4067a2ec,
- 0x4068230a,
- 0x4068a321,
- 0x40692339,
- 0x4069a34a,
- 0x406a235d,
- 0x406aa370,
- 0x406b2384,
- 0x406ba3a8,
- 0x406c23c3,
- 0x406ca3e4,
- 0x406d2408,
- 0x406da423,
- 0x406e2444,
- 0x406ea459,
- 0x406f2472,
- 0x406fa47f,
- 0x4070248d,
- 0x4070a49a,
- 0x407124b7,
- 0x4071a4d7,
- 0x407224f2,
- 0x4072a50b,
- 0x40732522,
- 0x4073a53c,
- 0x40742560,
- 0x4074a576,
- 0x4075258a,
- 0x4075a59f,
- 0x407625b9,
- 0x4076a5cb,
- 0x407725e0,
- 0x4077a606,
- 0x40782623,
- 0x4078a646,
- 0x4079266c,
- 0x4079a689,
- 0x407a26ac,
- 0x407aa6c8,
- 0x407b26e4,
- 0x407ba6f6,
- 0x407c2703,
- 0x407ca710,
- 0x407d272d,
- 0x407da744,
- 0x407e2760,
- 0x407ea776,
- 0x407f278e,
- 0x407fa7a1,
- 0x408027b6,
- 0x4080a7cf,
- 0x408127ed,
- 0x4081a80d,
- 0x40822816,
- 0x4082a832,
- 0x4083283b,
- 0x40839e60,
- 0x40841eef,
- 0x40849ebf,
+ 0x343209b7,
+ 0x343289c7,
+ 0x343309d2,
+ 0x343389df,
+ 0x383209e8,
+ 0x383289fb,
+ 0x38330a05,
+ 0x38338a17,
+ 0x3c320ab6,
+ 0x3c328ac4,
+ 0x3c330adb,
+ 0x3c338aef,
+ 0x3c340b0a,
+ 0x3c348b1b,
+ 0x3c350b27,
+ 0x3c358b3b,
+ 0x3c360b4d,
+ 0x3c368b76,
+ 0x3c370b83,
+ 0x3c378b90,
+ 0x3c380b9e,
+ 0x3c388bab,
+ 0x3c390bb8,
+ 0x3c398bdc,
+ 0x3c3a0bec,
+ 0x3c3a8c04,
+ 0x3c3b0c19,
+ 0x3c3b8c2e,
+ 0x3c3c0c3b,
+ 0x3c3c8c4e,
+ 0x3c3d0c61,
+ 0x3c3d8c85,
+ 0x3c3e0cad,
+ 0x3c3e8cc6,
+ 0x3c3f0cdc,
+ 0x3c3f8ce9,
+ 0x3c400cfc,
+ 0x3c408d0d,
+ 0x3c410d1e,
+ 0x3c418d37,
+ 0x3c420d50,
+ 0x3c428d66,
+ 0x3c430d83,
+ 0x3c438d99,
+ 0x3c440db5,
+ 0x3c448ddc,
+ 0x3c450dfa,
+ 0x3c458e14,
+ 0x3c460e2c,
+ 0x3c468e44,
+ 0x3c470e6f,
+ 0x3c478e9a,
+ 0x3c480ebb,
+ 0x3c488ee4,
+ 0x3c490eff,
+ 0x3c498f1a,
+ 0x3c4a0f27,
+ 0x3c4a8f3e,
+ 0x3c4b0f55,
+ 0x3c4b8f7e,
+ 0x3c4c0f8e,
+ 0x3c4c8f9a,
+ 0x3c4d0fb2,
+ 0x3c4d8fc5,
+ 0x3c4e0fd6,
+ 0x3c4e8fe7,
+ 0x3c4f0ff7,
+ 0x40321a01,
+ 0x40329a1b,
+ 0x40331a27,
+ 0x40339a3f,
+ 0x40341a5d,
+ 0x40349a7c,
+ 0x40351a93,
+ 0x40359aaf,
+ 0x40361acb,
+ 0x40369ae5,
+ 0x40371b04,
+ 0x40379b23,
+ 0x40381b3b,
+ 0x40389b58,
+ 0x40391b7b,
+ 0x40399b98,
+ 0x403a1bb6,
+ 0x403a9bc6,
+ 0x403b1bdb,
+ 0x403b9bf7,
+ 0x403c1c11,
+ 0x403c9c1c,
+ 0x403d1c3f,
+ 0x403d9c63,
+ 0x403e1c79,
+ 0x403e9c83,
+ 0x403f1c8f,
+ 0x403f9ca0,
+ 0x40401cb8,
+ 0x40409cc0,
+ 0x40411cc9,
+ 0x40419cd2,
+ 0x40421ce2,
+ 0x40429cf6,
+ 0x40431d01,
+ 0x40439d0d,
+ 0x40441d28,
+ 0x40449d34,
+ 0x40451d41,
+ 0x40459d54,
+ 0x40461d6c,
+ 0x40469d84,
+ 0x40471d9a,
+ 0x40479db5,
+ 0x40481dd0,
+ 0x40489de4,
+ 0x40491dfd,
+ 0x40499e16,
+ 0x404a1e30,
+ 0x404a9e3a,
+ 0x404b1e4a,
+ 0x404b9e6b,
+ 0x404c1e86,
+ 0x404c9e94,
+ 0x404d1ea1,
+ 0x404d9eb5,
+ 0x404e1ecd,
+ 0x404e9edb,
+ 0x404f1f05,
+ 0x404f9f1c,
+ 0x40501f2e,
+ 0x40509f5f,
+ 0x40511f90,
+ 0x40519fa5,
+ 0x40521fb6,
+ 0x40529fd6,
+ 0x40531ff1,
+ 0x4053a001,
+ 0x4054200d,
+ 0x4054a020,
+ 0x40552036,
+ 0x4055a054,
+ 0x40562061,
+ 0x4056a06b,
+ 0x40572079,
+ 0x4057a094,
+ 0x405820af,
+ 0x4058a0ce,
+ 0x405920e3,
+ 0x4059a0f8,
+ 0x405a2115,
+ 0x405aa129,
+ 0x405b2145,
+ 0x405ba15b,
+ 0x405c2178,
+ 0x405ca18a,
+ 0x405d21a1,
+ 0x405da1b2,
+ 0x405e21ce,
+ 0x405ea1e2,
+ 0x405f21f2,
+ 0x405fa20e,
+ 0x40602223,
+ 0x4060a239,
+ 0x40612256,
+ 0x4061a26f,
+ 0x40622282,
+ 0x4062a28b,
+ 0x4063229b,
+ 0x4063a2a7,
+ 0x406422bd,
+ 0x4064a2db,
+ 0x406522f0,
+ 0x4065a30d,
+ 0x40662324,
+ 0x4066a342,
+ 0x4067235f,
+ 0x4067a376,
+ 0x40682394,
+ 0x4068a3ab,
+ 0x406923c3,
+ 0x4069a3d4,
+ 0x406a23e7,
+ 0x406aa3fa,
+ 0x406b240e,
+ 0x406ba432,
+ 0x406c244d,
+ 0x406ca46e,
+ 0x406d2492,
+ 0x406da4ad,
+ 0x406e24ce,
+ 0x406ea4e3,
+ 0x406f24fc,
+ 0x406fa509,
+ 0x40702517,
+ 0x4070a524,
+ 0x40712541,
+ 0x4071a561,
+ 0x4072257c,
+ 0x4072a595,
+ 0x407325ac,
+ 0x4073a5c6,
+ 0x407425ea,
+ 0x4074a600,
+ 0x40752614,
+ 0x4075a629,
+ 0x40762643,
+ 0x4076a655,
+ 0x4077266a,
+ 0x4077a690,
+ 0x407826ad,
+ 0x4078a6d0,
+ 0x407926f6,
+ 0x4079a713,
+ 0x407a2736,
+ 0x407aa752,
+ 0x407b276e,
+ 0x407ba780,
+ 0x407c278d,
+ 0x407ca79a,
+ 0x407d27b7,
+ 0x407da7ce,
+ 0x407e27ea,
+ 0x407ea800,
+ 0x407f2818,
+ 0x407fa82b,
+ 0x40802840,
+ 0x4080a859,
+ 0x40812877,
+ 0x4081a897,
+ 0x408228a0,
+ 0x4082a8bc,
+ 0x408328c5,
+ 0x40839eea,
+ 0x40841f79,
+ 0x40849f49,
0x4432042a,
0x4432843c,
0x44330445,
@@ -580,89 +582,89 @@
0x44398522,
0x443a052c,
0x443a8536,
- 0x4c3215f1,
- 0x4c329600,
- 0x4c33160f,
- 0x4c339628,
- 0x4c341643,
- 0x4c34965f,
- 0x4c351671,
- 0x4c35967f,
- 0x4c361694,
- 0x4c3696a5,
- 0x4c3716b3,
- 0x4c3796c1,
- 0x4c3816d3,
- 0x4c3896e3,
- 0x4c3916ed,
- 0x4c399705,
- 0x4c3a171d,
- 0x4c3a9730,
- 0x50322ce6,
- 0x5032acfb,
- 0x50332d0c,
- 0x5033ad1f,
- 0x50342d30,
- 0x5034ad43,
- 0x50352d52,
- 0x5035ad67,
- 0x50362d77,
- 0x5036ad86,
- 0x50372d97,
- 0x5037ada7,
- 0x50382db8,
- 0x5038adcb,
- 0x50392ddd,
- 0x5039adf3,
- 0x503a2e05,
- 0x503aae16,
- 0x503b2e27,
- 0x503bae38,
- 0x503c2e43,
- 0x503cae4f,
- 0x503d2e5a,
- 0x503dae65,
- 0x503e2e72,
- 0x503eae87,
- 0x503f2e95,
- 0x503faea9,
- 0x50402ebc,
- 0x5040aecd,
- 0x50412ee7,
- 0x5041aef6,
- 0x50422eff,
- 0x5042af0e,
- 0x50432f20,
- 0x5043af2c,
- 0x50442f34,
- 0x5044af47,
- 0x50452f58,
- 0x5045af6e,
- 0x50462f7a,
- 0x5046af8e,
- 0x50472f9c,
- 0x5047afb0,
- 0x50482fca,
- 0x5048afde,
- 0x50492ff4,
- 0x5049b00b,
- 0x504a301d,
- 0x504ab031,
- 0x504b3046,
- 0x504bb05d,
- 0x504c3071,
- 0x504cb07a,
- 0x504d3082,
- 0x504db091,
- 0x504e30a1,
- 0x68320fbe,
- 0x68328fcf,
- 0x68330fdf,
- 0x68338fed,
- 0x68340ffa,
- 0x6c320fad,
- 0x74320a06,
- 0x74328a18,
+ 0x4c32167b,
+ 0x4c32968a,
+ 0x4c331699,
+ 0x4c3396b2,
+ 0x4c3416cd,
+ 0x4c3496e9,
+ 0x4c3516fb,
+ 0x4c359709,
+ 0x4c36171e,
+ 0x4c36972f,
+ 0x4c37173d,
+ 0x4c37974b,
+ 0x4c38175d,
+ 0x4c38976d,
+ 0x4c391777,
+ 0x4c39978f,
+ 0x4c3a17a7,
+ 0x4c3a97ba,
+ 0x50322d70,
+ 0x5032ad85,
+ 0x50332d96,
+ 0x5033ada9,
+ 0x50342dba,
+ 0x5034adcd,
+ 0x50352ddc,
+ 0x5035adf1,
+ 0x50362e01,
+ 0x5036ae10,
+ 0x50372e21,
+ 0x5037ae31,
+ 0x50382e42,
+ 0x5038ae55,
+ 0x50392e67,
+ 0x5039ae7d,
+ 0x503a2e8f,
+ 0x503aaea0,
+ 0x503b2eb1,
+ 0x503baec2,
+ 0x503c2ecd,
+ 0x503caed9,
+ 0x503d2ee4,
+ 0x503daeef,
+ 0x503e2efc,
+ 0x503eaf11,
+ 0x503f2f1f,
+ 0x503faf33,
+ 0x50402f46,
+ 0x5040af57,
+ 0x50412f71,
+ 0x5041af80,
+ 0x50422f89,
+ 0x5042af98,
+ 0x50432faa,
+ 0x5043afb6,
+ 0x50442fbe,
+ 0x5044afd1,
+ 0x50452fe2,
+ 0x5045aff8,
+ 0x50463004,
+ 0x5046b018,
+ 0x50473026,
+ 0x5047b03a,
+ 0x50483054,
+ 0x5048b068,
+ 0x5049307e,
+ 0x5049b095,
+ 0x504a30a7,
+ 0x504ab0bb,
+ 0x504b30d0,
+ 0x504bb0e7,
+ 0x504c30fb,
+ 0x504cb104,
+ 0x504d310c,
+ 0x504db11b,
+ 0x504e312b,
+ 0x68321018,
+ 0x68329029,
+ 0x68331039,
+ 0x68339047,
+ 0x68341054,
+ 0x6c321007,
+ 0x74320a60,
+ 0x74328a72,
0x783206c9,
0x783286fc,
0x7833070e,
@@ -672,30 +674,33 @@
0x78350766,
0x78358778,
0x7836078c,
- 0x783687a0,
- 0x783707b2,
- 0x783787c4,
- 0x783807d6,
- 0x783887ed,
- 0x78390804,
- 0x7839881b,
- 0x783a0837,
- 0x783a8853,
- 0x783b086f,
- 0x783b8885,
- 0x783c089b,
- 0x783c88b1,
- 0x783d08ce,
- 0x783d88dd,
- 0x783e08ec,
- 0x783e88fb,
- 0x783f0917,
- 0x783f8925,
- 0x78400933,
- 0x78408941,
- 0x7841094e,
+ 0x783687fa,
+ 0x7837080c,
+ 0x7837881e,
+ 0x78380830,
+ 0x78388847,
+ 0x7839085e,
+ 0x78398875,
+ 0x783a0891,
+ 0x783a88ad,
+ 0x783b08c9,
+ 0x783b88df,
+ 0x783c08f5,
+ 0x783c890b,
+ 0x783d0928,
+ 0x783d8937,
+ 0x783e0946,
+ 0x783e8955,
+ 0x783f0971,
+ 0x783f897f,
+ 0x7840098d,
+ 0x7840899b,
+ 0x784109a8,
0x784186db,
- 0x80321418,
+ 0x784207a0,
+ 0x784287be,
+ 0x784307dc,
+ 0x803214a2,
};
const size_t kOpenSSLFunctionValuesLen = sizeof(kOpenSSLFunctionValues) / sizeof(kOpenSSLFunctionValues[0]);
@@ -822,6 +827,9 @@
"EVP_CipherInit_ex\0"
"EVP_DecryptFinal_ex\0"
"EVP_EncryptFinal_ex\0"
+ "aead_aes_ctr_hmac_sha256_init\0"
+ "aead_aes_ctr_hmac_sha256_open\0"
+ "aead_aes_ctr_hmac_sha256_seal\0"
"aead_aes_gcm_init\0"
"aead_aes_gcm_open\0"
"aead_aes_gcm_seal\0"
@@ -932,6 +940,7 @@
"EVP_DigestVerifyInitFromAlgorithm\0"
"EVP_PKEY_CTX_ctrl\0"
"EVP_PKEY_CTX_dup\0"
+ "EVP_PKEY_CTX_get0_rsa_oaep_label\0"
"EVP_PKEY_copy_parameters\0"
"EVP_PKEY_decrypt\0"
"EVP_PKEY_decrypt_init\0"
@@ -975,6 +984,7 @@
"pkey_ec_keygen\0"
"pkey_ec_paramgen\0"
"pkey_ec_sign\0"
+ "pkey_hmac_ctrl\0"
"pkey_rsa_ctrl\0"
"pkey_rsa_decrypt\0"
"pkey_rsa_encrypt\0"
diff --git a/third_party/harfbuzz-ng/NEWS b/third_party/harfbuzz-ng/NEWS
index 3ff8e4c..c4950e2 100644
--- a/third_party/harfbuzz-ng/NEWS
+++ b/third_party/harfbuzz-ng/NEWS
@@ -1,3 +1,64 @@
+Overview of changes leading to 0.9.40
+Friday, March 20, 2015
+=====================================
+
+- Another hb-coretext crasher fix. Ouch!
+- Happy Norouz!
+
+
+Overview of changes leading to 0.9.39
+Wednesday, March 4, 2015
+=====================================
+
+- Critical hb-coretext fixes.
+- Optimizations and refactoring; no functional change
+ expected.
+- Misc build fixes.
+
+
+Overview of changes leading to 0.9.38
+Friday, January 23, 2015
+=====================================
+
+- Fix minor out-of-bounds access in Indic shaper.
+- Change New Tai Lue shaping engine from South-East Asian to default,
+ reflecting change in Unicode encoding model.
+- Add hb-shape --font-size. Can take up to two numbers for separate
+ x / y size.
+- Fix CoreText and FreeType scale issues with negative scales.
+- Reject blobs larger than 2GB. This might break some icu-le-hb clients
+ that need security fixes. See:
+ http://www.icu-project.org/trac/ticket/11450
+- Avoid accessing font tables during face destruction, in casce rogue
+ clients released face data already.
+- Fix up gobject-introspection a bit. Python bindings kinda working.
+ See README.python.
+- Misc fixes.
+- API additions:
+ hb_ft_face_create_referenced()
+ hb_ft_font_create_referenced()
+
+
+Overview of changes leading to 0.9.37
+Wednesday, December 17, 2014
+=====================================
+
+- Fix out-of-bounds access in Context lookup format 3.
+- Indic: Allow ZWJ/ZWNJ before syllable modifiers.
+
+
+Overview of changes leading to 0.9.36
+Thursday, November 20, 2014
+=====================================
+
+- First time that three months went by without a release since
+ 0.9.2 was released on August 10, 2012!
+- Fix performance bug in hb_ot_collect_glyphs():
+ https://bugzilla.mozilla.org/show_bug.cgi?id=1090869
+- Add basic vertical-text support to hb-ot-font.
+- Misc build fixes.
+
+
Overview of changes leading to 0.9.35
Saturday, August 13, 2014
=====================================
@@ -80,6 +141,16 @@
EOT flag.
+Overview of changes leading to 0.9.33
+Tuesday, July 22, 2014
+=====================================
+
+- Turn off ARabic 'cswh' feature that was accidentally turned on.
+- Add HB_TAG_MAX_SIGNED.
+- Make hb_face_make_immutable() really make face immutable!
+- Windows build fixes.
+
+
Overview of changes leading to 0.9.32
Thursday, July 17, 2014
=====================================
diff --git a/third_party/harfbuzz-ng/README b/third_party/harfbuzz-ng/README
index 74e739d..d34bc74 100644
--- a/third_party/harfbuzz-ng/README
+++ b/third_party/harfbuzz-ng/README
@@ -1,3 +1,6 @@
+[](https://travis-ci.org/behdad/harfbuzz)
+[](https://coveralls.io/r/behdad/harfbuzz)
+
This is HarfBuzz, a text shaping library.
For bug reports, mailing list, and other information please visit:
diff --git a/third_party/harfbuzz-ng/README.chromium b/third_party/harfbuzz-ng/README.chromium
index 5c70ed1..d38a5d0 100644
--- a/third_party/harfbuzz-ng/README.chromium
+++ b/third_party/harfbuzz-ng/README.chromium
@@ -1,8 +1,8 @@
Name: harfbuzz-ng
Short Name: harfbuzz-ng
URL: http://harfbuzz.org
-Version: 0.9.38
-Date: 20150212
+Version: 0.9.40
+Date: 20150320
Security Critical: yes
License: MIT
License File: COPYING
diff --git a/third_party/harfbuzz-ng/src/hb-buffer-deserialize-text.hh b/third_party/harfbuzz-ng/src/hb-buffer-deserialize-text.hh
index 803efbd..7a46ab2 100644
--- a/third_party/harfbuzz-ng/src/hb-buffer-deserialize-text.hh
+++ b/third_party/harfbuzz-ng/src/hb-buffer-deserialize-text.hh
@@ -1,5 +1,5 @@
-#line 1 "../../src/hb-buffer-deserialize-text.rl"
+#line 1 "hb-buffer-deserialize-text.rl"
/*
* Copyright © 2013 Google, Inc.
*
@@ -32,7 +32,7 @@
#include "hb-private.hh"
-#line 36 "../../src/hb-buffer-deserialize-text.hh"
+#line 36 "hb-buffer-deserialize-text.hh"
static const unsigned char _deserialize_text_trans_keys[] = {
0u, 0u, 9u, 122u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u,
48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 9u, 124u, 9u, 124u, 0u, 0u,
@@ -312,7 +312,7 @@
static const int deserialize_text_en_main = 1;
-#line 91 "../../src/hb-buffer-deserialize-text.rl"
+#line 91 "hb-buffer-deserialize-text.rl"
static hb_bool_t
@@ -339,12 +339,12 @@
hb_glyph_info_t info;
hb_glyph_position_t pos;
-#line 343 "../../src/hb-buffer-deserialize-text.hh"
+#line 343 "hb-buffer-deserialize-text.hh"
{
cs = deserialize_text_start;
}
-#line 348 "../../src/hb-buffer-deserialize-text.hh"
+#line 348 "hb-buffer-deserialize-text.hh"
{
int _slen;
int _trans;
@@ -370,13 +370,13 @@
switch ( _deserialize_text_trans_actions[_trans] ) {
case 2:
-#line 51 "../../src/hb-buffer-deserialize-text.rl"
+#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 5:
-#line 55 "../../src/hb-buffer-deserialize-text.rl"
+#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
@@ -385,41 +385,41 @@
}
break;
case 10:
-#line 62 "../../src/hb-buffer-deserialize-text.rl"
+#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
break;
case 3:
-#line 63 "../../src/hb-buffer-deserialize-text.rl"
+#line 63 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_offset )) return false; }
break;
case 12:
-#line 64 "../../src/hb-buffer-deserialize-text.rl"
+#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
break;
case 7:
-#line 65 "../../src/hb-buffer-deserialize-text.rl"
+#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
break;
case 1:
-#line 38 "../../src/hb-buffer-deserialize-text.rl"
+#line 38 "hb-buffer-deserialize-text.rl"
{
memset (&info, 0, sizeof (info));
memset (&pos , 0, sizeof (pos ));
}
-#line 51 "../../src/hb-buffer-deserialize-text.rl"
+#line 51 "hb-buffer-deserialize-text.rl"
{
tok = p;
}
break;
case 4:
-#line 55 "../../src/hb-buffer-deserialize-text.rl"
+#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -429,9 +429,9 @@
}
break;
case 9:
-#line 62 "../../src/hb-buffer-deserialize-text.rl"
+#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -441,9 +441,9 @@
}
break;
case 11:
-#line 64 "../../src/hb-buffer-deserialize-text.rl"
+#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -453,9 +453,9 @@
}
break;
case 6:
-#line 65 "../../src/hb-buffer-deserialize-text.rl"
+#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -465,9 +465,9 @@
}
break;
case 8:
-#line 66 "../../src/hb-buffer-deserialize-text.rl"
+#line 66 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -476,7 +476,7 @@
*end_ptr = p;
}
break;
-#line 480 "../../src/hb-buffer-deserialize-text.hh"
+#line 480 "hb-buffer-deserialize-text.hh"
}
_again:
@@ -489,14 +489,14 @@
{
switch ( _deserialize_text_eof_actions[cs] ) {
case 4:
-#line 55 "../../src/hb-buffer-deserialize-text.rl"
+#line 55 "hb-buffer-deserialize-text.rl"
{
if (!hb_font_glyph_from_string (font,
tok, p - tok,
&info.codepoint))
return false;
}
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -506,9 +506,9 @@
}
break;
case 9:
-#line 62 "../../src/hb-buffer-deserialize-text.rl"
+#line 62 "hb-buffer-deserialize-text.rl"
{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -518,9 +518,9 @@
}
break;
case 11:
-#line 64 "../../src/hb-buffer-deserialize-text.rl"
+#line 64 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_offset )) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -530,9 +530,9 @@
}
break;
case 6:
-#line 65 "../../src/hb-buffer-deserialize-text.rl"
+#line 65 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.x_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -542,9 +542,9 @@
}
break;
case 8:
-#line 66 "../../src/hb-buffer-deserialize-text.rl"
+#line 66 "hb-buffer-deserialize-text.rl"
{ if (!parse_int (tok, p, &pos.y_advance)) return false; }
-#line 43 "../../src/hb-buffer-deserialize-text.rl"
+#line 43 "hb-buffer-deserialize-text.rl"
{
buffer->add_info (info);
if (buffer->in_error)
@@ -553,14 +553,14 @@
*end_ptr = p;
}
break;
-#line 557 "../../src/hb-buffer-deserialize-text.hh"
+#line 557 "hb-buffer-deserialize-text.hh"
}
}
_out: {}
}
-#line 119 "../../src/hb-buffer-deserialize-text.rl"
+#line 119 "hb-buffer-deserialize-text.rl"
*end_ptr = p;
diff --git a/third_party/harfbuzz-ng/src/hb-buffer.cc b/third_party/harfbuzz-ng/src/hb-buffer.cc
index 942177c..b9fe263 100644
--- a/third_party/harfbuzz-ng/src/hb-buffer.cc
+++ b/third_party/harfbuzz-ng/src/hb-buffer.cc
@@ -443,7 +443,7 @@
{
unsigned int i, j;
- if (start == end - 1)
+ if (end - start < 2)
return;
for (i = start, j = end - 1; i < j; i++, j--) {
diff --git a/third_party/harfbuzz-ng/src/hb-ft.cc b/third_party/harfbuzz-ng/src/hb-ft.cc
index f57f566..322f93a 100644
--- a/third_party/harfbuzz-ng/src/hb-ft.cc
+++ b/third_party/harfbuzz-ng/src/hb-ft.cc
@@ -118,6 +118,9 @@
if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v)))
return 0;
+ if (font->y_scale < 0)
+ v = -v;
+
/* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
* have a Y growing upward. Hence the extra negation. */
return (-v + (1<<9)) >> 10;
@@ -154,6 +157,11 @@
*x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX;
*y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY);
+ if (font->x_scale < 0)
+ *x = -*x;
+ if (font->y_scale < 0)
+ *y = -*y;
+
return true;
}
diff --git a/third_party/harfbuzz-ng/src/hb-open-file-private.hh b/third_party/harfbuzz-ng/src/hb-open-file-private.hh
index 7500c32..178bc7c 100644
--- a/third_party/harfbuzz-ng/src/hb-open-file-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-open-file-private.hh
@@ -53,7 +53,8 @@
typedef struct TableRecord
{
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -102,7 +103,8 @@
}
public:
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && c->check_array (tables, TableRecord::static_size, numTables));
}
@@ -130,7 +132,8 @@
inline unsigned int get_face_count (void) const { return table.len; }
inline const OpenTypeFontFace& get_face (unsigned int i) const { return this+table[i]; }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (table.sanitize (c, this));
}
@@ -169,7 +172,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!u.header.version.sanitize (c))) return TRACE_RETURN (false);
switch (u.header.version.major) {
@@ -233,7 +237,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!u.tag.sanitize (c))) return TRACE_RETURN (false);
switch (u.tag) {
diff --git a/third_party/harfbuzz-ng/src/hb-open-type-private.hh b/third_party/harfbuzz-ng/src/hb-open-type-private.hh
index 477d9e2..75a0f56 100644
--- a/third_party/harfbuzz-ng/src/hb-open-type-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-open-type-private.hh
@@ -179,10 +179,13 @@
inline const char *get_name (void) { return "SANITIZE"; }
static const unsigned int max_debug_depth = HB_DEBUG_SANITIZE;
typedef bool return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format)
+ { return format->sanitize (this); }
template <typename T>
inline return_t dispatch (const T &obj) { return obj.sanitize (this); }
static return_t default_return_value (void) { return true; }
- bool stop_sublookup_iteration (const return_t r HB_UNUSED) const { return false; }
+ bool stop_sublookup_iteration (const return_t r) const { return !r; }
inline void init (hb_blob_t *b)
{
@@ -270,9 +273,9 @@
}
template <typename Type, typename ValueType>
- inline bool try_set (Type *obj, const ValueType &v) {
+ inline bool try_set (const Type *obj, const ValueType &v) {
if (this->may_edit (obj, obj->static_size)) {
- obj->set (v);
+ const_cast<Type *> (obj)->set (v);
return true;
}
return false;
@@ -546,12 +549,6 @@
return (v[0] << 8)
+ (v[1] );
}
- inline bool operator == (const BEInt<Type, 2>& o) const
- {
- return v[0] == o.v[0]
- && v[1] == o.v[1];
- }
- inline bool operator != (const BEInt<Type, 2>& o) const { return !(*this == o); }
private: uint8_t v[2];
};
template <typename Type>
@@ -570,13 +567,6 @@
+ (v[1] << 8)
+ (v[2] );
}
- inline bool operator == (const BEInt<Type, 3>& o) const
- {
- return v[0] == o.v[0]
- && v[1] == o.v[1]
- && v[2] == o.v[2];
- }
- inline bool operator != (const BEInt<Type, 3>& o) const { return !(*this == o); }
private: uint8_t v[3];
};
template <typename Type>
@@ -597,14 +587,6 @@
+ (v[2] << 8)
+ (v[3] );
}
- inline bool operator == (const BEInt<Type, 4>& o) const
- {
- return v[0] == o.v[0]
- && v[1] == o.v[1]
- && v[2] == o.v[2]
- && v[3] == o.v[3];
- }
- inline bool operator != (const BEInt<Type, 4>& o) const { return !(*this == o); }
private: uint8_t v[4];
};
@@ -614,12 +596,19 @@
{
inline void set (Type i) { v.set (i); }
inline operator Type(void) const { return v; }
- inline bool operator == (const IntType<Type,Size> &o) const { return v == o.v; }
- inline bool operator != (const IntType<Type,Size> &o) const { return v != o.v; }
+ inline bool operator == (const IntType<Type,Size> &o) const { return (Type) v == (Type) o.v; }
+ inline bool operator != (const IntType<Type,Size> &o) const { return !(*this == o); }
static inline int cmp (const IntType<Type,Size> *a, const IntType<Type,Size> *b) { return b->cmp (*a); }
- inline int cmp (IntType<Type,Size> va) const { Type a = va; Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
- inline int cmp (Type a) const { Type b = v; return a < b ? -1 : a == b ? 0 : +1; }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline int cmp (Type a) const
+ {
+ Type b = v;
+ if (sizeof (Type) < sizeof (int))
+ return (int) a - (int) b;
+ else
+ return a < b ? -1 : a == b ? 0 : +1;
+ }
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (likely (c->check_struct (this)));
}
@@ -646,7 +635,8 @@
* 1904. The value is represented as a signed 64-bit integer. */
struct LONGDATETIME
{
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (likely (c->check_struct (this)));
}
@@ -670,7 +660,10 @@
DEFINE_NULL_DATA (Tag, " ");
/* Glyph index number, same as uint16 (length = 16 bits) */
-typedef USHORT GlyphID;
+struct GlyphID : USHORT {
+ static inline int cmp (const GlyphID *a, const GlyphID *b) { return b->USHORT::cmp (*a); }
+ inline int cmp (hb_codepoint_t a) const { return (int) a - (int) *this; }
+};
/* Script/language-system/feature index */
struct Index : USHORT {
@@ -719,7 +712,8 @@
{
inline uint32_t to_int (void) const { return (major << 16) + minor; }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -747,33 +741,35 @@
return StructAtOffset<Type> (base, offset);
}
- inline Type& serialize (hb_serialize_context_t *c, void *base)
+ inline Type& serialize (hb_serialize_context_t *c, const void *base)
{
Type *t = c->start_embed<Type> ();
this->set ((char *) t - (char *) base); /* TODO(serialize) Overflow? */
return *t;
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
unsigned int offset = *this;
if (unlikely (!offset)) return TRACE_RETURN (true);
- Type &obj = StructAtOffset<Type> (base, offset);
+ const Type &obj = StructAtOffset<Type> (base, offset);
return TRACE_RETURN (likely (obj.sanitize (c)) || neuter (c));
}
template <typename T>
- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
unsigned int offset = *this;
if (unlikely (!offset)) return TRACE_RETURN (true);
- Type &obj = StructAtOffset<Type> (base, offset);
+ const Type &obj = StructAtOffset<Type> (base, offset);
return TRACE_RETURN (likely (obj.sanitize (c, user_data)) || neuter (c));
}
/* Set the offset to Null */
- inline bool neuter (hb_sanitize_context_t *c) {
+ inline bool neuter (hb_sanitize_context_t *c) const {
return c->try_set (this, 0);
}
DEFINE_SIZE_STATIC (sizeof(OffsetType));
@@ -838,7 +834,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
@@ -853,7 +850,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
unsigned int count = len;
@@ -863,7 +861,8 @@
return TRACE_RETURN (true);
}
template <typename T>
- inline bool sanitize (hb_sanitize_context_t *c, void *base, T user_data) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base, T user_data) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
unsigned int count = len;
@@ -884,7 +883,8 @@
}
private:
- inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && c->check_array (this, Type::static_size, len));
}
@@ -910,12 +910,14 @@
return this+this->array[i];
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this));
}
template <typename T>
- inline bool sanitize (hb_sanitize_context_t *c, T user_data) {
+ inline bool sanitize (hb_sanitize_context_t *c, T user_data) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (OffsetArrayOf<Type>::sanitize (c, this, user_data));
}
@@ -949,12 +951,14 @@
return TRACE_RETURN (true);
}
- inline bool sanitize_shallow (hb_sanitize_context_t *c) {
+ inline bool sanitize_shallow (hb_sanitize_context_t *c) const
+ {
return c->check_struct (this)
&& c->check_array (this, Type::static_size, len);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!sanitize_shallow (c))) return TRACE_RETURN (false);
diff --git a/third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh b/third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh
index d531411..0482312 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-cmap-table.hh
@@ -51,7 +51,8 @@
return true;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -125,7 +126,7 @@
return true;
}
- inline bool sanitize (hb_sanitize_context_t *c)
+ inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this)))
@@ -183,7 +184,8 @@
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -210,7 +212,8 @@
return true;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && glyphIdArray.sanitize (c));
}
@@ -242,7 +245,8 @@
return true;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && groups.sanitize (c));
}
@@ -288,7 +292,8 @@
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -309,7 +314,8 @@
return unicodeValue.cmp (codepoint);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -348,7 +354,8 @@
return varSelector.cmp (variation_selector);
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
defaultUVS.sanitize (c, base) &&
@@ -373,7 +380,8 @@
return record[record.bsearch(variation_selector)].get_glyph (codepoint, glyph, this);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
record.sanitize (c, this));
@@ -418,7 +426,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
@@ -461,7 +470,8 @@
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
subtable.sanitize (c, base));
@@ -496,7 +506,8 @@
return &(this+encodingRecord[result].subtable);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
likely (version == 0) &&
diff --git a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
index ec4e8c9..268f133 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-head-table.hh
@@ -45,13 +45,15 @@
{
static const hb_tag_t tableTag = HB_OT_TAG_head;
- inline unsigned int get_upem (void) const {
+ inline unsigned int get_upem (void) const
+ {
unsigned int upem = unitsPerEm;
/* If no valid head table found, assume 1000, which matches typical Type1 usage. */
return 16 <= upem && upem <= 16384 ? upem : 1000;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
index edc0e29..992fe55 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-hhea-table.hh
@@ -49,7 +49,8 @@
static const hb_tag_t hheaTag = HB_OT_TAG_hhea;
static const hb_tag_t vheaTag = HB_OT_TAG_vhea;
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && likely (version.major == 1));
}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh
index 317854c..a0e3855 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-hmtx-table.hh
@@ -57,7 +57,8 @@
static const hb_tag_t hmtxTag = HB_OT_TAG_hmtx;
static const hb_tag_t vmtxTag = HB_OT_TAG_vmtx;
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
/* We don't check for anything specific here. The users of the
* struct do all the hard work... */
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh
index abd063c..3db7f57 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-common-private.hh
@@ -37,6 +37,12 @@
namespace OT {
+#define TRACE_DISPATCH(this, format) \
+ hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
+ (&c->debug_depth, c->get_name (), this, HB_FUNC, \
+ "format %d", (int) format);
+
+
#define NOT_COVERED ((unsigned int) -1)
#define MAX_NESTING_LEVEL 8
#define MAX_CONTEXT_LENGTH 64
@@ -63,9 +69,10 @@
struct sanitize_closure_t {
hb_tag_t tag;
- void *list_base;
+ const void *list_base;
};
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
const sanitize_closure_t closure = {tag, base};
return TRACE_RETURN (c->check_struct (this) && offset.sanitize (c, base, &closure));
@@ -121,7 +128,8 @@
inline const Type& operator [] (unsigned int i) const
{ return this+RecordArrayOf<Type>::operator [](i).offset; }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (RecordArrayOf<Type>::sanitize (c, this));
}
@@ -134,7 +142,8 @@
return g < start ? -1 : g <= end ? 0 : +1 ;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -199,7 +208,8 @@
}
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<LangSys>::sanitize_closure_t * = NULL) {
+ const Record<LangSys>::sanitize_closure_t * = NULL) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && featureIndex.sanitize (c));
}
@@ -238,7 +248,8 @@
inline const LangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<Script>::sanitize_closure_t * = NULL) {
+ const Record<Script>::sanitize_closure_t * = NULL) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (defaultLangSys.sanitize (c, this) && langSys.sanitize (c, this));
}
@@ -260,7 +271,8 @@
/* http://www.microsoft.com/typography/otspec/features_pt.htm#size */
struct FeatureParamsSize
{
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!c->check_struct (this))) return TRACE_RETURN (false);
@@ -371,7 +383,8 @@
/* http://www.microsoft.com/typography/otspec/features_pt.htm#ssxx */
struct FeatureParamsStylisticSet
{
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
/* Right now minorVersion is at zero. Which means, any table supports
* the uiNameID field. */
@@ -404,7 +417,8 @@
/* http://www.microsoft.com/typography/otspec/features_ae.htm#cv01-cv99 */
struct FeatureParamsCharacterVariants
{
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
characters.sanitize (c));
@@ -444,7 +458,8 @@
struct FeatureParams
{
- inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) {
+ inline bool sanitize (hb_sanitize_context_t *c, hb_tag_t tag) const
+ {
TRACE_SANITIZE (this);
if (tag == HB_TAG ('s','i','z','e'))
return TRACE_RETURN (u.size.sanitize (c));
@@ -486,7 +501,8 @@
{ return this+featureParams; }
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<Feature>::sanitize_closure_t *closure) {
+ const Record<Feature>::sanitize_closure_t *closure) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!(c->check_struct (this) && lookupIndex.sanitize (c))))
return TRACE_RETURN (false);
@@ -561,6 +577,17 @@
{
inline unsigned int get_subtable_count (void) const { return subTable.len; }
+ template <typename SubTableType>
+ inline const SubTableType& get_subtable (unsigned int i) const
+ { return this+CastR<OffsetArrayOf<SubTableType> > (subTable)[i]; }
+
+ template <typename SubTableType>
+ inline const OffsetArrayOf<SubTableType>& get_subtables (void) const
+ { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+ template <typename SubTableType>
+ inline OffsetArrayOf<SubTableType>& get_subtables (void)
+ { return CastR<OffsetArrayOf<SubTableType> > (subTable); }
+
inline unsigned int get_type (void) const { return lookupType; }
/* lookup_props is a 32-bit integer where the lower 16-bit is LookupFlag and
@@ -577,6 +604,20 @@
return flag;
}
+ template <typename SubTableType, typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ unsigned int lookup_type = get_type ();
+ TRACE_DISPATCH (this, lookup_type);
+ unsigned int count = get_subtable_count ();
+ for (unsigned int i = 0; i < count; i++) {
+ typename context_t::return_t r = get_subtable<SubTableType> (i).dispatch (c, lookup_type);
+ if (c->stop_sublookup_iteration (r))
+ return TRACE_RETURN (r);
+ }
+ return TRACE_RETURN (c->default_return_value ());
+ }
+
inline bool serialize (hb_serialize_context_t *c,
unsigned int lookup_type,
uint32_t lookup_props,
@@ -595,18 +636,20 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
/* Real sanitize of the subtables is done by GSUB/GPOS/... */
if (!(c->check_struct (this) && subTable.sanitize (c))) return TRACE_RETURN (false);
if (lookupFlag & LookupFlag::UseMarkFilteringSet)
{
- USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
+ const USHORT &markFilteringSet = StructAfter<USHORT> (subTable);
if (!markFilteringSet.sanitize (c)) return TRACE_RETURN (false);
}
return TRACE_RETURN (true);
}
+ private:
USHORT lookupType; /* Different enumerations for GSUB and GPOS */
USHORT lookupFlag; /* Lookup qualifiers */
ArrayOf<Offset<> >
@@ -651,7 +694,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (glyphArray.sanitize (c));
}
@@ -737,7 +781,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (rangeRecord.sanitize (c));
}
@@ -832,7 +877,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
@@ -938,12 +984,14 @@
private:
inline unsigned int get_class (hb_codepoint_t glyph_id) const
{
- if (unlikely ((unsigned int) (glyph_id - startGlyph) < classValue.len))
- return classValue[glyph_id - startGlyph];
+ unsigned int i = (unsigned int) (glyph_id - startGlyph);
+ if (unlikely (i < classValue.len))
+ return classValue[i];
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && classValue.sanitize (c));
}
@@ -994,12 +1042,13 @@
inline unsigned int get_class (hb_codepoint_t glyph_id) const
{
int i = rangeRecord.bsearch (glyph_id);
- if (i != -1)
+ if (unlikely (i != -1))
return rangeRecord[i].value;
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (rangeRecord.sanitize (c));
}
@@ -1056,7 +1105,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
@@ -1148,7 +1198,8 @@
return USHORT::static_size * (4 + ((endSize - startSize) >> (4 - f)));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && c->check_range (this, this->get_size ()));
}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
index 84a5e79..7a6c04d 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gdef-table.hh
@@ -71,7 +71,8 @@
return points.len;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
}
@@ -101,7 +102,8 @@
return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -127,7 +129,8 @@
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -150,7 +153,8 @@
font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && deviceTable.sanitize (c, this));
}
@@ -178,7 +182,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
@@ -219,7 +224,8 @@
return carets.len;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (carets.sanitize (c, this));
}
@@ -253,7 +259,8 @@
return lig_glyph.get_lig_carets (font, direction, glyph_id, start_offset, caret_count, caret_array);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
}
@@ -275,7 +282,8 @@
inline bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this));
}
@@ -299,7 +307,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
@@ -364,7 +373,8 @@
inline bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
{ return version.to_int () >= 0x00010002u && (this+markGlyphSetsDef[0]).covers (set_index, glyph_id); }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (version.sanitize (c) &&
likely (version.major == 1) &&
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
index f7fef52..d88f787 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gpos-table.hh
@@ -146,7 +146,8 @@
}
private:
- inline bool sanitize_value_devices (hb_sanitize_context_t *c, void *base, Value *values) {
+ inline bool sanitize_value_devices (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ {
unsigned int format = *this;
if (format & xPlacement) values++;
@@ -177,12 +178,14 @@
return (format & devices) != 0;
}
- inline bool sanitize_value (hb_sanitize_context_t *c, void *base, Value *values) {
+ inline bool sanitize_value (hb_sanitize_context_t *c, const void *base, const Value *values) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_range (values, get_size ()) && (!has_device () || sanitize_value_devices (c, base, values)));
}
- inline bool sanitize_values (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count) {
+ inline bool sanitize_values (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count) const
+ {
TRACE_SANITIZE (this);
unsigned int len = get_len ();
@@ -200,7 +203,8 @@
}
/* Just sanitize referenced Device tables. Doesn't check the values themselves. */
- inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, void *base, Value *values, unsigned int count, unsigned int stride) {
+ inline bool sanitize_values_stride_unsafe (hb_sanitize_context_t *c, const void *base, const Value *values, unsigned int count, unsigned int stride) const
+ {
TRACE_SANITIZE (this);
if (!has_device ()) return TRACE_RETURN (true);
@@ -225,7 +229,8 @@
*y = font->em_scale_y (yCoordinate);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -254,7 +259,8 @@
*y = ret && y_ppem ? cy : font->em_scale_y (yCoordinate);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -282,7 +288,8 @@
*y += (this+yDeviceTable).get_x_delta (font);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && xDeviceTable.sanitize (c, this) && yDeviceTable.sanitize (c, this));
}
@@ -317,7 +324,8 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!u.format.sanitize (c)) return TRACE_RETURN (false);
switch (u.format) {
@@ -349,7 +357,8 @@
return this+matrixZ[row * cols + col];
}
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) {
+ inline bool sanitize (hb_sanitize_context_t *c, unsigned int cols) const
+ {
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return TRACE_RETURN (false);
if (unlikely (rows > 0 && cols >= ((unsigned int) -1) / rows)) return TRACE_RETURN (false);
@@ -374,7 +383,8 @@
{
friend struct MarkArray;
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && markAnchor.sanitize (c, base));
}
@@ -421,7 +431,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (ArrayOf<MarkRecord>::sanitize (c, this));
}
@@ -457,9 +468,12 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
- return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_value (c, this, values));
+ return TRACE_RETURN (c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && valueFormat.sanitize_value (c, this, values));
}
protected:
@@ -506,9 +520,12 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
- return TRACE_RETURN (c->check_struct (this) && coverage.sanitize (c, this) && valueFormat.sanitize_values (c, this, values, valueCount));
+ return TRACE_RETURN (c->check_struct (this)
+ && coverage.sanitize (c, this)
+ && valueFormat.sanitize_values (c, this, values, valueCount));
}
protected:
@@ -531,6 +548,7 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
case 2: return TRACE_RETURN (c->dispatch (u.format2));
@@ -538,16 +556,6 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -636,19 +644,20 @@
}
struct sanitize_closure_t {
- void *base;
- ValueFormat *valueFormats;
+ const void *base;
+ const ValueFormat *valueFormats;
unsigned int len1; /* valueFormats[0].get_len() */
unsigned int stride; /* 1 + len1 + len2 */
};
- inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) {
+ inline bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
+ {
TRACE_SANITIZE (this);
if (!(c->check_struct (this)
&& c->check_array (arrayZ, USHORT::static_size * closure->stride, len))) return TRACE_RETURN (false);
unsigned int count = len;
- PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
+ const PairValueRecord *record = CastP<PairValueRecord> (arrayZ);
return TRACE_RETURN (closure->valueFormats[0].sanitize_values_stride_unsafe (c, closure->base, &record->values[0], count, closure->stride)
&& closure->valueFormats[1].sanitize_values_stride_unsafe (c, closure->base, &record->values[closure->len1], count, closure->stride));
}
@@ -681,18 +690,18 @@
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return TRACE_RETURN (false);
return TRACE_RETURN ((this+pairSet[index]).apply (c, &valueFormat1, skippy_iter.idx));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
unsigned int len1 = valueFormat1.get_len ();
@@ -752,12 +761,11 @@
{
TRACE_APPLY (this);
hb_buffer_t *buffer = c->buffer;
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
unsigned int index = (this+coverage).get_coverage (buffer->cur().codepoint);
if (likely (index == NOT_COVERED)) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return TRACE_RETURN (false);
unsigned int len1 = valueFormat1.get_len ();
@@ -781,7 +789,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!(c->check_struct (this)
&& coverage.sanitize (c, this)
@@ -834,6 +843,7 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
case 2: return TRACE_RETURN (c->dispatch (u.format2));
@@ -841,16 +851,6 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -864,7 +864,8 @@
{
friend struct CursivePosFormat1;
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (entryAnchor.sanitize (c, base) && exitAnchor.sanitize (c, base));
}
@@ -903,12 +904,11 @@
/* We don't handle mark glyphs here. */
if (unlikely (_hb_glyph_info_is_mark (&buffer->cur()))) return TRACE_RETURN (false);
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, 1);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
-
const EntryExitRecord &this_record = entryExitRecord[(this+coverage).get_coverage (buffer->cur().codepoint)];
if (!this_record.exitAnchor) return TRACE_RETURN (false);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
if (!skippy_iter.next ()) return TRACE_RETURN (false);
const EntryExitRecord &next_record = entryExitRecord[(this+coverage).get_coverage (buffer->info[skippy_iter.idx].codepoint)];
@@ -978,7 +978,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && entryExitRecord.sanitize (c, this));
}
@@ -1001,21 +1002,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -1051,7 +1044,8 @@
if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a non-mark glyph */
- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
do {
if (!skippy_iter.prev ()) return TRACE_RETURN (false);
@@ -1069,7 +1063,8 @@
return TRACE_RETURN ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && baseCoverage.sanitize (c, this) &&
markArray.sanitize (c, this) && baseArray.sanitize (c, this, (unsigned int) classCount));
@@ -1100,21 +1095,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -1155,7 +1142,8 @@
if (likely (mark_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a non-mark glyph */
- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
if (!skippy_iter.prev ()) return TRACE_RETURN (false);
@@ -1189,7 +1177,8 @@
return TRACE_RETURN ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && markCoverage.sanitize (c, this) && ligatureCoverage.sanitize (c, this) &&
markArray.sanitize (c, this) && ligatureArray.sanitize (c, this, (unsigned int) classCount));
@@ -1221,21 +1210,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -1271,7 +1252,8 @@
if (likely (mark1_index == NOT_COVERED)) return TRACE_RETURN (false);
/* now we search backwards for a suitable mark glyph until a non-mark glyph */
- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, buffer->idx, 1);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, 1);
skippy_iter.set_lookup_props (c->lookup_props & ~LookupFlag::IgnoreFlags);
if (!skippy_iter.prev ()) return TRACE_RETURN (false);
@@ -1306,7 +1288,8 @@
return TRACE_RETURN ((this+mark1Array).apply (c, mark1_index, mark2_index, this+mark2Array, classCount, j));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) && mark1Coverage.sanitize (c, this) &&
mark2Coverage.sanitize (c, this) && mark1Array.sanitize (c, this)
@@ -1340,21 +1323,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -1399,6 +1374,8 @@
inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
{
TRACE_DISPATCH (this, lookup_type);
+ /* The sub_format passed to may_dispatch is unnecessary but harmless. */
+ if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
switch (lookup_type) {
case Single: return TRACE_RETURN (u.single.dispatch (c));
case Pair: return TRACE_RETURN (u.pair.dispatch (c));
@@ -1413,29 +1390,9 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
- TRACE_SANITIZE (this);
- if (!u.header.sub_format.sanitize (c))
- return TRACE_RETURN (false);
- switch (lookup_type) {
- case Single: return TRACE_RETURN (u.single.sanitize (c));
- case Pair: return TRACE_RETURN (u.pair.sanitize (c));
- case Cursive: return TRACE_RETURN (u.cursive.sanitize (c));
- case MarkBase: return TRACE_RETURN (u.markBase.sanitize (c));
- case MarkLig: return TRACE_RETURN (u.markLig.sanitize (c));
- case MarkMark: return TRACE_RETURN (u.markMark.sanitize (c));
- case Context: return TRACE_RETURN (u.context.sanitize (c));
- case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
- case Extension: return TRACE_RETURN (u.extension.sanitize (c));
- default: return TRACE_RETURN (true);
- }
- }
-
protected:
union {
- struct {
- USHORT sub_format;
- } header;
+ USHORT sub_format;
SinglePos single;
PairPos pair;
CursivePos cursive;
@@ -1447,48 +1404,37 @@
ExtensionPos extension;
} u;
public:
- DEFINE_SIZE_UNION (2, header.sub_format);
+ DEFINE_SIZE_UNION (2, sub_format);
};
struct PosLookup : Lookup
{
inline const PosLookupSubTable& get_subtable (unsigned int i) const
- { return this+CastR<OffsetArrayOf<PosLookupSubTable> > (subTable)[i]; }
+ { return Lookup::get_subtable<PosLookupSubTable> (i); }
inline bool is_reverse (void) const
{
return false;
}
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ return TRACE_RETURN (dispatch (c));
+ }
+
inline hb_collect_glyphs_context_t::return_t collect_glyphs (hb_collect_glyphs_context_t *c) const
{
TRACE_COLLECT_GLYPHS (this);
- c->set_recurse_func (NULL);
return TRACE_RETURN (dispatch (c));
}
template <typename set_t>
inline void add_coverage (set_t *glyphs) const
{
- hb_get_coverage_context_t c;
- const Coverage *last = NULL;
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++) {
- const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
- if (coverage != last) {
- coverage->add_coverage (glyphs);
- last = coverage;
- }
- }
- }
-
- inline bool apply_once (hb_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
- return TRACE_RETURN (false);
- return TRACE_RETURN (dispatch (c));
+ hb_add_coverage_context_t<set_t> c (glyphs);
+ dispatch (&c);
}
static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
@@ -1498,23 +1444,14 @@
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
- {
- unsigned int lookup_type = get_type ();
- TRACE_DISPATCH (this, lookup_type);
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++) {
- typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
- if (c->stop_sublookup_iteration (r))
- return TRACE_RETURN (r);
- }
- return TRACE_RETURN (c->default_return_value ());
- }
+ { return Lookup::dispatch<PosLookupSubTable> (c); }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
- OffsetArrayOf<PosLookupSubTable> &list = CastR<OffsetArrayOf<PosLookupSubTable> > (subTable);
- return TRACE_RETURN (list.sanitize (c, this, get_type ()));
+ const OffsetArrayOf<PosLookupSubTable> &list = get_subtables<PosLookupSubTable> ();
+ return TRACE_RETURN (dispatch (c));
}
};
@@ -1534,10 +1471,11 @@
static inline void position_start (hb_font_t *font, hb_buffer_t *buffer);
static inline void position_finish (hb_font_t *font, hb_buffer_t *buffer);
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
- OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
+ const OffsetTo<PosLookupList> &list = CastR<OffsetTo<PosLookupList> > (lookupList);
return TRACE_RETURN (list.sanitize (c, this));
}
public:
@@ -1632,8 +1570,8 @@
const PosLookup &l = gpos.get_lookup (lookup_index);
unsigned int saved_lookup_props = c->lookup_props;
c->set_lookup (l);
- bool ret = l.apply_once (c);
- c->lookup_props = saved_lookup_props;
+ bool ret = l.dispatch (c);
+ c->set_lookup_props (saved_lookup_props);
return ret;
}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
index 5d67be0..ebe4c9e 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsub-table.hh
@@ -97,7 +97,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
}
@@ -173,7 +174,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && substitute.sanitize (c));
}
@@ -223,6 +225,7 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
case 2: return TRACE_RETURN (c->dispatch (u.format2));
@@ -230,16 +233,6 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -312,7 +305,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (substitute.sanitize (c));
}
@@ -384,7 +378,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && sequence.sanitize (c, this));
}
@@ -423,21 +418,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -535,7 +522,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && alternateSet.sanitize (c, this));
}
@@ -574,21 +562,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -686,7 +666,8 @@
}
public:
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (ligGlyph.sanitize (c) && component.sanitize (c));
}
@@ -764,7 +745,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (ligature.sanitize (c, this));
}
@@ -848,7 +830,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ligatureSet.sanitize (c, this));
}
@@ -890,21 +873,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -1017,14 +992,15 @@
return TRACE_RETURN (false);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
return TRACE_RETURN (false);
- OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
if (!lookahead.sanitize (c, this))
return TRACE_RETURN (false);
- ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
+ const ArrayOf<GlyphID> &substitute = StructAfter<ArrayOf<GlyphID> > (lookahead);
return TRACE_RETURN (substitute.sanitize (c));
}
@@ -1054,21 +1030,13 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -1101,6 +1069,8 @@
inline typename context_t::return_t dispatch (context_t *c, unsigned int lookup_type) const
{
TRACE_DISPATCH (this, lookup_type);
+ /* The sub_format passed to may_dispatch is unnecessary but harmless. */
+ if (unlikely (!c->may_dispatch (this, &u.sub_format))) TRACE_RETURN (c->default_return_value ());
switch (lookup_type) {
case Single: return TRACE_RETURN (u.single.dispatch (c));
case Multiple: return TRACE_RETURN (u.multiple.dispatch (c));
@@ -1114,28 +1084,9 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c, unsigned int lookup_type) {
- TRACE_SANITIZE (this);
- if (!u.header.sub_format.sanitize (c))
- return TRACE_RETURN (false);
- switch (lookup_type) {
- case Single: return TRACE_RETURN (u.single.sanitize (c));
- case Multiple: return TRACE_RETURN (u.multiple.sanitize (c));
- case Alternate: return TRACE_RETURN (u.alternate.sanitize (c));
- case Ligature: return TRACE_RETURN (u.ligature.sanitize (c));
- case Context: return TRACE_RETURN (u.context.sanitize (c));
- case ChainContext: return TRACE_RETURN (u.chainContext.sanitize (c));
- case Extension: return TRACE_RETURN (u.extension.sanitize (c));
- case ReverseChainSingle: return TRACE_RETURN (u.reverseChainContextSingle.sanitize (c));
- default: return TRACE_RETURN (true);
- }
- }
-
protected:
union {
- struct {
- USHORT sub_format;
- } header;
+ USHORT sub_format;
SingleSubst single;
MultipleSubst multiple;
AlternateSubst alternate;
@@ -1146,14 +1097,14 @@
ReverseChainSingleSubst reverseChainContextSingle;
} u;
public:
- DEFINE_SIZE_UNION (2, header.sub_format);
+ DEFINE_SIZE_UNION (2, sub_format);
};
struct SubstLookup : Lookup
{
inline const SubstLookupSubTable& get_subtable (unsigned int i) const
- { return this+CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i]; }
+ { return Lookup::get_subtable<SubstLookupSubTable> (i); }
inline static bool lookup_type_is_reverse (unsigned int lookup_type)
{ return lookup_type == SubstLookupSubTable::ReverseChainSingle; }
@@ -1166,6 +1117,12 @@
return lookup_type_is_reverse (type);
}
+ inline bool apply (hb_apply_context_t *c) const
+ {
+ TRACE_APPLY (this);
+ return TRACE_RETURN (dispatch (c));
+ }
+
inline hb_closure_context_t::return_t closure (hb_closure_context_t *c) const
{
TRACE_CLOSURE (this);
@@ -1183,39 +1140,24 @@
template <typename set_t>
inline void add_coverage (set_t *glyphs) const
{
- hb_get_coverage_context_t c;
- const Coverage *last = NULL;
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++) {
- const Coverage *coverage = &get_subtable (i).dispatch (&c, get_type ());
- if (coverage != last) {
- coverage->add_coverage (glyphs);
- last = coverage;
- }
- }
+ hb_add_coverage_context_t<set_t> c (glyphs);
+ dispatch (&c);
}
- inline bool would_apply (hb_would_apply_context_t *c, const hb_set_digest_t *digest) const
+ inline bool would_apply (hb_would_apply_context_t *c,
+ const hb_ot_layout_lookup_accelerator_t *accel) const
{
TRACE_WOULD_APPLY (this);
if (unlikely (!c->len)) return TRACE_RETURN (false);
- if (!digest->may_have (c->glyphs[0])) return TRACE_RETURN (false);
+ if (!accel->may_have (c->glyphs[0])) return TRACE_RETURN (false);
return TRACE_RETURN (dispatch (c));
}
- inline bool apply_once (hb_apply_context_t *c) const
- {
- TRACE_APPLY (this);
- if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
- return TRACE_RETURN (false);
- return TRACE_RETURN (dispatch (c));
- }
-
static bool apply_recurse_func (hb_apply_context_t *c, unsigned int lookup_index);
inline SubstLookupSubTable& serialize_subtable (hb_serialize_context_t *c,
unsigned int i)
- { return CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable)[i].serialize (c, this); }
+ { return get_subtables<SubstLookupSubTable> ()[i].serialize (c, this); }
inline bool serialize_single (hb_serialize_context_t *c,
uint32_t lookup_props,
@@ -1274,24 +1216,14 @@
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
- {
- unsigned int lookup_type = get_type ();
- TRACE_DISPATCH (this, lookup_type);
- unsigned int count = get_subtable_count ();
- for (unsigned int i = 0; i < count; i++) {
- typename context_t::return_t r = get_subtable (i).dispatch (c, lookup_type);
- if (c->stop_sublookup_iteration (r))
- return TRACE_RETURN (r);
- }
- return TRACE_RETURN (c->default_return_value ());
- }
+ { return Lookup::dispatch<SubstLookupSubTable> (c); }
- inline bool sanitize (hb_sanitize_context_t *c)
+ inline bool sanitize (hb_sanitize_context_t *c) const
{
TRACE_SANITIZE (this);
if (unlikely (!Lookup::sanitize (c))) return TRACE_RETURN (false);
- OffsetArrayOf<SubstLookupSubTable> &list = CastR<OffsetArrayOf<SubstLookupSubTable> > (subTable);
- if (unlikely (!list.sanitize (c, this, get_type ()))) return TRACE_RETURN (false);
+ const OffsetArrayOf<SubstLookupSubTable> &list = get_subtables<SubstLookupSubTable> ();
+ if (unlikely (!dispatch (c))) return TRACE_RETURN (false);
if (unlikely (get_type () == SubstLookupSubTable::Extension))
{
@@ -1324,10 +1256,11 @@
static inline void substitute_start (hb_font_t *font, hb_buffer_t *buffer);
static inline void substitute_finish (hb_font_t *font, hb_buffer_t *buffer);
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (unlikely (!GSUBGPOS::sanitize (c))) return TRACE_RETURN (false);
- OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
+ const OffsetTo<SubstLookupList> &list = CastR<OffsetTo<SubstLookupList> > (lookupList);
return TRACE_RETURN (list.sanitize (c, this));
}
public:
@@ -1362,7 +1295,7 @@
{
unsigned int type = get_type ();
if (unlikely (type == SubstLookupSubTable::Extension))
- return CastR<ExtensionSubst> (get_subtable<SubstLookupSubTable>()).is_reverse ();
+ return CastR<ExtensionSubst> (get_subtable<LookupSubTable>()).is_reverse ();
return SubstLookup::lookup_type_is_reverse (type);
}
@@ -1380,8 +1313,8 @@
const SubstLookup &l = gsub.get_lookup (lookup_index);
unsigned int saved_lookup_props = c->lookup_props;
c->set_lookup (l);
- bool ret = l.apply_once (c);
- c->lookup_props = saved_lookup_props;
+ bool ret = l.dispatch (c);
+ c->set_lookup_props (saved_lookup_props);
return ret;
}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
index 57fc1e0..cbc6840 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-gsubgpos-private.hh
@@ -37,12 +37,6 @@
namespace OT {
-
-#define TRACE_DISPATCH(this, format) \
- hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
- (&c->debug_depth, c->get_name (), this, HB_FUNC, \
- "format %d", (int) format);
-
#ifndef HB_DEBUG_CLOSURE
#define HB_DEBUG_CLOSURE (HB_DEBUG+0)
#endif
@@ -58,6 +52,8 @@
static const unsigned int max_debug_depth = HB_DEBUG_CLOSURE;
typedef hb_void_t return_t;
typedef return_t (*recurse_func_t) (hb_closure_context_t *c, unsigned int lookup_index);
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
template <typename T>
inline return_t dispatch (const T &obj) { obj.closure (this); return HB_VOID; }
static return_t default_return_value (void) { return HB_VOID; }
@@ -107,6 +103,8 @@
inline const char *get_name (void) { return "WOULD_APPLY"; }
static const unsigned int max_debug_depth = HB_DEBUG_WOULD_APPLY;
typedef bool return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
template <typename T>
inline return_t dispatch (const T &obj) { return obj.would_apply (this); }
static return_t default_return_value (void) { return false; }
@@ -146,6 +144,8 @@
static const unsigned int max_debug_depth = HB_DEBUG_COLLECT_GLYPHS;
typedef hb_void_t return_t;
typedef return_t (*recurse_func_t) (hb_collect_glyphs_context_t *c, unsigned int lookup_index);
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
template <typename T>
inline return_t dispatch (const T &obj) { obj.collect_glyphs (this); return HB_VOID; }
static return_t default_return_value (void) { return HB_VOID; }
@@ -232,18 +232,28 @@
#define HB_DEBUG_GET_COVERAGE (HB_DEBUG+0)
#endif
-struct hb_get_coverage_context_t
+template <typename set_t>
+struct hb_add_coverage_context_t
{
inline const char *get_name (void) { return "GET_COVERAGE"; }
static const unsigned int max_debug_depth = HB_DEBUG_GET_COVERAGE;
typedef const Coverage &return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
template <typename T>
inline return_t dispatch (const T &obj) { return obj.get_coverage (); }
static return_t default_return_value (void) { return Null(Coverage); }
+ bool stop_sublookup_iteration (return_t r) const
+ {
+ r.add_coverage (set);
+ return false;
+ }
- hb_get_coverage_context_t (void) :
+ hb_add_coverage_context_t (set_t *set_) :
+ set (set_),
debug_depth (0) {}
+ set_t *set;
unsigned int debug_depth;
};
@@ -260,61 +270,6 @@
struct hb_apply_context_t
{
- inline const char *get_name (void) { return "APPLY"; }
- static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
- typedef bool return_t;
- typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
- template <typename T>
- inline return_t dispatch (const T &obj) { return obj.apply (this); }
- static return_t default_return_value (void) { return false; }
- bool stop_sublookup_iteration (return_t r) const { return r; }
- return_t recurse (unsigned int lookup_index)
- {
- if (unlikely (nesting_level_left == 0 || !recurse_func))
- return default_return_value ();
-
- nesting_level_left--;
- bool ret = recurse_func (this, lookup_index);
- nesting_level_left++;
- return ret;
- }
-
- unsigned int table_index; /* GSUB/GPOS */
- hb_font_t *font;
- hb_face_t *face;
- hb_buffer_t *buffer;
- hb_direction_t direction;
- hb_mask_t lookup_mask;
- bool auto_zwj;
- recurse_func_t recurse_func;
- unsigned int nesting_level_left;
- unsigned int lookup_props;
- const GDEF &gdef;
- bool has_glyph_classes;
- unsigned int debug_depth;
-
-
- hb_apply_context_t (unsigned int table_index_,
- hb_font_t *font_,
- hb_buffer_t *buffer_) :
- table_index (table_index_),
- font (font_), face (font->face), buffer (buffer_),
- direction (buffer_->props.direction),
- lookup_mask (1),
- auto_zwj (true),
- recurse_func (NULL),
- nesting_level_left (MAX_NESTING_LEVEL),
- lookup_props (0),
- gdef (*hb_ot_layout_from_face (face)->gdef),
- has_glyph_classes (gdef.has_glyph_classes ()),
- debug_depth (0) {}
-
- inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
- inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
- inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
- inline void set_lookup_props (unsigned int lookup_props_) { lookup_props = lookup_props_; }
- inline void set_lookup (const Lookup &l) { lookup_props = l.get_props (); }
-
struct matcher_t
{
inline matcher_t (void) :
@@ -390,29 +345,24 @@
const void *match_data;
};
- struct skipping_forward_iterator_t
+ struct skipping_iterator_t
{
- inline skipping_forward_iterator_t (hb_apply_context_t *c_,
- unsigned int start_index_,
- unsigned int num_items_,
- bool context_match = false) :
- idx (start_index_),
- c (c_),
- match_glyph_data (NULL),
- num_items (num_items_),
- end (c->buffer->len)
+ inline void init (hb_apply_context_t *c_, bool context_match = false)
{
+ c = c_;
+ match_glyph_data = NULL,
+ matcher.set_match_func (NULL, NULL);
matcher.set_lookup_props (c->lookup_props);
/* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
matcher.set_ignore_zwnj (context_match || c->table_index == 1);
/* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
- if (!context_match)
- matcher.set_mask (c->lookup_mask);
- matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+ matcher.set_mask (context_match ? -1 : c->lookup_mask);
}
- inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
- inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
+ inline void set_lookup_props (unsigned int lookup_props)
+ {
+ matcher.set_lookup_props (lookup_props);
+ }
inline void set_match_func (matcher_t::match_func_t match_func,
const void *match_data,
const USHORT glyph_data[])
@@ -421,12 +371,21 @@
match_glyph_data = glyph_data;
}
- inline bool has_no_chance (void) const { return unlikely (num_items && idx + num_items >= end); }
+ inline void reset (unsigned int start_index_,
+ unsigned int num_items_)
+ {
+ idx = start_index_;
+ num_items = num_items_;
+ end = c->buffer->len;
+ matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
+ }
+
inline void reject (void) { num_items++; match_glyph_data--; }
+
inline bool next (void)
{
assert (num_items > 0);
- while (!has_no_chance ())
+ while (idx + num_items < end)
{
idx++;
const hb_glyph_info_t &info = c->buffer->info[idx];
@@ -450,53 +409,10 @@
}
return false;
}
-
- unsigned int idx;
- protected:
- hb_apply_context_t *c;
- matcher_t matcher;
- const USHORT *match_glyph_data;
-
- unsigned int num_items;
- unsigned int end;
- };
-
- struct skipping_backward_iterator_t
- {
- inline skipping_backward_iterator_t (hb_apply_context_t *c_,
- unsigned int start_index_,
- unsigned int num_items_,
- bool context_match = false) :
- idx (start_index_),
- c (c_),
- match_glyph_data (NULL),
- num_items (num_items_)
- {
- matcher.set_lookup_props (c->lookup_props);
- /* Ignore ZWNJ if we are matching GSUB context, or matching GPOS. */
- matcher.set_ignore_zwnj (context_match || c->table_index == 1);
- /* Ignore ZWJ if we are matching GSUB context, or matching GPOS, or if asked to. */
- matcher.set_ignore_zwj (context_match || c->table_index == 1 || c->auto_zwj);
- if (!context_match)
- matcher.set_mask (c->lookup_mask);
- matcher.set_syllable (start_index_ == c->buffer->idx ? c->buffer->cur().syllable () : 0);
- }
- inline void set_lookup_props (unsigned int lookup_props) { matcher.set_lookup_props (lookup_props); }
- inline void set_syllable (unsigned int syllable) { matcher.set_syllable (syllable); }
- inline void set_match_func (matcher_t::match_func_t match_func,
- const void *match_data,
- const USHORT glyph_data[])
- {
- matcher.set_match_func (match_func, match_data);
- match_glyph_data = glyph_data;
- }
-
- inline bool has_no_chance (void) const { return unlikely (idx < num_items); }
- inline void reject (void) { num_items++; }
inline bool prev (void)
{
assert (num_items > 0);
- while (!has_no_chance ())
+ while (idx >= num_items)
{
idx--;
const hb_glyph_info_t &info = c->buffer->out_info[idx];
@@ -528,8 +444,75 @@
const USHORT *match_glyph_data;
unsigned int num_items;
+ unsigned int end;
};
+
+ inline const char *get_name (void) { return "APPLY"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+ typedef bool return_t;
+ typedef return_t (*recurse_func_t) (hb_apply_context_t *c, unsigned int lookup_index);
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return obj.apply (this); }
+ static return_t default_return_value (void) { return false; }
+ bool stop_sublookup_iteration (return_t r) const { return r; }
+ return_t recurse (unsigned int lookup_index)
+ {
+ if (unlikely (nesting_level_left == 0 || !recurse_func))
+ return default_return_value ();
+
+ nesting_level_left--;
+ bool ret = recurse_func (this, lookup_index);
+ nesting_level_left++;
+ return ret;
+ }
+
+ unsigned int table_index; /* GSUB/GPOS */
+ hb_font_t *font;
+ hb_face_t *face;
+ hb_buffer_t *buffer;
+ hb_direction_t direction;
+ hb_mask_t lookup_mask;
+ bool auto_zwj;
+ recurse_func_t recurse_func;
+ unsigned int nesting_level_left;
+ unsigned int lookup_props;
+ const GDEF &gdef;
+ bool has_glyph_classes;
+ skipping_iterator_t iter_input, iter_context;
+ unsigned int debug_depth;
+
+
+ hb_apply_context_t (unsigned int table_index_,
+ hb_font_t *font_,
+ hb_buffer_t *buffer_) :
+ table_index (table_index_),
+ font (font_), face (font->face), buffer (buffer_),
+ direction (buffer_->props.direction),
+ lookup_mask (1),
+ auto_zwj (true),
+ recurse_func (NULL),
+ nesting_level_left (MAX_NESTING_LEVEL),
+ lookup_props (0),
+ gdef (*hb_ot_layout_from_face (face)->gdef),
+ has_glyph_classes (gdef.has_glyph_classes ()),
+ iter_input (),
+ iter_context (),
+ debug_depth (0) {}
+
+ inline void set_lookup_mask (hb_mask_t mask) { lookup_mask = mask; }
+ inline void set_auto_zwj (bool auto_zwj_) { auto_zwj = auto_zwj_; }
+ inline void set_recurse_func (recurse_func_t func) { recurse_func = func; }
+ inline void set_lookup (const Lookup &l) { set_lookup_props (l.get_props ()); }
+ inline void set_lookup_props (unsigned int lookup_props_)
+ {
+ lookup_props = lookup_props_;
+ iter_input.init (this, false);
+ iter_context.init (this, true);
+ }
+
inline bool
match_properties_mark (hb_codepoint_t glyph,
unsigned int glyph_props,
@@ -741,9 +724,9 @@
hb_buffer_t *buffer = c->buffer;
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, buffer->idx, count - 1);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
+ skippy_iter.reset (buffer->idx, count - 1);
skippy_iter.set_match_func (match_func, match_data, input);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
/*
* This is perhaps the trickiest part of OpenType... Remarks:
@@ -910,9 +893,9 @@
{
TRACE_APPLY (NULL);
- hb_apply_context_t::skipping_backward_iterator_t skippy_iter (c, c->buffer->backtrack_len (), count, true);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+ skippy_iter.reset (c->buffer->backtrack_len (), count);
skippy_iter.set_match_func (match_func, match_data, backtrack);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
for (unsigned int i = 0; i < count; i++)
if (!skippy_iter.prev ())
@@ -930,9 +913,9 @@
{
TRACE_APPLY (NULL);
- hb_apply_context_t::skipping_forward_iterator_t skippy_iter (c, c->buffer->idx + offset - 1, count, true);
+ hb_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_context;
+ skippy_iter.reset (c->buffer->idx + offset - 1, count);
skippy_iter.set_match_func (match_func, match_data, lookahead);
- if (skippy_iter.has_no_chance ()) return TRACE_RETURN (false);
for (unsigned int i = 0; i < count; i++)
if (!skippy_iter.next ())
@@ -945,7 +928,8 @@
struct LookupRecord
{
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this));
}
@@ -1168,7 +1152,8 @@
}
public:
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return inputCount.sanitize (c)
&& lookupCount.sanitize (c)
@@ -1232,7 +1217,8 @@
return TRACE_RETURN (false);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (rule.sanitize (c, this));
}
@@ -1314,7 +1300,8 @@
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
}
@@ -1406,7 +1393,8 @@
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && classDef.sanitize (c, this) && ruleSet.sanitize (c, this));
}
@@ -1494,7 +1482,8 @@
return TRACE_RETURN (context_apply_lookup (c, glyphCount, (const USHORT *) (coverageZ + 1), lookupCount, lookupRecord, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!c->check_struct (this)) return TRACE_RETURN (false);
unsigned int count = glyphCount;
@@ -1502,7 +1491,7 @@
if (!c->check_array (coverageZ, coverageZ[0].static_size, count)) return TRACE_RETURN (false);
for (unsigned int i = 0; i < count; i++)
if (!coverageZ[i].sanitize (c, this)) return TRACE_RETURN (false);
- LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
+ const LookupRecord *lookupRecord = &StructAtOffset<LookupRecord> (coverageZ, coverageZ[0].static_size * count);
return TRACE_RETURN (c->check_array (lookupRecord, lookupRecord[0].static_size, lookupCount));
}
@@ -1526,6 +1515,7 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
case 2: return TRACE_RETURN (c->dispatch (u.format2));
@@ -1534,17 +1524,6 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- case 3: return TRACE_RETURN (u.format3.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -1726,14 +1705,15 @@
lookup.array, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!backtrack.sanitize (c)) return TRACE_RETURN (false);
- HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
+ const HeadlessArrayOf<USHORT> &input = StructAfter<HeadlessArrayOf<USHORT> > (backtrack);
if (!input.sanitize (c)) return TRACE_RETURN (false);
- ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
+ const ArrayOf<USHORT> &lookahead = StructAfter<ArrayOf<USHORT> > (input);
if (!lookahead.sanitize (c)) return TRACE_RETURN (false);
- ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
return TRACE_RETURN (lookup.sanitize (c));
}
@@ -1795,7 +1775,8 @@
return TRACE_RETURN (false);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (rule.sanitize (c, this));
}
@@ -1874,7 +1855,8 @@
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && ruleSet.sanitize (c, this));
}
@@ -1984,7 +1966,8 @@
return TRACE_RETURN (rule_set.apply (c, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (coverage.sanitize (c, this) && backtrackClassDef.sanitize (c, this) &&
inputClassDef.sanitize (c, this) && lookaheadClassDef.sanitize (c, this) &&
@@ -2105,15 +2088,16 @@
lookup.len, lookup.array, lookup_context));
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
if (!backtrack.sanitize (c, this)) return TRACE_RETURN (false);
- OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
+ const OffsetArrayOf<Coverage> &input = StructAfter<OffsetArrayOf<Coverage> > (backtrack);
if (!input.sanitize (c, this)) return TRACE_RETURN (false);
if (!input.len) return TRACE_RETURN (false); /* To be consistent with Context. */
- OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
+ const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage> > (input);
if (!lookahead.sanitize (c, this)) return TRACE_RETURN (false);
- ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
+ const ArrayOf<LookupRecord> &lookup = StructAfter<ArrayOf<LookupRecord> > (lookahead);
return TRACE_RETURN (lookup.sanitize (c));
}
@@ -2144,6 +2128,7 @@
inline typename context_t::return_t dispatch (context_t *c) const
{
TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
case 1: return TRACE_RETURN (c->dispatch (u.format1));
case 2: return TRACE_RETURN (c->dispatch (u.format2));
@@ -2152,17 +2137,6 @@
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
- switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- case 2: return TRACE_RETURN (u.format2.sanitize (c));
- case 3: return TRACE_RETURN (u.format3.sanitize (c));
- default:return TRACE_RETURN (true);
- }
- }
-
protected:
union {
USHORT format; /* Format identifier */
@@ -2173,14 +2147,32 @@
};
+template <typename T>
struct ExtensionFormat1
{
inline unsigned int get_type (void) const { return extensionLookupType; }
- inline unsigned int get_offset (void) const { return extensionOffset; }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ template <typename X>
+ inline const X& get_subtable (void) const
+ {
+ unsigned int offset = extensionOffset;
+ if (unlikely (!offset)) return Null(typename T::LookupSubTable);
+ return StructAtOffset<typename T::LookupSubTable> (this, offset);
+ }
+
+ template <typename context_t>
+ inline typename context_t::return_t dispatch (context_t *c) const
+ {
+ TRACE_DISPATCH (this, format);
+ if (unlikely (!c->may_dispatch (this, this))) TRACE_RETURN (c->default_return_value ());
+ return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
+ }
+
+ /* This is called from may_dispatch() above with hb_sanitize_context_t. */
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
- return TRACE_RETURN (c->check_struct (this));
+ return TRACE_RETURN (c->check_struct (this) && extensionOffset != 0);
}
protected:
@@ -2204,49 +2196,30 @@
default:return 0;
}
}
- inline unsigned int get_offset (void) const
- {
- switch (u.format) {
- case 1: return u.format1.get_offset ();
- default:return 0;
- }
- }
-
template <typename X>
inline const X& get_subtable (void) const
{
- unsigned int offset = get_offset ();
- if (unlikely (!offset)) return Null(typename T::LookupSubTable);
- return StructAtOffset<typename T::LookupSubTable> (this, offset);
+ switch (u.format) {
+ case 1: return u.format1.template get_subtable<typename T::LookupSubTable> ();
+ default:return Null(typename T::LookupSubTable);
+ }
}
template <typename context_t>
inline typename context_t::return_t dispatch (context_t *c) const
{
- return get_subtable<typename T::LookupSubTable> ().dispatch (c, get_type ());
- }
-
- inline bool sanitize_self (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!u.format.sanitize (c)) return TRACE_RETURN (false);
+ TRACE_DISPATCH (this, u.format);
+ if (unlikely (!c->may_dispatch (this, &u.format))) TRACE_RETURN (c->default_return_value ());
switch (u.format) {
- case 1: return TRACE_RETURN (u.format1.sanitize (c));
- default:return TRACE_RETURN (true);
+ case 1: return TRACE_RETURN (u.format1.dispatch (c));
+ default:return TRACE_RETURN (c->default_return_value ());
}
}
- inline bool sanitize (hb_sanitize_context_t *c) {
- TRACE_SANITIZE (this);
- if (!sanitize_self (c)) return TRACE_RETURN (false);
- unsigned int offset = get_offset ();
- if (unlikely (!offset)) return TRACE_RETURN (true);
- return TRACE_RETURN (StructAtOffset<typename T::LookupSubTable> (this, offset).sanitize (c, get_type ()));
- }
-
protected:
union {
USHORT format; /* Format identifier */
- ExtensionFormat1 format1;
+ ExtensionFormat1<T> format1;
} u;
};
@@ -2291,7 +2264,8 @@
inline const Lookup& get_lookup (unsigned int i) const
{ return (this+lookupList)[i]; }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
scriptList.sanitize (c, this) &&
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
index 67a6df5..739dfd9 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-jstf-table.hh
@@ -54,7 +54,8 @@
struct JstfPriority
{
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
shrinkageEnableGSUB.sanitize (c, this) &&
@@ -123,7 +124,8 @@
struct JstfLangSys : OffsetListOf<JstfPriority>
{
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<JstfLangSys>::sanitize_closure_t * = NULL) {
+ const Record<JstfLangSys>::sanitize_closure_t * = NULL) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (OffsetListOf<JstfPriority>::sanitize (c));
}
@@ -163,7 +165,8 @@
inline const JstfLangSys& get_default_lang_sys (void) const { return this+defaultLangSys; }
inline bool sanitize (hb_sanitize_context_t *c,
- const Record<JstfScript>::sanitize_closure_t * = NULL) {
+ const Record<JstfScript>::sanitize_closure_t * = NULL) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (extenderGlyphs.sanitize (c, this) &&
defaultLangSys.sanitize (c, this) &&
@@ -206,7 +209,8 @@
inline bool find_script_index (hb_tag_t tag, unsigned int *index) const
{ return scriptList.find_index (tag, index); }
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (version.sanitize (c) && likely (version.major == 1) &&
scriptList.sanitize (c, this));
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
index 3f7c858..47fecd2 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout-private.hh
@@ -130,6 +130,11 @@
{
}
+ inline bool may_have (hb_codepoint_t g) const {
+ return digest.may_have (g);
+ }
+
+ private:
hb_set_digest_t digest;
};
diff --git a/third_party/harfbuzz-ng/src/hb-ot-layout.cc b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
index 602b94e..b1e69e8 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-layout.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-layout.cc
@@ -699,7 +699,7 @@
const OT::SubstLookup& l = hb_ot_layout_from_face (face)->gsub->get_lookup (lookup_index);
- return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index].digest);
+ return l.would_apply (&c, &hb_ot_layout_from_face (face)->gsub_accels[lookup_index]);
}
void
@@ -829,26 +829,83 @@
};
-template <typename Lookup>
-static inline bool apply_once (OT::hb_apply_context_t *c,
- const Lookup &lookup)
+template <typename Obj>
+static inline bool
+apply_forward (OT::hb_apply_context_t *c,
+ const Obj &obj,
+ const hb_ot_layout_lookup_accelerator_t &accel)
{
- if (!c->check_glyph_property (&c->buffer->cur(), c->lookup_props))
- return false;
- return lookup.dispatch (c);
+ bool ret = false;
+ hb_buffer_t *buffer = c->buffer;
+ while (buffer->idx < buffer->len)
+ {
+ if (accel.may_have (buffer->cur().codepoint) &&
+ (buffer->cur().mask & c->lookup_mask) &&
+ c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
+ obj.apply (c))
+ ret = true;
+ else
+ buffer->next_glyph ();
+ }
+ return ret;
}
-template <typename Proxy>
+template <typename Obj>
static inline bool
+apply_backward (OT::hb_apply_context_t *c,
+ const Obj &obj,
+ const hb_ot_layout_lookup_accelerator_t &accel)
+{
+ bool ret = false;
+ hb_buffer_t *buffer = c->buffer;
+ do
+ {
+ if (accel.may_have (buffer->cur().codepoint) &&
+ (buffer->cur().mask & c->lookup_mask) &&
+ c->check_glyph_property (&buffer->cur(), c->lookup_props) &&
+ obj.apply (c))
+ ret = true;
+ /* The reverse lookup doesn't "advance" cursor (for good reason). */
+ buffer->idx--;
+
+ }
+ while ((int) buffer->idx >= 0);
+ return ret;
+}
+
+struct hb_apply_forward_context_t
+{
+ inline const char *get_name (void) { return "APPLY_FORWARD"; }
+ static const unsigned int max_debug_depth = HB_DEBUG_APPLY;
+ typedef bool return_t;
+ template <typename T, typename F>
+ inline bool may_dispatch (const T *obj, const F *format) { return true; }
+ template <typename T>
+ inline return_t dispatch (const T &obj) { return apply_forward (c, obj, accel); }
+ static return_t default_return_value (void) { return false; }
+ bool stop_sublookup_iteration (return_t r HB_UNUSED) const { return true; }
+
+ hb_apply_forward_context_t (OT::hb_apply_context_t *c_,
+ const hb_ot_layout_lookup_accelerator_t &accel_) :
+ c (c_),
+ accel (accel_),
+ debug_depth (0) {}
+
+ OT::hb_apply_context_t *c;
+ const hb_ot_layout_lookup_accelerator_t &accel;
+ unsigned int debug_depth;
+};
+
+template <typename Proxy>
+static inline void
apply_string (OT::hb_apply_context_t *c,
const typename Proxy::Lookup &lookup,
const hb_ot_layout_lookup_accelerator_t &accel)
{
- bool ret = false;
hb_buffer_t *buffer = c->buffer;
if (unlikely (!buffer->len || !c->lookup_mask))
- return false;
+ return;
c->set_lookup (lookup);
@@ -859,21 +916,20 @@
buffer->clear_output ();
buffer->idx = 0;
- while (buffer->idx < buffer->len)
+ bool ret;
+ if (lookup.get_subtable_count () == 1)
{
- if (accel.digest.may_have (buffer->cur().codepoint) &&
- (buffer->cur().mask & c->lookup_mask) &&
- apply_once (c, lookup))
- ret = true;
- else
- buffer->next_glyph ();
+ hb_apply_forward_context_t c_forward (c, accel);
+ ret = lookup.dispatch (&c_forward);
}
+ else
+ ret = apply_forward (c, lookup, accel);
if (ret)
{
if (!Proxy::inplace)
buffer->swap_buffers ();
else
- assert (!buffer->has_separate_output ());
+ assert (!buffer->has_separate_output ());
}
}
else
@@ -882,20 +938,9 @@
if (Proxy::table_index == 0)
buffer->remove_output ();
buffer->idx = buffer->len - 1;
- do
- {
- if (accel.digest.may_have (buffer->cur().codepoint) &&
- (buffer->cur().mask & c->lookup_mask) &&
- apply_once (c, lookup))
- ret = true;
- /* The reverse lookup doesn't "advance" cursor (for good reason). */
- buffer->idx--;
- }
- while ((int) buffer->idx >= 0);
+ apply_backward (c, lookup, accel);
}
-
- return ret;
}
template <typename Proxy>
diff --git a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
index b1f8328..0d9a0fa 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-maxp-table.hh
@@ -43,11 +43,13 @@
{
static const hb_tag_t tableTag = HB_OT_TAG_maxp;
- inline unsigned int get_num_glyphs (void) const {
+ inline unsigned int get_num_glyphs (void) const
+ {
return numGlyphs;
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
likely (version.major == 1 || (version.major == 0 && version.minor == 0x5000u)));
diff --git a/third_party/harfbuzz-ng/src/hb-ot-name-table.hh b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh
index 31d9fac..21450c6 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-name-table.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-name-table.hh
@@ -56,7 +56,8 @@
return 0;
}
- inline bool sanitize (hb_sanitize_context_t *c, void *base) {
+ inline bool sanitize (hb_sanitize_context_t *c, const void *base) const
+ {
TRACE_SANITIZE (this);
/* We can check from base all the way up to the end of string... */
return TRACE_RETURN (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset));
@@ -101,7 +102,7 @@
inline unsigned int get_size (void) const
{ return min_size + count * nameRecord[0].min_size; }
- inline bool sanitize_records (hb_sanitize_context_t *c) {
+ inline bool sanitize_records (hb_sanitize_context_t *c) const {
TRACE_SANITIZE (this);
char *string_pool = (char *) this + stringOffset;
unsigned int _count = count;
@@ -110,7 +111,8 @@
return TRACE_RETURN (true);
}
- inline bool sanitize (hb_sanitize_context_t *c) {
+ inline bool sanitize (hb_sanitize_context_t *c) const
+ {
TRACE_SANITIZE (this);
return TRACE_RETURN (c->check_struct (this) &&
likely (format == 0 || format == 1) &&
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh
index 3a20b50..8edd3ba 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-arabic-win1256.hh
@@ -133,7 +133,6 @@
*/
#define OT_LOOKUP_TYPE_SUBST_SINGLE 1u
-#define OT_LOOKUP_TYPE_SUBST_MULTIPLE 2u
#define OT_LOOKUP_TYPE_SUBST_LIGATURE 4u
#define OT_SUBLOOKUP_SINGLE_SUBST_FORMAT2(Name, FromGlyphs, ToGlyphs) \
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh
index 83ade21..29fdf9a 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-myanmar-machine.hh
@@ -1,5 +1,5 @@
-#line 1 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 1 "hb-ot-shape-complex-myanmar-machine.rl"
/*
* Copyright © 2011,2012 Google, Inc.
*
@@ -32,7 +32,7 @@
#include "hb-private.hh"
-#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.hh"
+#line 36 "hb-ot-shape-complex-myanmar-machine.hh"
static const unsigned char _myanmar_syllable_machine_trans_keys[] = {
1u, 31u, 3u, 30u, 5u, 29u, 5u, 8u, 5u, 29u, 3u, 25u, 5u, 25u, 5u, 25u,
3u, 29u, 3u, 29u, 3u, 29u, 3u, 29u, 1u, 16u, 3u, 29u, 3u, 29u, 3u, 29u,
@@ -261,11 +261,11 @@
static const int myanmar_syllable_machine_en_main = 0;
-#line 36 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 36 "hb-ot-shape-complex-myanmar-machine.rl"
-#line 93 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 93 "hb-ot-shape-complex-myanmar-machine.rl"
#define found_syllable(syllable_type) \
@@ -285,7 +285,7 @@
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 289 "../../src/hb-ot-shape-complex-myanmar-machine.hh"
+#line 289 "hb-ot-shape-complex-myanmar-machine.hh"
{
cs = myanmar_syllable_machine_start;
ts = 0;
@@ -293,7 +293,7 @@
act = 0;
}
-#line 114 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 114 "hb-ot-shape-complex-myanmar-machine.rl"
p = 0;
@@ -302,7 +302,7 @@
unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 306 "../../src/hb-ot-shape-complex-myanmar-machine.hh"
+#line 306 "hb-ot-shape-complex-myanmar-machine.hh"
{
int _slen;
int _trans;
@@ -316,7 +316,7 @@
#line 1 "NONE"
{ts = p;}
break;
-#line 320 "../../src/hb-ot-shape-complex-myanmar-machine.hh"
+#line 320 "hb-ot-shape-complex-myanmar-machine.hh"
}
_keys = _myanmar_syllable_machine_trans_keys + (cs<<1);
@@ -335,38 +335,38 @@
switch ( _myanmar_syllable_machine_trans_actions[_trans] ) {
case 7:
-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (consonant_syllable); }}
break;
case 5:
-#line 86 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 86 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (non_myanmar_cluster); }}
break;
case 10:
-#line 87 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 87 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (punctuation_cluster); }}
break;
case 4:
-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (broken_cluster); }}
break;
case 3:
-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p+1;{ found_syllable (non_myanmar_cluster); }}
break;
case 6:
-#line 85 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 85 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p;p--;{ found_syllable (consonant_syllable); }}
break;
case 8:
-#line 88 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 88 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
case 9:
-#line 89 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 89 "hb-ot-shape-complex-myanmar-machine.rl"
{te = p;p--;{ found_syllable (non_myanmar_cluster); }}
break;
-#line 370 "../../src/hb-ot-shape-complex-myanmar-machine.hh"
+#line 370 "hb-ot-shape-complex-myanmar-machine.hh"
}
_again:
@@ -375,7 +375,7 @@
#line 1 "NONE"
{ts = 0;}
break;
-#line 379 "../../src/hb-ot-shape-complex-myanmar-machine.hh"
+#line 379 "hb-ot-shape-complex-myanmar-machine.hh"
}
if ( ++p != pe )
@@ -391,7 +391,7 @@
}
-#line 123 "../../src/hb-ot-shape-complex-myanmar-machine.rl"
+#line 123 "hb-ot-shape-complex-myanmar-machine.rl"
}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-sea-machine.hh b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-sea-machine.hh
index 789e4d6..15b862f 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-complex-sea-machine.hh
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-complex-sea-machine.hh
@@ -1,5 +1,5 @@
-#line 1 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 1 "hb-ot-shape-complex-sea-machine.rl"
/*
* Copyright © 2011,2012,2013 Google, Inc.
*
@@ -32,7 +32,7 @@
#include "hb-private.hh"
-#line 36 "../../src/hb-ot-shape-complex-sea-machine.hh"
+#line 36 "hb-ot-shape-complex-sea-machine.hh"
static const unsigned char _sea_syllable_machine_trans_keys[] = {
1u, 1u, 1u, 1u, 1u, 29u, 3u, 29u, 3u, 29u, 1u, 1u, 0
};
@@ -89,11 +89,11 @@
static const int sea_syllable_machine_en_main = 2;
-#line 36 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 36 "hb-ot-shape-complex-sea-machine.rl"
-#line 67 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 67 "hb-ot-shape-complex-sea-machine.rl"
#define found_syllable(syllable_type) \
@@ -113,7 +113,7 @@
int cs;
hb_glyph_info_t *info = buffer->info;
-#line 117 "../../src/hb-ot-shape-complex-sea-machine.hh"
+#line 117 "hb-ot-shape-complex-sea-machine.hh"
{
cs = sea_syllable_machine_start;
ts = 0;
@@ -121,7 +121,7 @@
act = 0;
}
-#line 88 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 88 "hb-ot-shape-complex-sea-machine.rl"
p = 0;
@@ -130,7 +130,7 @@
unsigned int last = 0;
unsigned int syllable_serial = 1;
-#line 134 "../../src/hb-ot-shape-complex-sea-machine.hh"
+#line 134 "hb-ot-shape-complex-sea-machine.hh"
{
int _slen;
int _trans;
@@ -144,7 +144,7 @@
#line 1 "NONE"
{ts = p;}
break;
-#line 148 "../../src/hb-ot-shape-complex-sea-machine.hh"
+#line 148 "hb-ot-shape-complex-sea-machine.hh"
}
_keys = _sea_syllable_machine_trans_keys + (cs<<1);
@@ -167,30 +167,30 @@
{te = p+1;}
break;
case 6:
-#line 63 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 63 "hb-ot-shape-complex-sea-machine.rl"
{te = p+1;{ found_syllable (non_sea_cluster); }}
break;
case 7:
-#line 61 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 61 "hb-ot-shape-complex-sea-machine.rl"
{te = p;p--;{ found_syllable (consonant_syllable); }}
break;
case 8:
-#line 62 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 62 "hb-ot-shape-complex-sea-machine.rl"
{te = p;p--;{ found_syllable (broken_cluster); }}
break;
case 9:
-#line 63 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 63 "hb-ot-shape-complex-sea-machine.rl"
{te = p;p--;{ found_syllable (non_sea_cluster); }}
break;
case 1:
-#line 61 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 61 "hb-ot-shape-complex-sea-machine.rl"
{{p = ((te))-1;}{ found_syllable (consonant_syllable); }}
break;
case 3:
-#line 62 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 62 "hb-ot-shape-complex-sea-machine.rl"
{{p = ((te))-1;}{ found_syllable (broken_cluster); }}
break;
-#line 194 "../../src/hb-ot-shape-complex-sea-machine.hh"
+#line 194 "hb-ot-shape-complex-sea-machine.hh"
}
_again:
@@ -199,7 +199,7 @@
#line 1 "NONE"
{ts = 0;}
break;
-#line 203 "../../src/hb-ot-shape-complex-sea-machine.hh"
+#line 203 "hb-ot-shape-complex-sea-machine.hh"
}
if ( ++p != pe )
@@ -215,7 +215,7 @@
}
-#line 97 "../../src/hb-ot-shape-complex-sea-machine.rl"
+#line 97 "hb-ot-shape-complex-sea-machine.rl"
}
diff --git a/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc b/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc
index 80d7da8..53274b5 100644
--- a/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc
+++ b/third_party/harfbuzz-ng/src/hb-ot-shape-fallback.cc
@@ -441,13 +441,15 @@
OT::hb_apply_context_t c (1, font, buffer);
c.set_lookup_mask (plan->kern_mask);
c.set_lookup_props (OT::LookupFlag::IgnoreMarks);
+ OT::hb_apply_context_t::skipping_iterator_t &skippy_iter = c.iter_input;
+ skippy_iter.init (&c);
unsigned int count = buffer->len;
hb_glyph_info_t *info = buffer->info;
hb_glyph_position_t *pos = buffer->pos;
for (unsigned int idx = 0; idx < count;)
{
- OT::hb_apply_context_t::skipping_forward_iterator_t skippy_iter (&c, idx, 1);
+ skippy_iter.reset (idx, 1);
if (!skippy_iter.next ())
{
idx++;
diff --git a/third_party/harfbuzz-ng/src/hb-private.hh b/third_party/harfbuzz-ng/src/hb-private.hh
index 45b7712..06b24a8 100644
--- a/third_party/harfbuzz-ng/src/hb-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-private.hh
@@ -94,16 +94,6 @@
# endif
#endif
-#ifdef _MSC_VER
-#undef inline
-#define inline __inline
-#endif
-
-#ifdef __STRICT_ANSI__
-#undef inline
-#define inline __inline__
-#endif
-
#if __GNUC__ >= 3
#define HB_FUNC __PRETTY_FUNCTION__
#elif defined(_MSC_VER)
@@ -583,6 +573,30 @@
#define DEBUG_LEVEL_ENABLED(WHAT, LEVEL) (_hb_debug ((LEVEL), HB_DEBUG_##WHAT))
#define DEBUG_ENABLED(WHAT) (DEBUG_LEVEL_ENABLED (WHAT, 0))
+static inline void
+_hb_print_func (const char *func)
+{
+ if (func)
+ {
+ unsigned int func_len = strlen (func);
+ /* Skip "static" */
+ if (0 == strncmp (func, "static ", 7))
+ func += 7;
+ /* Skip "typename" */
+ if (0 == strncmp (func, "typename ", 9))
+ func += 9;
+ /* Skip return type */
+ const char *space = strchr (func, ' ');
+ if (space)
+ func = space + 1;
+ /* Skip parameter list */
+ const char *paren = strchr (func, '(');
+ if (paren)
+ func_len = paren - func;
+ fprintf (stderr, "%.*s", func_len, func);
+ }
+}
+
template <int max_level> static inline void
_hb_debug_msg_va (const char *what,
const void *obj,
@@ -628,27 +642,13 @@
} else
fprintf (stderr, " " VRBAR LBAR);
- if (func)
- {
- unsigned int func_len = strlen (func);
-#ifndef HB_DEBUG_VERBOSE
- /* Skip "typename" */
- if (0 == strncmp (func, "typename ", 9))
- func += 9;
- /* Skip return type */
- const char *space = strchr (func, ' ');
- if (space)
- func = space + 1;
- /* Skip parameter list */
- const char *paren = strchr (func, '(');
- if (paren)
- func_len = paren - func;
-#endif
- fprintf (stderr, "%.*s: ", func_len, func);
- }
+ _hb_print_func (func);
if (message)
+ {
+ fprintf (stderr, ": ");
vfprintf (stderr, message, ap);
+ }
fprintf (stderr, "\n");
}
@@ -820,7 +820,7 @@
/* The sizeof() is here to force template instantiation.
* I'm sure there are better ways to do this but can't think of
* one right now. Declaring a variable won't work as HB_UNUSED
- * is unsable on some platforms and unused types are less likely
+ * is unusable on some platforms and unused types are less likely
* to generate a warning than unused variables. */
ASSERT_STATIC (sizeof (hb_assert_unsigned_t<T>) >= 0);
diff --git a/third_party/harfbuzz-ng/src/hb-set-private.hh b/third_party/harfbuzz-ng/src/hb-set-private.hh
index 59e8f45..acba4e9 100644
--- a/third_party/harfbuzz-ng/src/hb-set-private.hh
+++ b/third_party/harfbuzz-ng/src/hb-set-private.hh
@@ -145,6 +145,8 @@
struct hb_set_t
{
+ friend struct hb_frozen_set_t;
+
hb_object_header_t header;
ASSERT_POD ();
bool in_error;
@@ -326,7 +328,7 @@
static const hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
elt_t &elt (hb_codepoint_t g) { return elts[g >> SHIFT]; }
- elt_t elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+ elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
elt_t elts[ELTS]; /* XXX 8kb */
@@ -335,6 +337,59 @@
ASSERT_STATIC (sizeof (elt_t) * 8 * ELTS > MAX_G);
};
+struct hb_frozen_set_t
+{
+ static const unsigned int SHIFT = hb_set_t::SHIFT;
+ static const unsigned int BITS = hb_set_t::BITS;
+ static const unsigned int MASK = hb_set_t::MASK;
+ typedef hb_set_t::elt_t elt_t;
+
+ inline void init (const hb_set_t &set)
+ {
+ start = count = 0;
+ elts = NULL;
+
+ unsigned int max = set.get_max ();
+ if (max == set.INVALID)
+ return;
+ unsigned int min = set.get_min ();
+ const elt_t &min_elt = set.elt (min);
+ const elt_t &max_elt = set.elt (max);
+
+ start = min & ~MASK;
+ count = max - start + 1;
+ unsigned int num_elts = (count + BITS - 1) / BITS;
+ unsigned int elts_size = num_elts * sizeof (elt_t);
+ elts = (elt_t *) malloc (elts_size);
+ if (unlikely (!elts))
+ {
+ start = count = 0;
+ return;
+ }
+ memcpy (elts, &min_elt, elts_size);
+ }
+
+ inline void fini (void)
+ {
+ if (elts)
+ free (elts);
+ }
+
+ inline bool has (hb_codepoint_t g) const
+ {
+ /* hb_codepoint_t is unsigned. */
+ g -= start;
+ if (unlikely (g > count)) return false;
+ return !!(elt (g) & mask (g));
+ }
+
+ elt_t const &elt (hb_codepoint_t g) const { return elts[g >> SHIFT]; }
+ elt_t mask (hb_codepoint_t g) const { return elt_t (1) << (g & MASK); }
+
+ private:
+ hb_codepoint_t start, count;
+ elt_t *elts;
+};
#endif /* HB_SET_PRIVATE_HH */
diff --git a/third_party/harfbuzz-ng/src/hb-version.h b/third_party/harfbuzz-ng/src/hb-version.h
index 896b065..648a46f 100644
--- a/third_party/harfbuzz-ng/src/hb-version.h
+++ b/third_party/harfbuzz-ng/src/hb-version.h
@@ -38,9 +38,9 @@
#define HB_VERSION_MAJOR 0
#define HB_VERSION_MINOR 9
-#define HB_VERSION_MICRO 37
+#define HB_VERSION_MICRO 40
-#define HB_VERSION_STRING "0.9.37"
+#define HB_VERSION_STRING "0.9.40"
#define HB_VERSION_ATLEAST(major,minor,micro) \
((major)*10000+(minor)*100+(micro) <= \
diff --git a/third_party/ots/README.chromium b/third_party/ots/README.chromium
index 906fd3b..ffe584d 100644
--- a/third_party/ots/README.chromium
+++ b/third_party/ots/README.chromium
@@ -1,6 +1,6 @@
Name: OTS
URL: https://github.com/khaledhosny/ots.git
-Version: ea88f974e00e7fe0b4fbfe8d0adad8cfedf49c57
+Version: 4d011721c2eadd4e649326f8d164423db060d85e
Security Critical: yes
License: BSD
diff --git a/third_party/ots/include/opentype-sanitiser.h b/third_party/ots/include/opentype-sanitiser.h
index c454f1e..1c445ae 100644
--- a/third_party/ots/include/opentype-sanitiser.h
+++ b/third_party/ots/include/opentype-sanitiser.h
@@ -203,7 +203,6 @@
// partial output may have been written.
// input: the OpenType file
// length: the size, in bytes, of |input|
- // context: optional context that holds various OTS settings like user callbacks
bool Process(OTSStream *output, const uint8_t *input, size_t length);
// This function will be called when OTS is reporting an error.
@@ -222,10 +221,6 @@
// For backward compatibility - remove once Chrome switches over to the new API.
bool Process(OTSStream *output, const uint8_t *input, size_t length);
-// For backward compatibility - remove once https://codereview.chromium.org/774253008/
-// is submitted.
-void EnableWOFF2();
-
} // namespace ots
#endif // OPENTYPE_SANITISER_H_
diff --git a/third_party/ots/src/cmap.cc b/third_party/ots/src/cmap.cc
index d9ca9fa..b1bf5fd 100644
--- a/third_party/ots/src/cmap.cc
+++ b/third_party/ots/src/cmap.cc
@@ -684,11 +684,11 @@
+ (subtable_headers[i].encoding << 16)
+ subtable_headers[i].language;
if ((i != 0) && (last_id >= current_id)) {
- return OTS_FAILURE_MSG("subtable %d with platform ID %d, encoding ID %d, language ID %d "
- "following subtable with platform ID %d, encoding ID %d, language ID %d",
- i,
- (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
- (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
+ OTS_WARNING("subtable %d with platform ID %d, encoding ID %d, language ID %d "
+ "following subtable with platform ID %d, encoding ID %d, language ID %d",
+ i,
+ (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
+ (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
}
last_id = current_id;
}
diff --git a/third_party/ots/src/ots.cc b/third_party/ots/src/ots.cc
index 197c649..5ba8dd9 100644
--- a/third_party/ots/src/ots.cc
+++ b/third_party/ots/src/ots.cc
@@ -284,7 +284,7 @@
// We don't care about these fields of the header:
// uint16_t major_version, minor_version
if (!file.Skip(2 * 2)) {
- return OTS_FAILURE_MSG_HDR("error skipping WOFF header fields");
+ return OTS_FAILURE_MSG_HDR("Failed to read 'majorVersion' or 'minorVersion'");
}
// Checks metadata block size.
@@ -294,11 +294,11 @@
if (!file.ReadU32(&meta_offset) ||
!file.ReadU32(&meta_length) ||
!file.ReadU32(&meta_length_orig)) {
- return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
+ return OTS_FAILURE_MSG_HDR("Failed to read header metadata block fields");
}
if (meta_offset) {
if (meta_offset >= length || length - meta_offset < meta_length) {
- return OTS_FAILURE_MSG_HDR("invalid metadata block location/size");
+ return OTS_FAILURE_MSG_HDR("Invalid metadata block offset or length");
}
}
@@ -307,11 +307,11 @@
uint32_t priv_length;
if (!file.ReadU32(&priv_offset) ||
!file.ReadU32(&priv_length)) {
- return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
+ return OTS_FAILURE_MSG_HDR("Failed to read header private block fields");
}
if (priv_offset) {
if (priv_offset >= length || length - priv_offset < priv_length) {
- return OTS_FAILURE_MSG_HDR("invalid private block location/size");
+ return OTS_FAILURE_MSG_HDR("Invalid private block offset or length");
}
}
@@ -366,26 +366,26 @@
}
if (meta_offset) {
if (block_end != meta_offset) {
- return OTS_FAILURE_MSG_HDR("invalid metadata block location");
+ return OTS_FAILURE_MSG_HDR("Invalid metadata block offset");
}
block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
static_cast<uint64_t>(meta_length));
if (block_end > std::numeric_limits<uint32_t>::max()) {
- return OTS_FAILURE_MSG_HDR("invalid metadata block size");
+ return OTS_FAILURE_MSG_HDR("Invalid metadata block length");
}
}
if (priv_offset) {
if (block_end != priv_offset) {
- return OTS_FAILURE_MSG_HDR("invalid private block location");
+ return OTS_FAILURE_MSG_HDR("Invalid private block offset");
}
block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
static_cast<uint64_t>(priv_length));
if (block_end > std::numeric_limits<uint32_t>::max()) {
- return OTS_FAILURE_MSG_HDR("invalid private block size");
+ return OTS_FAILURE_MSG_HDR("Invalid private block length");
}
}
if (block_end != ots::Round4(length)) {
- return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
+ return OTS_FAILURE_MSG_HDR("File length mismatch (trailing junk?)");
}
return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
@@ -395,17 +395,17 @@
ots::OTSStream *output, const uint8_t *data, size_t length) {
size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
if (decompressed_size == 0) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 is set to 0");
}
// decompressed font must be <= 30MB
if (decompressed_size > 30 * 1024 * 1024) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG_HDR("Size of decompressed WOFF 2.0 font exceeds 30MB");
}
std::vector<uint8_t> decompressed_buffer(decompressed_size);
- if (!ots::ConvertWOFF2ToTTF(header, &decompressed_buffer[0], decompressed_size,
- data, length)) {
- return OTS_FAILURE();
+ if (!ots::ConvertWOFF2ToSFNT(header, &decompressed_buffer[0], decompressed_size,
+ data, length)) {
+ return OTS_FAILURE_MSG_HDR("Failed to convert WOFF 2.0 font to SFNT");
}
return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
}
@@ -599,8 +599,14 @@
} else {
if (!header->glyf || !header->loca) {
// No TrueType glyph found.
- // Note: bitmap-only fonts are not supported.
- return OTS_FAILURE_MSG_HDR("neither PS nor TT glyphs present");
+#define PASSTHRU_TABLE(TAG) (table_map.find(Tag(TAG)) != table_map.end() && \
+ GetTableAction(header, Tag(TAG)) == ots::TABLE_ACTION_PASSTHRU)
+ // We don't sanitise bitmap table, but don't reject bitmap-only fonts if
+ // we keep the tables.
+ if (!PASSTHRU_TABLE("CBDT") || !PASSTHRU_TABLE("CBLC")) {
+ return OTS_FAILURE_MSG_HDR("no supported glyph shapes table(s) present");
+ }
+#undef PASSTHRU_TABLE
}
}
@@ -776,9 +782,6 @@
namespace ots {
-void EnableWOFF2() {
-}
-
bool IsValidVersionTag(uint32_t tag) {
return tag == Tag("\x00\x01\x00\x00") ||
// OpenType fonts with CFF data have 'OTTO' tag.
diff --git a/third_party/ots/src/woff2.cc b/third_party/ots/src/woff2.cc
index 54ab625..b244aec 100644
--- a/third_party/ots/src/woff2.cc
+++ b/third_party/ots/src/woff2.cc
@@ -45,6 +45,7 @@
// Note that the byte order is big-endian, not the same as ots.cc
#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
+#define CHR(t) (t >> 24), (t >> 16), (t >> 8), (t >> 0)
const unsigned int kWoff2FlagsTransform = 1 << 5;
@@ -135,6 +136,10 @@
transform_length(0),
dst_offset(0),
dst_length(0) {}
+
+ bool operator<(const Table& other) const {
+ return tag < other.tag;
+ }
};
// Based on section 6.1.1 of MicroType Express draft spec
@@ -509,35 +514,38 @@
}
// Reconstruct entire glyf table based on transformed original
-bool ReconstructGlyf(const uint8_t* data, size_t data_size,
+bool ReconstructGlyf(ots::OpenTypeFile* file,
+ const uint8_t* data, size_t data_size,
uint8_t* dst, size_t dst_size,
uint8_t* loca_buf, size_t loca_size) {
static const int kNumSubStreams = 7;
- ots::Buffer file(data, data_size);
+ ots::Buffer buffer(data, data_size);
uint32_t version;
std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
- if (!file.ReadU32(&version)) {
- return OTS_FAILURE();
+ if (!buffer.ReadU32(&version)) {
+ return OTS_FAILURE_MSG("Failed to read 'version' of transformed 'glyf' table");
}
uint16_t num_glyphs;
+ if (!buffer.ReadU16(&num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to read 'numGlyphs' from transformed 'glyf' table");
+ }
uint16_t index_format;
- if (!file.ReadU16(&num_glyphs) ||
- !file.ReadU16(&index_format)) {
- return OTS_FAILURE();
+ if (!buffer.ReadU16(&index_format)) {
+ return OTS_FAILURE_MSG("Failed to read 'indexFormat' from transformed 'glyf' table");
}
unsigned int offset = (2 + kNumSubStreams) * 4;
if (offset > data_size) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Size of transformed 'glyf' table is too small to fit its data");
}
// Invariant from here on: data_size >= offset
for (int i = 0; i < kNumSubStreams; ++i) {
uint32_t substream_size;
- if (!file.ReadU32(&substream_size)) {
- return OTS_FAILURE();
+ if (!buffer.ReadU32(&substream_size)) {
+ return OTS_FAILURE_MSG("Failed to read substream size %d of transformed 'glyf' table", i);
}
if (substream_size > data_size - offset) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Size of substream %d of transformed 'glyf' table does not fit in table size");
}
substreams.at(i) = std::make_pair(data + offset, substream_size);
offset += substream_size;
@@ -560,7 +568,7 @@
size_t glyph_size = 0;
uint16_t n_contours = 0;
if (!n_contour_stream.ReadU16(&n_contours)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to read 'numberOfContours' of glyph %d from transformed 'glyf' table", i);
}
uint8_t* glyf_dst = dst + loca_offset;
size_t glyf_dst_size = dst_size - loca_offset;
@@ -570,20 +578,20 @@
uint16_t instruction_size = 0;
if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
&glyph_size, &have_instructions)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to process composite glyph %d from transformed 'glyf' table", i);
}
if (have_instructions) {
if (!Read255UShort(&glyph_stream, &instruction_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to read 'instructionLength' of glyph %d from transformed 'glyf' table", i);
}
// No integer overflow here (instruction_size < 2^16).
if (instruction_size + 2U > glyf_dst_size - glyph_size) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("'instructionLength' of glyph %d from transformed 'glyf' table does not fit in the destination glyph size", i);
}
StoreU16(glyf_dst, glyph_size, instruction_size);
if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
instruction_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to read instructions of glyph %d from transformed 'glyf' table", i);
}
glyph_size += instruction_size + 2;
}
@@ -595,11 +603,11 @@
uint16_t n_points_contour;
for (uint32_t j = 0; j < n_contours; ++j) {
if (!Read255UShort(&n_points_stream, &n_points_contour)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to read number of points of contour %d of glyph %d from transformed 'glyf' table", j, i);
}
n_points_vec.push_back(n_points_contour);
if (total_n_points + n_points_contour < total_n_points) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Negative number of points of contour %d of glyph %d from transformed 'glyf' table", j, i);
}
total_n_points += n_points_contour;
}
@@ -654,7 +662,7 @@
}
if (!StorePoints(points, n_contours, instruction_size,
glyf_dst, glyf_dst_size, &glyph_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to store points of glyph %d from the transformed 'glyf' table", i);
}
} else {
glyph_size = 0;
@@ -675,7 +683,7 @@
assert(loca_values.size() == static_cast<size_t>(num_glyphs + 1));
if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values,
dst, dst_size)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Filed to process 'bboxStream' from the transformed 'glyf' table");
}
return StoreLoca(loca_values, index_format, loca_buf, loca_size);
}
@@ -693,7 +701,8 @@
return NULL;
}
-bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
+bool ReconstructTransformed(ots::OpenTypeFile* file,
+ const std::vector<Table>& tables, uint32_t tag,
const uint8_t* transformed_buf, size_t transformed_size,
uint8_t* dst, size_t dst_length) {
if (tag == TAG('g', 'l', 'y', 'f')) {
@@ -710,7 +719,7 @@
dst_length) {
return OTS_FAILURE();
}
- return ReconstructGlyf(transformed_buf, transformed_size,
+ return ReconstructGlyf(file, transformed_buf, transformed_size,
dst + glyf_table->dst_offset, glyf_table->dst_length,
dst + loca_table->dst_offset, loca_table->dst_length);
} else if (tag == TAG('l', 'o', 'c', 'a')) {
@@ -803,18 +812,18 @@
}
uint32_t dst_length;
if (!ReadBase128(buffer, &dst_length)) {
- return OTS_FAILURE_MSG("Failed to read \"origLength\" for table %4.4s", (char*)&tag);
+ return OTS_FAILURE_MSG("Failed to read 'origLength' for table '%c%c%c%c'", CHR(tag));
}
uint32_t transform_length = dst_length;
if ((flags & kWoff2FlagsTransform) != 0) {
if (!ReadBase128(buffer, &transform_length)) {
- return OTS_FAILURE_MSG("Failed to read \"transformLength\" for table %4.4s", (char*)&tag);
+ return OTS_FAILURE_MSG("Failed to read 'transformLength' for table '%c%c%c%c'", CHR(tag));
}
}
// Disallow huge numbers (> 1GB) for sanity.
if (transform_length > 1024 * 1024 * 1024 ||
dst_length > 1024 * 1024 * 1024) {
- return OTS_FAILURE_MSG("\"origLength\" or \"transformLength\" > 1GB");
+ return OTS_FAILURE_MSG("'origLength' or 'transformLength' > 1GB");
}
table->tag = tag;
table->flags = flags;
@@ -839,9 +848,9 @@
return total_length;
}
-bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
- uint8_t* result, size_t result_length,
- const uint8_t* data, size_t length) {
+bool ConvertWOFF2ToSFNT(ots::OpenTypeFile* file,
+ uint8_t* result, size_t result_length,
+ const uint8_t* data, size_t length) {
static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2"
ots::Buffer buffer(data, length);
@@ -849,30 +858,35 @@
uint32_t flavor = 0;
if (!buffer.ReadU32(&signature) || signature != kWoff2Signature ||
!buffer.ReadU32(&flavor)) {
- return OTS_FAILURE_MSG("Failed to read \"signature\" or \"flavor\", or not WOFF2 signature");
+ return OTS_FAILURE_MSG("Failed to read 'signature' or 'flavor', or not WOFF2 signature");
}
if (!IsValidVersionTag(ntohl(flavor))) {
- return OTS_FAILURE_MSG("Invalid \"flavor\"");
+ return OTS_FAILURE_MSG("Invalid 'flavor'");
}
uint32_t reported_length;
if (!buffer.ReadU32(&reported_length) || length != reported_length) {
- return OTS_FAILURE_MSG("Failed to read \"length\" or it does not match the actual file size");
+ return OTS_FAILURE_MSG("Failed to read 'length' or it does not match the actual file size");
}
uint16_t num_tables;
if (!buffer.ReadU16(&num_tables) || !num_tables) {
- return OTS_FAILURE_MSG("Failed to read \"numTables\"");
+ return OTS_FAILURE_MSG("Failed to read 'numTables'");
}
+
+ uint16_t reserved_value;
+ if (!buffer.ReadU16(&reserved_value)) {
+ return OTS_FAILURE_MSG("Failed to read 'reserved' field");
+ }
+
// We don't care about these fields of the header:
- // uint16_t reserved
- // uint32_t total_sfnt_size
- if (!buffer.Skip(6)) {
- return OTS_FAILURE_MSG("Failed to read \"reserve\" or \"totalSfntSize\"");
+ // uint32_t total_sfnt_size, the caller already passes it as result_length
+ if (!buffer.Skip(4)) {
+ return OTS_FAILURE_MSG("Failed to read 'totalSfntSize'");
}
uint32_t compressed_length;
if (!buffer.ReadU32(&compressed_length)) {
- return OTS_FAILURE_MSG("Failed to read \"totalCompressedSize\"");
+ return OTS_FAILURE_MSG("Failed to read 'totalCompressedSize'");
}
if (compressed_length > std::numeric_limits<uint32_t>::max()) {
return OTS_FAILURE();
@@ -880,11 +894,38 @@
// We don't care about these fields of the header:
// uint16_t major_version, minor_version
- // uint32_t meta_offset, meta_length, meta_orig_length
- // uint32_t priv_offset, priv_length
- if (!buffer.Skip(24)) {
- return OTS_FAILURE();
+ if (!buffer.Skip(2 * 2)) {
+ return OTS_FAILURE_MSG("Failed to read 'majorVersion' or 'minorVersion'");
}
+
+ // Checks metadata block size.
+ uint32_t meta_offset;
+ uint32_t meta_length;
+ uint32_t meta_length_orig;
+ if (!buffer.ReadU32(&meta_offset) ||
+ !buffer.ReadU32(&meta_length) ||
+ !buffer.ReadU32(&meta_length_orig)) {
+ return OTS_FAILURE_MSG("Failed to read header metadata block fields");
+ }
+ if (meta_offset) {
+ if (meta_offset >= length || length - meta_offset < meta_length) {
+ return OTS_FAILURE_MSG("Invalid metadata block offset or length");
+ }
+ }
+
+ // Checks private data block size.
+ uint32_t priv_offset;
+ uint32_t priv_length;
+ if (!buffer.ReadU32(&priv_offset) ||
+ !buffer.ReadU32(&priv_length)) {
+ return OTS_FAILURE_MSG("Failed to read header private block fields");
+ }
+ if (priv_offset) {
+ if (priv_offset >= length || length - priv_offset < priv_length) {
+ return OTS_FAILURE_MSG("Invalid private block offset or length");
+ }
+ }
+
std::vector<Table> tables(num_tables);
if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) {
return OTS_FAILURE_MSG("Failed to read table directory");
@@ -904,8 +945,10 @@
}
dst_offset = ots::Round4(dst_offset);
}
- if (ots::Round4(compressed_offset + compressed_length) > length || dst_offset > result_length) {
- return OTS_FAILURE();
+
+ uint64_t block_end = ots::Round4(compressed_offset + compressed_length);
+ if (block_end > length || dst_offset != result_length) {
+ return OTS_FAILURE_MSG("Uncompressed sfnt size mismatch");
}
const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
@@ -913,6 +956,32 @@
return OTS_FAILURE();
}
+ if (meta_offset) {
+ if (block_end != meta_offset) {
+ return OTS_FAILURE_MSG("Invalid metadata block offset");
+ }
+ block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
+ static_cast<uint64_t>(meta_length));
+ if (block_end > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG("Invalid metadata block length");
+ }
+ }
+
+ if (priv_offset) {
+ if (block_end != priv_offset) {
+ return OTS_FAILURE_MSG("Invalid private block offset");
+ }
+ block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
+ static_cast<uint64_t>(priv_length));
+ if (block_end > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG("Invalid private block length");
+ }
+ }
+
+ if (block_end != ots::Round4(length)) {
+ return OTS_FAILURE_MSG("File length mismatch (trailing junk?)");
+ }
+
// Start building the font
size_t offset = 0;
offset = StoreU32(result, offset, flavor);
@@ -925,8 +994,13 @@
offset = StoreU16(result, offset, output_search_range);
offset = StoreU16(result, offset, max_pow2);
offset = StoreU16(result, offset, (num_tables << 4) - output_search_range);
+
+ // sort tags in the table directory in ascending alphabetical order
+ std::vector<Table> sorted_tables(tables);
+ std::sort(sorted_tables.begin(), sorted_tables.end());
+
for (uint16_t i = 0; i < num_tables; ++i) {
- const Table* table = &tables.at(i);
+ const Table* table = &sorted_tables.at(i);
offset = StoreU32(result, offset, table->tag);
offset = StoreU32(result, offset, 0); // checksum, to fill in later
offset = StoreU32(result, offset, table->dst_offset);
@@ -951,7 +1025,7 @@
const uint8_t* src_buf = data + compressed_offset;
if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
src_buf, compressed_length)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to uncompress font data");
}
transform_buf = &uncompressed_buf[0];
@@ -971,9 +1045,9 @@
std::memcpy(result + table->dst_offset, transform_buf,
transform_length);
} else {
- if (!ReconstructTransformed(tables, table->tag,
+ if (!ReconstructTransformed(file, tables, table->tag,
transform_buf, transform_length, result, result_length)) {
- return OTS_FAILURE();
+ return OTS_FAILURE_MSG("Failed to reconstruct '%c%c%c%c' table", CHR(table->tag));
}
}
@@ -983,7 +1057,7 @@
}
}
- return FixChecksums(tables, result);
+ return FixChecksums(sorted_tables, result);
}
} // namespace ots
diff --git a/third_party/ots/src/woff2.h b/third_party/ots/src/woff2.h
index 1db259a..f03f4f5 100644
--- a/third_party/ots/src/woff2.h
+++ b/third_party/ots/src/woff2.h
@@ -13,8 +13,8 @@
// Decompresses the font into the target buffer. The result_length should
// be the same as determined by ComputeFinalSize(). Returns true on successful
// decompression.
-bool ConvertWOFF2ToTTF(OpenTypeFile *file, uint8_t *result, size_t result_length,
- const uint8_t *data, size_t length);
+bool ConvertWOFF2ToSFNT(OpenTypeFile *file, uint8_t *result, size_t result_length,
+ const uint8_t *data, size_t length);
}
#endif // OTS_WOFF2_H_
diff --git a/third_party/protobuf/protobuf.gyp b/third_party/protobuf/protobuf.gyp
index 25ddbae..7417eec 100644
--- a/third_party/protobuf/protobuf.gyp
+++ b/third_party/protobuf/protobuf.gyp
@@ -29,7 +29,7 @@
],
},
}],
- ['OS=="ios" and "<(GENERATOR)"!="ninja"', {
+ ['OS=="ios" and "<(GENERATOR)"=="xcode" and "<(GENERATOR_FLAVOR)"!="ninja"', {
'variables': {
'ninja_output_dir': 'ninja-protoc',
'ninja_product_dir':
@@ -170,7 +170,7 @@
{
'target_name': 'protoc',
'conditions': [
- ['OS!="ios" or "<(GENERATOR)"=="ninja"', {
+ ['OS!="ios" or "<(GENERATOR)"!="xcode" or "<(GENERATOR_FLAVOR)"=="ninja"', {
'type': 'executable',
'toolsets': ['host'],
'sources': [
@@ -238,7 +238,7 @@
'<(config_h_dir)',
'src/src',
],
- }, { # else, OS=="ios" and "<(GENERATOR)"!="ninja"
+ }, { # else, OS=="ios" and "<(GENERATOR)"=="xcode" and "<(GENERATOR_FLAVOR)"!="ninja"
'type': 'none',
'toolsets': ['host'],
'dependencies': [
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium
index fc027b0..fdd921d 100644
--- a/third_party/qcms/README.chromium
+++ b/third_party/qcms/README.chromium
@@ -57,5 +57,7 @@
- https://code.google.com/p/chromium/issues/detail?id=443863
- Apply upstream fix reject invalid sizes from
- https://bugzilla.mozilla.org/show_bug.cgi?id=1132468
+ - lut_inverse_interp16: remove odd whitespace formatting
+ - https://code.google.com/p/chromium/issues/detail?id=458024
To regenerate google.patch:
git diff b8456f38 src > google.patch
diff --git a/third_party/qcms/google.patch b/third_party/qcms/google.patch
index dea54fc..cf8b7c2 100644
--- a/third_party/qcms/google.patch
+++ b/third_party/qcms/google.patch
@@ -1,5 +1,5 @@
diff --git a/third_party/qcms/src/iccread.c b/third_party/qcms/src/iccread.c
-index 36b7011..6cec34a 100644
+index 36b7011..208ebee 100644
--- a/third_party/qcms/src/iccread.c
+++ b/third_party/qcms/src/iccread.c
@@ -266,7 +266,7 @@ qcms_bool qcms_profile_is_bogus(qcms_profile *profile)
@@ -230,7 +230,36 @@
}
static void mAB_release(struct lutmABType *lut)
-@@ -657,7 +817,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
+@@ -540,7 +700,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag
+ // We require 3in/out channels since we only support RGB->XYZ (or RGB->LAB)
+ // XXX: If we remove this restriction make sure that the number of channels
+ // is less or equal to the maximum number of mAB curves in qcmsint.h
+- // also check for clut_size overflow.
++ // also check for clut_size overflow. Also make sure it's != 0
+ if (num_in_channels != 3 || num_out_channels != 3)
+ return NULL;
+
+@@ -570,6 +730,9 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag
+ // clut_size can not overflow since lg(256^num_in_channels) = 24 bits.
+ for (i = 0; i < num_in_channels; i++) {
+ clut_size *= read_u8(src, clut_offset + i);
++ if (clut_size == 0) {
++ invalid_source(src, "bad clut_size");
++ }
+ }
+ } else {
+ clut_size = 0;
+@@ -590,6 +753,9 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag
+
+ for (i = 0; i < num_in_channels; i++) {
+ lut->num_grid_points[i] = read_u8(src, clut_offset + i);
++ if (lut->num_grid_points[i] == 0) {
++ invalid_source(src, "bad grid_points");
++ }
+ }
+
+ // Reverse the processing of transformation elements for mBA type.
+@@ -657,7 +823,7 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
uint16_t num_input_table_entries;
uint16_t num_output_table_entries;
uint8_t in_chan, grid_points, out_chan;
@@ -239,7 +268,50 @@
uint32_t clut_size;
size_t entry_size;
struct lutType *lut;
-@@ -979,6 +1139,9 @@ qcms_profile* qcms_profile_sRGB(void)
+@@ -672,6 +838,10 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
+ } else if (type == LUT16_TYPE) {
+ num_input_table_entries = read_u16(src, offset + 48);
+ num_output_table_entries = read_u16(src, offset + 50);
++ if (num_input_table_entries == 0 || num_output_table_entries == 0) {
++ invalid_source(src, "Bad channel count");
++ return NULL;
++ }
+ entry_size = 2;
+ } else {
+ assert(0); // the caller checks that this doesn't happen
+@@ -685,15 +855,18 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
+
+ clut_size = pow(grid_points, in_chan);
+ if (clut_size > MAX_CLUT_SIZE) {
++ invalid_source(src, "CLUT too large");
+ return NULL;
+ }
+
+ if (in_chan != 3 || out_chan != 3) {
++ invalid_source(src, "CLUT only supports RGB");
+ return NULL;
+ }
+
+ lut = malloc(sizeof(struct lutType) + (num_input_table_entries * in_chan + clut_size*out_chan + num_output_table_entries * out_chan)*sizeof(float));
+ if (!lut) {
++ invalid_source(src, "CLUT too large");
+ return NULL;
+ }
+
+@@ -704,9 +877,9 @@ static struct lutType *read_tag_lutType(struct mem_source *src, struct tag_index
+
+ lut->num_input_table_entries = num_input_table_entries;
+ lut->num_output_table_entries = num_output_table_entries;
+- lut->num_input_channels = read_u8(src, offset + 8);
+- lut->num_output_channels = read_u8(src, offset + 9);
+- lut->num_clut_grid_points = read_u8(src, offset + 10);
++ lut->num_input_channels = in_chan;
++ lut->num_output_channels = out_chan;
++ lut->num_clut_grid_points = grid_points;
+ lut->e00 = read_s15Fixed16Number(src, offset+12);
+ lut->e01 = read_s15Fixed16Number(src, offset+16);
+ lut->e02 = read_s15Fixed16Number(src, offset+20);
+@@ -979,6 +1152,9 @@ qcms_profile* qcms_profile_sRGB(void)
return NO_MEM_PROFILE;
profile = qcms_profile_create_rgb_with_table(D65, Rec709Primaries, table, 1024);
@@ -249,7 +321,7 @@
free(table);
return profile;
}
-@@ -997,6 +1160,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
+@@ -997,6 +1173,9 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
source.size = size;
source.valid = true;
@@ -259,7 +331,7 @@
length = read_u32(src, 0);
if (length <= size) {
// shrink the area that we can read if appropriate
-@@ -1028,6 +1194,15 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
+@@ -1028,6 +1207,15 @@ qcms_profile* qcms_profile_from_memory(const void *mem, size_t size)
if (!src->valid || !index.tags)
goto invalid_tag_table;
@@ -275,7 +347,7 @@
if (find_tag(index, TAG_CHAD)) {
profile->chromaticAdaption = read_tag_s15Fixed16ArrayType(src, index, TAG_CHAD);
} else {
-@@ -1098,6 +1273,16 @@ invalid_profile:
+@@ -1098,6 +1286,16 @@ invalid_profile:
return INVALID_PROFILE;
}
@@ -1282,7 +1354,7 @@
qcms_bool qcms_supports_iccv4;
diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c
-index e8447e5..f4338b2 100644
+index e8447e5..f616c3f 100644
--- a/third_party/qcms/src/transform_util.c
+++ b/third_party/qcms/src/transform_util.c
@@ -36,7 +36,7 @@
@@ -1365,7 +1437,88 @@
}
struct matrix build_colorant_matrix(qcms_profile *p)
-@@ -390,7 +408,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
+@@ -295,7 +313,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
+
+ NumZeroes = 0;
+ while (LutTable[NumZeroes] == 0 && NumZeroes < length-1)
+- NumZeroes++;
++ NumZeroes++;
+
+ // There are no zeros at the beginning and we are trying to find a zero, so
+ // return anything. It seems zero would be the less destructive choice
+@@ -305,22 +323,22 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
+
+ NumPoles = 0;
+ while (LutTable[length-1- NumPoles] == 0xFFFF && NumPoles < length-1)
+- NumPoles++;
++ NumPoles++;
+
+ // Does the curve belong to this case?
+ if (NumZeroes > 1 || NumPoles > 1)
+- {
++ {
+ int a, b;
+
+- // Identify if value fall downto 0 or FFFF zone
++ // Identify if value fall downto 0 or FFFF zone
+ if (Value == 0) return 0;
+ // if (Value == 0xFFFF) return 0xFFFF;
+
+ // else restrict to valid zone
+
+- a = ((NumZeroes-1) * 0xFFFF) / (length-1);
++ a = ((NumZeroes-1) * 0xFFFF) / (length-1);
+ b = ((length-1 - NumPoles) * 0xFFFF) / (length-1);
+-
++
+ l = a - 1;
+ r = b + 1;
+ }
+@@ -332,12 +350,12 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
+
+ x = (l + r) / 2;
+
+- res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length);
++ res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length);
+
+ if (res == Value) {
+
+- // Found exact match.
+-
++ // Found exact match.
++
+ return (uint16_fract_t) (x - 1);
+ }
+
+@@ -347,14 +365,14 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
+
+ // Not found, should we interpolate?
+
+-
++
+ // Get surrounding nodes
+-
++
+ val2 = (length-1) * ((double) (x - 1) / 65535.0);
+
+ cell0 = (int) floor(val2);
+ cell1 = (int) ceil(val2);
+-
++
+ if (cell0 == cell1) return (uint16_fract_t) x;
+
+ y0 = LutTable[cell0] ;
+@@ -373,8 +391,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
+ if (f < 0.0) return (uint16_fract_t) 0;
+ if (f >= 65535.0) return (uint16_fract_t) 0xFFFF;
+
+- return (uint16_fract_t) floor(f + 0.5);
+-
++ return (uint16_fract_t) floor(f + 0.5);
+ }
+
+ /*
+@@ -390,7 +407,7 @@ uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len
which has an maximum error of about 9855 (pixel difference of ~38.346)
For now, we punt the decision of output size to the caller. */
diff --git a/third_party/qcms/src/transform_util.c b/third_party/qcms/src/transform_util.c
index f4338b2..f616c3f 100644
--- a/third_party/qcms/src/transform_util.c
+++ b/third_party/qcms/src/transform_util.c
@@ -313,7 +313,7 @@
NumZeroes = 0;
while (LutTable[NumZeroes] == 0 && NumZeroes < length-1)
- NumZeroes++;
+ NumZeroes++;
// There are no zeros at the beginning and we are trying to find a zero, so
// return anything. It seems zero would be the less destructive choice
@@ -323,22 +323,22 @@
NumPoles = 0;
while (LutTable[length-1- NumPoles] == 0xFFFF && NumPoles < length-1)
- NumPoles++;
+ NumPoles++;
// Does the curve belong to this case?
if (NumZeroes > 1 || NumPoles > 1)
- {
+ {
int a, b;
- // Identify if value fall downto 0 or FFFF zone
+ // Identify if value fall downto 0 or FFFF zone
if (Value == 0) return 0;
// if (Value == 0xFFFF) return 0xFFFF;
// else restrict to valid zone
- a = ((NumZeroes-1) * 0xFFFF) / (length-1);
+ a = ((NumZeroes-1) * 0xFFFF) / (length-1);
b = ((length-1 - NumPoles) * 0xFFFF) / (length-1);
-
+
l = a - 1;
r = b + 1;
}
@@ -350,12 +350,12 @@
x = (l + r) / 2;
- res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length);
+ res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable, length);
if (res == Value) {
- // Found exact match.
-
+ // Found exact match.
+
return (uint16_fract_t) (x - 1);
}
@@ -365,14 +365,14 @@
// Not found, should we interpolate?
-
+
// Get surrounding nodes
-
+
val2 = (length-1) * ((double) (x - 1) / 65535.0);
cell0 = (int) floor(val2);
cell1 = (int) ceil(val2);
-
+
if (cell0 == cell1) return (uint16_fract_t) x;
y0 = LutTable[cell0] ;
@@ -391,8 +391,7 @@
if (f < 0.0) return (uint16_fract_t) 0;
if (f >= 65535.0) return (uint16_fract_t) 0xFFFF;
- return (uint16_fract_t) floor(f + 0.5);
-
+ return (uint16_fract_t) floor(f + 0.5);
}
/*
diff --git a/third_party/zlib/google/zip_reader.cc b/third_party/zlib/google/zip_reader.cc
index a1dddfb..59d96da 100644
--- a/third_party/zlib/google/zip_reader.cc
+++ b/third_party/zlib/google/zip_reader.cc
@@ -23,6 +23,103 @@
namespace zip {
+namespace {
+
+// FilePathWriterDelegate ------------------------------------------------------
+
+// A writer delegate that writes a file at a given path.
+class FilePathWriterDelegate : public WriterDelegate {
+ public:
+ explicit FilePathWriterDelegate(const base::FilePath& output_file_path);
+ ~FilePathWriterDelegate() override;
+
+ // WriterDelegate methods:
+
+ // Creates the output file and any necessary intermediate directories.
+ bool PrepareOutput() override;
+
+ // Writes |num_bytes| bytes of |data| to the file, returning false if not all
+ // bytes could be written.
+ bool WriteBytes(const char* data, int num_bytes) override;
+
+ private:
+ base::FilePath output_file_path_;
+ base::File file_;
+
+ DISALLOW_COPY_AND_ASSIGN(FilePathWriterDelegate);
+};
+
+FilePathWriterDelegate::FilePathWriterDelegate(
+ const base::FilePath& output_file_path)
+ : output_file_path_(output_file_path) {
+}
+
+FilePathWriterDelegate::~FilePathWriterDelegate() {
+}
+
+bool FilePathWriterDelegate::PrepareOutput() {
+ // We can't rely on parent directory entries being specified in the
+ // zip, so we make sure they are created.
+ if (!base::CreateDirectory(output_file_path_.DirName()))
+ return false;
+
+ file_.Initialize(output_file_path_,
+ base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
+ return file_.IsValid();
+}
+
+bool FilePathWriterDelegate::WriteBytes(const char* data, int num_bytes) {
+ return num_bytes == file_.WriteAtCurrentPos(data, num_bytes);
+}
+
+
+// StringWriterDelegate --------------------------------------------------------
+
+// A writer delegate that writes no more than |max_read_bytes| to a given
+// std::string.
+class StringWriterDelegate : public WriterDelegate {
+ public:
+ StringWriterDelegate(size_t max_read_bytes, std::string* output);
+ ~StringWriterDelegate() override;
+
+ // WriterDelegate methods:
+
+ // Returns true.
+ bool PrepareOutput() override;
+
+ // Appends |num_bytes| bytes from |data| to the output string. Returns false
+ // if |num_bytes| will cause the string to exceed |max_read_bytes|.
+ bool WriteBytes(const char* data, int num_bytes) override;
+
+ private:
+ size_t max_read_bytes_;
+ std::string* output_;
+
+ DISALLOW_COPY_AND_ASSIGN(StringWriterDelegate);
+};
+
+StringWriterDelegate::StringWriterDelegate(size_t max_read_bytes,
+ std::string* output)
+ : max_read_bytes_(max_read_bytes),
+ output_(output) {
+}
+
+StringWriterDelegate::~StringWriterDelegate() {
+}
+
+bool StringWriterDelegate::PrepareOutput() {
+ return true;
+}
+
+bool StringWriterDelegate::WriteBytes(const char* data, int num_bytes) {
+ if (output_->size() + num_bytes > max_read_bytes_)
+ return false;
+ output_->append(data, num_bytes);
+ return true;
+}
+
+} // namespace
+
// TODO(satorux): The implementation assumes that file names in zip files
// are encoded in UTF-8. This is true for zip files created by Zip()
// function in zip.h, but not true for user-supplied random zip files.
@@ -187,33 +284,20 @@
return OpenCurrentEntryInZip();
}
-bool ZipReader::ExtractCurrentEntryToFilePath(
- const base::FilePath& output_file_path) {
+bool ZipReader::ExtractCurrentEntry(WriterDelegate* delegate) const {
DCHECK(zip_file_);
- // If this is a directory, just create it and return.
- if (current_entry_info()->is_directory())
- return base::CreateDirectory(output_file_path);
-
const int open_result = unzOpenCurrentFile(zip_file_);
if (open_result != UNZ_OK)
return false;
- // We can't rely on parent directory entries being specified in the
- // zip, so we make sure they are created.
- base::FilePath output_dir_path = output_file_path.DirName();
- if (!base::CreateDirectory(output_dir_path))
- return false;
-
- base::File file(output_file_path,
- base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
- if (!file.IsValid())
+ if (!delegate->PrepareOutput())
return false;
bool success = true; // This becomes false when something bad happens.
+ scoped_ptr<char[]> buf(new char[internal::kZipBufSize]);
while (true) {
- char buf[internal::kZipBufSize];
- const int num_bytes_read = unzReadCurrentFile(zip_file_, buf,
+ const int num_bytes_read = unzReadCurrentFile(zip_file_, buf.get(),
internal::kZipBufSize);
if (num_bytes_read == 0) {
// Reached the end of the file.
@@ -223,21 +307,39 @@
success = false;
break;
} else if (num_bytes_read > 0) {
- // Some data is read. Write it to the output file.
- if (num_bytes_read != file.WriteAtCurrentPos(buf, num_bytes_read)) {
+ // Some data is read.
+ if (!delegate->WriteBytes(buf.get(), num_bytes_read)) {
success = false;
break;
}
}
}
- file.Close();
unzCloseCurrentFile(zip_file_);
- if (current_entry_info()->last_modified() != base::Time::UnixEpoch())
+ return success;
+}
+
+bool ZipReader::ExtractCurrentEntryToFilePath(
+ const base::FilePath& output_file_path) const {
+ DCHECK(zip_file_);
+
+ // If this is a directory, just create it and return.
+ if (current_entry_info()->is_directory())
+ return base::CreateDirectory(output_file_path);
+
+ bool success = false;
+ {
+ FilePathWriterDelegate writer(output_file_path);
+ success = ExtractCurrentEntry(&writer);
+ }
+
+ if (success &&
+ current_entry_info()->last_modified() != base::Time::UnixEpoch()) {
base::TouchFile(output_file_path,
base::Time::Now(),
current_entry_info()->last_modified());
+ }
return success;
}
@@ -296,7 +398,7 @@
}
bool ZipReader::ExtractCurrentEntryIntoDirectory(
- const base::FilePath& output_directory_path) {
+ const base::FilePath& output_directory_path) const {
DCHECK(current_entry_info_.get());
base::FilePath output_file_path = output_directory_path.Append(
@@ -304,61 +406,29 @@
return ExtractCurrentEntryToFilePath(output_file_path);
}
-#if defined(OS_POSIX)
-bool ZipReader::ExtractCurrentEntryToFd(const int fd) {
+bool ZipReader::ExtractCurrentEntryToFile(base::File* file) const {
DCHECK(zip_file_);
- // If this is a directory, there's nothing to extract to the file descriptor,
- // so return false.
+ // If this is a directory, there's nothing to extract to the file, so return
+ // false.
if (current_entry_info()->is_directory())
return false;
- const int open_result = unzOpenCurrentFile(zip_file_);
- if (open_result != UNZ_OK)
- return false;
-
- bool success = true; // This becomes false when something bad happens.
- while (true) {
- char buf[internal::kZipBufSize];
- const int num_bytes_read = unzReadCurrentFile(zip_file_, buf,
- internal::kZipBufSize);
- if (num_bytes_read == 0) {
- // Reached the end of the file.
- break;
- } else if (num_bytes_read < 0) {
- // If num_bytes_read < 0, then it's a specific UNZ_* error code.
- success = false;
- break;
- } else if (num_bytes_read > 0) {
- // Some data is read. Write it to the output file descriptor.
- if (!base::WriteFileDescriptor(fd, buf, num_bytes_read)) {
- success = false;
- break;
- }
- }
- }
-
- unzCloseCurrentFile(zip_file_);
- return success;
+ FileWriterDelegate writer(file);
+ return ExtractCurrentEntry(&writer);
}
-#endif // defined(OS_POSIX)
-bool ZipReader::ExtractCurrentEntryToString(
- size_t max_read_bytes,
- std::string* output) const {
+bool ZipReader::ExtractCurrentEntryToString(size_t max_read_bytes,
+ std::string* output) const {
DCHECK(output);
DCHECK(zip_file_);
- DCHECK(max_read_bytes != 0);
+ DCHECK_NE(0U, max_read_bytes);
if (current_entry_info()->is_directory()) {
output->clear();
return true;
}
- const int open_result = unzOpenCurrentFile(zip_file_);
- if (open_result != UNZ_OK)
- return false;
-
// The original_size() is the best hint for the real size, so it saves
// doing reallocations for the common case when the uncompressed size is
// correct. However, we need to assume that the uncompressed size could be
@@ -368,32 +438,11 @@
static_cast<int64>(max_read_bytes),
current_entry_info()->original_size())));
- bool success = true; // This becomes false when something bad happens.
- char buf[internal::kZipBufSize];
- while (true) {
- const int num_bytes_read = unzReadCurrentFile(zip_file_, buf,
- internal::kZipBufSize);
- if (num_bytes_read == 0) {
- // Reached the end of the file.
- break;
- } else if (num_bytes_read < 0) {
- // If num_bytes_read < 0, then it's a specific UNZ_* error code.
- success = false;
- break;
- } else if (num_bytes_read > 0) {
- if (contents.size() + num_bytes_read > max_read_bytes) {
- success = false;
- break;
- }
- contents.append(buf, num_bytes_read);
- }
- }
-
- unzCloseCurrentFile(zip_file_);
- if (success)
- output->swap(contents);
-
- return success;
+ StringWriterDelegate writer(max_read_bytes, &contents);
+ if (!ExtractCurrentEntry(&writer))
+ return false;
+ output->swap(contents);
+ return true;
}
bool ZipReader::OpenInternal() {
@@ -461,5 +510,30 @@
}
}
+// FileWriterDelegate ----------------------------------------------------------
+
+FileWriterDelegate::FileWriterDelegate(base::File* file)
+ : file_(file),
+ file_length_(0) {
+}
+
+FileWriterDelegate::~FileWriterDelegate() {
+#if !defined(NDEBUG)
+ const bool success =
+#endif
+ file_->SetLength(file_length_);
+ DPLOG_IF(ERROR, !success) << "Failed updating length of written file";
+}
+
+bool FileWriterDelegate::PrepareOutput() {
+ return file_->Seek(base::File::FROM_BEGIN, 0) >= 0;
+}
+
+bool FileWriterDelegate::WriteBytes(const char* data, int num_bytes) {
+ int bytes_written = file_->WriteAtCurrentPos(data, num_bytes);
+ if (bytes_written > 0)
+ file_length_ += bytes_written;
+ return bytes_written == num_bytes;
+}
} // namespace zip
diff --git a/third_party/zlib/google/zip_reader.h b/third_party/zlib/google/zip_reader.h
index 9280f23..da6cc93 100644
--- a/third_party/zlib/google/zip_reader.h
+++ b/third_party/zlib/google/zip_reader.h
@@ -23,6 +23,21 @@
namespace zip {
+// A delegate interface used to stream out an entry; see
+// ZipReader::ExtractCurrentEntry.
+class WriterDelegate {
+ public:
+ virtual ~WriterDelegate() {}
+
+ // Invoked once before any data is streamed out to pave the way (e.g., to open
+ // the output file). Return false on failure to cancel extraction.
+ virtual bool PrepareOutput() = 0;
+
+ // Invoked to write the next chunk of data. Return false on failure to cancel
+ // extraction.
+ virtual bool WriteBytes(const char* data, int num_bytes) = 0;
+};
+
// This class is used for reading zip files. A typical use case of this
// class is to scan entries in a zip file and extract them. The code will
// look like:
@@ -141,6 +156,9 @@
// success. On failure, current_entry_info() becomes NULL.
bool LocateAndOpenEntry(const base::FilePath& path_in_zip);
+ // Extracts the current entry in chunks to |delegate|.
+ bool ExtractCurrentEntry(WriterDelegate* delegate) const;
+
// Extracts the current entry to the given output file path. If the
// current file is a directory, just creates a directory
// instead. Returns true on success. OpenCurrentEntryInZip() must be
@@ -148,7 +166,8 @@
//
// This function preserves the timestamp of the original entry. If that
// timestamp is not valid, the timestamp will be set to the current time.
- bool ExtractCurrentEntryToFilePath(const base::FilePath& output_file_path);
+ bool ExtractCurrentEntryToFilePath(
+ const base::FilePath& output_file_path) const;
// Asynchronously extracts the current entry to the given output file path.
// If the current entry is a directory it just creates the directory
@@ -174,13 +193,11 @@
// This function preserves the timestamp of the original entry. If that
// timestamp is not valid, the timestamp will be set to the current time.
bool ExtractCurrentEntryIntoDirectory(
- const base::FilePath& output_directory_path);
+ const base::FilePath& output_directory_path) const;
-#if defined(OS_POSIX)
- // Extracts the current entry by writing directly to a file descriptor.
- // Does not close the file descriptor. Returns true on success.
- bool ExtractCurrentEntryToFd(int fd);
-#endif
+ // Extracts the current entry by writing directly to a platform file.
+ // Does not close the file. Returns true on success.
+ bool ExtractCurrentEntryToFile(base::File* file) const;
// Extracts the current entry into memory. If the current entry is a directory
// the |output| parameter is set to the empty string. If the current entry is
@@ -232,6 +249,30 @@
DISALLOW_COPY_AND_ASSIGN(ZipReader);
};
+// A writer delegate that writes to a given File.
+class FileWriterDelegate : public WriterDelegate {
+ public:
+ explicit FileWriterDelegate(base::File* file);
+
+ // Truncates the file to the number of bytes written.
+ ~FileWriterDelegate() override;
+
+ // WriterDelegate methods:
+
+ // Seeks to the beginning of the file, returning false if the seek fails.
+ bool PrepareOutput() override;
+
+ // Writes |num_bytes| bytes of |data| to the file, returning false on error or
+ // if not all bytes could be written.
+ bool WriteBytes(const char* data, int num_bytes) override;
+
+ private:
+ base::File* file_;
+ int64_t file_length_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileWriterDelegate);
+};
+
} // namespace zip
#endif // THIRD_PARTY_ZLIB_GOOGLE_ZIP_READER_H_
diff --git a/third_party/zlib/google/zip_reader_unittest.cc b/third_party/zlib/google/zip_reader_unittest.cc
index d4bb579..89b4ac5 100644
--- a/third_party/zlib/google/zip_reader_unittest.cc
+++ b/third_party/zlib/google/zip_reader_unittest.cc
@@ -18,10 +18,14 @@
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/platform_test.h"
#include "third_party/zlib/google/zip_internal.h"
+using ::testing::Return;
+using ::testing::_;
+
namespace {
const static std::string kQuuxExpectedMD5 = "d1ae4ac8a17a0e09317113ab284b57a6";
@@ -47,6 +51,8 @@
base::PlatformFile platform_file() { return file_.GetPlatformFile(); }
+ base::File* file() { return &file_; }
+
private:
base::File file_;
};
@@ -93,6 +99,12 @@
int64 current_progress_;
};
+class MockWriterDelegate : public zip::WriterDelegate {
+ public:
+ MOCK_METHOD0(PrepareOutput, bool());
+ MOCK_METHOD2(WriteBytes, bool(const char*, int));
+};
+
} // namespace
namespace zip {
@@ -287,8 +299,7 @@
EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
}
-#if defined(OS_POSIX)
-TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFd_RegularFile) {
+TEST_F(ZipReaderTest, PlatformFileExtractCurrentEntryToFile_RegularFile) {
ZipReader reader;
FileWrapper zip_fd_wrapper(test_zip_file_, FileWrapper::READ_ONLY);
ASSERT_TRUE(reader.OpenFromPlatformFile(zip_fd_wrapper.platform_file()));
@@ -296,18 +307,16 @@
base::FilePath out_path = test_dir_.AppendASCII("quux.txt");
FileWrapper out_fd_w(out_path, FileWrapper::READ_WRITE);
ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
- ASSERT_TRUE(reader.ExtractCurrentEntryToFd(out_fd_w.platform_file()));
+ ASSERT_TRUE(reader.ExtractCurrentEntryToFile(out_fd_w.file()));
// Read the output file and compute the MD5.
std::string output;
- ASSERT_TRUE(base::ReadFileToString(test_dir_.AppendASCII("quux.txt"),
- &output));
+ ASSERT_TRUE(base::ReadFileToString(out_path, &output));
const std::string md5 = base::MD5String(output);
EXPECT_EQ(kQuuxExpectedMD5, md5);
// quux.txt should be larger than kZipBufSize so that we can exercise
// the loop in ExtractCurrentEntry().
EXPECT_LT(static_cast<size_t>(internal::kZipBufSize), output.size());
}
-#endif
TEST_F(ZipReaderTest, ExtractCurrentEntryToFilePath_Directory) {
ZipReader reader;
@@ -582,4 +591,97 @@
}
}
+// Test that when WriterDelegate::PrepareMock returns false, no other methods on
+// the delegate are called and the extraction fails.
+TEST_F(ZipReaderTest, ExtractCurrentEntryPrepareFailure) {
+ testing::StrictMock<MockWriterDelegate> mock_writer;
+
+ EXPECT_CALL(mock_writer, PrepareOutput())
+ .WillOnce(Return(false));
+
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ZipReader reader;
+
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
+}
+
+// Test that when WriterDelegate::WriteBytes returns false, no other methods on
+// the delegate are called and the extraction fails.
+TEST_F(ZipReaderTest, ExtractCurrentEntryWriteBytesFailure) {
+ testing::StrictMock<MockWriterDelegate> mock_writer;
+
+ EXPECT_CALL(mock_writer, PrepareOutput())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_writer, WriteBytes(_, _))
+ .WillOnce(Return(false));
+
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ZipReader reader;
+
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_FALSE(reader.ExtractCurrentEntry(&mock_writer));
+}
+
+// Test that extraction succeeds when the writer delegate reports all is well.
+TEST_F(ZipReaderTest, ExtractCurrentEntrySuccess) {
+ testing::StrictMock<MockWriterDelegate> mock_writer;
+
+ EXPECT_CALL(mock_writer, PrepareOutput())
+ .WillOnce(Return(true));
+ EXPECT_CALL(mock_writer, WriteBytes(_, _))
+ .WillRepeatedly(Return(true));
+
+ base::FilePath target_path(FILE_PATH_LITERAL("foo/bar/quux.txt"));
+ ZipReader reader;
+
+ ASSERT_TRUE(reader.Open(test_zip_file_));
+ ASSERT_TRUE(reader.LocateAndOpenEntry(target_path));
+ ASSERT_TRUE(reader.ExtractCurrentEntry(&mock_writer));
+}
+
+class FileWriterDelegateTest : public ::testing::Test {
+ protected:
+ void SetUp() override {
+ ASSERT_TRUE(base::CreateTemporaryFile(&temp_file_path_));
+ file_.Initialize(temp_file_path_, (base::File::FLAG_CREATE_ALWAYS |
+ base::File::FLAG_READ |
+ base::File::FLAG_WRITE |
+ base::File::FLAG_TEMPORARY |
+ base::File::FLAG_DELETE_ON_CLOSE));
+ ASSERT_TRUE(file_.IsValid());
+ }
+
+ // Writes data to the file, leaving the current position at the end of the
+ // write.
+ void PopulateFile() {
+ static const char kSomeData[] = "this sure is some data.";
+ static const size_t kSomeDataLen = sizeof(kSomeData) - 1;
+ ASSERT_NE(-1LL, file_.Write(0LL, kSomeData, kSomeDataLen));
+ }
+
+ base::FilePath temp_file_path_;
+ base::File file_;
+};
+
+TEST_F(FileWriterDelegateTest, WriteToStartAndTruncate) {
+ // Write stuff and advance.
+ PopulateFile();
+
+ // This should rewind, write, then truncate.
+ static const char kSomeData[] = "short";
+ static const int kSomeDataLen = sizeof(kSomeData) - 1;
+ {
+ FileWriterDelegate writer(&file_);
+ ASSERT_TRUE(writer.PrepareOutput());
+ ASSERT_TRUE(writer.WriteBytes(kSomeData, kSomeDataLen));
+ }
+ ASSERT_EQ(kSomeDataLen, file_.GetLength());
+ char buf[kSomeDataLen] = {};
+ ASSERT_EQ(kSomeDataLen, file_.Read(0LL, buf, kSomeDataLen));
+ ASSERT_EQ(std::string(kSomeData), std::string(buf, kSomeDataLen));
+}
+
} // namespace zip
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 2cc6958..7c4a214 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -24,7 +24,7 @@
# in bringup. Use a pinned revision to make it slightly more stable.
if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and
not 'LLVM_FORCE_HEAD_REVISION' in os.environ):
- LLVM_WIN_REVISION = '231949'
+ LLVM_WIN_REVISION = '232554'
# Path constants. (All of these should be absolute paths.)
THIS_DIR = os.path.abspath(os.path.dirname(__file__))
diff --git a/tools/idl_parser/idl_parser.py b/tools/idl_parser/idl_parser.py
index bdd6dc7..27b1914 100755
--- a/tools/idl_parser/idl_parser.py
+++ b/tools/idl_parser/idl_parser.py
@@ -273,6 +273,7 @@
def p_InterfaceMember(self, p):
"""InterfaceMember : Const
| Operation
+ | Serializer
| Stringifier
| StaticMember
| Iterable
@@ -467,7 +468,74 @@
p[0] = ListFromConcat(self.BuildAttribute('TYPE', 'float'),
self.BuildAttribute('VALUE', val))
- # [30-34] NOT IMPLEMENTED (Serializer)
+ # [30]
+ def p_Serializer(self, p):
+ """Serializer : SERIALIZER SerializerRest"""
+ p[0] = self.BuildProduction('Serializer', p, 1, p[2])
+
+ # [31]
+ # TODO(jl): This adds ReturnType and ';', missing from the spec's grammar.
+ # https://www.w3.org/Bugs/Public/show_bug.cgi?id=20361
+ def p_SerializerRest(self, p):
+ """SerializerRest : ReturnType OperationRest
+ | '=' SerializationPattern ';'
+ | ';'"""
+ if len(p) == 3:
+ p[2].AddChildren(p[1])
+ p[0] = p[2]
+ elif len(p) == 4:
+ p[0] = p[2]
+
+ # [32]
+ def p_SerializationPattern(self, p):
+ """SerializationPattern : '{' SerializationPatternMap '}'
+ | '[' SerializationPatternList ']'
+ | identifier"""
+ if len(p) > 2:
+ p[0] = p[2]
+ else:
+ p[0] = self.BuildAttribute('ATTRIBUTE', p[1])
+
+ # [33]
+ # TODO(jl): This adds the "ATTRIBUTE" and "INHERIT ',' ATTRIBUTE" variants,
+ # missing from the spec's grammar.
+ # https://www.w3.org/Bugs/Public/show_bug.cgi?id=20361
+ def p_SerializationPatternMap(self, p):
+ """SerializationPatternMap : GETTER
+ | ATTRIBUTE
+ | INHERIT ',' ATTRIBUTE
+ | INHERIT Identifiers
+ | identifier Identifiers
+ |"""
+ p[0] = self.BuildProduction('Map', p, 0)
+ if len(p) == 4:
+ p[0].AddChildren(self.BuildTrue('INHERIT'))
+ p[0].AddChildren(self.BuildTrue('ATTRIBUTE'))
+ elif len(p) > 1:
+ if p[1] == 'getter':
+ p[0].AddChildren(self.BuildTrue('GETTER'))
+ elif p[1] == 'attribute':
+ p[0].AddChildren(self.BuildTrue('ATTRIBUTE'))
+ else:
+ if p[1] == 'inherit':
+ p[0].AddChildren(self.BuildTrue('INHERIT'))
+ attributes = p[2]
+ else:
+ attributes = ListFromConcat(p[1], p[2])
+ p[0].AddChildren(self.BuildAttribute('ATTRIBUTES', attributes))
+
+ # [34]
+ def p_SerializationPatternList(self, p):
+ """SerializationPatternList : GETTER
+ | identifier Identifiers
+ |"""
+ p[0] = self.BuildProduction('List', p, 0)
+ if len(p) > 1:
+ if p[1] == 'getter':
+ p[0].AddChildren(self.BuildTrue('GETTER'))
+ else:
+ attributes = ListFromConcat(p[1], p[2])
+ p[0].AddChildren(self.BuildAttribute('ATTRIBUTES', attributes))
# [35]
def p_Stringifier(self, p):
diff --git a/tools/idl_parser/test_parser/interface_web.idl b/tools/idl_parser/test_parser/interface_web.idl
index b1f3278..90b0e83 100644
--- a/tools/idl_parser/test_parser/interface_web.idl
+++ b/tools/idl_parser/test_parser/interface_web.idl
@@ -323,3 +323,49 @@
readonly setlike<long>;
setlike<double>;
};
+
+/* TREE
+ *Interface(MyIfaceSerializer)
+ * Serializer()
+ * Serializer()
+ * Operation(toJSON)
+ * Arguments()
+ * Type()
+ * Any()
+ * Serializer()
+ * Serializer()
+ * Map()
+ * Serializer()
+ * Map()
+ * Serializer()
+ * Map()
+ * Serializer()
+ * Map()
+ * Serializer()
+ * Map()
+ * Serializer()
+ * Map()
+ * Serializer()
+ * Map()
+ * Serializer()
+ * List()
+ * Serializer()
+ * List()
+ * Serializer()
+ * List()
+ */
+interface MyIfaceSerializer {
+ serializer;
+ serializer any toJSON();
+ serializer = name;
+ serializer = {};
+ serializer = { getter };
+ serializer = { attribute };
+ serializer = { inherit, attribute };
+ serializer = { inherit };
+ serializer = { inherit, name1, name2 };
+ serializer = { name1, name2 };
+ serializer = [];
+ serializer = [getter];
+ serializer = [name1, name2];
+};
diff --git a/tools/valgrind/asan/asan_symbolize.py b/tools/valgrind/asan/asan_symbolize.py
index 898edf4..0107406 100755
--- a/tools/valgrind/asan/asan_symbolize.py
+++ b/tools/valgrind/asan/asan_symbolize.py
@@ -246,9 +246,6 @@
disable_buffering()
set_symbolizer_path()
- # Disallow fallback to addr2line/atos if llvm-symbolizer is not present. Those
- # are slow and we don't want to use them ever.
- asan_symbolize.allow_system_symbolizer = False
asan_symbolize.demangle = True
asan_symbolize.fix_filename_patterns = args.strip_path_prefix
# Most source paths for Chromium binaries start with
diff --git a/tools/valgrind/asan/third_party/README.chromium b/tools/valgrind/asan/third_party/README.chromium
index 63a1761..5c363ea 100644
--- a/tools/valgrind/asan/third_party/README.chromium
+++ b/tools/valgrind/asan/third_party/README.chromium
@@ -1,6 +1,6 @@
Name: asan_symbolize.py
License: University of Illinois Open Source License.
-Version: r231492
+Version: r227327
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/scripts/asan_symbolize.py?view=co&content-type=text%2Fplain
Security Critical: no
diff --git a/tools/valgrind/asan/third_party/asan_symbolize.py b/tools/valgrind/asan/third_party/asan_symbolize.py
index b9d3ad3..59fceaa 100755
--- a/tools/valgrind/asan/third_party/asan_symbolize.py
+++ b/tools/valgrind/asan/third_party/asan_symbolize.py
@@ -23,7 +23,6 @@
binary_name_filter = None
fix_filename_patterns = None
logfile = sys.stdin
-allow_system_symbolizer = True
# FIXME: merge the code that calls fix_filename().
def fix_filename(file_name):
@@ -393,8 +392,6 @@
[BreakpadSymbolizerFactory(binary), self.llvm_symbolizers[binary]])
result = symbolizers[binary].symbolize(addr, binary, offset)
if result is None:
- if not allow_system_symbolizer:
- raise Exception('Failed to launch or use llvm-symbolizer.')
# Initialize system symbolizer only if other symbolizers failed.
symbolizers[binary].append_symbolizer(
SystemSymbolizerFactory(self.system, addr, binary))
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index dfe57e2..81fcb31 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1900,3 +1900,26 @@
*!std::char_traits<>::compare
...
*!*::*URLRequest*::TestBody
+
+UNINITIALIZED READ
+name=bug_468169
+...
+*!vp9_foreach_transformed_block_in_plane
+...
+*!encode_superblock
+*!encode_b_rt
+*!encode_sb_rt
+*!encode_sb_rt
+*!encode_sb_rt
+*!encode_sb_rt
+*!nonrd_select_partition
+*!encode_nonrd_sb_row
+*!vp9_encode_tile
+
+UNINITIALIZED READ
+name=bug_468638
+*!egl::ConfigSorter::operator()
+*!std::_Insertion_sort1<>
+*!std::_Sort<>
+*!egl::ConfigSet::filter
+*!ConfigSetTest_*_BitSizes_Test::TestBody
diff --git a/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt b/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt
index 5abd383..337b367 100644
--- a/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt
+++ b/tools/valgrind/gtest_exclude/browser_tests.gtest-memcheck.txt
@@ -43,8 +43,6 @@
NewTabUIBrowserTest.LoadNTPInExistingProcess
OutOfProcessPPAPITest.NetAddressPrivate_GetAnyAddress
OutOfProcessPPAPITest.NetAddressPrivate_ReplacePort
-PageCyclerCachedBrowserTest.PlaybackMode
-PageCyclerCachedBrowserTest.URLNotInCache
PPAPITest.ImeInputEvent
PrerenderBrowserTest.*
PrerenderBrowserTestWithNaCl.PrerenderNaClPluginEnabled
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 121f26b..4374a72 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -2151,6 +2151,7 @@
fun:_ZN3WTF9BitVector15resizeOutOfLineEm
fun:_ZN3WTF9BitVector10ensureSizeEm
fun:_ZN3WTF9BitVectorC*
+ ...
fun:_ZN5blink10UseCounter17recordMeasurementENS0_7FeatureE
}
{
@@ -3350,7 +3351,6 @@
fun:_ZNK8SkBitmap12copyPixelsToEPvmmb
fun:_ZN5blink19ImageFrameGenerator14decodeAndScaleERK11SkImageInfomPvm
fun:_ZN5blink22DecodingImageGenerator11onGetPixelsERK11SkImageInfoPvmPjPi
- fun:_ZN16SkImageGenerator9getPixelsERK11SkImageInfoPvmPjPi
}
{
bug_424056a
@@ -3628,6 +3628,7 @@
bug_455732
Memcheck:Leak
fun:_Znw*
+ ...
fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16ScopedHandleBaseINS_17MessagePipeHandleEEEPK15MojoAsyncWaiter
fun:_ZN4mojo7BindingINS_15ServiceProviderEE4BindENS_16InterfaceRequestIS1_EEPK15MojoAsyncWaiter
fun:_ZN7content19ServiceRegistryImpl4BindEN4mojo16InterfaceRequestINS1_15ServiceProviderEEE
diff --git a/ui/gl/BUILD.gn b/ui/gl/BUILD.gn
index 12a44cc..ae1132e 100644
--- a/ui/gl/BUILD.gn
+++ b/ui/gl/BUILD.gn
@@ -183,6 +183,8 @@
}
if (is_win) {
sources += [
+ "angle_platform_impl.cc",
+ "angle_platform_impl.h",
"gl_bindings_autogen_wgl.cc",
"gl_bindings_autogen_wgl.h",
"gl_context_wgl.cc",
diff --git a/ui/gl/DEPS b/ui/gl/DEPS
index 862c555..e582c0d 100644
--- a/ui/gl/DEPS
+++ b/ui/gl/DEPS
@@ -12,5 +12,9 @@
# get access to desktop OpenGL.
"gl_surface_osmesa.cc": [
"+third_party/mesa/src/include/GL/osmesa.h",
- ]
+ ],
+# Allow us to include ANGLE's base platform implementation.
+ "angle_platform_impl.h": [
+ "+third_party/angle/include/platform/Platform.h",
+ ],
}
diff --git a/ui/gl/angle_platform_impl.cc b/ui/gl/angle_platform_impl.cc
new file mode 100644
index 0000000..2ce12b8
--- /dev/null
+++ b/ui/gl/angle_platform_impl.cc
@@ -0,0 +1,50 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ui/gl/angle_platform_impl.h"
+
+#include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
+
+namespace gfx {
+
+ANGLEPlatformImpl::ANGLEPlatformImpl() {
+}
+
+ANGLEPlatformImpl::~ANGLEPlatformImpl() {
+}
+
+void ANGLEPlatformImpl::histogramCustomCounts(const char* name,
+ int sample,
+ int min,
+ int max,
+ int bucket_count) {
+ // Copied from histogram macro, but without the static variable caching
+ // the histogram because name is dynamic.
+ base::HistogramBase* counter = base::Histogram::FactoryGet(
+ name, min, max, bucket_count,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ DCHECK_EQ(name, counter->histogram_name());
+ counter->Add(sample);
+}
+
+void ANGLEPlatformImpl::histogramEnumeration(const char* name,
+ int sample,
+ int boundary_value) {
+ // Copied from histogram macro, but without the static variable caching
+ // the histogram because name is dynamic.
+ base::HistogramBase* counter = base::LinearHistogram::FactoryGet(
+ name, 1, boundary_value, boundary_value + 1,
+ base::HistogramBase::kUmaTargetedHistogramFlag);
+ DCHECK_EQ(name, counter->histogram_name());
+ counter->Add(sample);
+}
+
+void ANGLEPlatformImpl::histogramSparse(const char* name, int sample) {
+ // For sparse histograms, we can use the macro, as it does not incorporate a
+ // static.
+ UMA_HISTOGRAM_SPARSE_SLOWLY(name, sample);
+}
+
+} // namespace gfx
diff --git a/ui/gl/angle_platform_impl.h b/ui/gl/angle_platform_impl.h
new file mode 100644
index 0000000..2d12f60
--- /dev/null
+++ b/ui/gl/angle_platform_impl.h
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_GL_ANGLE_PLATFORM_IMPL_H_
+#define UI_GL_ANGLE_PLATFORM_IMPL_H_
+
+// Implements the ANGLE platform interface, for functionality like
+// histograms and trace profiling.
+
+#include "base/macros.h"
+#include "third_party/angle/include/platform/Platform.h"
+
+namespace gfx {
+
+// Derives the base ANGLE platform and provides implementations
+class ANGLEPlatformImpl : public angle::Platform {
+ public:
+ ANGLEPlatformImpl();
+ ~ANGLEPlatformImpl() override;
+
+ // angle::Platform:
+ void histogramCustomCounts(const char* name,
+ int sample,
+ int min,
+ int max,
+ int bucket_count) override;
+ void histogramEnumeration(const char* name,
+ int sample,
+ int boundary_value) override;
+ void histogramSparse(const char* name, int sample) override;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ANGLEPlatformImpl);
+};
+
+} // namespace gfx
+
+#endif // UI_GL_ANGLE_PLATFORM_IMPL_H_
diff --git a/ui/gl/gl.gyp b/ui/gl/gl.gyp
index 0538107..d11014b 100644
--- a/ui/gl/gl.gyp
+++ b/ui/gl/gl.gyp
@@ -186,6 +186,8 @@
}],
['OS=="win"', {
'sources': [
+ 'angle_platform_impl.cc',
+ 'angle_platform_impl.h',
'gl_bindings_autogen_wgl.cc',
'gl_bindings_autogen_wgl.h',
'gl_context_wgl.cc',
diff --git a/ui/gl/gl_implementation_win.cc b/ui/gl/gl_implementation_win.cc
index 477f5a5..49ffa89 100644
--- a/ui/gl/gl_implementation_win.cc
+++ b/ui/gl/gl_implementation_win.cc
@@ -9,6 +9,7 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/files/file_path.h"
+#include "base/lazy_instance.h"
#include "base/logging.h"
#include "base/native_library.h"
#include "base/path_service.h"
@@ -16,6 +17,8 @@
#include "base/threading/thread_restrictions.h"
#include "base/trace_event/trace_event.h"
#include "base/win/windows_version.h"
+// TODO(jmadill): Apply to all platforms eventually
+#include "ui/gl/angle_platform_impl.h"
#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context_stub_with_extensions.h"
#include "ui/gl/gl_egl_api_implementation.h"
@@ -97,6 +100,12 @@
GetCategoryEnabledFlagFunc get_category_enabled_flag,
AddTraceEventFunc add_trace_event_func);
+// TODO(jmadill): Apply to all platforms eventually
+base::LazyInstance<ANGLEPlatformImpl> g_angle_platform_impl =
+ LAZY_INSTANCE_INITIALIZER;
+
+ANGLEPlatformShutdownFunc g_angle_platform_shutdown = nullptr;
+
} // namespace
void GetAllowedGLImplementations(std::vector<GLImplementation>* impls) {
@@ -204,6 +213,7 @@
#endif
if (!using_swift_shader) {
+ // TODO(jmadill): remove when platform impl supports tracing
SetTraceFunctionPointersFunc set_trace_function_pointers =
reinterpret_cast<SetTraceFunctionPointersFunc>(
base::GetFunctionPointerFromNativeLibrary(
@@ -212,6 +222,23 @@
set_trace_function_pointers(&AngleGetTraceCategoryEnabledFlag,
&AngleAddTraceEvent);
}
+
+ // Init ANGLE platform here, before we call GetPlatformDisplay().
+ // TODO(jmadill): Apply to all platforms eventually
+ ANGLEPlatformInitializeFunc angle_platform_init =
+ reinterpret_cast<ANGLEPlatformInitializeFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ gles_library,
+ "ANGLEPlatformInitialize"));
+ if (angle_platform_init) {
+ angle_platform_init(&g_angle_platform_impl.Get());
+
+ g_angle_platform_shutdown =
+ reinterpret_cast<ANGLEPlatformShutdownFunc>(
+ base::GetFunctionPointerFromNativeLibrary(
+ gles_library,
+ "ANGLEPlatformShutdown"));
+ }
}
GLGetProcAddressProc get_proc_address =
@@ -348,6 +375,11 @@
}
void ClearGLBindings() {
+ // TODO(jmadill): Apply to all platforms eventually
+ if (g_angle_platform_shutdown) {
+ g_angle_platform_shutdown();
+ }
+
ClearGLBindingsEGL();
ClearGLBindingsGL();
ClearGLBindingsOSMESA();