Update from chromium a8e7c94b1b79a0948d05a1fcfff53391d22ce37a
Review URL: https://codereview.chromium.org/664803003
diff --git a/DEPS b/DEPS
index 6740daf..de6d2fe 100644
--- a/DEPS
+++ b/DEPS
@@ -30,16 +30,16 @@
'skia_git': 'https://skia.googlesource.com',
'boringssl_git': 'https://boringssl.googlesource.com',
'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
- 'skia_revision': 'dd5a1e094c19fa10202c37c50a1f799e5af5dac0',
+ 'skia_revision': '22b5ab644e0381e672c6fcf8aff26bf82ee71989',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Skia
# and V8 without interference from each other.
'v8_branch': 'trunk',
- 'v8_revision': '233fccf1872781e1f8ac2314511de15ca7a232ad', # from svn revision 24772
+ 'v8_revision': 'b404893cc89fe7419e614abccb1fddf69d308abc', # from svn revision 24791
# 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": "8e92923010c568a445c0f22e1a36f462fcabc8f3",
+ "angle_revision": "d2f756be4fd198d630b64dc6c3568184363e6d14",
# 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.
@@ -79,7 +79,7 @@
Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'),
'src/third_party/icu':
- Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + '8ac906faf7b66180f2208380c35ae1e07136c5cc', # from svn revision 292317
+ Var('chromium_git') + '/chromium/deps/icu52.git' + '@' + 'd8b2a9d7b0039a4950ee008c5b1d998902c44c60', # from svn revision 292476
'src/third_party/libc++/trunk':
Var('chromium_git') + '/chromium/llvm-project/libcxx.git' + '@' + Var('libcxx_revision'),
diff --git a/base/PRESUBMIT.py b/base/PRESUBMIT.py
index 758a790..4e9e64b 100644
--- a/base/PRESUBMIT.py
+++ b/base/PRESUBMIT.py
@@ -8,10 +8,6 @@
for more details on the presubmit API built into gcl.
"""
-import re
-
-BASE_SOURCE_FILES=(r'^base/.*\.(cc|h|mm)$',)
-
def _CheckNoInterfacesInBase(input_api, output_api):
"""Checks to make sure no files in libbase.a have |@interface|."""
pattern = input_api.re.compile(r'^\s*@interface', input_api.re.MULTILINE)
@@ -40,45 +36,8 @@
results.extend(_CheckNoInterfacesInBase(input_api, output_api))
return results
-def _CheckOverrideFinal(input_api, output_api,
- whitelist=BASE_SOURCE_FILES, blacklist=None):
- """Make sure new lines of code don't use the OVERRIDE or FINAL macros."""
-
- # TODO(mostynb): remove this check once the macros are removed
- # from base/compiler_specific.h.
-
- errors = []
-
- source_file_filter = lambda x: input_api.FilterSourceFile(
- x, white_list=BASE_SOURCE_FILES, black_list=None)
-
- override_files = []
- final_files = []
-
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
-
- # "override" and "final" should be used instead of OVERRIDE/FINAL now.
- if re.search(r"\bOVERRIDE\b", contents):
- override_files.append(f.LocalPath())
-
- if re.search(r"\bFINAL\b", contents):
- final_files.append(f.LocalPath())
-
- if override_files:
- return [output_api.PresubmitError(
- 'These files use OVERRIDE instead of using override:',
- items=override_files)]
- if final_files:
- return [output_api.PresubmitError(
- 'These files use FINAL instead of using final:',
- items=final_files)]
-
- return []
-
def CheckChangeOnUpload(input_api, output_api):
results = []
- results.extend(_CheckOverrideFinal(input_api, output_api))
results.extend(_CommonChecks(input_api, output_api))
return results
@@ -92,12 +51,12 @@
def GetPreferredTryMasters(project, change):
return {
'tryserver.chromium.linux': {
- 'linux_chromium_rel_swarming': set(['defaulttests']),
+ 'linux_chromium_rel': set(['defaulttests']),
},
'tryserver.chromium.mac': {
- 'mac_chromium_rel_swarming': set(['defaulttests']),
+ 'mac_chromium_rel': set(['defaulttests']),
},
'tryserver.chromium.win': {
- 'win_chromium_rel_swarming': set(['defaulttests']),
+ 'win_chromium_rel': set(['defaulttests']),
}
}
diff --git a/base/basictypes.h b/base/basictypes.h
index 12d4c97..bf75e67 100644
--- a/base/basictypes.h
+++ b/base/basictypes.h
@@ -22,24 +22,11 @@
typedef int8_t int8;
typedef uint8_t uint8;
typedef int16_t int16;
-typedef int32_t int32;
typedef uint16_t uint16;
+typedef int32_t int32;
typedef uint32_t uint32;
-
-// TODO(vtl): Figure what's up with the 64-bit types. Can we just define them as
-// |int64_t|/|uint64_t|?
-// The NSPR system headers define 64-bit as |long| when possible, except on
-// Mac OS X. In order to not have typedef mismatches, we do the same on LP64.
-//
-// On Mac OS X, |long long| is used for 64-bit types for compatibility with
-// <inttypes.h> format macros even in the LP64 model.
-#if defined(__LP64__) && !defined(OS_MACOSX) && !defined(OS_OPENBSD)
-typedef long int64;
-typedef unsigned long uint64;
-#else
-typedef long long int64;
-typedef unsigned long long uint64;
-#endif
+typedef int64_t int64;
+typedef uint64_t uint64;
// DEPRECATED: Please use std::numeric_limits (from <limits>) instead.
const uint8 kuint8max = 0xFF;
diff --git a/base/compiler_specific.h b/base/compiler_specific.h
index 6210d1a..47ca977 100644
--- a/base/compiler_specific.h
+++ b/base/compiler_specific.h
@@ -139,12 +139,6 @@
#define ALIGNOF(type) __alignof__(type)
#endif
-// Annotate a virtual method indicating it must be overriding a virtual
-// method in the parent class.
-// Use like:
-// virtual void foo() OVERRIDE;
-#define OVERRIDE override
-
// Annotate a function indicating the caller must examine the return value.
// Use like:
// int foo() WARN_UNUSED_RESULT;
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index fb5ba62..4078920 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -105,25 +105,25 @@
bool is_dir);
protected:
- virtual ~FilePathWatcherImpl() {}
+ ~FilePathWatcherImpl() override {}
private:
// Start watching |path| for changes and notify |delegate| on each change.
// Returns true if watch for |path| has been added successfully.
- virtual bool Watch(const FilePath& path,
- bool recursive,
- const FilePathWatcher::Callback& callback) override;
+ bool Watch(const FilePath& path,
+ bool recursive,
+ const FilePathWatcher::Callback& callback) override;
// Cancel the watch. This unregisters the instance with InotifyReader.
- virtual void Cancel() override;
+ void Cancel() override;
// Cleans up and stops observing the message_loop() thread.
- virtual void CancelOnMessageLoopThread() override;
+ void CancelOnMessageLoopThread() override;
// Deletion of the FilePathWatcher will call Cancel() to dispose of this
// object in the right thread. This also observes destruction of the required
// cleanup thread, in case it quits before Cancel() is called.
- virtual void WillDestroyCurrentMessageLoop() override;
+ void WillDestroyCurrentMessageLoop() override;
// Inotify watches are installed for all directory components of |target_|. A
// WatchEntry instance holds the watch descriptor for a component and the
diff --git a/base/i18n/icu_string_conversions_unittest.cc b/base/i18n/icu_string_conversions_unittest.cc
index 107e240..d4d3251 100644
--- a/base/i18n/icu_string_conversions_unittest.cc
+++ b/base/i18n/icu_string_conversions_unittest.cc
@@ -343,7 +343,8 @@
{"foo-\xe4.html", "iso-8859-1", true, "foo-\xc3\xa4.html"},
{"foo-\xe4.html", "iso-8859-7", true, "foo-\xce\xb4.html"},
{"foo-\xe4.html", "foo-bar", false, ""},
- {"foo-\xff.html", "ascii", false, ""},
+ // HTML Encoding spec treats US-ASCII as synonymous with windows-1252
+ {"foo-\xff.html", "ascii", true, "foo-\xc3\xbf.html"},
{"foo.html", "ascii", true, "foo.html"},
{"foo-a\xcc\x88.html", "utf-8", true, "foo-\xc3\xa4.html"},
{"\x95\x32\x82\x36\xD2\xBB", "gb18030", true, "\xF0\xA0\x80\x80\xE4\xB8\x80"},
diff --git a/base/memory/scoped_ptr.h b/base/memory/scoped_ptr.h
index f3bbd12..ae9eb0f 100644
--- a/base/memory/scoped_ptr.h
+++ b/base/memory/scoped_ptr.h
@@ -73,16 +73,6 @@
//
// scoped_ptr<Foo> foo(new Foo());
// scoped_ptr<FooParent> parent(foo.Pass());
-//
-// PassAs<>() should be used to upcast return value in return statement:
-//
-// scoped_ptr<Foo> CreateFoo() {
-// scoped_ptr<FooChild> result(new FooChild());
-// return result.PassAs<Foo>();
-// }
-//
-// Note that PassAs<>() is implemented only for scoped_ptr<T>, but not for
-// scoped_ptr<T[]>. This is because casting array pointers may not be safe.
#ifndef BASE_MEMORY_SCOPED_PTR_H_
#define BASE_MEMORY_SCOPED_PTR_H_
@@ -436,17 +426,6 @@
return impl_.release();
}
- // C++98 doesn't support functions templates with default parameters which
- // makes it hard to write a PassAs() that understands converting the deleter
- // while preserving simple calling semantics.
- //
- // Until there is a use case for PassAs() with custom deleters, just ignore
- // the custom deleter.
- template <typename PassAsType>
- scoped_ptr<PassAsType> PassAs() {
- return scoped_ptr<PassAsType>(Pass());
- }
-
private:
// Needed to reach into |impl_| in the constructor.
template <typename U, typename V> friend class scoped_ptr;
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 6af19b6..3f169a7 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -94,11 +94,6 @@
return scoped_ptr<ConDecLogger>(new ConDecLogger(constructed));
}
-scoped_ptr<ConDecLoggerParent> UpcastUsingPassAs(
- scoped_ptr<ConDecLogger> object) {
- return object.PassAs<ConDecLoggerParent>();
-}
-
} // namespace
TEST(ScopedPtrTest, ScopedPtr) {
@@ -462,22 +457,6 @@
EXPECT_EQ(0, constructed);
}
-TEST(ScopedPtrTest, PassAs) {
- int constructed = 0;
- {
- scoped_ptr<ConDecLogger> scoper(new ConDecLogger(&constructed));
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper.get());
-
- scoped_ptr<ConDecLoggerParent> scoper_parent;
- scoper_parent = UpcastUsingPassAs(scoper.Pass());
- EXPECT_EQ(1, constructed);
- EXPECT_TRUE(scoper_parent.get());
- EXPECT_FALSE(scoper.get());
- }
- EXPECT_EQ(0, constructed);
-}
-
TEST(ScopedPtrTest, CustomDeleter) {
double dummy_value; // Custom deleter never touches this value.
int deletes = 0;
diff --git a/base/memory/weak_ptr.h b/base/memory/weak_ptr.h
index f6001e2..8a43392 100644
--- a/base/memory/weak_ptr.h
+++ b/base/memory/weak_ptr.h
@@ -48,17 +48,18 @@
// ------------------------- IMPORTANT: Thread-safety -------------------------
// Weak pointers may be passed safely between threads, but must always be
-// dereferenced and invalidated on the same thread otherwise checking the
-// pointer would be racey.
+// dereferenced and invalidated on the same SequencedTaskRunner otherwise
+// checking the pointer would be racey.
//
// To ensure correct use, the first time a WeakPtr issued by a WeakPtrFactory
// is dereferenced, the factory and its WeakPtrs become bound to the calling
-// thread, and cannot be dereferenced or invalidated on any other thread. Bound
-// WeakPtrs can still be handed off to other threads, e.g. to use to post tasks
-// back to object on the bound thread.
+// thread or current SequencedWorkerPool token, and cannot be dereferenced or
+// invalidated on any other task runner. Bound WeakPtrs can still be handed
+// off to other task runners, e.g. to use to post tasks back to object on the
+// bound sequence.
//
-// Invalidating the factory's WeakPtrs un-binds it from the thread, allowing it
-// to be passed for a different thread to use or delete it.
+// Invalidating the factory's WeakPtrs un-binds it from the sequence, allowing
+// it to be passed for a different sequence to use or delete it.
#ifndef BASE_MEMORY_WEAK_PTR_H_
#define BASE_MEMORY_WEAK_PTR_H_
@@ -81,8 +82,8 @@
class BASE_EXPORT WeakReference {
public:
- // Although Flag is bound to a specific thread, it may be deleted from another
- // via base::WeakPtr::~WeakPtr().
+ // Although Flag is bound to a specific SequencedTaskRunner, it may be
+ // deleted from another via base::WeakPtr::~WeakPtr().
class BASE_EXPORT Flag : public RefCountedThreadSafe<Flag> {
public:
Flag();
diff --git a/base/message_loop/message_pump_glib.h b/base/message_loop/message_pump_glib.h
index 0f797c5..9f44571 100644
--- a/base/message_loop/message_pump_glib.h
+++ b/base/message_loop/message_pump_glib.h
@@ -22,7 +22,7 @@
class BASE_EXPORT MessagePumpGlib : public MessagePump {
public:
MessagePumpGlib();
- virtual ~MessagePumpGlib();
+ ~MessagePumpGlib() override;
// Internal methods used for processing the pump callbacks. They are
// public for simplicity but should not be used directly. HandlePrepare
@@ -35,10 +35,10 @@
void HandleDispatch();
// Overridden from MessagePump:
- virtual void Run(Delegate* delegate) override;
- virtual void Quit() override;
- virtual void ScheduleWork() override;
- virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+ void Run(Delegate* delegate) override;
+ void Quit() override;
+ void ScheduleWork() override;
+ void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
private:
bool ShouldQuit() const;
diff --git a/base/process/kill_posix.cc b/base/process/kill_posix.cc
index bff7be4..b02453c 100644
--- a/base/process/kill_posix.cc
+++ b/base/process/kill_posix.cc
@@ -415,7 +415,7 @@
}
// Overridden from PlatformThread::Delegate:
- virtual void ThreadMain() override {
+ void ThreadMain() override {
WaitForChildToDie();
delete this;
}
diff --git a/base/win/pe_image.h b/base/win/pe_image.h
index 878ef52..d93e99d 100644
--- a/base/win/pe_image.h
+++ b/base/win/pe_image.h
@@ -23,7 +23,7 @@
namespace win {
// This class is a wrapper for the Portable Executable File Format (PE).
-// It's main purpose is to provide an easy way to work with imports and exports
+// Its main purpose is to provide an easy way to work with imports and exports
// from a file, mapped in memory as image.
class PEImage {
public:
@@ -84,6 +84,8 @@
module_ = reinterpret_cast<HMODULE>(const_cast<void*>(module));
}
+ virtual ~PEImage() {}
+
// Gets the HMODULE for this object.
HMODULE module() const;
diff --git a/build/android/buildbot/OWNERS b/build/android/buildbot/OWNERS
index 425f1d9..f289720 100644
--- a/build/android/buildbot/OWNERS
+++ b/build/android/buildbot/OWNERS
@@ -1,9 +1,6 @@
set noparent
cmp@chromium.org
-craigdh@chromium.org
-frankf@chromium.org
+jbudorick@chromium.org
navabi@chromium.org
-# backup
-ilevy@chromium.org
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index 2eb3626..6d736a1 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -252,7 +252,7 @@
try:
if 'adb' in p.name:
yield p
- except (psutil.error.NoSuchProcess, psutil.error.AccessDenied):
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
for sig in [signal.SIGTERM, signal.SIGQUIT, signal.SIGKILL]:
@@ -261,12 +261,12 @@
print 'kill %d %d (%s [%s])' % (sig, p.pid, p.name,
' '.join(p.cmdline))
p.send_signal(sig)
- except (psutil.error.NoSuchProcess, psutil.error.AccessDenied):
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
for p in GetAllAdb():
try:
print 'Unable to kill %d (%s [%s])' % (p.pid, p.name, ' '.join(p.cmdline))
- except (psutil.error.NoSuchProcess, psutil.error.AccessDenied):
+ except (psutil.NoSuchProcess, psutil.AccessDenied):
pass
diff --git a/build/android/buildbot/bb_device_steps.py b/build/android/buildbot/bb_device_steps.py
index c0f9fe7..e95a552 100755
--- a/build/android/buildbot/bb_device_steps.py
+++ b/build/android/buildbot/bb_device_steps.py
@@ -145,6 +145,9 @@
args.append('--tool=asan')
if options.gtest_filter:
args.append('--gtest-filter=%s' % options.gtest_filter)
+ if options.flakiness_server:
+ args.append('--flakiness-dashboard-server=%s' %
+ options.flakiness_server)
for suite in suites:
bb_annotations.PrintNamedStep(suite)
@@ -186,7 +189,7 @@
test = I('ChromeSyncShell',
'ChromeSyncShell.apk',
'org.chromium.chrome.browser.sync',
- 'ChromeSyncShellTest.apk',
+ 'ChromeSyncShellTest',
'chrome:chrome/test/data/android/device_files')
RunInstrumentationSuite(options, test)
diff --git a/build/android/pylib/OWNERS b/build/android/pylib/OWNERS
index 3899fa3..dbbbba7 100644
--- a/build/android/pylib/OWNERS
+++ b/build/android/pylib/OWNERS
@@ -1,4 +1,4 @@
-frankf@chromium.org
jbudorick@chromium.org
+klundberg@chromium.org
navabi@chromium.org
skyostil@chromium.org
diff --git a/build/android/pylib/base/test_dispatcher.py b/build/android/pylib/base/test_dispatcher.py
index cb789de..677a908 100644
--- a/build/android/pylib/base/test_dispatcher.py
+++ b/build/android/pylib/base/test_dispatcher.py
@@ -272,7 +272,6 @@
# for the above are switched or wrapped.
android_commands.errors.DeviceUnresponsiveError) as e:
logging.error(e)
- exit_code = constants.WARNING_EXIT_CODE
if not all((len(tc) == 0 for tc in test_collections)):
logging.error('Only ran %d tests (all devices are likely offline).' %
diff --git a/build/android/pylib/utils/json_results_generator.py b/build/android/pylib/utils/json_results_generator.py
index 52446b1..d40860d 100644
--- a/build/android/pylib/utils/json_results_generator.py
+++ b/build/android/pylib/utils/json_results_generator.py
@@ -516,7 +516,7 @@
this_test = this_test[segment]
if not len(this_test):
- self._PopulateResutlsAndTimesJSON(this_test)
+ self._PopulateResultsAndTimesJSON(this_test)
if self.RESULTS in this_test:
self._InsertItemRunLengthEncoded(result, this_test[self.RESULTS])
@@ -558,7 +558,7 @@
results[self.TESTS] = test_results_trie
- def _PopulateResutlsAndTimesJSON(self, results_and_times):
+ def _PopulateResultsAndTimesJSON(self, results_and_times):
results_and_times[self.RESULTS] = []
results_and_times[self.TIMES] = []
return results_and_times
diff --git a/build/android/pylib/utils/report_results.py b/build/android/pylib/utils/report_results.py
index b13b9bc..9841dc6 100644
--- a/build/android/pylib/utils/report_results.py
+++ b/build/android/pylib/utils/report_results.py
@@ -39,24 +39,28 @@
logging.info('Upload results for test type "%s", test package "%s" to %s' %
(test_type, test_package, flakiness_server))
- # TODO(frankf): Enable uploading for gtests.
- if test_type != 'Instrumentation':
- logging.warning('Invalid test type.')
- return
-
try:
- if flakiness_server == constants.UPSTREAM_FLAKINESS_SERVER:
- assert test_package in ['ContentShellTest',
+ if test_type == 'Instrumentation':
+ if flakiness_server == constants.UPSTREAM_FLAKINESS_SERVER:
+ assert test_package in ['ContentShellTest',
'ChromeShellTest',
- 'AndroidWebViewTest']
- dashboard_test_type = ('%s_instrumentation_tests' %
- test_package.lower().rstrip('test'))
- # Downstream server.
+ 'AndroidWebViewTest']
+ dashboard_test_type = ('%s_instrumentation_tests' %
+ test_package.lower().rstrip('test'))
+ # Downstream server.
+ else:
+ dashboard_test_type = 'Chromium_Android_Instrumentation'
+
+ elif test_type == 'Unit test':
+ dashboard_test_type = test_package
+
else:
- dashboard_test_type = 'Chromium_Android_Instrumentation'
+ logging.warning('Invalid test type')
+ return
flakiness_dashboard_results_uploader.Upload(
results, flakiness_server, dashboard_test_type)
+
except Exception as e:
logging.error(e)
diff --git a/build/common.gypi b/build/common.gypi
index 0ad62ee..8f9cb38 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -903,7 +903,7 @@
'use_allocator%': 'none',
# sysroot needs to be an absolute path otherwise it generates
# incorrect results when passed to pkg-config
- 'sysroot%': '<!(cd <(DEPTH) && pwd -P)/arm-sysroot',
+ 'sysroot%': '<!(cd <(DEPTH) && pwd -P)/chrome/installer/linux/debian_wheezy_arm-sysroot',
}], # OS=="linux" and target_arch=="arm" and chromeos==0
['OS=="linux" and branding=="Chrome" and buildtype=="Official" and chromeos==0', {
diff --git a/build/go/rules.gni b/build/go/rules.gni
index 79453d1..ab703d6 100644
--- a/build/go/rules.gni
+++ b/build/go/rules.gni
@@ -53,8 +53,9 @@
rebase_path("//", root_build_dir),
"-I" + rebase_path("//"),
" -L" + rebase_path(target_out_dir) +
+ " -L" + rebase_path(root_build_dir + "/obj/third_party/libevent") +
" -l" + static_library_name +
- " -lstdc++ -lpthread -lm -lglib-2.0",
+ " -lstdc++ -lpthread -lm -lglib-2.0 -levent",
"test", "-c",
] + rebase_path(invoker.sources, build_dir)
}
diff --git a/build/linux/install-arm-sysroot.py b/build/linux/install-arm-sysroot.py
index 4d593cc..495fc75 100755
--- a/build/linux/install-arm-sysroot.py
+++ b/build/linux/install-arm-sysroot.py
@@ -3,103 +3,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Script to install ARM root image for cross building of ARM chrome on linux.
-This script can be run manually but is more often run as part of gclient
-hooks. When run from hooks this script should be a no-op on non-linux
-platforms.
-
-The sysroot image could be constructed from scratch based on the current
-state or precise/arm but for consistency we currently use a pre-built root
-image which was originally designed for building trusted NaCl code. The image
-will normally need to be rebuilt every time chrome's build dependancies are
-changed.
-
-Steps to rebuild the arm sysroot image:
-
-- cd $SRC/native_client
-- ./tools/trusted_cross_toolchains/trusted-toolchain-creator.armel.precise.sh \
- UpdatePackageLists
-- ./tools/trusted_cross_toolchains/trusted-toolchain-creator.armel.precise.sh \
- BuildJail $SRC/out/arm-sysroot.tar.gz
-- gsutil cp -a public-read $SRC/out/arm-sysroot.tar.gz \
- nativeclient-archive2/toolchain/$NACL_REV/sysroot-arm-trusted.tgz
-"""
-
-# TODO(sbc): merge this script into:
-# chrome/installer/linux/sysroot_scripts/install-debian.wheezy.sysroot.py
-
-import hashlib
-import os
-import shutil
-import subprocess
import sys
-
-SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
-URL_PREFIX = 'https://storage.googleapis.com'
-URL_PATH = 'chrome-linux-sysroot/toolchain'
-REVISION = 285950
-TARBALL = 'debian_wheezy_arm_sysroot.tgz'
-TARBALL_SHA1SUM = 'fc2f54db168887c5190c4c6686c869bedf668b4e'
-
-
-def get_sha1(filename):
- sha1 = hashlib.sha1()
- with open(filename, 'rb') as f:
- while True:
- # Read in 1mb chunks, so it doesn't all have to be loaded into memory.
- chunk = f.read(1024*1024)
- if not chunk:
- break
- sha1.update(chunk)
- return sha1.hexdigest()
-
-
-def main(args):
- if '--linux-only' in args:
- # This argument is passed when run from the gclient hooks.
- # In this case we return early on non-linux platforms
- # or if GYP_DEFINES doesn't include target_arch=arm
- if not sys.platform.startswith('linux'):
- return 0
-
- if "target_arch=arm" not in os.environ.get('GYP_DEFINES', ''):
- return 0
-
- src_root = os.path.dirname(os.path.dirname(SCRIPT_DIR))
- sysroot = os.path.join(src_root, 'arm-sysroot')
- url = "%s/%s/%s/%s" % (URL_PREFIX, URL_PATH, REVISION, TARBALL)
-
- stamp = os.path.join(sysroot, ".stamp")
- if os.path.exists(stamp):
- with open(stamp) as s:
- if s.read() == url:
- print "ARM root image already up-to-date: %s" % sysroot
- return 0
-
- print "Installing ARM root image: %s" % sysroot
- if os.path.isdir(sysroot):
- shutil.rmtree(sysroot)
- os.mkdir(sysroot)
- tarball = os.path.join(sysroot, TARBALL)
- curl = ['curl', '--fail', '-L', url, '-o', tarball]
- if os.isatty(sys.stdout.fileno()):
- curl.append('--progress')
- else:
- curl.append('--silent')
- subprocess.check_call(curl)
- sha1sum = get_sha1(tarball)
- if sha1sum != TARBALL_SHA1SUM:
- print 'Tarball sha1sum is wrong.'
- print 'Expected %s, actual: %s' % (TARBALL_SHA1SUM, sha1sum)
- return 1
- subprocess.check_call(['tar', 'xf', tarball, '-C', sysroot])
- os.remove(tarball)
-
- with open(stamp, 'w') as s:
- s.write(url)
- return 0
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv[1:]))
+msg = '''\
+ERROR: This script has merged with install-debian.wheezy.sysroot.py.
+Please use that instead (with --arch=arm).
+'''
+sys.stderr.write(msg)
diff --git a/build/linux/install-chromeos-fonts.py b/build/linux/install-chromeos-fonts.py
index 98c3a57..a24adc9 100755
--- a/build/linux/install-chromeos-fonts.py
+++ b/build/linux/install-chromeos-fonts.py
@@ -12,16 +12,12 @@
import subprocess
import sys
-URL_PREFIX = 'https://commondatastorage.googleapis.com'
-URL_DIR = 'chromeos-localmirror/distfiles'
-URL_FILE = 'notofonts-20121206.tar.gz'
+# Taken from the media-fonts/notofonts ebuild in chromiumos-overlay.
+VERSION = '20140815'
+URL = ('https://commondatastorage.googleapis.com/chromeos-localmirror/'
+ 'distfiles/notofonts-%s.tar.bz2') % (VERSION)
FONTS_DIR = '/usr/local/share/fonts'
-# The URL matches the URL in the ebuild script in chromiumos. See:
-# /path/to/chromiumos/src/
-# third_party/chromiumos-overlay/media-fonts/notofonts/
-# notofonts-20121206.ebuild
-
def main(args):
if not sys.platform.startswith('linux'):
print "Error: %s must be run on Linux." % __file__
@@ -37,12 +33,10 @@
dest_dir = os.path.join(FONTS_DIR, 'chromeos')
- url = "%s/%s/%s" % (URL_PREFIX, URL_DIR, URL_FILE)
-
stamp = os.path.join(dest_dir, ".stamp02")
if os.path.exists(stamp):
with open(stamp) as s:
- if s.read() == url:
+ if s.read() == URL:
print "Chrome OS fonts already up-to-date in %s." % dest_dir
return 0
@@ -52,8 +46,8 @@
os.chmod(dest_dir, 0755)
print "Installing Chrome OS fonts to %s." % dest_dir
- tarball = os.path.join(dest_dir, URL_FILE)
- subprocess.check_call(['curl', '-L', url, '-o', tarball])
+ tarball = os.path.join(dest_dir, os.path.basename(URL))
+ subprocess.check_call(['curl', '-L', URL, '-o', tarball])
subprocess.check_call(['tar', '--no-same-owner', '--no-same-permissions',
'-xf', tarball, '-C', dest_dir])
os.remove(tarball)
@@ -65,7 +59,7 @@
s.write("Script: %s\n" % __file__)
with open(stamp, 'w') as s:
- s.write(url)
+ s.write(URL)
for base, dirs, files in os.walk(dest_dir):
for dir in dirs:
diff --git a/build/whitespace_file.txt b/build/whitespace_file.txt
index 4e9bf38..f11fa16 100644
--- a/build/whitespace_file.txt
+++ b/build/whitespace_file.txt
@@ -141,3 +141,5 @@
It was love at first sight. The moment Yossarian first laid eyes on the chaplain, he fell madly in love with him.
Cool whitespace change for git-cl land
+
+Oh god the bots are red! I'm blind! Mmmm, donuts.
diff --git a/cc/PRESUBMIT.py b/cc/PRESUBMIT.py
index 1aa48f3..46c3a54 100644
--- a/cc/PRESUBMIT.py
+++ b/cc/PRESUBMIT.py
@@ -191,12 +191,6 @@
errors.append(output_api.PresubmitError(
'%s:%d uses scoped_ptr<T>(). Use nullptr instead.' %
(f.LocalPath(), line_number)))
- # Disallow:
- # foo.PassAs<T>();
- if re.search(r'\bPassAs<.*?>\(\)', line):
- errors.append(output_api.PresubmitError(
- '%s:%d uses PassAs<T>(). Use Pass() instead.' %
- (f.LocalPath(), line_number)))
return errors
def FindUnquotedQuote(contents, pos):
@@ -332,42 +326,6 @@
else:
return []
-def CheckOverrideFinal(input_api, output_api,
- whitelist=CC_SOURCE_FILES, blacklist=None):
- """Make sure new lines of code don't use the OVERRIDE or FINAL macros."""
-
- # TODO(mostynb): remove this check once the macros are removed
- # from base/compiler_specific.h.
-
- errors = []
-
- source_file_filter = lambda x: input_api.FilterSourceFile(
- x, white_list=CC_SOURCE_FILES, black_list=None)
-
- override_files = []
- final_files = []
-
- for f in input_api.AffectedSourceFiles(source_file_filter):
- contents = input_api.ReadFile(f, 'rb')
-
- # "override" and "final" should be used instead of OVERRIDE/FINAL now.
- if re.search(r"\bOVERRIDE\b", contents):
- override_files.append(f.LocalPath())
-
- if re.search(r"\bFINAL\b", contents):
- final_files.append(f.LocalPath())
-
- if override_files:
- return [output_api.PresubmitError(
- 'These files use OVERRIDE instead of using override:',
- items=override_files)]
- if final_files:
- return [output_api.PresubmitError(
- 'These files use FINAL instead of using final:',
- items=final_files)]
-
- return []
-
def CheckChangeOnUpload(input_api, output_api):
results = []
results += CheckAsserts(input_api, output_api)
@@ -380,7 +338,6 @@
results += CheckNamespace(input_api, output_api)
results += CheckForUseOfWrongClock(input_api, output_api)
results += FindUselessIfdefs(input_api, output_api)
- results += CheckOverrideFinal(input_api, output_api)
results += input_api.canned_checks.CheckPatchFormatted(input_api, output_api)
return results
diff --git a/cc/debug/rasterize_and_record_benchmark_impl.cc b/cc/debug/rasterize_and_record_benchmark_impl.cc
index 77bc259..57e7f15 100644
--- a/cc/debug/rasterize_and_record_benchmark_impl.cc
+++ b/cc/debug/rasterize_and_record_benchmark_impl.cc
@@ -211,9 +211,10 @@
FixedInvalidationPictureLayerTilingClient client(
layer, gfx::Rect(layer->content_bounds()));
- PictureLayerTilingSet tiling_set(&client, layer->content_bounds());
+ PictureLayerTilingSet tiling_set(&client);
- PictureLayerTiling* tiling = tiling_set.AddTiling(layer->contents_scale_x());
+ PictureLayerTiling* tiling =
+ tiling_set.AddTiling(layer->contents_scale_x(), layer->bounds());
tiling->CreateAllTilesForTesting();
for (PictureLayerTiling::CoverageIterator it(
tiling, layer->contents_scale_x(), layer->visible_content_rect());
diff --git a/cc/layers/delegated_renderer_layer_impl_unittest.cc b/cc/layers/delegated_renderer_layer_impl_unittest.cc
index e66cc76..3fb1c48 100644
--- a/cc/layers/delegated_renderer_layer_impl_unittest.cc
+++ b/cc/layers/delegated_renderer_layer_impl_unittest.cc
@@ -1416,7 +1416,12 @@
pass1_id,
gfx::Rect(layer_size),
gfx::Transform());
- AddRenderPassQuad(pass1, pass2, 0, FilterOperations(), transform);
+ AddRenderPassQuad(pass1,
+ pass2,
+ 0,
+ FilterOperations(),
+ transform,
+ SkXfermode::kSrcOver_Mode);
delegated_renderer_layer_impl->SetFrameDataForRenderPasses(
1.f, &delegated_render_passes);
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 4c16da7..2973519 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -625,6 +625,13 @@
float scale = layer_tree_impl()->page_scale_factor();
gfx::Vector2dF delta_from_scroll = scroll_clip_layer_->bounds_delta();
+
+ // In virtual-viewport mode, we don't need to compensate for pinch zoom or
+ // scale since the fixed container is the outer viewport, which sits below
+ // the page scale.
+ if (layer_tree_impl()->settings().use_pinch_virtual_viewport)
+ return delta_from_scroll;
+
delta_from_scroll.Scale(1.f / scale);
// The delta-from-pinch component requires some explanation: A viewport of
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index 2851392..6ae23a7 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -63,8 +63,7 @@
new TestablePictureImageLayerImpl(tree, id);
layer->SetBounds(gfx::Size(100, 200));
layer->SetContentBounds(gfx::Size(100, 200));
- layer->tilings_.reset(new PictureLayerTilingSet(&tiling_client_,
- layer->bounds()));
+ layer->tilings_.reset(new PictureLayerTilingSet(&tiling_client_));
layer->pile_ = tiling_client_.GetPile();
return make_scoped_ptr(layer);
}
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index c0344e2..2599852 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -483,6 +483,9 @@
was_screen_space_transform_animating_ =
draw_properties().screen_space_transform_is_animating;
+ if (draw_transform_is_animating())
+ pile_->set_likely_to_be_used_for_transform_animation();
+
should_update_tile_priorities_ = true;
UpdateTilePriorities(occlusion_in_content_space);
@@ -790,7 +793,7 @@
const PictureLayerTiling* tiling) {
if (!CanHaveTilingWithScale(tiling->contents_scale()))
return;
- tilings_->AddTiling(tiling->contents_scale());
+ tilings_->AddTiling(tiling->contents_scale(), bounds());
// If this tree needs update draw properties, then the tiling will
// get updated prior to drawing or activation. If this tree does not
@@ -840,7 +843,7 @@
DCHECK(layer_tree_impl()->IsPendingTree());
if (!tilings_)
- tilings_.reset(new PictureLayerTilingSet(this, bounds()));
+ tilings_ = make_scoped_ptr(new PictureLayerTilingSet(this));
DCHECK(!twin_layer_);
twin_layer_ = static_cast<PictureLayerImpl*>(
@@ -861,7 +864,7 @@
DCHECK(CanHaveTilingWithScale(contents_scale)) <<
"contents_scale: " << contents_scale;
- PictureLayerTiling* tiling = tilings_->AddTiling(contents_scale);
+ PictureLayerTiling* tiling = tilings_->AddTiling(contents_scale, bounds());
DCHECK(pile_->HasRecordings());
@@ -1239,19 +1242,7 @@
}
bool PictureLayerImpl::ShouldAdjustRasterScaleDuringScaleAnimations() const {
- if (!layer_tree_impl()->use_gpu_rasterization())
- return false;
-
- // Re-rastering text at different scales using GPU rasterization causes
- // texture uploads for glyphs at each scale (see crbug.com/366225). To
- // workaround this performance issue, we don't re-rasterize layers with
- // text during scale animations.
- // TODO(ajuma): Remove this workaround once text can be efficiently
- // re-rastered at different scales (e.g. by using distance-field fonts).
- if (pile_->has_text())
- return false;
-
- return true;
+ return layer_tree_impl()->use_gpu_rasterization();
}
float PictureLayerImpl::MaximumTilingContentsScale() const {
@@ -1450,7 +1441,7 @@
PictureLayerTiling::TilingRasterTileIterator(tiling);
}
- if (tiling->resolution() == LOW_RESOLUTION) {
+ if (prioritize_low_res && tiling->resolution() == LOW_RESOLUTION) {
iterators_[LOW_RES] =
PictureLayerTiling::TilingRasterTileIterator(tiling);
}
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 73906af..038dc2a 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2194,16 +2194,20 @@
SetupDrawPropertiesAndUpdateTiles(
active_layer_, 0.5f, 0.5f, 0.5f, 0.5f, false);
+ pending_layer_->tilings()->RemoveAllTilings();
active_layer_->tilings()->RemoveAllTilings();
- PictureLayerTiling* tiling = active_layer_->tilings()->AddTiling(0.5f);
- active_layer_->tilings()->AddTiling(1.5f);
- active_layer_->tilings()->AddTiling(0.25f);
+ PictureLayerTiling* tiling = active_layer_->AddTiling(0.5f);
+ active_layer_->AddTiling(1.5f);
+ active_layer_->AddTiling(0.25f);
tiling->set_resolution(HIGH_RESOLUTION);
// Sanity checks.
ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
ASSERT_EQ(tiling, active_layer_->tilings()->TilingAtScale(0.5f));
+ pending_layer_->tilings()->RemoveAllTilings();
+ ASSERT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
// Now, set the bounds to be 1x1 (so that minimum contents scale becomes
// 1.0f). Note that we should also ensure that the pending layer needs post
// commit initialization, since this is what would happen during commit. In
@@ -2602,8 +2606,9 @@
static_cast<FakePicturePileImpl*>(pending_layer_->pile())->set_has_text(true);
static_cast<FakePicturePileImpl*>(active_layer_->pile())->set_has_text(true);
- // Since we're GPU-rasterizing but have text, starting an animation should
- // cause tiling resolution to get set to the maximum animation scale.
+ // When we're GPU-rasterizing, even if we have text, starting an animation
+ // should cause tiling resolution to get set to the content scale, since we
+ // render animating text at content scale using distance fields.
animating_transform = true;
contents_scale = 2.f;
maximum_animation_scale = 3.f;
@@ -2613,10 +2618,10 @@
page_scale,
maximum_animation_scale,
animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
- // Further changes to scale during the animation should not cause a new
- // high-res tiling to get created.
+ // Further changes to scale during the animation should still cause a new
+ // high-res tiling to get created at content scale.
contents_scale = 4.f;
maximum_animation_scale = 5.f;
@@ -2625,7 +2630,7 @@
page_scale,
maximum_animation_scale,
animating_transform);
- EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
+ EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
// Once we stop animating, a new high-res tiling should be created.
animating_transform = false;
@@ -2704,7 +2709,7 @@
EXPECT_TRUE(reached_prepaint);
EXPECT_EQ(0u, non_ideal_tile_count);
- EXPECT_EQ(1u, low_res_tile_count);
+ EXPECT_EQ(0u, low_res_tile_count);
EXPECT_EQ(16u, high_res_tile_count);
EXPECT_EQ(low_res_tile_count + high_res_tile_count + non_ideal_tile_count,
unique_tiles.size());
@@ -2761,8 +2766,7 @@
non_ideal_tile_count = 0;
low_res_tile_count = 0;
high_res_tile_count = 0;
- for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
- it;
+ for (it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, true); it;
++it) {
Tile* tile = *it;
TilePriority priority = tile->priority(PENDING_TREE);
@@ -3794,7 +3798,7 @@
if (tile_is_visible)
unoccluded_tile_count++;
}
- EXPECT_EQ(unoccluded_tile_count, 25 + 4);
+ EXPECT_EQ(unoccluded_tile_count, 25);
// Partial occlusion.
pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
@@ -3824,7 +3828,7 @@
if (tile_is_visible)
unoccluded_tile_count++;
}
- EXPECT_EQ(20 + 2, unoccluded_tile_count);
+ EXPECT_EQ(20, unoccluded_tile_count);
// Full occlusion.
layer1->SetPosition(gfx::Point(0, 0));
@@ -4490,6 +4494,65 @@
EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
}
+TEST_F(PictureLayerImplTest, ChangeInViewportAllowsTilingUpdates) {
+ base::TimeTicks time_ticks;
+ time_ticks += base::TimeDelta::FromMilliseconds(1);
+ host_impl_.SetCurrentBeginFrameArgs(
+ CreateBeginFrameArgsForTesting(time_ticks));
+
+ gfx::Size tile_size(100, 100);
+ gfx::Size layer_bounds(400, 4000);
+
+ scoped_refptr<FakePicturePileImpl> pending_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+ scoped_refptr<FakePicturePileImpl> active_pile =
+ FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+ SetupTrees(pending_pile, active_pile);
+
+ Region invalidation;
+ gfx::Rect viewport = gfx::Rect(0, 0, 100, 100);
+ gfx::Transform transform;
+
+ host_impl_.SetRequiresHighResToDraw();
+
+ // Update tiles.
+ pending_layer_->draw_properties().visible_content_rect = viewport;
+ pending_layer_->draw_properties().screen_space_transform = transform;
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
+
+ // Ensure we can't activate.
+ EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+ // Now in the same frame, move the viewport (this can happen during
+ // animation).
+ viewport = gfx::Rect(0, 2000, 100, 100);
+
+ // Update tiles.
+ pending_layer_->draw_properties().visible_content_rect = viewport;
+ pending_layer_->draw_properties().screen_space_transform = transform;
+ SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+ pending_layer_->HighResTiling()->UpdateAllTilePrioritiesForTesting();
+
+ // Make sure all viewport tiles (viewport from the tiling) are ready to draw.
+ std::vector<Tile*> tiles;
+ for (PictureLayerTiling::CoverageIterator iter(
+ pending_layer_->HighResTiling(),
+ 1.f,
+ pending_layer_->HighResTiling()->GetCurrentVisibleRectForTesting());
+ iter;
+ ++iter) {
+ if (*iter)
+ tiles.push_back(*iter);
+ }
+
+ host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
+
+ // Ensure we can activate.
+ EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+}
+
class TileSizeSettings : public ImplSidePaintingSettings {
public:
TileSizeSettings() {
diff --git a/cc/layers/tiled_layer_unittest.cc b/cc/layers/tiled_layer_unittest.cc
index 925cdc8..862ff1f 100644
--- a/cc/layers/tiled_layer_unittest.cc
+++ b/cc/layers/tiled_layer_unittest.cc
@@ -128,8 +128,7 @@
nullptr,
0,
false,
- 1,
- false);
+ 1);
host_impl_ = make_scoped_ptr(
new FakeLayerTreeHostImpl(proxy_, shared_bitmap_manager_.get()));
}
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 6b15faf..24e9f30 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -123,6 +123,44 @@
}
}
+BlendMode BlendModeFromSkXfermode(SkXfermode::Mode mode) {
+ switch (mode) {
+ case SkXfermode::kSrcOver_Mode:
+ return BlendModeNormal;
+ case SkXfermode::kOverlay_Mode:
+ return BlendModeOverlay;
+ case SkXfermode::kDarken_Mode:
+ return BlendModeDarken;
+ case SkXfermode::kLighten_Mode:
+ return BlendModeLighten;
+ case SkXfermode::kColorDodge_Mode:
+ return BlendModeColorDodge;
+ case SkXfermode::kColorBurn_Mode:
+ return BlendModeColorBurn;
+ case SkXfermode::kHardLight_Mode:
+ return BlendModeHardLight;
+ case SkXfermode::kSoftLight_Mode:
+ return BlendModeSoftLight;
+ case SkXfermode::kDifference_Mode:
+ return BlendModeDifference;
+ case SkXfermode::kExclusion_Mode:
+ return BlendModeExclusion;
+ case SkXfermode::kMultiply_Mode:
+ return BlendModeMultiply;
+ case SkXfermode::kHue_Mode:
+ return BlendModeHue;
+ case SkXfermode::kSaturation_Mode:
+ return BlendModeSaturation;
+ case SkXfermode::kColor_Mode:
+ return BlendModeColor;
+ case SkXfermode::kLuminosity_Mode:
+ return BlendModeLuminosity;
+ default:
+ NOTREACHED();
+ return BlendModeNormal;
+ }
+}
+
// Smallest unit that impact anti-aliasing output. We use this to
// determine when anti-aliasing is unnecessary.
const float kAntiAliasingEpsilon = 1.0f / 1024.0f;
@@ -723,140 +761,6 @@
GLC(gl_, gl_->BlendEquation(GL_FUNC_ADD));
}
-static skia::RefPtr<SkImage> ApplyBlendModeWithBackdrop(
- scoped_ptr<GLRenderer::ScopedUseGrContext> use_gr_context,
- ResourceProvider* resource_provider,
- skia::RefPtr<SkImage> source_bitmap_with_filters,
- ScopedResource* source_texture_resource,
- ScopedResource* background_texture_resource,
- SkXfermode::Mode blend_mode) {
- if (!use_gr_context)
- return source_bitmap_with_filters;
-
- DCHECK(background_texture_resource);
- DCHECK(source_texture_resource);
-
- gfx::Size source_size = source_texture_resource->size();
- gfx::Size background_size = background_texture_resource->size();
-
- DCHECK_LE(background_size.width(), source_size.width());
- DCHECK_LE(background_size.height(), source_size.height());
-
- int source_texture_with_filters_id;
- scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
- if (source_bitmap_with_filters) {
- DCHECK_EQ(source_size.width(), source_bitmap_with_filters->width());
- DCHECK_EQ(source_size.height(), source_bitmap_with_filters->height());
- GrTexture* texture =
- reinterpret_cast<GrTexture*>(source_bitmap_with_filters->getTexture());
- source_texture_with_filters_id = texture->getTextureHandle();
- } else {
- lock.reset(new ResourceProvider::ScopedReadLockGL(
- resource_provider, source_texture_resource->id()));
- source_texture_with_filters_id = lock->texture_id();
- }
-
- ResourceProvider::ScopedReadLockGL lock_background(
- resource_provider, background_texture_resource->id());
-
- // Wrap the source texture in a Ganesh platform texture.
- GrBackendTextureDesc backend_texture_description;
- backend_texture_description.fConfig = kSkia8888_GrPixelConfig;
- backend_texture_description.fOrigin = kBottomLeft_GrSurfaceOrigin;
-
- backend_texture_description.fWidth = source_size.width();
- backend_texture_description.fHeight = source_size.height();
- backend_texture_description.fTextureHandle = source_texture_with_filters_id;
- skia::RefPtr<GrTexture> source_texture =
- skia::AdoptRef(use_gr_context->context()->wrapBackendTexture(
- backend_texture_description));
- if (!source_texture) {
- TRACE_EVENT_INSTANT0(
- "cc",
- "ApplyBlendModeWithBackdrop wrap source texture failed",
- TRACE_EVENT_SCOPE_THREAD);
- return skia::RefPtr<SkImage>();
- }
-
- backend_texture_description.fWidth = background_size.width();
- backend_texture_description.fHeight = background_size.height();
- backend_texture_description.fTextureHandle = lock_background.texture_id();
- skia::RefPtr<GrTexture> background_texture =
- skia::AdoptRef(use_gr_context->context()->wrapBackendTexture(
- backend_texture_description));
- if (!background_texture) {
- TRACE_EVENT_INSTANT0(
- "cc",
- "ApplyBlendModeWithBackdrop wrap background texture failed",
- TRACE_EVENT_SCOPE_THREAD);
- return skia::RefPtr<SkImage>();
- }
-
- SkImageInfo source_info =
- SkImageInfo::MakeN32Premul(source_size.width(), source_size.height());
- // Place the platform texture inside an SkBitmap.
- SkBitmap source;
- source.setInfo(source_info);
- skia::RefPtr<SkGrPixelRef> source_pixel_ref =
- skia::AdoptRef(new SkGrPixelRef(source_info, source_texture.get()));
- source.setPixelRef(source_pixel_ref.get());
-
- SkImageInfo background_info = SkImageInfo::MakeN32Premul(
- background_size.width(), background_size.height());
-
- SkBitmap background;
- background.setInfo(background_info);
- skia::RefPtr<SkGrPixelRef> background_pixel_ref =
- skia::AdoptRef(new SkGrPixelRef(
- background_info, background_texture.get()));
- background.setPixelRef(background_pixel_ref.get());
-
- // Create a scratch texture for backing store.
- GrTextureDesc desc;
- desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit;
- desc.fSampleCnt = 0;
- desc.fWidth = source.width();
- desc.fHeight = source.height();
- desc.fConfig = kSkia8888_GrPixelConfig;
- desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
- skia::RefPtr<GrTexture> backing_store =
- skia::AdoptRef(use_gr_context->context()->refScratchTexture(
- desc, GrContext::kExact_ScratchTexMatch));
- if (!backing_store) {
- TRACE_EVENT_INSTANT0(
- "cc",
- "ApplyBlendModeWithBackdrop scratch texture allocation failed",
- TRACE_EVENT_SCOPE_THREAD);
- return source_bitmap_with_filters;
- }
-
- // Create a device and canvas using that backing store.
- skia::RefPtr<SkSurface> surface = skia::AdoptRef(
- SkSurface::NewRenderTargetDirect(backing_store->asRenderTarget()));
- if (!surface)
- return skia::RefPtr<SkImage>();
- skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
-
- // Draw the source bitmap through the filter to the canvas.
- canvas->clear(SK_ColorTRANSPARENT);
- canvas->drawSprite(background, 0, 0);
- SkPaint paint;
- paint.setXfermodeMode(blend_mode);
- canvas->drawSprite(source, 0, 0, &paint);
-
- skia::RefPtr<SkImage> image = skia::AdoptRef(surface->newImageSnapshot());
- if (!image || !image->getTexture()) {
- return skia::RefPtr<SkImage>();
- }
-
- // Flush the GrContext to ensure all buffered GL calls are drawn to the
- // backing store before we access and return it, and have cc begin using the
- // GL context again.
- canvas->flush();
-
- return image;
-}
-
bool GLRenderer::ShouldApplyBackgroundFilters(DrawingFrame* frame,
const RenderPassDrawQuad* quad) {
if (quad->background_filters.IsEmpty())
@@ -878,7 +782,8 @@
gfx::Rect GLRenderer::GetBackdropBoundingBoxForRenderPassQuad(
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform) {
+ const gfx::Transform& contents_device_transform,
+ bool use_aa) {
gfx::Rect backdrop_rect = gfx::ToEnclosingRect(MathUtil::MapClippedRect(
contents_device_transform, SharedGeometryQuad().BoundingBox()));
@@ -888,6 +793,11 @@
backdrop_rect.Inset(-left, -top, -right, -bottom);
}
+ if (!backdrop_rect.IsEmpty() && use_aa) {
+ const int kOutsetForAntialiasing = 1;
+ backdrop_rect.Inset(-kOutsetForAntialiasing, -kOutsetForAntialiasing);
+ }
+
backdrop_rect.Intersect(
MoveFromDrawToWindowSpace(frame->current_render_pass->output_rect));
return backdrop_rect;
@@ -932,7 +842,6 @@
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform_inverse,
- ScopedResource* device_background_texture,
skia::RefPtr<SkImage> filtered_device_background,
const gfx::Rect& backdrop_bounding_rect) {
// This method draws a background filter, which applies a filter to any pixels
@@ -959,18 +868,9 @@
// TODO(danakj): When this algorithm changes, update
// LayerTreeHost::PrioritizeTextures() accordingly.
- DCHECK(device_background_texture);
+ DCHECK(filtered_device_background);
- int filtered_device_background_texture_id = 0;
- scoped_ptr<ResourceProvider::ScopedReadLockGL> lock;
- if (filtered_device_background) {
- GrTexture* texture = filtered_device_background->getTexture();
- filtered_device_background_texture_id = texture->getTextureHandle();
- } else {
- lock.reset(new ResourceProvider::ScopedReadLockGL(
- resource_provider_, device_background_texture->id()));
- filtered_device_background_texture_id = lock->texture_id();
- }
+ GrTexture* texture = filtered_device_background->getTexture();
scoped_ptr<ScopedResource> background_texture =
ScopedResource::Create(resource_provider_);
@@ -1004,7 +904,7 @@
bool flip_vertically = false;
CopyTextureToFramebuffer(frame,
- filtered_device_background_texture_id,
+ texture->getTextureHandle(),
backdrop_bounding_rect,
device_to_framebuffer_transform,
flip_vertically);
@@ -1020,9 +920,9 @@
void GLRenderer::DrawRenderPassQuad(DrawingFrame* frame,
const RenderPassDrawQuad* quad) {
SkXfermode::Mode blend_mode = quad->shared_quad_state->blend_mode;
- SetBlendEnabled(quad->ShouldDrawWithBlending() ||
- (!IsDefaultBlendMode(blend_mode) &&
- CanApplyBlendModeUsingBlendFunc(blend_mode)));
+ SetBlendEnabled(
+ CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+ (quad->ShouldDrawWithBlending() || !IsDefaultBlendMode(blend_mode)));
ScopedResource* contents_texture =
render_pass_textures_.get(quad->render_pass_id);
@@ -1041,44 +941,70 @@
if (!contents_device_transform.GetInverse(&contents_device_transform_inverse))
return;
+ bool clipped = false;
+ gfx::QuadF device_quad = MathUtil::MapQuad(
+ contents_device_transform, SharedGeometryQuad(), &clipped);
+ // Use anti-aliasing programs only when necessary.
+ bool use_aa =
+ !clipped &&
+ (settings_->force_antialiasing || !device_quad.IsRectilinear() ||
+ !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(),
+ kAntiAliasingEpsilon));
+
bool need_background_texture = !CanApplyBlendModeUsingBlendFunc(blend_mode) ||
ShouldApplyBackgroundFilters(frame, quad);
scoped_ptr<ScopedResource> background_texture;
+ skia::RefPtr<SkImage> background_image;
+ gfx::Rect background_rect;
if (need_background_texture) {
+ // Compute a bounding box around the pixels that will be visible through
+ // the quad.
+ background_rect = GetBackdropBoundingBoxForRenderPassQuad(
+ frame, quad, contents_device_transform, use_aa);
+ }
+
+ if (!background_rect.IsEmpty()) {
// The pixels from the filtered background should completely replace the
// current pixel values.
bool disable_blending = blend_enabled();
if (disable_blending)
SetBlendEnabled(false);
- // Compute a bounding box around the pixels that will be visible through
- // the quad.
- gfx::Rect backdrop_rect = GetBackdropBoundingBoxForRenderPassQuad(
- frame, quad, contents_device_transform);
-
// Read the pixels in the bounding box into a buffer R.
scoped_ptr<ScopedResource> scoped_background_texture =
- GetBackdropTexture(backdrop_rect);
+ GetBackdropTexture(background_rect);
skia::RefPtr<SkImage> background_with_filters;
- if (ShouldApplyBackgroundFilters(frame, quad)) {
+ if (ShouldApplyBackgroundFilters(frame, quad) &&
+ scoped_background_texture) {
// Apply the background filters to R, so that it is applied in the pixels'
// coordinate space.
background_with_filters =
ApplyBackgroundFilters(frame, quad, scoped_background_texture.get());
}
- // Apply the quad's inverse transform to map the pixels in R into the
- // quad's content space. This implicitly clips R by the content bounds of
- // the quad since the destination texture has bounds matching the quad's
- // content.
- background_texture = ApplyInverseTransformForBackgroundFilters(
- frame,
- quad,
- contents_device_transform_inverse,
- scoped_background_texture.get(),
- background_with_filters,
- backdrop_rect);
+
+ if (CanApplyBlendModeUsingBlendFunc(blend_mode) &&
+ background_with_filters) {
+ // The background with filters will be copied to the frame buffer.
+ // Apply the quad's inverse transform to map the pixels in R into the
+ // quad's content space. This implicitly clips R by the content bounds of
+ // the quad since the destination texture has bounds matching the quad's
+ // content.
+ background_texture = ApplyInverseTransformForBackgroundFilters(
+ frame,
+ quad,
+ contents_device_transform_inverse,
+ background_with_filters,
+ background_rect);
+ } else if (!CanApplyBlendModeUsingBlendFunc(blend_mode)) {
+ if (background_with_filters) {
+ // The background with filters will be used as backdrop for blending.
+ background_image = background_with_filters;
+ } else {
+ background_texture = scoped_background_texture.Pass();
+ }
+ }
if (disable_blending)
SetBlendEnabled(true);
@@ -1116,49 +1042,27 @@
}
}
- if (background_texture) {
- if (CanApplyBlendModeUsingBlendFunc(blend_mode)) {
- // Draw the background texture if it has some filters applied.
- DCHECK(ShouldApplyBackgroundFilters(frame, quad));
- DCHECK(background_texture->size() == quad->rect.size());
- ResourceProvider::ScopedReadLockGL lock(resource_provider_,
- background_texture->id());
+ if (background_texture && ShouldApplyBackgroundFilters(frame, quad)) {
+ // Draw the background texture if it has some filters applied.
+ DCHECK(CanApplyBlendModeUsingBlendFunc(blend_mode));
+ DCHECK(background_texture->size() == quad->rect.size());
+ ResourceProvider::ScopedReadLockGL lock(resource_provider_,
+ background_texture->id());
- // The background_texture is oriented the same as the frame buffer. The
- // transform we are copying with has a vertical flip, so flip the contents
- // in the shader to maintain orientation
- bool flip_vertically = true;
+ // The background_texture is oriented the same as the frame buffer. The
+ // transform we are copying with has a vertical flip, so flip the contents
+ // in the shader to maintain orientation
+ bool flip_vertically = true;
- CopyTextureToFramebuffer(frame,
- lock.texture_id(),
- quad->rect,
- quad->quadTransform(),
- flip_vertically);
- } else {
- // If blending is applied using shaders, the background texture with
- // filters will be used as backdrop for blending operation, so we don't
- // need to copy it to the frame buffer.
- filter_image =
- ApplyBlendModeWithBackdrop(ScopedUseGrContext::Create(this, frame),
- resource_provider_,
- filter_image,
- contents_texture,
- background_texture.get(),
- quad->shared_quad_state->blend_mode);
- }
+ CopyTextureToFramebuffer(frame,
+ lock.texture_id(),
+ quad->rect,
+ quad->quadTransform(),
+ flip_vertically);
}
- bool clipped = false;
- gfx::QuadF device_quad = MathUtil::MapQuad(
- contents_device_transform, SharedGeometryQuad(), &clipped);
LayerQuad device_layer_bounds(gfx::QuadF(device_quad.BoundingBox()));
LayerQuad device_layer_edges(device_quad);
-
- // Use anti-aliasing programs only when necessary.
- bool use_aa =
- !clipped && (!device_quad.IsRectilinear() ||
- !gfx::IsNearestRectWithinDistance(device_quad.BoundingBox(),
- kAntiAliasingEpsilon));
if (use_aa) {
device_layer_bounds.InflateAntiAliasingDistance();
device_layer_edges.InflateAntiAliasingDistance();
@@ -1210,10 +1114,17 @@
int shader_color_matrix_location = -1;
int shader_color_offset_location = -1;
int shader_tex_transform_location = -1;
+ int shader_backdrop_location = -1;
+ int shader_backdrop_rect_location = -1;
+
+ BlendMode shader_blend_mode = ((background_texture || background_image) &&
+ !CanApplyBlendModeUsingBlendFunc(blend_mode))
+ ? BlendModeFromSkXfermode(blend_mode)
+ : BlendModeNormal;
if (use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgramAA* program =
- GetRenderPassMaskProgramAA(tex_coord_precision);
+ GetRenderPassMaskProgramAA(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1230,9 +1141,12 @@
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (!use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgram* program =
- GetRenderPassMaskProgram(tex_coord_precision);
+ GetRenderPassMaskProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1246,9 +1160,12 @@
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (use_aa && !mask_texture_id && !use_color_matrix) {
const RenderPassProgramAA* program =
- GetRenderPassProgramAA(tex_coord_precision);
+ GetRenderPassProgramAA(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1259,9 +1176,13 @@
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (use_aa && mask_texture_id && use_color_matrix) {
const RenderPassMaskColorMatrixProgramAA* program =
- GetRenderPassMaskColorMatrixProgramAA(tex_coord_precision);
+ GetRenderPassMaskColorMatrixProgramAA(tex_coord_precision,
+ shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1282,9 +1203,13 @@
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (use_aa && !mask_texture_id && use_color_matrix) {
const RenderPassColorMatrixProgramAA* program =
- GetRenderPassColorMatrixProgramAA(tex_coord_precision);
+ GetRenderPassColorMatrixProgramAA(tex_coord_precision,
+ shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1299,9 +1224,13 @@
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (!use_aa && mask_texture_id && use_color_matrix) {
const RenderPassMaskColorMatrixProgram* program =
- GetRenderPassMaskColorMatrixProgram(tex_coord_precision);
+ GetRenderPassMaskColorMatrixProgram(tex_coord_precision,
+ shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1319,9 +1248,12 @@
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else if (!use_aa && !mask_texture_id && use_color_matrix) {
const RenderPassColorMatrixProgram* program =
- GetRenderPassColorMatrixProgram(tex_coord_precision);
+ GetRenderPassColorMatrixProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1333,9 +1265,12 @@
program->fragment_shader().color_matrix_location();
shader_color_offset_location =
program->fragment_shader().color_offset_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
} else {
const RenderPassProgram* program =
- GetRenderPassProgram(tex_coord_precision);
+ GetRenderPassProgram(tex_coord_precision, shader_blend_mode);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -1343,6 +1278,9 @@
shader_alpha_location = program->fragment_shader().alpha_location();
shader_tex_transform_location =
program->vertex_shader().tex_transform_location();
+ shader_backdrop_location = program->fragment_shader().backdrop_location();
+ shader_backdrop_rect_location =
+ program->fragment_shader().backdrop_rect_location();
}
float tex_scale_x =
quad->rect.width() / static_cast<float>(contents_texture->size().width());
@@ -1362,6 +1300,7 @@
tex_scale_x,
-tex_scale_y));
+ GLint last_texture_unit = 0;
scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_mask_sampler_lock;
if (shader_mask_sampler_location != -1) {
DCHECK_NE(shader_mask_tex_coord_scale_location, 1);
@@ -1382,6 +1321,8 @@
gl_->Uniform2f(shader_mask_tex_coord_scale_location,
mask_uv_rect.width() / tex_scale_x,
-mask_uv_rect.height() / tex_scale_y));
+
+ last_texture_unit = 1;
}
if (shader_edge_location != -1) {
@@ -1417,6 +1358,37 @@
GLC(gl_, gl_->Uniform4fv(shader_color_offset_location, 1, offset));
}
+ scoped_ptr<ResourceProvider::ScopedSamplerGL> shader_background_sampler_lock;
+ if (shader_backdrop_location != -1) {
+ DCHECK(background_texture || background_image);
+ DCHECK_NE(shader_backdrop_location, 0);
+ DCHECK_NE(shader_backdrop_rect_location, 0);
+
+ GLC(gl_, gl_->Uniform1i(shader_backdrop_location, ++last_texture_unit));
+
+ GLC(gl_,
+ gl_->Uniform4f(shader_backdrop_rect_location,
+ background_rect.x(),
+ background_rect.y(),
+ background_rect.width(),
+ background_rect.height()));
+
+ if (background_image) {
+ GrTexture* texture = background_image->getTexture();
+ GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0 + last_texture_unit));
+ gl_->BindTexture(GL_TEXTURE_2D, texture->getTextureHandle());
+ GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0));
+ } else {
+ shader_background_sampler_lock = make_scoped_ptr(
+ new ResourceProvider::ScopedSamplerGL(resource_provider_,
+ background_texture->id(),
+ GL_TEXTURE0 + last_texture_unit,
+ GL_LINEAR));
+ DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
+ shader_background_sampler_lock->target());
+ }
+ }
+
// Map device space quad to surface space. contents_device_transform has no 3d
// component since it was flattened, so we don't need to project.
gfx::QuadF surface_quad = MathUtil::MapQuad(contents_device_transform_inverse,
@@ -2352,7 +2324,8 @@
TexCoordPrecision tex_coord_precision = TexCoordPrecisionRequired(
gl_, &highp_threshold_cache_, highp_threshold_min_, rect.bottom_right());
- const RenderPassProgram* program = GetRenderPassProgram(tex_coord_precision);
+ const RenderPassProgram* program =
+ GetRenderPassProgram(tex_coord_precision, BlendModeNormal);
SetUseProgram(program->program());
GLC(gl_, gl_->Uniform1i(program->fragment_shader().sampler_location(), 0));
@@ -2831,112 +2804,155 @@
}
const GLRenderer::RenderPassProgram* GLRenderer::GetRenderPassProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassProgram* program = &render_pass_program_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassProgram* program = &render_pass_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassProgramAA* GLRenderer::GetRenderPassProgramAA(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassProgramAA* program = &render_pass_program_aa_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassProgramAA* program =
+ &render_pass_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskProgram* GLRenderer::GetRenderPassMaskProgram(
- TexCoordPrecision precision) {
+ TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassMaskProgram* program = &render_pass_mask_program_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassMaskProgram* program =
+ &render_pass_mask_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskProgramAA*
-GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassMaskProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
- RenderPassMaskProgramAA* program = &render_pass_mask_program_aa_[precision];
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
+ RenderPassMaskProgramAA* program =
+ &render_pass_mask_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassMaskProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassColorMatrixProgram*
-GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassColorMatrixProgram* program =
- &render_pass_color_matrix_program_[precision];
+ &render_pass_color_matrix_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::renderPassColorMatrixProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassColorMatrixProgramAA*
-GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassColorMatrixProgramAA* program =
- &render_pass_color_matrix_program_aa_[precision];
+ &render_pass_color_matrix_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassColorMatrixProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskColorMatrixProgram*
-GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassMaskColorMatrixProgram* program =
- &render_pass_mask_color_matrix_program_[precision];
+ &render_pass_mask_color_matrix_program_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassMaskColorMatrixProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
const GLRenderer::RenderPassMaskColorMatrixProgramAA*
-GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
+GLRenderer::GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
DCHECK_GE(precision, 0);
DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_GE(blend_mode, 0);
+ DCHECK_LT(blend_mode, NumBlendModes);
RenderPassMaskColorMatrixProgramAA* program =
- &render_pass_mask_color_matrix_program_aa_[precision];
+ &render_pass_mask_color_matrix_program_aa_[precision][blend_mode];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::renderPassMaskColorMatrixProgramAA::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(),
+ precision,
+ SamplerType2D,
+ blend_mode);
}
return program;
}
@@ -3162,15 +3178,16 @@
tile_program_aa_[i][j].Cleanup(gl_);
tile_program_swizzle_aa_[i][j].Cleanup(gl_);
}
-
- render_pass_mask_program_[i].Cleanup(gl_);
- render_pass_program_[i].Cleanup(gl_);
- render_pass_mask_program_aa_[i].Cleanup(gl_);
- render_pass_program_aa_[i].Cleanup(gl_);
- render_pass_color_matrix_program_[i].Cleanup(gl_);
- render_pass_mask_color_matrix_program_aa_[i].Cleanup(gl_);
- render_pass_color_matrix_program_aa_[i].Cleanup(gl_);
- render_pass_mask_color_matrix_program_[i].Cleanup(gl_);
+ for (int j = 0; j < NumBlendModes; j++) {
+ render_pass_mask_program_[i][j].Cleanup(gl_);
+ render_pass_program_[i][j].Cleanup(gl_);
+ render_pass_mask_program_aa_[i][j].Cleanup(gl_);
+ render_pass_program_aa_[i][j].Cleanup(gl_);
+ render_pass_color_matrix_program_[i][j].Cleanup(gl_);
+ render_pass_mask_color_matrix_program_aa_[i][j].Cleanup(gl_);
+ render_pass_color_matrix_program_aa_[i][j].Cleanup(gl_);
+ render_pass_mask_color_matrix_program_[i][j].Cleanup(gl_);
+ }
texture_program_[i].Cleanup(gl_);
nonpremultiplied_texture_program_[i].Cleanup(gl_);
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index a379dc0..676e7b7 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -153,7 +153,8 @@
gfx::Rect GetBackdropBoundingBoxForRenderPassQuad(
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
- const gfx::Transform& contents_device_transform);
+ const gfx::Transform& contents_device_transform,
+ bool use_aa);
scoped_ptr<ScopedResource> GetBackdropTexture(const gfx::Rect& bounding_rect);
static bool ShouldApplyBackgroundFilters(DrawingFrame* frame,
@@ -166,7 +167,6 @@
DrawingFrame* frame,
const RenderPassDrawQuad* quad,
const gfx::Transform& contents_device_transform_inverse,
- ScopedResource* background_texture,
skia::RefPtr<SkImage> backdrop_bitmap,
const gfx::Rect& backdrop_bounding_rect);
@@ -328,22 +328,28 @@
const TileCheckerboardProgram* GetTileCheckerboardProgram();
- const RenderPassProgram* GetRenderPassProgram(
- TexCoordPrecision precision);
- const RenderPassProgramAA* GetRenderPassProgramAA(
- TexCoordPrecision precision);
+ const RenderPassProgram* GetRenderPassProgram(TexCoordPrecision precision,
+ BlendMode blend_mode);
+ const RenderPassProgramAA* GetRenderPassProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskProgram* GetRenderPassMaskProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskProgramAA* GetRenderPassMaskProgramAA(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassColorMatrixProgram* GetRenderPassColorMatrixProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassColorMatrixProgramAA* GetRenderPassColorMatrixProgramAA(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskColorMatrixProgram* GetRenderPassMaskColorMatrixProgram(
- TexCoordPrecision precision);
+ TexCoordPrecision precision,
+ BlendMode blend_mode);
const RenderPassMaskColorMatrixProgramAA*
- GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision);
+ GetRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode);
const TextureProgram* GetTextureProgram(
TexCoordPrecision precision);
@@ -388,18 +394,21 @@
nonpremultiplied_texture_background_program_[NumTexCoordPrecisions];
TextureProgram texture_io_surface_program_[NumTexCoordPrecisions];
- RenderPassProgram render_pass_program_[NumTexCoordPrecisions];
- RenderPassProgramAA render_pass_program_aa_[NumTexCoordPrecisions];
- RenderPassMaskProgram render_pass_mask_program_[NumTexCoordPrecisions];
- RenderPassMaskProgramAA render_pass_mask_program_aa_[NumTexCoordPrecisions];
+ RenderPassProgram render_pass_program_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassProgramAA
+ render_pass_program_aa_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskProgram
+ render_pass_mask_program_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskProgramAA
+ render_pass_mask_program_aa_[NumTexCoordPrecisions][NumBlendModes];
RenderPassColorMatrixProgram
- render_pass_color_matrix_program_[NumTexCoordPrecisions];
- RenderPassColorMatrixProgramAA
- render_pass_color_matrix_program_aa_[NumTexCoordPrecisions];
- RenderPassMaskColorMatrixProgram
- render_pass_mask_color_matrix_program_[NumTexCoordPrecisions];
- RenderPassMaskColorMatrixProgramAA
- render_pass_mask_color_matrix_program_aa_[NumTexCoordPrecisions];
+ render_pass_color_matrix_program_[NumTexCoordPrecisions][NumBlendModes];
+ RenderPassColorMatrixProgramAA render_pass_color_matrix_program_aa_
+ [NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskColorMatrixProgram render_pass_mask_color_matrix_program_
+ [NumTexCoordPrecisions][NumBlendModes];
+ RenderPassMaskColorMatrixProgramAA render_pass_mask_color_matrix_program_aa_
+ [NumTexCoordPrecisions][NumBlendModes];
VideoYUVProgram video_yuv_program_[NumTexCoordPrecisions];
VideoYUVAProgram video_yuva_program_[NumTexCoordPrecisions];
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index 42e4b5e..8de90c4 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -55,6 +55,44 @@
EXPECT_TRUE((program_binding)->initialized()); \
} while (false)
+static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
+ switch (blend_mode) {
+ case BlendModeNormal:
+ return SkXfermode::kSrcOver_Mode;
+ case BlendModeOverlay:
+ return SkXfermode::kOverlay_Mode;
+ case BlendModeDarken:
+ return SkXfermode::kDarken_Mode;
+ case BlendModeLighten:
+ return SkXfermode::kLighten_Mode;
+ case BlendModeColorDodge:
+ return SkXfermode::kColorDodge_Mode;
+ case BlendModeColorBurn:
+ return SkXfermode::kColorBurn_Mode;
+ case BlendModeHardLight:
+ return SkXfermode::kHardLight_Mode;
+ case BlendModeSoftLight:
+ return SkXfermode::kSoftLight_Mode;
+ case BlendModeDifference:
+ return SkXfermode::kDifference_Mode;
+ case BlendModeExclusion:
+ return SkXfermode::kExclusion_Mode;
+ case BlendModeMultiply:
+ return SkXfermode::kMultiply_Mode;
+ case BlendModeHue:
+ return SkXfermode::kHue_Mode;
+ case BlendModeSaturation:
+ return SkXfermode::kSaturation_Mode;
+ case BlendModeColor:
+ return SkXfermode::kColor_Mode;
+ case BlendModeLuminosity:
+ return SkXfermode::kLuminosity_Mode;
+ case NumBlendModes:
+ NOTREACHED();
+ }
+ return SkXfermode::kSrcOver_Mode;
+}
+
// Explicitly named to be a friend in GLRenderer for shader access.
class GLRendererShaderPixelTest : public GLRendererPixelTest {
public:
@@ -70,18 +108,25 @@
}
void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgram(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassProgramAA(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgram(precision));
- EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskProgramAA(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassColorMatrixProgram(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassMaskColorMatrixProgramAA(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassColorMatrixProgramAA(precision));
- EXPECT_PROGRAM_VALID(
- renderer()->GetRenderPassMaskColorMatrixProgram(precision));
+ for (int i = 0; i < NumBlendModes; ++i) {
+ BlendMode blend_mode = static_cast<BlendMode>(i);
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassProgramAA(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassMaskProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassMaskProgramAA(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassColorMatrixProgram(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgramAA(
+ precision, blend_mode));
+ EXPECT_PROGRAM_VALID(
+ renderer()->GetRenderPassColorMatrixProgramAA(precision, blend_mode));
+ EXPECT_PROGRAM_VALID(renderer()->GetRenderPassMaskColorMatrixProgram(
+ precision, blend_mode));
+ }
EXPECT_PROGRAM_VALID(renderer()->GetTextureProgram(precision));
EXPECT_PROGRAM_VALID(
renderer()->GetNonPremultipliedTextureProgram(precision));
@@ -159,8 +204,7 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
renderer_ = make_scoped_ptr(new FakeRendererGL(&renderer_client_,
&settings_,
output_surface_.get(),
@@ -196,69 +240,91 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
renderer_.reset(new FakeRendererGL(&renderer_client_,
&settings_,
output_surface_.get(),
resource_provider_.get()));
}
- void TestRenderPassProgram(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_[precision]);
- EXPECT_EQ(renderer_->render_pass_program_[precision].program(),
- renderer_->program_shadow_);
- }
-
- void TestRenderPassColorMatrixProgram(TexCoordPrecision precision) {
+ void TestRenderPassProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_color_matrix_program_[precision]);
- EXPECT_EQ(renderer_->render_pass_color_matrix_program_[precision].program(),
+ &renderer_->render_pass_program_[precision][blend_mode]);
+ EXPECT_EQ(renderer_->render_pass_program_[precision][blend_mode].program(),
renderer_->program_shadow_);
}
- void TestRenderPassMaskProgram(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_[precision]);
- EXPECT_EQ(renderer_->render_pass_mask_program_[precision].program(),
- renderer_->program_shadow_);
- }
-
- void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision) {
+ void TestRenderPassColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_mask_color_matrix_program_[precision]);
+ &renderer_->render_pass_color_matrix_program_[precision][blend_mode]);
EXPECT_EQ(
- renderer_->render_pass_mask_color_matrix_program_[precision].program(),
+ renderer_->render_pass_color_matrix_program_[precision][blend_mode]
+ .program(),
renderer_->program_shadow_);
}
- void TestRenderPassProgramAA(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_program_aa_[precision]);
- EXPECT_EQ(renderer_->render_pass_program_aa_[precision].program(),
- renderer_->program_shadow_);
- }
-
- void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision) {
+ void TestRenderPassMaskProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_color_matrix_program_aa_[precision]);
+ &renderer_->render_pass_mask_program_[precision][blend_mode]);
EXPECT_EQ(
- renderer_->render_pass_color_matrix_program_aa_[precision].program(),
+ renderer_->render_pass_mask_program_[precision][blend_mode].program(),
renderer_->program_shadow_);
}
- void TestRenderPassMaskProgramAA(TexCoordPrecision precision) {
- EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_program_aa_[precision]);
- EXPECT_EQ(renderer_->render_pass_mask_program_aa_[precision].program(),
- renderer_->program_shadow_);
+ void TestRenderPassMaskColorMatrixProgram(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_
+ ->render_pass_mask_color_matrix_program_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_mask_color_matrix_program_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
}
- void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision) {
+ void TestRenderPassProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
EXPECT_PROGRAM_VALID(
- &renderer_->render_pass_mask_color_matrix_program_aa_[precision]);
- EXPECT_EQ(renderer_->render_pass_mask_color_matrix_program_aa_[precision]
+ &renderer_->render_pass_program_aa_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_program_aa_[precision][blend_mode].program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_
+ ->render_pass_color_matrix_program_aa_[precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_->render_pass_color_matrix_program_aa_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
+ }
+
+ void TestRenderPassMaskProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(
+ &renderer_->render_pass_mask_program_aa_[precision][blend_mode]);
+ EXPECT_EQ(renderer_->render_pass_mask_program_aa_[precision][blend_mode]
.program(),
renderer_->program_shadow_);
}
+ void TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecision precision,
+ BlendMode blend_mode) {
+ EXPECT_PROGRAM_VALID(&renderer_->render_pass_mask_color_matrix_program_aa_
+ [precision][blend_mode]);
+ EXPECT_EQ(
+ renderer_
+ ->render_pass_mask_color_matrix_program_aa_[precision][blend_mode]
+ .program(),
+ renderer_->program_shadow_);
+ }
+
void TestSolidColorProgramAA() {
EXPECT_PROGRAM_VALID(&renderer_->solid_color_program_aa_);
EXPECT_EQ(renderer_->solid_color_program_aa_.program(),
@@ -470,8 +536,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -511,8 +576,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -551,8 +615,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -604,8 +667,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -650,8 +712,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -736,8 +797,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -808,8 +868,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -900,8 +959,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
settings.should_clear_root_render_pass = false;
@@ -999,8 +1057,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -1098,8 +1155,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
settings.partial_swap_enabled = true;
@@ -1288,8 +1344,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
LayerTreeSettings settings;
FakeRendererClient renderer_client;
@@ -1361,191 +1416,224 @@
gfx::Transform transform_causing_aa;
transform_causing_aa.Rotate(20.0);
- // RenderPassProgram
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- gfx::Transform());
+ for (int i = 0; i < NumBlendModes; ++i) {
+ BlendMode blend_mode = static_cast<BlendMode>(i);
+ SkXfermode::Mode xfer_mode = BlendModeToSkXfermode(blend_mode);
+ // RenderPassProgram
+ render_passes_in_draw_order_.clear();
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, 0, FilterOperations(), gfx::Transform());
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ gfx::Transform(),
+ xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassProgram(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassProgram(TexCoordPrecisionMedium, blend_mode);
- // RenderPassColorMatrixProgram
- render_passes_in_draw_order_.clear();
+ // RenderPassColorMatrixProgram
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(root_pass, child_pass, 0, filters, gfx::Transform());
+ AddRenderPassQuad(
+ root_pass, child_pass, 0, filters, gfx::Transform(), xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium, blend_mode);
- // RenderPassMaskProgram
- render_passes_in_draw_order_.clear();
+ // RenderPassMaskProgram
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- gfx::Transform());
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, mask, FilterOperations(), gfx::Transform());
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ mask,
+ FilterOperations(),
+ gfx::Transform(),
+ xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskProgram(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskProgram(TexCoordPrecisionMedium, blend_mode);
- // RenderPassMaskColorMatrixProgram
- render_passes_in_draw_order_.clear();
+ // RenderPassMaskColorMatrixProgram
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- gfx::Transform());
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ gfx::Transform());
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(root_pass, child_pass, mask, filters, gfx::Transform());
+ AddRenderPassQuad(
+ root_pass, child_pass, mask, filters, gfx::Transform(), xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskColorMatrixProgram(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskColorMatrixProgram(TexCoordPrecisionMedium, blend_mode);
- // RenderPassProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, 0, FilterOperations(), transform_causing_aa);
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ transform_causing_aa,
+ xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassProgramAA(TexCoordPrecisionMedium, blend_mode);
- // RenderPassColorMatrixProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(root_pass, child_pass, 0, filters, transform_causing_aa);
+ AddRenderPassQuad(
+ root_pass, child_pass, 0, filters, transform_causing_aa, xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium, blend_mode);
- // RenderPassMaskProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassMaskProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- gfx::Transform());
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, mask, FilterOperations(), transform_causing_aa);
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ mask,
+ FilterOperations(),
+ transform_causing_aa,
+ xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskProgramAA(TexCoordPrecisionMedium, blend_mode);
- // RenderPassMaskColorMatrixProgramAA
- render_passes_in_draw_order_.clear();
+ // RenderPassMaskColorMatrixProgramAA
+ render_passes_in_draw_order_.clear();
- child_pass = AddRenderPass(&render_passes_in_draw_order_,
- child_pass_id,
- child_rect,
- transform_causing_aa);
+ child_pass = AddRenderPass(&render_passes_in_draw_order_,
+ child_pass_id,
+ child_rect,
+ transform_causing_aa);
- root_pass = AddRenderPass(&render_passes_in_draw_order_,
- root_pass_id,
- viewport_rect,
- transform_causing_aa);
+ root_pass = AddRenderPass(&render_passes_in_draw_order_,
+ root_pass_id,
+ viewport_rect,
+ transform_causing_aa);
- AddRenderPassQuad(root_pass, child_pass, mask, filters, transform_causing_aa);
+ AddRenderPassQuad(
+ root_pass, child_pass, mask, filters, transform_causing_aa, xfer_mode);
- renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
- renderer_->DrawFrame(&render_passes_in_draw_order_,
- 1.f,
- viewport_rect,
- viewport_rect,
- false);
- TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecisionMedium);
+ renderer_->DecideRenderPassAllocationsForFrame(
+ render_passes_in_draw_order_);
+ renderer_->DrawFrame(&render_passes_in_draw_order_,
+ 1.f,
+ viewport_rect,
+ viewport_rect,
+ false);
+ TestRenderPassMaskColorMatrixProgramAA(TexCoordPrecisionMedium, blend_mode);
+ }
}
// At this time, the AA code path cannot be taken if the surface's rect would
@@ -1580,8 +1668,12 @@
viewport_rect,
gfx::Transform());
- AddRenderPassQuad(
- root_pass, child_pass, 0, FilterOperations(), transform_preventing_aa);
+ AddRenderPassQuad(root_pass,
+ child_pass,
+ 0,
+ FilterOperations(),
+ transform_preventing_aa,
+ SkXfermode::kSrcOver_Mode);
renderer_->DecideRenderPassAllocationsForFrame(render_passes_in_draw_order_);
renderer_->DrawFrame(&render_passes_in_draw_order_,
@@ -1592,7 +1684,7 @@
// If use_aa incorrectly ignores clipping, it will use the
// RenderPassProgramAA shader instead of the RenderPassProgram.
- TestRenderPassProgram(TexCoordPrecisionMedium);
+ TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNormal);
}
TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
@@ -1668,8 +1760,7 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
renderer_.reset(new FakeRendererGL(&renderer_client_,
&settings_,
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 92b19c7..8b7dc2a 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -244,15 +244,8 @@
scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
new TestSharedBitmapManager());
- scoped_ptr<ResourceProvider> resource_provider(
- ResourceProvider::Create(&output_surface,
- shared_bitmap_manager.get(),
- NULL,
- NULL,
- 0,
- false,
- 1,
- false));
+ scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
+ &output_surface, shared_bitmap_manager.get(), NULL, NULL, 0, false, 1));
scoped_ptr<DefaultOverlayProcessor> overlay_processor(
new DefaultOverlayProcessor(&output_surface, resource_provider.get()));
@@ -276,8 +269,7 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
overlay_processor_.reset(new SingleOverlayProcessor(
output_surface_.get(), resource_provider_.get()));
@@ -588,7 +580,7 @@
output_surface_.reset(new OverlayOutputSurface(provider_));
CHECK(output_surface_->BindToClient(&output_surface_client_));
resource_provider_ = ResourceProvider::Create(
- output_surface_.get(), NULL, NULL, NULL, 0, false, 1, false);
+ output_surface_.get(), NULL, NULL, NULL, 0, false, 1);
provider_->support()->SetScheduleOverlayPlaneCallback(base::Bind(
&MockOverlayScheduler::Schedule, base::Unretained(&scheduler_)));
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h
index 912329e..722c782 100644
--- a/cc/output/program_binding.h
+++ b/cc/output/program_binding.h
@@ -58,13 +58,16 @@
void Initialize(ContextProvider* context_provider,
TexCoordPrecision precision,
- SamplerType sampler) {
+ SamplerType sampler,
+ BlendMode blend_mode = BlendModeNormal) {
DCHECK(context_provider);
DCHECK(!initialized_);
if (context_provider->IsContextLost())
return;
+ fragment_shader_.set_blend_mode(blend_mode);
+
if (!ProgramBindingBase::Init(
context_provider->ContextGL(),
vertex_shader_.GetShaderString(),
diff --git a/cc/output/renderer_unittest.cc b/cc/output/renderer_unittest.cc
index 229558d..6e43cc0 100644
--- a/cc/output/renderer_unittest.cc
+++ b/cc/output/renderer_unittest.cc
@@ -83,7 +83,7 @@
output_surface_.reset(new TestOutputSurface(context_provider_));
output_surface_->BindToClient(&output_surface_client_);
resource_provider_ = ResourceProvider::Create(
- output_surface_.get(), NULL, NULL, NULL, 0, false, 1, false);
+ output_surface_.get(), NULL, NULL, NULL, 0, false, 1);
renderer_ = CreateRenderer<T>(&renderer_client_,
&tree_settings_,
output_surface_.get(),
diff --git a/cc/output/shader.cc b/cc/output/shader.cc
index 8a25214..98bde8d 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -13,9 +13,10 @@
#define SHADER0(Src) #Src
#define VERTEX_SHADER(Src) SetVertexTexCoordPrecision(SHADER0(Src))
-#define FRAGMENT_SHADER(Src) \
- SetFragmentTexCoordPrecision(precision, \
- SetFragmentSamplerType(sampler, SHADER0(Src)))
+#define FRAGMENT_SHADER(Src) \
+ SetFragmentTexCoordPrecision( \
+ precision, \
+ SetFragmentSamplerType(sampler, SetBlendModeFunctions(SHADER0(Src))))
using gpu::gles2::GLES2Interface;
@@ -666,6 +667,308 @@
// clang-format on
}
+#define BLEND_MODE_UNIFORMS "s_backdropTexture", "backdropRect"
+#define UNUSED_BLEND_MODE_UNIFORMS (is_default_blend_mode() ? 2 : 0)
+#define BLEND_MODE_SET_LOCATIONS(X, POS) \
+ if (!is_default_blend_mode()) { \
+ DCHECK_LT(static_cast<size_t>(POS) + 1, arraysize(X)); \
+ backdrop_location_ = locations[POS]; \
+ backdrop_rect_location_ = locations[POS + 1]; \
+ }
+
+FragmentTexBlendMode::FragmentTexBlendMode()
+ : backdrop_location_(-1),
+ backdrop_rect_location_(-1),
+ blend_mode_(BlendModeNormal) {
+}
+
+std::string FragmentTexBlendMode::SetBlendModeFunctions(
+ std::string shader_string) const {
+ if (shader_string.find("ApplyBlendMode") == std::string::npos)
+ return shader_string;
+
+ if (is_default_blend_mode()) {
+ return "#define ApplyBlendMode(X) (X)\n" + shader_string;
+ }
+
+ // clang-format off
+ static const std::string kFunctionApplyBlendMode = SHADER0(
+ // clang-format on
+ uniform SamplerType s_backdropTexture;
+ uniform TexCoordPrecision vec4 backdropRect;
+
+ vec4 GetBackdropColor() {
+ TexCoordPrecision vec2 bgTexCoord = gl_FragCoord.xy - backdropRect.xy;
+ bgTexCoord.x /= backdropRect.z;
+ bgTexCoord.y /= backdropRect.w;
+ return TextureLookup(s_backdropTexture, bgTexCoord);
+ }
+
+ vec4 ApplyBlendMode(vec4 src) {
+ vec4 dst = GetBackdropColor();
+ return Blend(src, dst);
+ }
+ // clang-format off
+ );
+ // clang-format on
+
+ return "precision mediump float;" + GetHelperFunctions() +
+ GetBlendFunction() + kFunctionApplyBlendMode + shader_string;
+}
+
+std::string FragmentTexBlendMode::GetHelperFunctions() const {
+ // clang-format off
+ static const std::string kFunctionHardLight = SHADER0(
+ // clang-format on
+ vec3 hardLight(vec4 src, vec4 dst) {
+ vec3 result;
+ result.r =
+ (2.0 * src.r <= src.a)
+ ? (2.0 * src.r * dst.r)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.r) * (src.a - src.r));
+ result.g =
+ (2.0 * src.g <= src.a)
+ ? (2.0 * src.g * dst.g)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.g) * (src.a - src.g));
+ result.b =
+ (2.0 * src.b <= src.a)
+ ? (2.0 * src.b * dst.b)
+ : (src.a * dst.a - 2.0 * (dst.a - dst.b) * (src.a - src.b));
+ result.rgb += src.rgb * (1.0 - dst.a) + dst.rgb * (1.0 - src.a);
+ return result;
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionColorDodgeComponent = SHADER0(
+ // clang-format on
+ float getColorDodgeComponent(
+ float srcc, float srca, float dstc, float dsta) {
+ if (0.0 == dstc)
+ return srcc * (1.0 - dsta);
+ float d = srca - srcc;
+ if (0.0 == d)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ d = min(dsta, dstc * srca / d);
+ return d * srca + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionColorBurnComponent = SHADER0(
+ // clang-format on
+ float getColorBurnComponent(
+ float srcc, float srca, float dstc, float dsta) {
+ if (dsta == dstc)
+ return srca * dsta + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ if (0.0 == srcc)
+ return dstc * (1.0 - srca);
+ float d = max(0.0, dsta - (dsta - dstc) * srca / srcc);
+ return srca * d + srcc * (1.0 - dsta) + dstc * (1.0 - srca);
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionSoftLightComponentPosDstAlpha = SHADER0(
+ // clang-format on
+ float getSoftLightComponent(
+ float srcc, float srca, float dstc, float dsta) {
+ if (2.0 * srcc <= srca) {
+ return (dstc * dstc * (srca - 2.0 * srcc)) / dsta +
+ (1.0 - dsta) * srcc + dstc * (-srca + 2.0 * srcc + 1.0);
+ } else if (4.0 * dstc <= dsta) {
+ float DSqd = dstc * dstc;
+ float DCub = DSqd * dstc;
+ float DaSqd = dsta * dsta;
+ float DaCub = DaSqd * dsta;
+ return (-DaCub * srcc +
+ DaSqd * (srcc - dstc * (3.0 * srca - 6.0 * srcc - 1.0)) +
+ 12.0 * dsta * DSqd * (srca - 2.0 * srcc) -
+ 16.0 * DCub * (srca - 2.0 * srcc)) /
+ DaSqd;
+ } else {
+ return -sqrt(dsta * dstc) * (srca - 2.0 * srcc) - dsta * srcc +
+ dstc * (srca - 2.0 * srcc + 1.0) + srcc;
+ }
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionLum = SHADER0(
+ // clang-format on
+ float luminance(vec3 color) { return dot(vec3(0.3, 0.59, 0.11), color); }
+
+ vec3 set_luminance(vec3 hueSat, float alpha, vec3 lumColor) {
+ float diff = luminance(lumColor - hueSat);
+ vec3 outColor = hueSat + diff;
+ float outLum = luminance(outColor);
+ float minComp = min(min(outColor.r, outColor.g), outColor.b);
+ float maxComp = max(max(outColor.r, outColor.g), outColor.b);
+ if (minComp < 0.0) {
+ outColor = outLum +
+ ((outColor - vec3(outLum, outLum, outLum)) * outLum) /
+ (outLum - minComp);
+ }
+ if (maxComp > alpha) {
+ outColor =
+ outLum +
+ ((outColor - vec3(outLum, outLum, outLum)) * (alpha - outLum)) /
+ (maxComp - outLum);
+ }
+ return outColor;
+ }
+ // clang-format off
+ );
+
+ static const std::string kFunctionSat = SHADER0(
+ // clang-format on
+ float saturation(vec3 color) {
+ return max(max(color.r, color.g), color.b) -
+ min(min(color.r, color.g), color.b);
+ }
+
+ vec3 set_saturation_helper(
+ float minComp, float midComp, float maxComp, float sat) {
+ if (minComp < maxComp) {
+ vec3 result;
+ result.r = 0.0;
+ result.g = sat * (midComp - minComp) / (maxComp - minComp);
+ result.b = sat;
+ return result;
+ } else {
+ return vec3(0, 0, 0);
+ }
+ }
+
+ vec3 set_saturation(vec3 hueLumColor, vec3 satColor) {
+ float sat = saturation(satColor);
+ if (hueLumColor.r <= hueLumColor.g) {
+ if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.rgb = set_saturation_helper(
+ hueLumColor.r, hueLumColor.g, hueLumColor.b, sat);
+ } else if (hueLumColor.r <= hueLumColor.b) {
+ hueLumColor.rbg = set_saturation_helper(
+ hueLumColor.r, hueLumColor.b, hueLumColor.g, sat);
+ } else {
+ hueLumColor.brg = set_saturation_helper(
+ hueLumColor.b, hueLumColor.r, hueLumColor.g, sat);
+ }
+ } else if (hueLumColor.r <= hueLumColor.b) {
+ hueLumColor.grb = set_saturation_helper(
+ hueLumColor.g, hueLumColor.r, hueLumColor.b, sat);
+ } else if (hueLumColor.g <= hueLumColor.b) {
+ hueLumColor.gbr = set_saturation_helper(
+ hueLumColor.g, hueLumColor.b, hueLumColor.r, sat);
+ } else {
+ hueLumColor.bgr = set_saturation_helper(
+ hueLumColor.b, hueLumColor.g, hueLumColor.r, sat);
+ }
+ return hueLumColor;
+ }
+ // clang-format off
+ );
+ // clang-format on
+
+ switch (blend_mode_) {
+ case BlendModeOverlay:
+ case BlendModeHardLight:
+ return kFunctionHardLight;
+ case BlendModeColorDodge:
+ return kFunctionColorDodgeComponent;
+ case BlendModeColorBurn:
+ return kFunctionColorBurnComponent;
+ case BlendModeSoftLight:
+ return kFunctionSoftLightComponentPosDstAlpha;
+ case BlendModeHue:
+ case BlendModeSaturation:
+ return kFunctionLum + kFunctionSat;
+ case BlendModeColor:
+ case BlendModeLuminosity:
+ return kFunctionLum;
+ default:
+ return std::string();
+ }
+}
+
+std::string FragmentTexBlendMode::GetBlendFunction() const {
+ return "vec4 Blend(vec4 src, vec4 dst) {"
+ " vec4 result;"
+ " result.a = src.a + (1.0 - src.a) * dst.a;" +
+ GetBlendFunctionBodyForRGB() +
+ " return result;"
+ "}";
+}
+
+std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
+ switch (blend_mode_) {
+ case BlendModeLighten:
+ return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
+ " (1.0 - dst.a) * src.rgb + dst.rgb);";
+ case BlendModeOverlay:
+ return "result.rgb = hardLight(dst, src);";
+ case BlendModeDarken:
+ return "result.rgb = min((1.0 - src.a) * dst.rgb + src.rgb,"
+ " (1.0 - dst.a) * src.rgb + dst.rgb);";
+ case BlendModeColorDodge:
+ return "result.r = getColorDodgeComponent(src.r, src.a, dst.r, dst.a);"
+ "result.g = getColorDodgeComponent(src.g, src.a, dst.g, dst.a);"
+ "result.b = getColorDodgeComponent(src.b, src.a, dst.b, dst.a);";
+ case BlendModeColorBurn:
+ return "result.r = getColorBurnComponent(src.r, src.a, dst.r, dst.a);"
+ "result.g = getColorBurnComponent(src.g, src.a, dst.g, dst.a);"
+ "result.b = getColorBurnComponent(src.b, src.a, dst.b, dst.a);";
+ case BlendModeHardLight:
+ return "result.rgb = hardLight(src, dst);";
+ case BlendModeSoftLight:
+ return "if (0.0 == dst.a) {"
+ " result.rgb = src.rgb;"
+ "} else {"
+ " result.r = getSoftLightComponent(src.r, src.a, dst.r, dst.a);"
+ " result.g = getSoftLightComponent(src.g, src.a, dst.g, dst.a);"
+ " result.b = getSoftLightComponent(src.b, src.a, dst.b, dst.a);"
+ "}";
+ case BlendModeDifference:
+ return "result.rgb = src.rgb + dst.rgb -"
+ " 2.0 * min(src.rgb * dst.a, dst.rgb * src.a);";
+ case BlendModeExclusion:
+ return "result.rgb = dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb;";
+ case BlendModeMultiply:
+ return "result.rgb = (1.0 - src.a) * dst.rgb +"
+ " (1.0 - dst.a) * src.rgb + src.rgb * dst.rgb;";
+ case BlendModeHue:
+ return "vec4 dstSrcAlpha = dst * src.a;"
+ "result.rgb ="
+ " set_luminance(set_saturation(src.rgb * dst.a,"
+ " dstSrcAlpha.rgb),"
+ " dstSrcAlpha.a,"
+ " dstSrcAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BlendModeSaturation:
+ return "vec4 dstSrcAlpha = dst * src.a;"
+ "result.rgb = set_luminance(set_saturation(dstSrcAlpha.rgb,"
+ " src.rgb * dst.a),"
+ " dstSrcAlpha.a,"
+ " dstSrcAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BlendModeColor:
+ return "vec4 srcDstAlpha = src * dst.a;"
+ "result.rgb = set_luminance(srcDstAlpha.rgb,"
+ " srcDstAlpha.a,"
+ " dst.rgb * src.a);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ case BlendModeLuminosity:
+ return "vec4 srcDstAlpha = src * dst.a;"
+ "result.rgb = set_luminance(dst.rgb * src.a,"
+ " srcDstAlpha.a,"
+ " srcDstAlpha.rgb);"
+ "result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
+ default:
+ NOTREACHED();
+ // simple alpha compositing
+ return "result.rgb = src.rgb * src.a + dst.rgb * dst.a * (1 - src.a)";
+ }
+}
+
FragmentTexAlphaBinding::FragmentTexAlphaBinding()
: sampler_location_(-1), alpha_location_(-1) {
}
@@ -674,18 +977,19 @@
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha",
+ "s_texture", "alpha", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
sampler_location_ = locations[0];
alpha_location_ = locations[1];
+ BLEND_MODE_SET_LOCATIONS(locations, 2);
}
FragmentTexColorMatrixAlphaBinding::FragmentTexColorMatrixAlphaBinding()
@@ -699,13 +1003,13 @@
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha", "colorMatrix", "colorOffset",
+ "s_texture", "alpha", "colorMatrix", "colorOffset", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -713,6 +1017,7 @@
alpha_location_ = locations[1];
color_matrix_location_ = locations[2];
color_offset_location_ = locations[3];
+ BLEND_MODE_SET_LOCATIONS(locations, 4);
}
FragmentTexOpaqueBinding::FragmentTexOpaqueBinding() : sampler_location_(-1) {
@@ -747,7 +1052,7 @@
uniform float alpha;
void main() {
vec4 texColor = TextureLookup(s_texture, v_texCoord);
- gl_FragColor = texColor * alpha;
+ gl_FragColor = ApplyBlendMode(texColor * alpha);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -773,7 +1078,7 @@
texColor = colorMatrix * texColor + colorOffset;
texColor.rgb *= texColor.a;
texColor = clamp(texColor, 0.0, 1.0);
- gl_FragColor = texColor * alpha;
+ gl_FragColor = ApplyBlendMode(texColor * alpha);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -966,18 +1271,19 @@
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha",
+ "s_texture", "alpha", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
sampler_location_ = locations[0];
alpha_location_ = locations[1];
+ BLEND_MODE_SET_LOCATIONS(locations, 2);
}
std::string FragmentShaderRGBATexAlphaAA::GetShaderString(
@@ -997,7 +1303,7 @@
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1097,13 +1403,18 @@
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "s_mask", "alpha", "maskTexCoordScale", "maskTexCoordOffset",
+ "s_texture",
+ "s_mask",
+ "alpha",
+ "maskTexCoordScale",
+ "maskTexCoordOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1112,6 +1423,7 @@
alpha_location_ = locations[2];
mask_tex_coord_scale_location_ = locations[3];
mask_tex_coord_offset_location_ = locations[4];
+ BLEND_MODE_SET_LOCATIONS(locations, 5);
}
std::string FragmentShaderRGBATexAlphaMask::GetShaderString(
@@ -1133,7 +1445,7 @@
vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- gl_FragColor = texColor * alpha * maskColor.w;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1152,13 +1464,18 @@
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "s_mask", "alpha", "maskTexCoordScale", "maskTexCoordOffset",
+ "s_texture",
+ "s_mask",
+ "alpha",
+ "maskTexCoordScale",
+ "maskTexCoordOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1167,6 +1484,7 @@
alpha_location_ = locations[2];
mask_tex_coord_scale_location_ = locations[3];
mask_tex_coord_offset_location_ = locations[4];
+ BLEND_MODE_SET_LOCATIONS(locations, 5);
}
std::string FragmentShaderRGBATexAlphaMaskAA::GetShaderString(
@@ -1193,7 +1511,7 @@
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * maskColor.w * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1222,12 +1540,13 @@
"maskTexCoordOffset",
"colorMatrix",
"colorOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1238,6 +1557,7 @@
mask_tex_coord_offset_location_ = locations[4];
color_matrix_location_ = locations[5];
color_offset_location_ = locations[6];
+ BLEND_MODE_SET_LOCATIONS(locations, 7);
}
std::string FragmentShaderRGBATexAlphaMaskColorMatrixAA::GetShaderString(
@@ -1271,7 +1591,7 @@
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * maskColor.w * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1290,13 +1610,13 @@
unsigned program,
int* base_uniform_index) {
static const char* uniforms[] = {
- "s_texture", "alpha", "colorMatrix", "colorOffset",
+ "s_texture", "alpha", "colorMatrix", "colorOffset", BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1304,6 +1624,7 @@
alpha_location_ = locations[1];
color_matrix_location_ = locations[2];
color_offset_location_ = locations[3];
+ BLEND_MODE_SET_LOCATIONS(locations, 4);
}
std::string FragmentShaderRGBATexAlphaColorMatrixAA::GetShaderString(
@@ -1330,7 +1651,7 @@
vec4 d4 = min(edge_dist[0], edge_dist[1]);
vec2 d2 = min(d4.xz, d4.yw);
float aa = clamp(gl_FragCoord.w * min(d2.x, d2.y), 0.0, 1.0);
- gl_FragColor = texColor * alpha * aa;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * aa);
}
// clang-format off
); // NOLINT(whitespace/parens)
@@ -1356,12 +1677,13 @@
"maskTexCoordOffset",
"colorMatrix",
"colorOffset",
+ BLEND_MODE_UNIFORMS,
};
int locations[arraysize(uniforms)];
GetProgramUniformLocations(context,
program,
- arraysize(uniforms),
+ arraysize(uniforms) - UNUSED_BLEND_MODE_UNIFORMS,
uniforms,
locations,
base_uniform_index);
@@ -1372,6 +1694,7 @@
mask_tex_coord_offset_location_ = locations[4];
color_matrix_location_ = locations[5];
color_offset_location_ = locations[6];
+ BLEND_MODE_SET_LOCATIONS(locations, 7);
}
std::string FragmentShaderRGBATexAlphaMaskColorMatrix::GetShaderString(
@@ -1400,7 +1723,7 @@
vec2(maskTexCoordOffset.x + v_texCoord.x * maskTexCoordScale.x,
maskTexCoordOffset.y + v_texCoord.y * maskTexCoordScale.y);
vec4 maskColor = TextureLookup(s_mask, maskTexCoord);
- gl_FragColor = texColor * alpha * maskColor.w;
+ gl_FragColor = ApplyBlendMode(texColor * alpha * maskColor.w);
}
// clang-format off
); // NOLINT(whitespace/parens)
diff --git a/cc/output/shader.h b/cc/output/shader.h
index 3039c80..0384366 100644
--- a/cc/output/shader.h
+++ b/cc/output/shader.h
@@ -38,6 +38,25 @@
NumSamplerTypes = 4
};
+enum BlendMode {
+ BlendModeNormal,
+ BlendModeOverlay,
+ BlendModeDarken,
+ BlendModeLighten,
+ BlendModeColorDodge,
+ BlendModeColorBurn,
+ BlendModeHardLight,
+ BlendModeSoftLight,
+ BlendModeDifference,
+ BlendModeExclusion,
+ BlendModeMultiply,
+ BlendModeHue,
+ BlendModeSaturation,
+ BlendModeColor,
+ BlendModeLuminosity,
+ NumBlendModes
+};
+
// Note: The highp_threshold_cache must be provided by the caller to make
// the caching multi-thread/context safe in an easy low-overhead manner.
// The caller must make sure to clear highp_threshold_cache to 0, so it can be
@@ -279,7 +298,32 @@
DISALLOW_COPY_AND_ASSIGN(VertexShaderVideoTransform);
};
-class FragmentTexAlphaBinding {
+class FragmentTexBlendMode {
+ public:
+ int backdrop_location() const { return backdrop_location_; }
+ int backdrop_rect_location() const { return backdrop_rect_location_; }
+
+ BlendMode blend_mode() const { return blend_mode_; }
+ void set_blend_mode(BlendMode blend_mode) { blend_mode_ = blend_mode; }
+ bool is_default_blend_mode() const { return blend_mode_ == BlendModeNormal; }
+
+ protected:
+ FragmentTexBlendMode();
+
+ std::string SetBlendModeFunctions(std::string shader_string) const;
+
+ int backdrop_location_;
+ int backdrop_rect_location_;
+
+ private:
+ BlendMode blend_mode_;
+
+ std::string GetHelperFunctions() const;
+ std::string GetBlendFunction() const;
+ std::string GetBlendFunctionBodyForRGB() const;
+};
+
+class FragmentTexAlphaBinding : public FragmentTexBlendMode {
public:
FragmentTexAlphaBinding();
@@ -297,7 +341,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentTexAlphaBinding);
};
-class FragmentTexColorMatrixAlphaBinding {
+class FragmentTexColorMatrixAlphaBinding : public FragmentTexBlendMode {
public:
FragmentTexColorMatrixAlphaBinding();
@@ -317,7 +361,7 @@
int color_offset_location_;
};
-class FragmentTexOpaqueBinding {
+class FragmentTexOpaqueBinding : public FragmentTexBlendMode {
public:
FragmentTexOpaqueBinding();
@@ -335,7 +379,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentTexOpaqueBinding);
};
-class FragmentTexBackgroundBinding {
+class FragmentTexBackgroundBinding : public FragmentTexBlendMode {
public:
FragmentTexBackgroundBinding();
@@ -417,7 +461,7 @@
TexCoordPrecision precision, SamplerType sampler) const;
};
-class FragmentShaderRGBATexAlphaAA {
+class FragmentShaderRGBATexAlphaAA : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaAA();
@@ -437,7 +481,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentShaderRGBATexAlphaAA);
};
-class FragmentTexClampAlphaAABinding {
+class FragmentTexClampAlphaAABinding : public FragmentTexBlendMode {
public:
FragmentTexClampAlphaAABinding();
@@ -473,7 +517,7 @@
TexCoordPrecision precision, SamplerType sampler) const;
};
-class FragmentShaderRGBATexAlphaMask {
+class FragmentShaderRGBATexAlphaMask : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMask();
std::string GetShaderString(
@@ -502,7 +546,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentShaderRGBATexAlphaMask);
};
-class FragmentShaderRGBATexAlphaMaskAA {
+class FragmentShaderRGBATexAlphaMaskAA : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMaskAA();
std::string GetShaderString(
@@ -531,7 +575,8 @@
DISALLOW_COPY_AND_ASSIGN(FragmentShaderRGBATexAlphaMaskAA);
};
-class FragmentShaderRGBATexAlphaMaskColorMatrixAA {
+class FragmentShaderRGBATexAlphaMaskColorMatrixAA
+ : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMaskColorMatrixAA();
std::string GetShaderString(
@@ -562,7 +607,7 @@
int color_offset_location_;
};
-class FragmentShaderRGBATexAlphaColorMatrixAA {
+class FragmentShaderRGBATexAlphaColorMatrixAA : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaColorMatrixAA();
std::string GetShaderString(
@@ -583,7 +628,7 @@
int color_offset_location_;
};
-class FragmentShaderRGBATexAlphaMaskColorMatrix {
+class FragmentShaderRGBATexAlphaMaskColorMatrix : public FragmentTexBlendMode {
public:
FragmentShaderRGBATexAlphaMaskColorMatrix();
std::string GetShaderString(
@@ -614,7 +659,7 @@
int color_offset_location_;
};
-class FragmentShaderYUVVideo {
+class FragmentShaderYUVVideo : public FragmentTexBlendMode {
public:
FragmentShaderYUVVideo();
std::string GetShaderString(
@@ -641,8 +686,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentShaderYUVVideo);
};
-
-class FragmentShaderYUVAVideo {
+class FragmentShaderYUVAVideo : public FragmentTexBlendMode {
public:
FragmentShaderYUVAVideo();
std::string GetShaderString(
@@ -672,7 +716,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentShaderYUVAVideo);
};
-class FragmentShaderColor {
+class FragmentShaderColor : public FragmentTexBlendMode {
public:
FragmentShaderColor();
std::string GetShaderString(
@@ -689,7 +733,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentShaderColor);
};
-class FragmentShaderColorAA {
+class FragmentShaderColorAA : public FragmentTexBlendMode {
public:
FragmentShaderColorAA();
std::string GetShaderString(
@@ -706,7 +750,7 @@
DISALLOW_COPY_AND_ASSIGN(FragmentShaderColorAA);
};
-class FragmentShaderCheckerboard {
+class FragmentShaderCheckerboard : public FragmentTexBlendMode {
public:
FragmentShaderCheckerboard();
std::string GetShaderString(
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index c3cb828..acc897f 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -239,14 +239,16 @@
current_canvas_->setMatrix(sk_device_matrix);
current_paint_.reset();
- if (!IsScaleAndIntegerTranslate(sk_device_matrix)) {
+ if (settings_->force_antialiasing ||
+ !IsScaleAndIntegerTranslate(sk_device_matrix)) {
// TODO(danakj): Until we can enable AA only on exterior edges of the
// layer, disable AA if any interior edges are present. crbug.com/248175
bool all_four_edges_are_exterior = quad->IsTopEdge() &&
quad->IsLeftEdge() &&
quad->IsBottomEdge() &&
quad->IsRightEdge();
- if (settings_->allow_antialiasing && all_four_edges_are_exterior)
+ if (settings_->allow_antialiasing &&
+ (settings_->force_antialiasing || all_four_edges_are_exterior))
current_paint_.setAntiAlias(true);
current_paint_.setFilterLevel(SkPaint::kLow_FilterLevel);
}
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index 1e373b2..60f75d9 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -42,8 +42,7 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
renderer_ = SoftwareRenderer::Create(
this, &settings_, output_surface_.get(), resource_provider());
}
diff --git a/cc/resources/gpu_raster_worker_pool.cc b/cc/resources/gpu_raster_worker_pool.cc
index a0bc86f..cba427e 100644
--- a/cc/resources/gpu_raster_worker_pool.cc
+++ b/cc/resources/gpu_raster_worker_pool.cc
@@ -26,17 +26,25 @@
public:
RasterBufferImpl(ResourceProvider* resource_provider,
const Resource* resource,
- SkMultiPictureDraw* multi_picture_draw)
+ SkMultiPictureDraw* multi_picture_draw,
+ bool use_distance_field_text)
: lock_(resource_provider, resource->id()),
resource_(resource),
- multi_picture_draw_(multi_picture_draw) {}
+ multi_picture_draw_(multi_picture_draw),
+ use_distance_field_text_(use_distance_field_text) {}
// Overridden from RasterBuffer:
void Playback(const PicturePileImpl* picture_pile,
const gfx::Rect& rect,
float scale,
RenderingStatsInstrumentation* stats) override {
- if (!lock_.sk_surface())
+ // Turn on distance fields for layers that have ever animated.
+ bool use_distance_field_text =
+ use_distance_field_text_ ||
+ picture_pile->likely_to_be_used_for_transform_animation();
+ SkSurface* sk_surface = lock_.GetSkSurface(use_distance_field_text);
+
+ if (!sk_surface)
return;
SkPictureRecorder recorder;
@@ -50,13 +58,14 @@
// Add the canvas and recorded picture to |multi_picture_draw_|.
skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
- multi_picture_draw_->add(lock_.sk_surface()->getCanvas(), picture.get());
+ multi_picture_draw_->add(sk_surface->getCanvas(), picture.get());
}
private:
ResourceProvider::ScopedWriteLockGr lock_;
const Resource* resource_;
SkMultiPictureDraw* multi_picture_draw_;
+ bool use_distance_field_text_;
DISALLOW_COPY_AND_ASSIGN(RasterBufferImpl);
};
@@ -67,20 +76,26 @@
scoped_ptr<RasterWorkerPool> GpuRasterWorkerPool::Create(
base::SequencedTaskRunner* task_runner,
ContextProvider* context_provider,
- ResourceProvider* resource_provider) {
- return make_scoped_ptr<RasterWorkerPool>(new GpuRasterWorkerPool(
- task_runner, context_provider, resource_provider));
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text) {
+ return make_scoped_ptr<RasterWorkerPool>(
+ new GpuRasterWorkerPool(task_runner,
+ context_provider,
+ resource_provider,
+ use_distance_field_text));
}
GpuRasterWorkerPool::GpuRasterWorkerPool(base::SequencedTaskRunner* task_runner,
ContextProvider* context_provider,
- ResourceProvider* resource_provider)
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text)
: task_runner_(task_runner),
task_graph_runner_(new TaskGraphRunner),
namespace_token_(task_graph_runner_->GetNamespaceToken()),
context_provider_(context_provider),
resource_provider_(resource_provider),
run_tasks_on_origin_thread_pending_(false),
+ use_distance_field_text_(use_distance_field_text),
raster_finished_weak_ptr_factory_(this),
weak_ptr_factory_(this) {
DCHECK(context_provider_);
@@ -190,7 +205,10 @@
scoped_ptr<RasterBuffer> GpuRasterWorkerPool::AcquireBufferForRaster(
const Resource* resource) {
return make_scoped_ptr<RasterBuffer>(
- new RasterBufferImpl(resource_provider_, resource, &multi_picture_draw_));
+ new RasterBufferImpl(resource_provider_,
+ resource,
+ &multi_picture_draw_,
+ use_distance_field_text_));
}
void GpuRasterWorkerPool::ReleaseBufferForRaster(
diff --git a/cc/resources/gpu_raster_worker_pool.h b/cc/resources/gpu_raster_worker_pool.h
index a4e4197..c5ff13f 100644
--- a/cc/resources/gpu_raster_worker_pool.h
+++ b/cc/resources/gpu_raster_worker_pool.h
@@ -23,7 +23,8 @@
static scoped_ptr<RasterWorkerPool> Create(
base::SequencedTaskRunner* task_runner,
ContextProvider* context_provider,
- ResourceProvider* resource_provider);
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text);
// Overridden from RasterWorkerPool:
Rasterizer* AsRasterizer() override;
@@ -42,7 +43,8 @@
private:
GpuRasterWorkerPool(base::SequencedTaskRunner* task_runner,
ContextProvider* context_provider,
- ResourceProvider* resource_provider);
+ ResourceProvider* resource_provider,
+ bool use_distance_field_text);
void OnRasterFinished(TaskSet task_set);
void ScheduleRunTasksOnOriginThread();
@@ -58,6 +60,7 @@
SkMultiPictureDraw multi_picture_draw_;
bool run_tasks_on_origin_thread_pending_;
+ bool use_distance_field_text_;
TaskSetCollection raster_pending_;
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 9cc3a59..8f91763 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -40,8 +40,7 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
}
virtual void SetUp() override {
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index 1806ebc..96b47a6 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -19,12 +19,8 @@
} // namespace
-
-PictureLayerTilingSet::PictureLayerTilingSet(
- PictureLayerTilingClient* client,
- const gfx::Size& layer_bounds)
- : client_(client),
- layer_bounds_(layer_bounds) {
+PictureLayerTilingSet::PictureLayerTilingSet(PictureLayerTilingClient* client)
+ : client_(client) {
}
PictureLayerTilingSet::~PictureLayerTilingSet() {
@@ -47,7 +43,6 @@
float minimum_contents_scale) {
if (new_layer_bounds.IsEmpty()) {
RemoveAllTilings();
- layer_bounds_ = new_layer_bounds;
return false;
}
@@ -99,17 +94,17 @@
}
tilings_.sort(LargestToSmallestScaleFunctor());
- layer_bounds_ = new_layer_bounds;
return have_high_res_tiling;
}
-PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) {
+PictureLayerTiling* PictureLayerTilingSet::AddTiling(
+ float contents_scale,
+ const gfx::Size& layer_bounds) {
for (size_t i = 0; i < tilings_.size(); ++i)
DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
- tilings_.push_back(PictureLayerTiling::Create(contents_scale,
- layer_bounds_,
- client_));
+ tilings_.push_back(
+ PictureLayerTiling::Create(contents_scale, layer_bounds, client_));
PictureLayerTiling* appended = tilings_.back();
tilings_.sort(LargestToSmallestScaleFunctor());
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h
index 63f3110..6f61243 100644
--- a/cc/resources/picture_layer_tiling_set.h
+++ b/cc/resources/picture_layer_tiling_set.h
@@ -34,8 +34,7 @@
size_t end;
};
- PictureLayerTilingSet(PictureLayerTilingClient* client,
- const gfx::Size& layer_bounds);
+ explicit PictureLayerTilingSet(PictureLayerTilingClient* client);
~PictureLayerTilingSet();
void SetClient(PictureLayerTilingClient* client);
@@ -53,9 +52,8 @@
const Region& layer_invalidation,
float minimum_contents_scale);
- gfx::Size layer_bounds() const { return layer_bounds_; }
-
- PictureLayerTiling* AddTiling(float contents_scale);
+ PictureLayerTiling* AddTiling(float contents_scale,
+ const gfx::Size& layer_bounds);
size_t num_tilings() const { return tilings_.size(); }
int NumHighResTilings() const;
PictureLayerTiling* tiling_at(size_t idx) { return tilings_[idx]; }
@@ -126,7 +124,6 @@
private:
PictureLayerTilingClient* client_;
- gfx::Size layer_bounds_;
ScopedPtrVector<PictureLayerTiling> tilings_;
friend class Iterator;
diff --git a/cc/resources/picture_layer_tiling_set_unittest.cc b/cc/resources/picture_layer_tiling_set_unittest.cc
index f4059e4..3d249f3 100644
--- a/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -23,12 +23,12 @@
TEST(PictureLayerTilingSetTest, NoResources) {
FakePictureLayerTilingClient client;
gfx::Size layer_bounds(1000, 800);
- PictureLayerTilingSet set(&client, layer_bounds);
+ PictureLayerTilingSet set(&client);
client.SetTileSize(gfx::Size(256, 256));
- set.AddTiling(1.0);
- set.AddTiling(1.5);
- set.AddTiling(2.0);
+ set.AddTiling(1.0, layer_bounds);
+ set.AddTiling(1.5, layer_bounds);
+ set.AddTiling(2.0, layer_bounds);
float contents_scale = 2.0;
gfx::Size content_bounds(
@@ -64,14 +64,14 @@
PictureLayerTiling* high_res_tiling;
PictureLayerTiling* low_res_tiling;
- PictureLayerTilingSet set(&client, layer_bounds);
- set.AddTiling(2.0);
- high_res_tiling = set.AddTiling(1.0);
+ PictureLayerTilingSet set(&client);
+ set.AddTiling(2.0, layer_bounds);
+ high_res_tiling = set.AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
- set.AddTiling(0.5);
- low_res_tiling = set.AddTiling(0.25);
+ set.AddTiling(0.5, layer_bounds);
+ low_res_tiling = set.AddTiling(0.25, layer_bounds);
low_res_tiling->set_resolution(LOW_RESOLUTION);
- set.AddTiling(0.125);
+ set.AddTiling(0.125, layer_bounds);
higher_than_high_res_range =
set.GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
@@ -96,12 +96,12 @@
EXPECT_EQ(4u, lower_than_low_res_range.start);
EXPECT_EQ(5u, lower_than_low_res_range.end);
- PictureLayerTilingSet set_without_low_res(&client, layer_bounds);
- set_without_low_res.AddTiling(2.0);
- high_res_tiling = set_without_low_res.AddTiling(1.0);
+ PictureLayerTilingSet set_without_low_res(&client);
+ set_without_low_res.AddTiling(2.0, layer_bounds);
+ high_res_tiling = set_without_low_res.AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
- set_without_low_res.AddTiling(0.5);
- set_without_low_res.AddTiling(0.25);
+ set_without_low_res.AddTiling(0.5, layer_bounds);
+ set_without_low_res.AddTiling(0.25, layer_bounds);
higher_than_high_res_range = set_without_low_res.GetTilingRange(
PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
@@ -126,10 +126,10 @@
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
- PictureLayerTilingSet set_with_only_high_and_low_res(&client, layer_bounds);
- high_res_tiling = set_with_only_high_and_low_res.AddTiling(1.0);
+ PictureLayerTilingSet set_with_only_high_and_low_res(&client);
+ high_res_tiling = set_with_only_high_and_low_res.AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
- low_res_tiling = set_with_only_high_and_low_res.AddTiling(0.5);
+ low_res_tiling = set_with_only_high_and_low_res.AddTiling(0.5, layer_bounds);
low_res_tiling->set_resolution(LOW_RESOLUTION);
higher_than_high_res_range = set_with_only_high_and_low_res.GetTilingRange(
@@ -158,8 +158,8 @@
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
- PictureLayerTilingSet set_with_only_high_res(&client, layer_bounds);
- high_res_tiling = set_with_only_high_res.AddTiling(1.0);
+ PictureLayerTilingSet set_with_only_high_res(&client);
+ high_res_tiling = set_with_only_high_res.AddTiling(1.0, layer_bounds);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
higher_than_high_res_range = set_with_only_high_res.GetTilingRange(
@@ -209,18 +209,17 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
FakePictureLayerTilingClient client(resource_provider.get());
client.SetTileSize(gfx::Size(256, 256));
client.set_tree(PENDING_TREE);
gfx::Size layer_bounds(1000, 800);
- PictureLayerTilingSet set(&client, layer_bounds);
+ PictureLayerTilingSet set(&client);
float scale = min_scale;
for (int i = 0; i < num_tilings; ++i, scale += scale_increment) {
- PictureLayerTiling* tiling = set.AddTiling(scale);
+ PictureLayerTiling* tiling = set.AddTiling(scale, layer_bounds);
tiling->CreateAllTilesForTesting();
std::vector<Tile*> tiles = tiling->AllTilesForTesting();
client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
@@ -298,8 +297,8 @@
source_client_.set_tree(PENDING_TREE);
target_client_.SetTileSize(tile_size_);
target_client_.set_tree(PENDING_TREE);
- source_.reset(new PictureLayerTilingSet(&source_client_, source_bounds_));
- target_.reset(new PictureLayerTilingSet(&target_client_, target_bounds_));
+ source_.reset(new PictureLayerTilingSet(&source_client_));
+ target_.reset(new PictureLayerTilingSet(&target_client_));
}
// Sync from source to target.
@@ -329,7 +328,6 @@
void VerifyTargetEqualsSource(const gfx::Size& new_bounds) {
ASSERT_FALSE(new_bounds.IsEmpty());
EXPECT_EQ(target_->num_tilings(), source_->num_tilings());
- EXPECT_EQ(target_->layer_bounds().ToString(), new_bounds.ToString());
for (size_t i = 0; i < target_->num_tilings(); ++i) {
ASSERT_GT(source_->num_tilings(), i);
@@ -404,21 +402,20 @@
TEST_F(PictureLayerTilingSetSyncTest, EmptyBounds) {
float source_scales[] = {1.f, 1.2f};
for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i]);
+ source_->AddTiling(source_scales[i], source_bounds_);
- gfx::Size new_bounds;
- SyncTilings(new_bounds);
+ gfx::Size empty_bounds;
+ SyncTilings(empty_bounds);
EXPECT_EQ(target_->num_tilings(), 0u);
- EXPECT_EQ(target_->layer_bounds().ToString(), new_bounds.ToString());
}
TEST_F(PictureLayerTilingSetSyncTest, AllNew) {
float source_scales[] = {0.5f, 1.f, 1.2f};
for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i]);
+ source_->AddTiling(source_scales[i], source_bounds_);
float target_scales[] = {0.75f, 1.4f, 3.f};
for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i]);
+ target_->AddTiling(target_scales[i], target_bounds_);
gfx::Size new_bounds(15, 40);
SyncTilings(new_bounds);
@@ -437,10 +434,10 @@
TEST_F(PictureLayerTilingSetSyncTest, KeepExisting) {
float source_scales[] = {0.7f, 1.f, 1.1f, 2.f};
for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i]);
+ source_->AddTiling(source_scales[i], source_bounds_);
float target_scales[] = {0.5f, 1.f, 2.f};
for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i]);
+ target_->AddTiling(target_scales[i], target_bounds_);
PictureLayerTiling* tiling1 = source_->TilingAtScale(1.f);
ASSERT_TRUE(tiling1);
@@ -472,7 +469,7 @@
TEST_F(PictureLayerTilingSetSyncTest, EmptySet) {
float target_scales[] = {0.2f, 1.f};
for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i]);
+ target_->AddTiling(target_scales[i], target_bounds_);
gfx::Size new_bounds(15, 40);
SyncTilings(new_bounds);
@@ -482,10 +479,10 @@
TEST_F(PictureLayerTilingSetSyncTest, MinimumScale) {
float source_scales[] = {0.7f, 1.f, 1.1f, 2.f};
for (size_t i = 0; i < arraysize(source_scales); ++i)
- source_->AddTiling(source_scales[i]);
+ source_->AddTiling(source_scales[i], source_bounds_);
float target_scales[] = {0.5f, 0.7f, 1.f, 1.1f, 2.f};
for (size_t i = 0; i < arraysize(target_scales); ++i)
- target_->AddTiling(target_scales[i]);
+ target_->AddTiling(target_scales[i], target_bounds_);
gfx::Size new_bounds(15, 40);
float minimum_scale = 1.5f;
@@ -497,8 +494,8 @@
}
TEST_F(PictureLayerTilingSetSyncTest, Invalidation) {
- source_->AddTiling(2.f);
- target_->AddTiling(2.f);
+ source_->AddTiling(2.f, source_bounds_);
+ target_->AddTiling(2.f, target_bounds_);
target_->tiling_at(0)->CreateAllTilesForTesting();
Region layer_invalidation;
@@ -535,8 +532,8 @@
}
TEST_F(PictureLayerTilingSetSyncTest, TileSizeChange) {
- source_->AddTiling(1.f);
- target_->AddTiling(1.f);
+ source_->AddTiling(1.f, source_bounds_);
+ target_->AddTiling(1.f, target_bounds_);
target_->tiling_at(0)->CreateAllTilesForTesting();
std::vector<Tile*> original_tiles =
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index c871da4..07da353 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -1262,15 +1262,8 @@
scoped_ptr<FakeOutputSurface> output_surface = FakeOutputSurface::Create3d();
CHECK(output_surface->BindToClient(&output_surface_client));
TestSharedBitmapManager shared_bitmap_manager;
- scoped_ptr<ResourceProvider> resource_provider =
- ResourceProvider::Create(output_surface.get(),
- &shared_bitmap_manager,
- NULL,
- NULL,
- 0,
- false,
- 1,
- false);
+ scoped_ptr<ResourceProvider> resource_provider = ResourceProvider::Create(
+ output_surface.get(), &shared_bitmap_manager, NULL, NULL, 0, false, 1);
FakePictureLayerTilingClient client(resource_provider.get());
scoped_ptr<TestablePictureLayerTiling> tiling;
@@ -1463,9 +1456,9 @@
client_.SetTileSize(tile_size);
client_.set_tree(PENDING_TREE);
- PictureLayerTilingSet active_set(&client_, layer_bounds);
+ PictureLayerTilingSet active_set(&client_);
- active_set.AddTiling(1.f);
+ active_set.AddTiling(1.f, layer_bounds);
VerifyTiles(active_set.tiling_at(0),
1.f,
@@ -1485,7 +1478,7 @@
base::Bind(&TileExists, true));
// Add the same tilings to the pending set.
- PictureLayerTilingSet pending_set(&client_, layer_bounds);
+ PictureLayerTilingSet pending_set(&client_);
Region invalidation;
pending_set.SyncTilings(active_set, layer_bounds, invalidation, 0.f);
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index f4fbdf2..e19dd2c 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -28,11 +28,13 @@
return make_scoped_refptr(new PicturePileImpl(other));
}
-PicturePileImpl::PicturePileImpl() {
+PicturePileImpl::PicturePileImpl()
+ : likely_to_be_used_for_transform_animation_(false) {
}
PicturePileImpl::PicturePileImpl(const PicturePileBase* other)
- : PicturePileBase(other) {
+ : PicturePileBase(other),
+ likely_to_be_used_for_transform_animation_(false) {
}
PicturePileImpl::~PicturePileImpl() {
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index a9bef0c..243601e 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -58,6 +58,13 @@
skia::RefPtr<SkPicture> GetFlattenedPicture();
+ bool likely_to_be_used_for_transform_animation() const {
+ return likely_to_be_used_for_transform_animation_;
+ }
+ void set_likely_to_be_used_for_transform_animation() {
+ likely_to_be_used_for_transform_animation_ = true;
+ }
+
struct CC_EXPORT Analysis {
Analysis();
~Analysis();
@@ -124,6 +131,8 @@
RenderingStatsInstrumentation* rendering_stats_instrumentation,
bool is_analysis) const;
+ bool likely_to_be_used_for_transform_animation_;
+
DISALLOW_COPY_AND_ASSIGN(PicturePileImpl);
};
diff --git a/cc/resources/prioritized_resource_unittest.cc b/cc/resources/prioritized_resource_unittest.cc
index 5109a60..8869e70 100644
--- a/cc/resources/prioritized_resource_unittest.cc
+++ b/cc/resources/prioritized_resource_unittest.cc
@@ -34,8 +34,7 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
}
virtual ~PrioritizedResourceTest() {
diff --git a/cc/resources/raster_worker_pool_perftest.cc b/cc/resources/raster_worker_pool_perftest.cc
index 4264373..0f7a845 100644
--- a/cc/resources/raster_worker_pool_perftest.cc
+++ b/cc/resources/raster_worker_pool_perftest.cc
@@ -262,7 +262,8 @@
raster_worker_pool_ =
GpuRasterWorkerPool::Create(task_runner_.get(),
context_provider_.get(),
- resource_provider_.get());
+ resource_provider_.get(),
+ false);
break;
case RASTER_WORKER_POOL_TYPE_BITMAP:
CreateSoftwareOutputSurfaceAndResourceProvider();
@@ -406,8 +407,7 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
}
void CreateSoftwareOutputSurfaceAndResourceProvider() {
@@ -420,8 +420,7 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
}
std::string TestModifierString() const {
@@ -491,7 +490,7 @@
CHECK(output_surface_->BindToClient(&output_surface_client_));
resource_provider_ =
ResourceProvider::Create(
- output_surface_.get(), NULL, NULL, NULL, 0, false, 1, false).Pass();
+ output_surface_.get(), NULL, NULL, NULL, 0, false, 1).Pass();
}
void RunBuildRasterTaskQueueTest(const std::string& test_name,
diff --git a/cc/resources/raster_worker_pool_unittest.cc b/cc/resources/raster_worker_pool_unittest.cc
index 2227128..a6d6c65 100644
--- a/cc/resources/raster_worker_pool_unittest.cc
+++ b/cc/resources/raster_worker_pool_unittest.cc
@@ -164,7 +164,8 @@
raster_worker_pool_ =
GpuRasterWorkerPool::Create(base::MessageLoopProxy::current().get(),
context_provider_.get(),
- resource_provider_.get());
+ resource_provider_.get(),
+ false);
break;
case RASTER_WORKER_POOL_TYPE_BITMAP:
CreateSoftwareOutputSurfaceAndResourceProvider();
@@ -279,8 +280,7 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
}
void CreateSoftwareOutputSurfaceAndResourceProvider() {
@@ -293,8 +293,7 @@
NULL,
0,
false,
- 1,
- false).Pass();
+ 1).Pass();
}
void OnTaskCompleted(scoped_ptr<ScopedResource> resource,
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 1697ac2..550475b 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -411,8 +411,7 @@
BlockingTaskRunner* blocking_main_thread_task_runner,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size,
- bool use_distance_field_text) {
+ size_t id_allocation_chunk_size) {
scoped_ptr<ResourceProvider> resource_provider(
new ResourceProvider(output_surface,
shared_bitmap_manager,
@@ -420,8 +419,7 @@
blocking_main_thread_task_runner,
highp_threshold_min,
use_rgba_4444_texture_format,
- id_allocation_chunk_size,
- use_distance_field_text));
+ id_allocation_chunk_size));
if (resource_provider->ContextGL())
resource_provider->InitializeGL();
@@ -995,38 +993,12 @@
resource->read_lock_fences_enabled = true;
}
-const ResourceProvider::Resource* ResourceProvider::LockForWriteToSkSurface(
- ResourceId id) {
+void ResourceProvider::LockForWriteToSkSurface(ResourceId id) {
Resource* resource = GetResource(id);
DCHECK_EQ(GLTexture, resource->type);
DCHECK(CanLockForWrite(id));
resource->locked_for_write = true;
- if (!resource->sk_surface) {
- class GrContext* gr_context = GrContext();
- // TODO(alokp): Implement TestContextProvider::GrContext().
- if (!gr_context)
- return resource;
-
- LazyAllocate(resource);
-
- GrBackendTextureDesc desc;
- desc.fFlags = kRenderTarget_GrBackendTextureFlag;
- desc.fWidth = resource->size.width();
- desc.fHeight = resource->size.height();
- desc.fConfig = ToGrPixelConfig(resource->format);
- desc.fOrigin = kTopLeft_GrSurfaceOrigin;
- desc.fTextureHandle = resource->gl_id;
- skia::RefPtr<GrTexture> gr_texture =
- skia::AdoptRef(gr_context->wrapBackendTexture(desc));
- SkSurface::TextRenderMode text_render_mode =
- use_distance_field_text_ ? SkSurface::kDistanceField_TextRenderMode
- : SkSurface::kStandard_TextRenderMode;
- resource->sk_surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
- gr_texture->asRenderTarget(), text_render_mode));
- }
-
- return resource;
}
void ResourceProvider::UnlockForWriteToSkSurface(ResourceId id) {
@@ -1141,16 +1113,49 @@
ResourceProvider::ScopedWriteLockGr::ScopedWriteLockGr(
ResourceProvider* resource_provider,
ResourceProvider::ResourceId resource_id)
- : resource_provider_(resource_provider),
- resource_id_(resource_id),
- sk_surface_(resource_provider->LockForWriteToSkSurface(resource_id)
- ->sk_surface.get()) {
+ : resource_provider_(resource_provider), resource_id_(resource_id) {
+ resource_provider->LockForWriteToSkSurface(resource_id);
}
ResourceProvider::ScopedWriteLockGr::~ScopedWriteLockGr() {
resource_provider_->UnlockForWriteToSkSurface(resource_id_);
}
+SkSurface* ResourceProvider::ScopedWriteLockGr::GetSkSurface(
+ bool use_distance_field_text) {
+ Resource* resource = resource_provider_->GetResource(resource_id_);
+ DCHECK(resource->locked_for_write);
+
+ // If the surface doesn't exist, or doesn't have the correct dff setting,
+ // recreate the surface within the resource.
+ if (!resource->sk_surface ||
+ use_distance_field_text !=
+ resource->sk_surface->props().isUseDistanceFieldFonts()) {
+ class GrContext* gr_context = resource_provider_->GrContext();
+ // TODO(alokp): Implement TestContextProvider::GrContext().
+ if (!gr_context)
+ return nullptr;
+
+ resource_provider_->LazyAllocate(resource);
+
+ GrBackendTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrBackendTextureFlag;
+ desc.fWidth = resource->size.width();
+ desc.fHeight = resource->size.height();
+ desc.fConfig = ToGrPixelConfig(resource->format);
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fTextureHandle = resource->gl_id;
+ skia::RefPtr<GrTexture> gr_texture =
+ skia::AdoptRef(gr_context->wrapBackendTexture(desc));
+ SkSurface::TextRenderMode text_render_mode =
+ use_distance_field_text ? SkSurface::kDistanceField_TextRenderMode
+ : SkSurface::kStandard_TextRenderMode;
+ resource->sk_surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
+ gr_texture->asRenderTarget(), text_render_mode));
+ }
+ return resource->sk_surface.get();
+}
+
ResourceProvider::ResourceProvider(
OutputSurface* output_surface,
SharedBitmapManager* shared_bitmap_manager,
@@ -1158,8 +1163,7 @@
BlockingTaskRunner* blocking_main_thread_task_runner,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size,
- bool use_distance_field_text)
+ size_t id_allocation_chunk_size)
: output_surface_(output_surface),
shared_bitmap_manager_(shared_bitmap_manager),
gpu_memory_buffer_manager_(gpu_memory_buffer_manager),
@@ -1177,8 +1181,7 @@
best_texture_format_(RGBA_8888),
use_rgba_4444_texture_format_(use_rgba_4444_texture_format),
id_allocation_chunk_size_(id_allocation_chunk_size),
- use_sync_query_(false),
- use_distance_field_text_(use_distance_field_text) {
+ use_sync_query_(false) {
DCHECK(output_surface_->HasClient());
DCHECK(id_allocation_chunk_size_);
}
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 1e70132..fbec8d1 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -83,8 +83,7 @@
BlockingTaskRunner* blocking_main_thread_task_runner,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size,
- bool use_distance_field_text);
+ size_t id_allocation_chunk_size);
virtual ~ResourceProvider();
void InitializeSoftware();
@@ -328,12 +327,11 @@
ResourceProvider::ResourceId resource_id);
~ScopedWriteLockGr();
- SkSurface* sk_surface() { return sk_surface_; }
+ SkSurface* GetSkSurface(bool use_distance_field_text);
private:
ResourceProvider* resource_provider_;
ResourceProvider::ResourceId resource_id_;
- SkSurface* sk_surface_;
DISALLOW_COPY_AND_ASSIGN(ScopedWriteLockGr);
};
@@ -488,8 +486,7 @@
BlockingTaskRunner* blocking_main_thread_task_runner,
int highp_threshold_min,
bool use_rgba_4444_texture_format,
- size_t id_allocation_chunk_size,
- bool use_distance_field_text);
+ size_t id_allocation_chunk_size);
void CleanUpGLIfNeeded();
@@ -500,7 +497,7 @@
void UnlockForWrite(ResourceId id);
const Resource* LockForWriteToGpuMemoryBuffer(ResourceId id);
void UnlockForWriteToGpuMemoryBuffer(ResourceId id);
- const Resource* LockForWriteToSkSurface(ResourceId id);
+ void LockForWriteToSkSurface(ResourceId id);
void UnlockForWriteToSkSurface(ResourceId id);
static void PopulateSkBitmapWithResource(SkBitmap* sk_bitmap,
@@ -562,8 +559,6 @@
bool use_sync_query_;
- bool use_distance_field_text_;
-
DISALLOW_COPY_AND_ASSIGN(ResourceProvider);
};
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 3aea34f..2c585c4 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -423,8 +423,7 @@
main_thread_task_runner_.get(),
0,
false,
- 1,
- false);
+ 1);
child_resource_provider_ =
ResourceProvider::Create(child_output_surface_.get(),
shared_bitmap_manager_.get(),
@@ -432,8 +431,7 @@
main_thread_task_runner_.get(),
0,
false,
- 1,
- false);
+ 1);
}
static void CollectResources(ReturnedResourceArray* array,
@@ -1168,8 +1166,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -1651,8 +1648,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
scoped_ptr<TextureStateTrackingContext> parent_context_owned(
new TextureStateTrackingContext);
@@ -1670,8 +1666,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2303,8 +2298,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2391,8 +2385,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2447,8 +2440,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2507,8 +2499,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -2581,8 +2572,7 @@
main_thread_task_runner_.get(),
0,
false,
- 1,
- false));
+ 1));
uint32 release_sync_point = 0;
bool lost_resource = false;
@@ -2634,8 +2624,7 @@
main_thread_task_runner_.get(),
0,
false,
- 1,
- false));
+ 1));
unsigned texture_id = 1;
uint32 sync_point = 30;
@@ -2720,8 +2709,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
unsigned texture_id = 1;
uint32 sync_point = 30;
@@ -2796,8 +2784,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
uint32 sync_point = 30;
unsigned target = GL_TEXTURE_2D;
@@ -2856,8 +2843,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
uint32 sync_point = 0;
unsigned target = GL_TEXTURE_2D;
@@ -2983,8 +2969,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(2, 2);
gfx::Vector2d offset(0, 0);
@@ -3064,8 +3049,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(2, 2);
@@ -3125,8 +3109,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
gfx::Size size(2, 2);
const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888};
@@ -3185,8 +3168,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
@@ -3233,8 +3215,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
@@ -3281,8 +3262,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id));
@@ -3327,8 +3307,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
@@ -3415,8 +3394,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
source_id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
@@ -3498,8 +3476,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
@@ -3538,8 +3515,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
int texture_id = 123;
ResourceProvider::ResourceId id = resource_provider->CreateResource(
@@ -3575,8 +3551,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
int texture_id = 123;
uint8_t pixels[8];
@@ -3637,8 +3612,7 @@
NULL,
0,
false,
- kTextureAllocationChunkSize,
- false));
+ kTextureAllocationChunkSize));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
@@ -3658,8 +3632,7 @@
NULL,
0,
false,
- kTextureAllocationChunkSize,
- false));
+ kTextureAllocationChunkSize));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
diff --git a/cc/resources/resource_update_controller_unittest.cc b/cc/resources/resource_update_controller_unittest.cc
index 49f7b47..d6b4f39 100644
--- a/cc/resources/resource_update_controller_unittest.cc
+++ b/cc/resources/resource_update_controller_unittest.cc
@@ -130,8 +130,7 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
}
void AppendFullUploadsOfIndexedTextureToUpdateQueue(int count,
diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc
index 7c7e055..a141218 100644
--- a/cc/resources/scoped_resource_unittest.cc
+++ b/cc/resources/scoped_resource_unittest.cc
@@ -28,8 +28,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
@@ -55,8 +54,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
texture->Allocate(
@@ -85,8 +83,7 @@
NULL,
0,
false,
- 1,
- false));
+ 1));
{
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 46f2e14..3671081 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -157,21 +157,26 @@
}
EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(17u, tile_count);
+ EXPECT_EQ(16u, tile_count);
// Sanity check, all tiles should be visible.
std::set<Tile*> smoothness_tiles;
queue.Reset();
host_impl_.BuildRasterQueue(&queue, SMOOTHNESS_TAKES_PRIORITY);
+ bool had_low_res = false;
while (!queue.IsEmpty()) {
Tile* tile = queue.Top();
EXPECT_TRUE(tile);
EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin);
- smoothness_tiles.insert(tile);
+ if (tile->priority(ACTIVE_TREE).resolution == LOW_RESOLUTION)
+ had_low_res = true;
+ else
+ smoothness_tiles.insert(tile);
queue.Pop();
}
EXPECT_EQ(all_tiles, smoothness_tiles);
+ EXPECT_TRUE(had_low_res);
Region invalidation(gfx::Rect(0, 0, 500, 500));
@@ -198,10 +203,13 @@
// Populate all tiles directly from the tilings.
all_tiles.clear();
+ std::set<Tile*> high_res_tiles;
std::vector<Tile*> pending_high_res_tiles =
pending_layer_->HighResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < pending_high_res_tiles.size(); ++i)
+ for (size_t i = 0; i < pending_high_res_tiles.size(); ++i) {
all_tiles.insert(pending_high_res_tiles[i]);
+ high_res_tiles.insert(pending_high_res_tiles[i]);
+ }
std::vector<Tile*> pending_low_res_tiles =
pending_layer_->LowResTiling()->AllTilesForTesting();
@@ -210,8 +218,10 @@
std::vector<Tile*> active_high_res_tiles =
active_layer_->HighResTiling()->AllTilesForTesting();
- for (size_t i = 0; i < active_high_res_tiles.size(); ++i)
+ for (size_t i = 0; i < active_high_res_tiles.size(); ++i) {
all_tiles.insert(active_high_res_tiles[i]);
+ high_res_tiles.insert(active_high_res_tiles[i]);
+ }
std::vector<Tile*> active_low_res_tiles =
active_layer_->LowResTiling()->AllTilesForTesting();
@@ -275,6 +285,7 @@
// Here we expect to get increasing PENDING_TREE priority_bin.
queue.Reset();
host_impl_.BuildRasterQueue(&queue, NEW_CONTENT_TAKES_PRIORITY);
+ tile_count = 0;
while (!queue.IsEmpty()) {
Tile* tile = queue.Top();
EXPECT_TRUE(tile);
@@ -300,14 +311,15 @@
last_tile = tile;
new_content_tiles.insert(tile);
+ ++tile_count;
queue.Pop();
}
EXPECT_EQ(tile_count, new_content_tiles.size());
- EXPECT_EQ(all_tiles, new_content_tiles);
+ EXPECT_EQ(high_res_tiles, new_content_tiles);
// Since we don't guarantee increasing distance due to spiral iterator, we
// should check that we're _mostly_ right.
- EXPECT_GT(increasing_distance_tiles, 3 * tile_count / 4);
+ EXPECT_GE(increasing_distance_tiles, 3 * tile_count / 4);
}
TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueue) {
@@ -332,7 +344,7 @@
}
EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(17u, tile_count);
+ EXPECT_EQ(16u, tile_count);
tile_manager()->InitializeTilesWithResourcesForTesting(
std::vector<Tile*>(all_tiles.begin(), all_tiles.end()));
@@ -507,7 +519,7 @@
raster_queue.Pop();
}
EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(34u, tile_count);
+ EXPECT_EQ(32u, tile_count);
pending_layer_->ResetAllTilesPriorities();
@@ -609,7 +621,7 @@
}
EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(17u, tile_count);
+ EXPECT_EQ(16u, tile_count);
queue.Reset();
for (int i = 1; i < 10; ++i) {
@@ -633,7 +645,7 @@
queue.Pop();
}
EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(17u, tile_count);
+ EXPECT_EQ(16u, tile_count);
}
TEST_F(TileManagerTilePriorityQueueTest, EvictionTilePriorityQueueEmptyLayers) {
@@ -655,7 +667,7 @@
raster_queue.Pop();
}
EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(17u, tile_count);
+ EXPECT_EQ(16u, tile_count);
std::vector<Tile*> tiles(all_tiles.begin(), all_tiles.end());
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
@@ -682,7 +694,7 @@
queue.Pop();
}
EXPECT_EQ(tile_count, all_tiles.size());
- EXPECT_EQ(17u, tile_count);
+ EXPECT_EQ(16u, tile_count);
}
} // namespace
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index bb6238c..c0a4af4 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -35,8 +35,7 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
}
scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index a395f5c..29b0f8e 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -58,7 +58,6 @@
int highp_threshold_min = 0;
bool use_rgba_4444_texture_format = false;
size_t id_allocation_chunk_size = 1;
- bool use_distance_field_text = false;
scoped_ptr<ResourceProvider> resource_provider =
ResourceProvider::Create(output_surface_.get(),
bitmap_manager_,
@@ -66,8 +65,7 @@
blocking_main_thread_task_runner_.get(),
highp_threshold_min,
use_rgba_4444_texture_format,
- id_allocation_chunk_size,
- use_distance_field_text);
+ id_allocation_chunk_size);
if (!resource_provider)
return;
diff --git a/cc/surfaces/surface_aggregator_unittest.cc b/cc/surfaces/surface_aggregator_unittest.cc
index ef369f4..cea06ea 100644
--- a/cc/surfaces/surface_aggregator_unittest.cc
+++ b/cc/surfaces/surface_aggregator_unittest.cc
@@ -1127,8 +1127,7 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
aggregator_.reset(
new SurfaceAggregator(&manager_, resource_provider_.get()));
diff --git a/cc/test/data/background_filter_blur_off_axis.png b/cc/test/data/background_filter_blur_off_axis.png
index b5777f4..050ec54 100644
--- a/cc/test/data/background_filter_blur_off_axis.png
+++ b/cc/test/data/background_filter_blur_off_axis.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass.png b/cc/test/data/blending_render_pass.png
new file mode 100644
index 0000000..76fe369
--- /dev/null
+++ b/cc/test/data/blending_render_pass.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_cm.png b/cc/test/data/blending_render_pass_cm.png
new file mode 100644
index 0000000..9a72d44
--- /dev/null
+++ b/cc/test/data/blending_render_pass_cm.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_mask.png b/cc/test/data/blending_render_pass_mask.png
new file mode 100644
index 0000000..8b63f35
--- /dev/null
+++ b/cc/test/data/blending_render_pass_mask.png
Binary files differ
diff --git a/cc/test/data/blending_render_pass_mask_cm.png b/cc/test/data/blending_render_pass_mask_cm.png
new file mode 100644
index 0000000..4e210aa
--- /dev/null
+++ b/cc/test/data/blending_render_pass_mask_cm.png
Binary files differ
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index c47a083..1565b8a 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -124,8 +124,7 @@
main_thread_task_runner_.get(),
0,
false,
- 1,
- false);
+ 1);
texture_mailbox_deleter_ = make_scoped_ptr(
new TextureMailboxDeleter(base::MessageLoopProxy::current()));
@@ -173,8 +172,7 @@
main_thread_task_runner_.get(),
0,
false,
- 1,
- false);
+ 1);
renderer_ = SoftwareRenderer::Create(
this, &settings_, output_surface_.get(), resource_provider_.get());
}
diff --git a/cc/test/render_pass_test_utils.cc b/cc/test/render_pass_test_utils.cc
index 519c74a..c923b63 100644
--- a/cc/test/render_pass_test_utils.cc
+++ b/cc/test/render_pass_test_utils.cc
@@ -111,7 +111,8 @@
TestRenderPass* contributing_pass,
ResourceProvider::ResourceId mask_resource_id,
const FilterOperations& filters,
- gfx::Transform transform) {
+ gfx::Transform transform,
+ SkXfermode::Mode blend_mode) {
gfx::Rect output_rect = contributing_pass->output_rect;
SharedQuadState* shared_state = to_pass->CreateAndAppendSharedQuadState();
shared_state->SetAll(transform,
@@ -120,7 +121,7 @@
output_rect,
false,
1,
- SkXfermode::kSrcOver_Mode,
+ blend_mode,
0);
RenderPassDrawQuad* quad =
to_pass->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
diff --git a/cc/test/render_pass_test_utils.h b/cc/test/render_pass_test_utils.h
index 7bf026c..49ea113 100644
--- a/cc/test/render_pass_test_utils.h
+++ b/cc/test/render_pass_test_utils.h
@@ -53,7 +53,8 @@
TestRenderPass* contributing_pass,
ResourceProvider::ResourceId mask_resource_id,
const FilterOperations& filters,
- gfx::Transform transform);
+ gfx::Transform transform,
+ SkXfermode::Mode blend_mode);
} // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index ddb315f..4ccc5fe 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2028,8 +2028,11 @@
GL_TEXTURE_2D,
resource_provider_->best_texture_format());
- raster_worker_pool_ = GpuRasterWorkerPool::Create(
- task_runner, context_provider, resource_provider_.get());
+ raster_worker_pool_ =
+ GpuRasterWorkerPool::Create(task_runner,
+ context_provider,
+ resource_provider_.get(),
+ settings_.use_distance_field_text);
} else if (UseZeroCopyRasterizer()) {
resource_pool_ = ResourcePool::Create(
resource_provider_.get(),
@@ -2135,8 +2138,7 @@
proxy_->blocking_main_thread_task_runner(),
settings_.highp_threshold_min,
settings_.use_rgba_4444_textures,
- settings_.texture_id_allocation_chunk_size,
- settings_.use_distance_field_text);
+ settings_.texture_id_allocation_chunk_size);
if (output_surface_->capabilities().deferred_gl_initialization)
EnforceZeroBudget(true);
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 7b466d0..51d86d3 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -901,19 +901,10 @@
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
- gfx::Vector2dF expected_container_size_delta(
- container_layer->bounds().width(), container_layer->bounds().height());
- expected_container_size_delta.Scale((1.f - page_scale_delta) /
- (page_scale_factor * page_scale_delta));
host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
- // While the gesture is still active, the scroll layer should have a
- // container size delta = container->bounds() * ((1.f -
- // page_scale_delta)/())
- EXPECT_EQ(expected_container_size_delta,
- scroll_layer->FixedContainerSizeDelta());
host_impl_->PinchGestureEnd();
host_impl_->ScrollEnd();
EXPECT_FALSE(did_request_animate_);
@@ -2244,6 +2235,7 @@
clip_size_(layer_size_) {
settings_.calculate_top_controls_position = true;
settings_.top_controls_height = 50;
+ settings_.use_pinch_virtual_viewport = true;
viewport_size_ =
gfx::Size(clip_size_.width(),
@@ -2386,8 +2378,8 @@
}
TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsByFractionalAmount) {
- CreateHostImpl(settings_, CreateOutputSurface());
- SetupTopControlsAndScrollLayer();
+ SetupTopControlsAndScrollLayerWithVirtualViewport(
+ gfx::Size(10, 10), gfx::Size(10, 10), gfx::Size(10, 10));
DrawFrame();
EXPECT_EQ(InputHandler::ScrollStarted,
@@ -2409,36 +2401,56 @@
inner_viewport_scroll_layer->FixedContainerSizeDelta());
}
-TEST_F(LayerTreeHostImplTopControlsTest, ScrollTopControlsWithPageScale) {
- CreateHostImpl(settings_, CreateOutputSurface());
- SetupTopControlsAndScrollLayer();
+// Test that the fixed position container delta is appropriately adjusted
+// by the top controls showing/hiding and page scale doesn't affect it.
+TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) {
+ SetupTopControlsAndScrollLayerWithVirtualViewport(
+ gfx::Size(100, 100), gfx::Size(100, 100), gfx::Size(100, 100));
DrawFrame();
+ float page_scale = 1.5f;
+ float top_controls_height = settings_.top_controls_height;
+ LayerImpl* outer_viewport_scroll_layer =
+ host_impl_->active_tree()->OuterViewportScrollLayer();
+
+ // Zoom in, since the fixed container is the outer viewport, the delta should
+ // not be scaled.
+ host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale, 1.f, 2.f);
+
EXPECT_EQ(InputHandler::ScrollStarted,
host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- float page_scale = 1.5f;
- host_impl_->active_tree()->SetPageScaleFactorAndLimits(page_scale, 1.f, 2.f);
-
- gfx::Vector2dF top_controls_scroll_delta(0.f, 5.f);
- gfx::Vector2dF expected_container_size_delta =
- ScaleVector2d(top_controls_scroll_delta, 1.f / page_scale);
+ // Scroll down, the top controls hiding should expand the viewport size so
+ // the delta should be equal to the scroll distance.
+ gfx::Vector2dF top_controls_scroll_delta(0.f, 20.f);
host_impl_->top_controls_manager()->ScrollBegin();
host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
- host_impl_->top_controls_manager()->ScrollEnd();
-
- LayerImpl* inner_viewport_scroll_layer =
- host_impl_->active_tree()->InnerViewportScrollLayer();
- DCHECK(inner_viewport_scroll_layer);
+ EXPECT_EQ(top_controls_height - top_controls_scroll_delta.y(),
+ host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_VECTOR_EQ(top_controls_scroll_delta,
+ outer_viewport_scroll_layer->FixedContainerSizeDelta());
host_impl_->ScrollEnd();
- // Use a tolerance that requires the container size delta to be within 0.01
- // pixels.
- double tolerance = 0.0001;
- EXPECT_LT(
- (expected_container_size_delta -
- inner_viewport_scroll_layer->FixedContainerSizeDelta()).LengthSquared(),
- tolerance);
+ // Scroll past the maximum extent. The delta shouldn't be greater than the
+ // top controls height.
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
+ host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
+ host_impl_->top_controls_manager()->ScrollBy(top_controls_scroll_delta);
+ EXPECT_EQ(0.f, host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_VECTOR_EQ(gfx::Vector2dF(0, top_controls_height),
+ outer_viewport_scroll_layer->FixedContainerSizeDelta());
+ host_impl_->ScrollEnd();
+
+ // Scroll in the direction to make the top controls show.
+ host_impl_->top_controls_manager()->ScrollBegin();
+ host_impl_->top_controls_manager()->ScrollBy(-top_controls_scroll_delta);
+ EXPECT_EQ(top_controls_scroll_delta.y(),
+ host_impl_->top_controls_manager()->ContentTopOffset());
+ EXPECT_VECTOR_EQ(
+ gfx::Vector2dF(0, top_controls_height - top_controls_scroll_delta.y()),
+ outer_viewport_scroll_layer->FixedContainerSizeDelta());
+ host_impl_->top_controls_manager()->ScrollEnd();
}
// Ensure setting the top controls position explicitly using the setters on the
diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
index f01d426..bebd612 100644
--- a/cc/trees/layer_tree_host_pixeltest_blending.cc
+++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "cc/layers/image_layer.h"
#include "cc/layers/solid_color_layer.h"
-#include "cc/layers/texture_layer.h"
#include "cc/test/layer_tree_pixel_test.h"
#include "cc/test/pixel_comparator.h"
@@ -22,7 +22,36 @@
SkXfermode::kHue_Mode, SkXfermode::kSaturation_Mode,
SkXfermode::kColor_Mode, SkXfermode::kLuminosity_Mode};
+SkColor kCSSTestColors[] = {
+ 0xffff0000, // red
+ 0xff00ff00, // lime
+ 0xff0000ff, // blue
+ 0xff00ffff, // aqua
+ 0xffff00ff, // fuchsia
+ 0xffffff00, // yellow
+ 0xff008000, // green
+ 0xff800000, // maroon
+ 0xff000080, // navy
+ 0xff800080, // purple
+ 0xff808000, // olive
+ 0xff008080, // teal
+ 0xfffa8072, // salmon
+ 0xffc0c0c0, // silver
+ 0xff000000, // black
+ 0xff808080, // gray
+ 0x80000000, // black with transparency
+ 0xffffffff, // white
+ 0x80ffffff, // white with transparency
+ 0x00000000 // transparent
+};
+
const int kBlendModesCount = arraysize(kBlendModes);
+const int kCSSTestColorsCount = arraysize(kCSSTestColors);
+
+using RenderPassOptions = uint32;
+const uint32 kUseMasks = 1 << 0;
+const uint32 kUseAntialiasing = 1 << 1;
+const uint32 kUseColorMatrix = 1 << 2;
class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
public:
@@ -30,6 +59,10 @@
pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
}
+ virtual void InitializeSettings(LayerTreeSettings* settings) override {
+ settings->force_antialiasing = force_antialiasing_;
+ }
+
protected:
void RunBlendingWithRootPixelTestType(PixelTestType type) {
const int kLaneWidth = 15;
@@ -82,6 +115,175 @@
root,
base::FilePath(FILE_PATH_LITERAL("blending_transparent.png")));
}
+
+ scoped_refptr<Layer> CreateColorfulBackdropLayer(int width, int height) {
+ // Draw the backdrop with horizontal lanes.
+ const int kLaneWidth = width;
+ const int kLaneHeight = height / kCSSTestColorsCount;
+ SkBitmap backing_store;
+ backing_store.allocN32Pixels(width, height);
+ SkCanvas canvas(backing_store);
+ canvas.clear(SK_ColorTRANSPARENT);
+ for (int i = 0; i < kCSSTestColorsCount; ++i) {
+ SkPaint paint;
+ paint.setColor(kCSSTestColors[i]);
+ canvas.drawRect(
+ SkRect::MakeXYWH(0, i * kLaneHeight, kLaneWidth, kLaneHeight), paint);
+ }
+ scoped_refptr<ImageLayer> layer = ImageLayer::Create();
+ layer->SetIsDrawable(true);
+ layer->SetBounds(gfx::Size(width, height));
+ layer->SetBitmap(backing_store);
+ return layer;
+ }
+
+ void SetupMaskLayer(scoped_refptr<Layer> layer) {
+ const int kMaskOffset = 5;
+ gfx::Size bounds = layer->bounds();
+ scoped_refptr<ImageLayer> mask = ImageLayer::Create();
+ mask->SetIsDrawable(true);
+ mask->SetIsMask(true);
+ mask->SetBounds(bounds);
+
+ SkBitmap bitmap;
+ bitmap.allocN32Pixels(bounds.width(), bounds.height());
+ SkCanvas canvas(bitmap);
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ canvas.clear(SK_ColorTRANSPARENT);
+ canvas.drawRect(SkRect::MakeXYWH(kMaskOffset,
+ kMaskOffset,
+ bounds.width() - kMaskOffset * 2,
+ bounds.height() - kMaskOffset * 2),
+ paint);
+ mask->SetBitmap(bitmap);
+ layer->SetMaskLayer(mask.get());
+ }
+
+ void SetupColorMatrix(scoped_refptr<Layer> layer) {
+ FilterOperations filter_operations;
+ filter_operations.Append(FilterOperation::CreateSepiaFilter(1.f));
+ layer->SetFilters(filter_operations);
+ }
+
+ void CreateBlendingColorLayers(int width,
+ int height,
+ scoped_refptr<Layer> background,
+ RenderPassOptions flags) {
+ const int kLanesCount = kBlendModesCount + 4;
+ int lane_width = width / kLanesCount;
+ const SkColor kMiscOpaqueColor = 0xffc86464;
+ const SkColor kMiscTransparentColor = 0x80c86464;
+ const SkXfermode::Mode kCoeffBlendMode = SkXfermode::kScreen_Mode;
+ const SkXfermode::Mode kShaderBlendMode = SkXfermode::kColorBurn_Mode;
+ // add vertical lanes with each of the blend modes
+ for (int i = 0; i < kLanesCount; ++i) {
+ gfx::Rect child_rect(i * lane_width, 0, lane_width, height);
+ SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
+ float opacity = 1.f;
+ SkColor color = kMiscOpaqueColor;
+
+ if (i < kBlendModesCount) {
+ blend_mode = kBlendModes[i];
+ } else if (i == kBlendModesCount) {
+ blend_mode = kCoeffBlendMode;
+ opacity = 0.5f;
+ } else if (i == kBlendModesCount + 1) {
+ blend_mode = kCoeffBlendMode;
+ color = kMiscTransparentColor;
+ } else if (i == kBlendModesCount + 2) {
+ blend_mode = kShaderBlendMode;
+ opacity = 0.5f;
+ } else if (i == kBlendModesCount + 3) {
+ blend_mode = kShaderBlendMode;
+ color = kMiscTransparentColor;
+ }
+
+ scoped_refptr<SolidColorLayer> lane =
+ CreateSolidColorLayer(child_rect, color);
+ lane->SetBlendMode(blend_mode);
+ lane->SetOpacity(opacity);
+ lane->SetForceRenderSurface(true);
+ if (flags & kUseMasks)
+ SetupMaskLayer(lane);
+ if (flags & kUseColorMatrix) {
+ SetupColorMatrix(lane);
+ }
+ background->AddChild(lane);
+ }
+ }
+
+ void RunBlendingWithRenderPass(PixelTestType type,
+ const base::FilePath::CharType* expected_path,
+ RenderPassOptions flags) {
+ const int kRootSize = 400;
+
+ scoped_refptr<SolidColorLayer> root =
+ CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), SK_ColorWHITE);
+ scoped_refptr<Layer> background =
+ CreateColorfulBackdropLayer(kRootSize, kRootSize);
+
+ background->SetIsRootForIsolatedGroup(true);
+ root->AddChild(background);
+
+ CreateBlendingColorLayers(kRootSize, kRootSize, background.get(), flags);
+
+ this->impl_side_painting_ = false;
+ this->force_antialiasing_ = (flags & kUseAntialiasing);
+
+ if ((flags & kUseAntialiasing) && (type == GL_WITH_BITMAP)) {
+ // Anti aliasing causes differences up to 7 pixels at the edges.
+ int large_error_allowed = 7;
+ // Blending results might differ with one pixel.
+ int small_error_allowed = 1;
+ // Most of the errors are one pixel errors.
+ float percentage_pixels_small_error = 12.5f;
+ // Because of anti-aliasing, around 3% of pixels (at the edges) have
+ // bigger errors (from small_error_allowed + 1 to large_error_allowed).
+ float percentage_pixels_error = 15.0f;
+ // The average error is still close to 1.
+ float average_error_allowed_in_bad_pixels = 1.3f;
+
+ // The sepia filter generates more small errors, but the number of large
+ // errors remains around 3%.
+ if (flags & kUseColorMatrix) {
+ percentage_pixels_small_error = 26.f;
+ percentage_pixels_error = 29.f;
+ }
+
+ // Anti-aliased pixels in combination with non-separable blend modes and
+ // a white background produces several black pixels (6 for these tests).
+ // Having a mask will hide the black pixels.
+ // TODO(rosca): fix this issue for non-separable blend modes.
+ if (!(flags & kUseMasks))
+ large_error_allowed = 255;
+
+ pixel_comparator_.reset(
+ new FuzzyPixelComparator(false, // discard_alpha
+ percentage_pixels_error,
+ percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels,
+ large_error_allowed,
+ small_error_allowed));
+ } else if ((flags & kUseColorMatrix) && (type == GL_WITH_BITMAP)) {
+ float percentage_pixels_error = 100.f;
+ float percentage_pixels_small_error = 0.f;
+ float average_error_allowed_in_bad_pixels = 1.f;
+ int large_error_allowed = 2;
+ int small_error_allowed = 0;
+ pixel_comparator_.reset(
+ new FuzzyPixelComparator(false, // discard_alpha
+ percentage_pixels_error,
+ percentage_pixels_small_error,
+ average_error_allowed_in_bad_pixels,
+ large_error_allowed,
+ small_error_allowed));
+ }
+
+ RunPixelTest(type, root, base::FilePath(expected_path));
+ }
+
+ bool force_antialiasing_ = false;
};
TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) {
@@ -128,6 +330,113 @@
RunBlendingWithTransparentPixelTestType(SOFTWARE_WITH_BITMAP);
}
+// Tests for render passes
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_GL) {
+ RunBlendingWithRenderPass(
+ GL_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_Software) {
+ RunBlendingWithRenderPass(
+ SOFTWARE_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass.png"),
+ kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMask_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMask_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskAA_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskAA_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask.png"),
+ kUseMasks | kUseAntialiasing);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassColorMatrix_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) {
+ RunBlendingWithRenderPass(GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseAntialiasing | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassColorMatrixAA_Software) {
+ RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_cm.png"),
+ kUseAntialiasing | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrix_GL) {
+ RunBlendingWithRenderPass(
+ GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrix_Software) {
+ RunBlendingWithRenderPass(
+ SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrixAA_GL) {
+ RunBlendingWithRenderPass(
+ GL_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
+}
+
+TEST_F(LayerTreeHostBlendingPixelTest,
+ BlendingWithRenderPassWithMaskColorMatrixAA_Software) {
+ RunBlendingWithRenderPass(
+ SOFTWARE_WITH_BITMAP,
+ FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
+ kUseMasks | kUseAntialiasing | kUseColorMatrix);
+}
+
} // namespace
} // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index b9e15c6..5dafb7f 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -912,8 +912,7 @@
NULL,
0,
false,
- 1,
- false);
+ 1);
}
static void EmptyReleaseCallback(unsigned sync_point, bool lost) {}
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 8e11015..e4d5f1d 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -15,6 +15,7 @@
LayerTreeSettings::LayerTreeSettings()
: impl_side_painting(false),
allow_antialiasing(true),
+ force_antialiasing(false),
throttle_frame_production(true),
single_thread_proxy_scheduler(true),
begin_frame_scheduling_enabled(false),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index c0c1453..fff1084 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -20,6 +20,7 @@
bool impl_side_painting;
bool allow_antialiasing;
+ bool force_antialiasing;
bool throttle_frame_production;
bool single_thread_proxy_scheduler;
bool begin_frame_scheduling_enabled;
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 1bc8aad..0b8d68d 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -9746,11 +9746,11 @@
const void* cmd_data) {
const gles2::cmds::WaitSyncPointCHROMIUM& c =
*static_cast<const gles2::cmds::WaitSyncPointCHROMIUM*>(cmd_data);
- group_->mailbox_manager()->PullTextureUpdates();
+ uint32 sync_point = c.sync_point;
if (wait_sync_point_callback_.is_null())
return error::kNoError;
- return wait_sync_point_callback_.Run(c.sync_point) ?
+ return wait_sync_point_callback_.Run(sync_point) ?
error::kNoError : error::kDeferCommandUntilLater;
}
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 33e5a2c..1e7cc1f 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -177,11 +177,6 @@
base::LazyInstance<SyncPointManager> g_sync_point_manager =
LAZY_INSTANCE_INITIALIZER;
-bool WaitSyncPoint(uint32 sync_point) {
- g_sync_point_manager.Get().WaitSyncPoint(sync_point);
- return true;
-}
-
} // anonyous namespace
InProcessCommandBuffer::Service::Service() {}
@@ -422,7 +417,9 @@
decoder_->SetResizeCallback(base::Bind(
&InProcessCommandBuffer::OnResizeView, gpu_thread_weak_ptr_));
}
- decoder_->SetWaitSyncPointCallback(base::Bind(&WaitSyncPoint));
+ decoder_->SetWaitSyncPointCallback(
+ base::Bind(&InProcessCommandBuffer::WaitSyncPointOnGpuThread,
+ base::Unretained(this)));
return true;
}
@@ -658,7 +655,7 @@
make_current_success = MakeCurrent();
}
if (make_current_success)
- mailbox_manager->PushTextureUpdates();
+ mailbox_manager->PushTextureUpdates(sync_point);
}
g_sync_point_manager.Get().RetireSyncPoint(sync_point);
}
@@ -672,6 +669,14 @@
WrapCallback(callback)));
}
+bool InProcessCommandBuffer::WaitSyncPointOnGpuThread(unsigned sync_point) {
+ g_sync_point_manager.Get().WaitSyncPoint(sync_point);
+ gles2::MailboxManager* mailbox_manager =
+ decoder_->GetContextGroup()->mailbox_manager();
+ mailbox_manager->PullTextureUpdates(sync_point);
+ return true;
+}
+
void InProcessCommandBuffer::SignalSyncPointOnGpuThread(
unsigned sync_point,
const base::Closure& callback) {
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index ec06ecd..e7b2260 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -181,6 +181,7 @@
void RetireSyncPointOnGpuThread(uint32 sync_point);
void SignalSyncPointOnGpuThread(uint32 sync_point,
const base::Closure& callback);
+ bool WaitSyncPointOnGpuThread(uint32 sync_point);
void SignalQueryOnGpuThread(unsigned query_id, const base::Closure& callback);
void DestroyTransferBufferOnGpuThread(int32 id);
diff --git a/gpu/command_buffer/service/mailbox_manager.cc b/gpu/command_buffer/service/mailbox_manager.cc
index e6962df..b4d6e79 100644
--- a/gpu/command_buffer/service/mailbox_manager.cc
+++ b/gpu/command_buffer/service/mailbox_manager.cc
@@ -84,14 +84,14 @@
sync_->TextureDeleted(texture);
}
-void MailboxManager::PushTextureUpdates() {
+void MailboxManager::PushTextureUpdates(uint32 sync_point) {
if (sync_)
- sync_->PushTextureUpdates(this);
+ sync_->PushTextureUpdates(this, sync_point);
}
-void MailboxManager::PullTextureUpdates() {
+void MailboxManager::PullTextureUpdates(uint32 sync_point) {
if (sync_)
- sync_->PullTextureUpdates(this);
+ sync_->PullTextureUpdates(this, sync_point);
}
MailboxManager::TargetName::TargetName(unsigned target, const Mailbox& mailbox)
diff --git a/gpu/command_buffer/service/mailbox_manager.h b/gpu/command_buffer/service/mailbox_manager.h
index e1b36cb..a00b965 100644
--- a/gpu/command_buffer/service/mailbox_manager.h
+++ b/gpu/command_buffer/service/mailbox_manager.h
@@ -41,8 +41,8 @@
// Used with the MailboxSynchronizer to push/pull texture state to/from
// other manager instances.
- void PushTextureUpdates();
- void PullTextureUpdates();
+ void PushTextureUpdates(uint32 sync_point);
+ void PullTextureUpdates(uint32 sync_point);
// Destroy any mailbox that reference the given texture.
void TextureDeleted(Texture* texture);
diff --git a/gpu/command_buffer/service/mailbox_manager_unittest.cc b/gpu/command_buffer/service/mailbox_manager_unittest.cc
index df1cd4e..63ffc6d 100644
--- a/gpu/command_buffer/service/mailbox_manager_unittest.cc
+++ b/gpu/command_buffer/service/mailbox_manager_unittest.cc
@@ -300,8 +300,8 @@
EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
// Synchronize
- manager_->PushTextureUpdates();
- manager2_->PullTextureUpdates();
+ manager_->PushTextureUpdates(0);
+ manager2_->PullTextureUpdates(0);
DestroyTexture(texture);
EXPECT_EQ(NULL, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
@@ -321,8 +321,8 @@
EXPECT_EQ(texture, manager_->ConsumeTexture(GL_TEXTURE_2D, name));
// Synchronize
- manager_->PushTextureUpdates();
- manager2_->PullTextureUpdates();
+ manager_->PushTextureUpdates(0);
+ manager2_->PullTextureUpdates(0);
EXPECT_CALL(*gl_, GenTextures(1, _))
.WillOnce(SetArgPointee<1>(kNewTextureId));
@@ -349,10 +349,10 @@
EXPECT_TRUE(texture->GetLevelImage(GL_TEXTURE_2D, 0) == NULL);
// Synchronize again
- manager_->PushTextureUpdates();
+ manager_->PushTextureUpdates(0);
SetupUpdateTexParamExpectations(
kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
- manager2_->PullTextureUpdates();
+ manager2_->PullTextureUpdates(0);
GLsizei width, height;
new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
EXPECT_EQ(16, width);
@@ -382,7 +382,7 @@
// The last change to the texture should be visible without a sync point (i.e.
// push).
- manager2_->PullTextureUpdates();
+ manager2_->PullTextureUpdates(0);
new_texture->GetLevelSize(GL_TEXTURE_2D, 0, &width, &height);
EXPECT_EQ(64, width);
EXPECT_EQ(64, height);
@@ -410,8 +410,8 @@
manager2_->ProduceTexture(GL_TEXTURE_2D, name2, texture2);
// Make visible.
- manager_->PushTextureUpdates();
- manager2_->PushTextureUpdates();
+ manager_->PushTextureUpdates(0);
+ manager2_->PushTextureUpdates(0);
// Create textures in the other manager instances for texture1 and texture2,
// respectively to create a real sharing scenario. Otherwise, there would
@@ -438,7 +438,7 @@
SetParameter(texture1, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
// Make sure this does not clobber it with the previous version we pushed.
- manager_->PullTextureUpdates();
+ manager_->PullTextureUpdates(0);
// Make a change to texture2
DCHECK_EQ(static_cast<GLuint>(GL_LINEAR), texture2->mag_filter());
@@ -448,16 +448,16 @@
Mock::VerifyAndClearExpectations(gl_.get());
// Synchronize in both directions
- manager_->PushTextureUpdates();
- manager2_->PushTextureUpdates();
+ manager_->PushTextureUpdates(0);
+ manager2_->PushTextureUpdates(0);
// manager1 should see the change to texture2 mag_filter being applied.
SetupUpdateTexParamExpectations(
new_texture2->service_id(), GL_LINEAR, GL_NEAREST, GL_REPEAT, GL_REPEAT);
- manager_->PullTextureUpdates();
+ manager_->PullTextureUpdates(0);
// manager2 should see the change to texture1 min_filter being applied.
SetupUpdateTexParamExpectations(
new_texture1->service_id(), GL_NEAREST, GL_LINEAR, GL_REPEAT, GL_REPEAT);
- manager2_->PullTextureUpdates();
+ manager2_->PullTextureUpdates(0);
DestroyTexture(texture1);
DestroyTexture(texture2);
diff --git a/gpu/command_buffer/service/mailbox_synchronizer.cc b/gpu/command_buffer/service/mailbox_synchronizer.cc
index eac31f9..81a2793 100644
--- a/gpu/command_buffer/service/mailbox_synchronizer.cc
+++ b/gpu/command_buffer/service/mailbox_synchronizer.cc
@@ -7,8 +7,13 @@
#include "base/bind.h"
#include "gpu/command_buffer/service/mailbox_manager.h"
#include "gpu/command_buffer/service/texture_manager.h"
+#include "ui/gl/gl_fence.h"
#include "ui/gl/gl_implementation.h"
+#if !defined(OS_MACOSX)
+#include "ui/gl/gl_fence_egl.h"
+#endif
+
namespace gpu {
namespace gles2 {
@@ -136,7 +141,8 @@
}
}
-void MailboxSynchronizer::PushTextureUpdates(MailboxManager* manager) {
+void MailboxSynchronizer::PushTextureUpdates(MailboxManager* manager,
+ uint32 sync_point) {
base::AutoLock lock(lock_);
for (MailboxManager::MailboxToTextureMap::const_iterator texture_it =
manager->mailbox_to_textures_.begin();
@@ -179,6 +185,33 @@
textures_.insert(std::make_pair(texture, TextureVersion(group)));
}
}
+
+ CreateFenceLocked(sync_point);
+}
+
+void MailboxSynchronizer::CreateFenceLocked(uint32 sync_point) {
+ lock_.AssertAcquired();
+ if (gfx::GetGLImplementation() == gfx::kGLImplementationMockGL)
+ return;
+
+#if !defined(OS_MACOSX)
+ if (sync_point) {
+ while (!sync_points_.empty() &&
+ sync_points_.front()->second->HasCompleted()) {
+ sync_point_to_fence_.erase(sync_points_.front());
+ sync_points_.pop();
+ }
+ // Need to use EGL fences since we are likely not in a single share group.
+ linked_ptr<gfx::GLFence> fence(make_linked_ptr(new gfx::GLFenceEGL(true)));
+ if (fence.get()) {
+ std::pair<SyncPointToFenceMap::iterator, bool> result =
+ sync_point_to_fence_.insert(std::make_pair(sync_point, fence));
+ DCHECK(result.second);
+ sync_points_.push(result.first);
+ }
+ DCHECK(sync_points_.size() == sync_point_to_fence_.size());
+ }
+#endif
}
void MailboxSynchronizer::UpdateTextureLocked(Texture* texture,
@@ -208,8 +241,20 @@
gl_image ? image_buffer : NULL);
}
-void MailboxSynchronizer::PullTextureUpdates(MailboxManager* manager) {
+void MailboxSynchronizer::AcquireFenceLocked(uint32 sync_point) {
+ lock_.AssertAcquired();
+ SyncPointToFenceMap::iterator fence_it =
+ sync_point_to_fence_.find(sync_point);
+ if (fence_it != sync_point_to_fence_.end()) {
+ fence_it->second->ServerWait();
+ }
+}
+
+void MailboxSynchronizer::PullTextureUpdates(MailboxManager* manager,
+ uint32 sync_point) {
base::AutoLock lock(lock_);
+ AcquireFenceLocked(sync_point);
+
for (MailboxManager::MailboxToTextureMap::const_iterator texture_it =
manager->mailbox_to_textures_.begin();
texture_it != manager->mailbox_to_textures_.end();
diff --git a/gpu/command_buffer/service/mailbox_synchronizer.h b/gpu/command_buffer/service/mailbox_synchronizer.h
index a845963..3ddb9d0 100644
--- a/gpu/command_buffer/service/mailbox_synchronizer.h
+++ b/gpu/command_buffer/service/mailbox_synchronizer.h
@@ -8,6 +8,7 @@
#include "gpu/command_buffer/common/mailbox.h"
#include <map>
+#include <queue>
#include <set>
#include "base/memory/linked_ptr.h"
@@ -15,6 +16,10 @@
#include "gpu/command_buffer/service/texture_definition.h"
#include "gpu/gpu_export.h"
+namespace gfx {
+class GLFence;
+}
+
namespace gpu {
namespace gles2 {
@@ -34,8 +39,8 @@
// Create a texture from a globally visible mailbox.
Texture* CreateTextureFromMailbox(unsigned target, const Mailbox& mailbox);
- void PushTextureUpdates(MailboxManager* manager);
- void PullTextureUpdates(MailboxManager* manager);
+ void PushTextureUpdates(MailboxManager* manager, uint32 sync_point);
+ void PullTextureUpdates(MailboxManager* manager, uint32 sync_point);
void TextureDeleted(Texture* texture);
@@ -85,6 +90,12 @@
const TargetName& target_name,
TextureGroup* group);
void UpdateTextureLocked(Texture* texture, TextureVersion& texture_version);
+ void CreateFenceLocked(uint32 sync_point);
+ void AcquireFenceLocked(uint32 sync_point);
+
+ typedef std::map<uint32, linked_ptr<gfx::GLFence> > SyncPointToFenceMap;
+ SyncPointToFenceMap sync_point_to_fence_;
+ std::queue<SyncPointToFenceMap::iterator> sync_points_;
DISALLOW_COPY_AND_ASSIGN(MailboxSynchronizer);
};
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 63a64b7..ac7021a 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -81,8 +81,8 @@
return true;
}
-bool IsBuiltInVarying(const std::string& name) {
- // Built-in variables.
+bool IsBuiltInFragmentVarying(const std::string& name) {
+ // Built-in variables for fragment shaders.
const char* kBuiltInVaryings[] = {
"gl_FragCoord",
"gl_FrontFacing",
@@ -95,6 +95,14 @@
return false;
}
+bool IsBuiltInInvariant(
+ const VaryingMap& varyings, const std::string& name) {
+ VaryingMap::const_iterator hit = varyings.find(name);
+ if (hit == varyings.end())
+ return false;
+ return hit->second.isInvariant;
+}
+
} // anonymous namespace.
Program::UniformInfo::UniformInfo()
@@ -526,6 +534,11 @@
set_log_info(ProcessLogInfo(info_log).c_str());
return false;
}
+ if (DetectBuiltInInvariantConflicts()) {
+ set_log_info("Invariant settings for certain built-in varyings "
+ "have to match");
+ return false;
+ }
if (DetectGlobalNameConflicts(&conflicting_name)) {
std::string info_log = "Name conflicts between an uniform and an "
"attribute: " + conflicting_name;
@@ -1071,7 +1084,7 @@
for (VaryingMap::const_iterator iter = fragment_varyings->begin();
iter != fragment_varyings->end(); ++iter) {
const std::string& name = iter->first;
- if (IsBuiltInVarying(name))
+ if (IsBuiltInFragmentVarying(name))
continue;
VaryingMap::const_iterator hit = vertex_varyings->find(name);
@@ -1092,6 +1105,28 @@
return false;
}
+bool Program::DetectBuiltInInvariantConflicts() const {
+ DCHECK(attached_shaders_[0].get() &&
+ attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
+ attached_shaders_[1].get() &&
+ attached_shaders_[1]->shader_type() == GL_FRAGMENT_SHADER);
+ const VaryingMap& vertex_varyings = attached_shaders_[0]->varying_map();
+ const VaryingMap& fragment_varyings = attached_shaders_[1]->varying_map();
+
+ bool gl_position_invariant = IsBuiltInInvariant(
+ vertex_varyings, "gl_Position");
+ bool gl_point_size_invariant = IsBuiltInInvariant(
+ vertex_varyings, "gl_PointSize");
+
+ bool gl_frag_coord_invariant = IsBuiltInInvariant(
+ fragment_varyings, "gl_FragCoord");
+ bool gl_point_coord_invariant = IsBuiltInInvariant(
+ fragment_varyings, "gl_PointCoord");
+
+ return ((gl_frag_coord_invariant && !gl_position_invariant) ||
+ (gl_point_coord_invariant && !gl_point_size_invariant));
+}
+
bool Program::DetectGlobalNameConflicts(std::string* conflicting_name) const {
DCHECK(attached_shaders_[0].get() &&
attached_shaders_[0]->shader_type() == GL_VERTEX_SHADER &&
@@ -1130,7 +1165,7 @@
iter != fragment_varyings->end(); ++iter) {
if (!iter->second.staticUse && option == kCountOnlyStaticallyUsed)
continue;
- if (!IsBuiltInVarying(iter->first)) {
+ if (!IsBuiltInFragmentVarying(iter->first)) {
VaryingMap::const_iterator vertex_iter =
vertex_varyings->find(iter->first);
if (vertex_iter == vertex_varyings->end() ||
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 9698fc1..dbe9c14 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -215,6 +215,10 @@
// is not declared in vertex shader.
bool DetectVaryingsMismatch(std::string* conflicting_name) const;
+ // Return true if any built-in invariant matching rules are broken as in
+ // GLSL ES spec 1.00.17, section 4.6.4, Invariance and Linkage.
+ bool DetectBuiltInInvariantConflicts() const;
+
// Return true if an uniform and an attribute share the same name.
bool DetectGlobalNameConflicts(std::string* conflicting_name) const;
diff --git a/gpu/command_buffer/service/shader_translator_unittest.cc b/gpu/command_buffer/service/shader_translator_unittest.cc
index 198ea82..40d5be7 100644
--- a/gpu/command_buffer/service/shader_translator_unittest.cc
+++ b/gpu/command_buffer/service/shader_translator_unittest.cc
@@ -69,10 +69,11 @@
EXPECT_TRUE(info_log.empty());
// Translated shader must be valid and non-empty.
ASSERT_FALSE(translated_source.empty());
- // There should be no attributes, uniforms, varyings.
+ // There should be no attributes, uniforms, and only one built-in
+ // varying: gl_Position.
EXPECT_TRUE(attrib_map.empty());
EXPECT_TRUE(uniform_map.empty());
- EXPECT_TRUE(varying_map.empty());
+ EXPECT_EQ(1u, varying_map.size());
// There should be no name mapping.
EXPECT_TRUE(name_map.empty());
}
diff --git a/gpu/command_buffer/service/texture_definition.cc b/gpu/command_buffer/service/texture_definition.cc
index cf385d2..abde56a 100644
--- a/gpu/command_buffer/service/texture_definition.cc
+++ b/gpu/command_buffer/service/texture_definition.cc
@@ -15,7 +15,6 @@
#include "ui/gl/scoped_binders.h"
#if !defined(OS_MACOSX)
-#include "ui/gl/gl_fence_egl.h"
#include "ui/gl/gl_surface_egl.h"
#endif
@@ -88,23 +87,15 @@
}
void GLImageSync::WillUseTexImage() {
- if (buffer_.get())
- buffer_->WillRead(this);
}
void GLImageSync::DidUseTexImage() {
- if (buffer_.get())
- buffer_->DidRead(this);
}
void GLImageSync::WillModifyTexImage() {
- if (buffer_.get())
- buffer_->WillWrite(this);
}
void GLImageSync::DidModifyTexImage() {
- if (buffer_.get())
- buffer_->DidWrite(this);
}
bool GLImageSync::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
@@ -128,10 +119,6 @@
virtual void RemoveClient(gfx::GLImage* client) override;
virtual bool IsClient(gfx::GLImage* client) override;
virtual void BindToTexture(GLenum target) override;
- virtual void WillRead(gfx::GLImage* client) override;
- virtual void WillWrite(gfx::GLImage* client) override;
- virtual void DidRead(gfx::GLImage* client) override;
- virtual void DidWrite(gfx::GLImage* client) override;
EGLDisplay egl_display_;
EGLImageKHR egl_image_;
@@ -144,10 +131,8 @@
gfx::GLImage* client;
bool needs_wait_before_read;
- linked_ptr<gfx::GLFence> read_fence;
};
std::list<ClientInfo> client_infos_;
- scoped_ptr<gfx::GLFence> write_fence_;
gfx::GLImage* write_client_;
DISALLOW_COPY_AND_ASSIGN(NativeImageBufferEGL);
@@ -164,8 +149,7 @@
DCHECK(gfx::g_driver_egl.ext.b_EGL_KHR_image_base &&
gfx::g_driver_egl.ext.b_EGL_KHR_gl_texture_2D_image &&
- gfx::g_driver_gl.ext.b_GL_OES_EGL_image &&
- gfx::g_driver_egl.ext.b_EGL_KHR_fence_sync);
+ gfx::g_driver_gl.ext.b_GL_OES_EGL_image);
const EGLint egl_attrib_list[] = {
EGL_GL_TEXTURE_LEVEL_KHR, 0, EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE};
@@ -191,7 +175,6 @@
: NativeImageBuffer(),
egl_display_(display),
egl_image_(image),
- write_fence_(new gfx::GLFenceEGL(true)),
write_client_(NULL) {
DCHECK(egl_display_ != EGL_NO_DISPLAY);
DCHECK(egl_image_ != EGL_NO_IMAGE_KHR);
@@ -241,64 +224,6 @@
DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
}
-void NativeImageBufferEGL::WillRead(gfx::GLImage* client) {
- base::AutoLock lock(lock_);
- if (!write_fence_.get() || write_client_ == client)
- return;
-
- for (std::list<ClientInfo>::iterator it = client_infos_.begin();
- it != client_infos_.end();
- it++) {
- if (it->client == client) {
- if (it->needs_wait_before_read) {
- it->needs_wait_before_read = false;
- write_fence_->ServerWait();
- }
- return;
- }
- }
- NOTREACHED();
-}
-
-void NativeImageBufferEGL::WillWrite(gfx::GLImage* client) {
- base::AutoLock lock(lock_);
- if (write_client_ != client)
- write_fence_->ServerWait();
-
- for (std::list<ClientInfo>::iterator it = client_infos_.begin();
- it != client_infos_.end();
- it++) {
- if (it->read_fence.get() && it->client != client)
- it->read_fence->ServerWait();
- }
-}
-
-void NativeImageBufferEGL::DidRead(gfx::GLImage* client) {
- base::AutoLock lock(lock_);
- for (std::list<ClientInfo>::iterator it = client_infos_.begin();
- it != client_infos_.end();
- it++) {
- if (it->client == client) {
- it->read_fence = make_linked_ptr(new gfx::GLFenceEGL(true));
- return;
- }
- }
- NOTREACHED();
-}
-
-void NativeImageBufferEGL::DidWrite(gfx::GLImage* client) {
- base::AutoLock lock(lock_);
- // Sharing semantics require the client to flush in order to make changes
- // visible to other clients.
- write_fence_.reset(new gfx::GLFenceEGL(false));
- write_client_ = client;
- for (std::list<ClientInfo>::iterator it = client_infos_.begin();
- it != client_infos_.end();
- it++) {
- it->needs_wait_before_read = true;
- }
-}
-
#endif
class NativeImageBufferStub : public NativeImageBuffer {
@@ -311,10 +236,6 @@
void RemoveClient(gfx::GLImage* client) override {}
bool IsClient(gfx::GLImage* client) override { return true; }
void BindToTexture(GLenum target) override {}
- void WillRead(gfx::GLImage* client) override {}
- void WillWrite(gfx::GLImage* client) override {}
- void DidRead(gfx::GLImage* client) override {}
- void DidWrite(gfx::GLImage* client) override {}
DISALLOW_COPY_AND_ASSIGN(NativeImageBufferStub);
};
diff --git a/gpu/command_buffer/service/texture_definition.h b/gpu/command_buffer/service/texture_definition.h
index 6df4b86..cb21abd 100644
--- a/gpu/command_buffer/service/texture_definition.h
+++ b/gpu/command_buffer/service/texture_definition.h
@@ -27,10 +27,6 @@
virtual void RemoveClient(gfx::GLImage* client) = 0;
virtual bool IsClient(gfx::GLImage* client) = 0;
virtual void BindToTexture(GLenum target) = 0;
- virtual void WillRead(gfx::GLImage* client) = 0;
- virtual void WillWrite(gfx::GLImage* client) = 0;
- virtual void DidRead(gfx::GLImage* client) = 0;
- virtual void DidWrite(gfx::GLImage* client) = 0;
protected:
friend class base::RefCountedThreadSafe<NativeImageBuffer>;
diff --git a/net/PRESUBMIT.py b/net/PRESUBMIT.py
index e898d99..e82166c 100644
--- a/net/PRESUBMIT.py
+++ b/net/PRESUBMIT.py
@@ -11,13 +11,13 @@
def GetPreferredTryMasters(project, change):
masters = {
'tryserver.chromium.linux': {
- 'linux_chromium_rel_swarming': set(['defaulttests']),
+ 'linux_chromium_rel': set(['defaulttests']),
},
'tryserver.chromium.mac': {
- 'mac_chromium_rel_swarming': set(['defaulttests']),
+ 'mac_chromium_rel': set(['defaulttests']),
},
'tryserver.chromium.win': {
- 'win_chromium_rel_swarming': set(['defaulttests']),
+ 'win_chromium_rel': set(['defaulttests']),
}
}
# Changes that touch NSS files will likely need a corresponding OpenSSL edit.
diff --git a/net/base/data_url_unittest.cc b/net/base/data_url_unittest.cc
index 3876301..bcb2b49 100644
--- a/net/base/data_url_unittest.cc
+++ b/net/base/data_url_unittest.cc
@@ -184,6 +184,44 @@
"",
"" },
+ // BiDi control characters should be unescaped and preserved as is, and
+ // should not be replaced with % versions. In the below case, \xE2\x80\x8F
+ // is the RTL mark and the parsed text should preserve it as is.
+ {
+ "data:text/plain;charset=utf-8,\xE2\x80\x8Ftest",
+ true,
+ "text/plain",
+ "utf-8",
+ "\xE2\x80\x8Ftest"},
+
+ // Same as above but with Arabic text after RTL mark.
+ {
+ "data:text/plain;charset=utf-8,"
+ "\xE2\x80\x8F\xD8\xA7\xD8\xAE\xD8\xAA\xD8\xA8\xD8\xA7\xD8\xB1",
+ true,
+ "text/plain",
+ "utf-8",
+ "\xE2\x80\x8F\xD8\xA7\xD8\xAE\xD8\xAA\xD8\xA8\xD8\xA7\xD8\xB1"},
+
+ // RTL mark encoded as %E2%80%8F should be unescaped too. Note that when
+ // wrapped in a GURL, this URL and the next effectively become the same as
+ // the previous two URLs.
+ {
+ "data:text/plain;charset=utf-8,%E2%80%8Ftest",
+ true,
+ "text/plain",
+ "utf-8",
+ "\xE2\x80\x8Ftest"},
+
+ // Same as above but with Arabic text after RTL mark.
+ {
+ "data:text/plain;charset=utf-8,"
+ "%E2%80%8F\xD8\xA7\xD8\xAE\xD8\xAA\xD8\xA8\xD8\xA7\xD8\xB1",
+ true,
+ "text/plain",
+ "utf-8",
+ "\xE2\x80\x8F\xD8\xA7\xD8\xAE\xD8\xAA\xD8\xA8\xD8\xA7\xD8\xB1"}
+
// TODO(darin): add more interesting tests
};
diff --git a/net/base/escape.cc b/net/base/escape.cc
index 1798b6c..3c8adc6 100644
--- a/net/base/escape.cc
+++ b/net/base/escape.cc
@@ -120,6 +120,44 @@
return false;
}
+// Returns true if there is an Arabic Language Mark at |index|. |first_byte|
+// is the byte at |index|.
+template<typename STR>
+bool HasArabicLanguageMarkAtIndex(const STR& escaped_text,
+ unsigned char first_byte,
+ size_t index) {
+ if (first_byte != 0xD8)
+ return false;
+ unsigned char second_byte;
+ if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 3, &second_byte))
+ return false;
+ return second_byte == 0x9c;
+}
+
+// Returns true if there is a BiDi control char at |index|. |first_byte| is the
+// byte at |index|.
+template<typename STR>
+bool HasThreeByteBidiControlCharAtIndex(const STR& escaped_text,
+ unsigned char first_byte,
+ size_t index) {
+ if (first_byte != 0xE2)
+ return false;
+ unsigned char second_byte;
+ if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 3, &second_byte))
+ return false;
+ if (second_byte != 0x80 && second_byte != 0x81)
+ return false;
+ unsigned char third_byte;
+ if (!UnescapeUnsignedCharAtIndex(escaped_text, index + 6, &third_byte))
+ return false;
+ if (second_byte == 0x80) {
+ return third_byte == 0x8E ||
+ third_byte == 0x8F ||
+ (third_byte >= 0xAA && third_byte <= 0xAE);
+ }
+ return third_byte >= 0xA6 && third_byte <= 0xA9;
+}
+
// Unescapes |escaped_text| according to |rules|, returning the resulting
// string. Fills in an |adjustments| parameter, if non-NULL, so it reflects
// the alterations done to the string that are not one-character-to-one-
@@ -172,27 +210,21 @@
// U+2067 RIGHT-TO-LEFT ISOLATE (%E2%81%A7)
// U+2068 FIRST STRONG ISOLATE (%E2%81%A8)
// U+2069 POP DIRECTIONAL ISOLATE (%E2%81%A9)
-
- unsigned char second_byte;
- // Check for ALM.
- if ((first_byte == 0xD8) &&
- UnescapeUnsignedCharAtIndex(escaped_text, i + 3, &second_byte) &&
- (second_byte == 0x9c)) {
- result.append(escaped_text, i, 6);
- i += 5;
- continue;
- }
-
- // Check for other BiDi control characters.
- if ((first_byte == 0xE2) &&
- UnescapeUnsignedCharAtIndex(escaped_text, i + 3, &second_byte) &&
- ((second_byte == 0x80) || (second_byte == 0x81))) {
- unsigned char third_byte;
- if (UnescapeUnsignedCharAtIndex(escaped_text, i + 6, &third_byte) &&
- ((second_byte == 0x80) ?
- ((third_byte == 0x8E) || (third_byte == 0x8F) ||
- ((third_byte >= 0xAA) && (third_byte <= 0xAE))) :
- ((third_byte >= 0xA6) && (third_byte <= 0xA9)))) {
+ //
+ // However, some schemes such as data: and file: need to parse the exact
+ // binary data when loading the URL. For that reason, CONTROL_CHARS allows
+ // unescaping BiDi control characters.
+ // DO NOT use CONTROL_CHARS if the parsed URL is going to be displayed
+ // in the UI.
+ if (!(rules & UnescapeRule::CONTROL_CHARS)) {
+ if (HasArabicLanguageMarkAtIndex(escaped_text, first_byte, i)) {
+ // Keep Arabic Language Mark escaped.
+ result.append(escaped_text, i, 6);
+ i += 5;
+ continue;
+ }
+ if (HasThreeByteBidiControlCharAtIndex(escaped_text, first_byte, i)) {
+ // Keep BiDi control char escaped.
result.append(escaped_text, i, 9);
i += 8;
continue;
diff --git a/net/base/escape.h b/net/base/escape.h
index 1915d24..bc58439 100644
--- a/net/base/escape.h
+++ b/net/base/escape.h
@@ -88,7 +88,10 @@
// Unescapes control characters such as %01. This INCLUDES NULLs. This is
// used for rare cases such as data: URL decoding where the result is binary
- // data. You should not use this for normal URLs!
+ // data. This flag also unescapes BiDi control characters.
+ //
+ // DO NOT use CONTROL_CHARS if the URL is going to be displayed in the UI
+ // for security reasons.
CONTROL_CHARS = 8,
// URL queries use "+" for space. This flag controls that replacement.
diff --git a/net/base/escape_unittest.cc b/net/base/escape_unittest.cc
index 74ae293..1e82239 100644
--- a/net/base/escape_unittest.cc
+++ b/net/base/escape_unittest.cc
@@ -232,7 +232,8 @@
{L"Some%20random text %25%E2%80%84OK", UnescapeRule::NORMAL,
L"Some%20random text %25\xE2\x80\x84OK"},
- // BiDi Control characters should not be unescaped.
+ // BiDi Control characters should not be unescaped unless explicity told to
+ // do so with UnescapeRule::CONTROL_CHARS
{L"Some%20random text %25%D8%9COK", UnescapeRule::NORMAL,
L"Some%20random text %25%D8%9COK"},
{L"Some%20random text %25%E2%80%8EOK", UnescapeRule::NORMAL,
@@ -249,6 +250,31 @@
L"Some%20random text %25%E2%81%A6OK"},
{L"Some%20random text %25%E2%81%A9OK", UnescapeRule::NORMAL,
L"Some%20random text %25%E2%81%A9OK"},
+ // UnescapeRule::CONTROL_CHARS should unescape BiDi Control characters.
+ {L"Some%20random text %25%D8%9COK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xD8\x9COK"},
+ {L"Some%20random text %25%E2%80%8EOK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xE2\x80\x8EOK"},
+ {L"Some%20random text %25%E2%80%8FOK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xE2\x80\x8FOK"},
+ {L"Some%20random text %25%E2%80%AAOK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xE2\x80\xAAOK"},
+ {L"Some%20random text %25%E2%80%ABOK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xE2\x80\xABOK"},
+ {L"Some%20random text %25%E2%80%AEOK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xE2\x80\xAEOK"},
+ {L"Some%20random text %25%E2%81%A6OK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xE2\x81\xA6OK"},
+ {L"Some%20random text %25%E2%81%A9OK",
+ UnescapeRule::NORMAL | UnescapeRule::CONTROL_CHARS,
+ L"Some%20random text %25\xE2\x81\xA9OK"},
{L"Some%20random text %25%2dOK", UnescapeRule::SPACES,
L"Some random text %25-OK"},
diff --git a/net/base/trace_net_log_observer.cc b/net/base/trace_net_log_observer.cc
index 15960c3..5d98c41 100644
--- a/net/base/trace_net_log_observer.cc
+++ b/net/base/trace_net_log_observer.cc
@@ -19,6 +19,9 @@
namespace {
+// TraceLog category for NetLog events.
+const char kNetLogTracingCategory[] = TRACE_DISABLED_BY_DEFAULT("netlog");
+
class TracedValue : public base::debug::ConvertableToTraceFormat {
public:
explicit TracedValue(scoped_ptr<base::Value> value) : value_(value.Pass()) {}
@@ -55,21 +58,24 @@
switch (entry.phase()) {
case NetLog::PHASE_BEGIN:
TRACE_EVENT_NESTABLE_ASYNC_BEGIN2(
- "netlog", NetLog::EventTypeToString(entry.type()), entry.source().id,
+ kNetLogTracingCategory,
+ NetLog::EventTypeToString(entry.type()), entry.source().id,
"source_type", NetLog::SourceTypeToString(entry.source().type),
"params", scoped_refptr<base::debug::ConvertableToTraceFormat>(
new TracedValue(params.Pass())));
break;
case NetLog::PHASE_END:
TRACE_EVENT_NESTABLE_ASYNC_END2(
- "netlog", NetLog::EventTypeToString(entry.type()), entry.source().id,
+ kNetLogTracingCategory,
+ NetLog::EventTypeToString(entry.type()), entry.source().id,
"source_type", NetLog::SourceTypeToString(entry.source().type),
"params", scoped_refptr<base::debug::ConvertableToTraceFormat>(
new TracedValue(params.Pass())));
break;
case NetLog::PHASE_NONE:
TRACE_EVENT_NESTABLE_ASYNC_INSTANT2(
- "netlog", NetLog::EventTypeToString(entry.type()), entry.source().id,
+ kNetLogTracingCategory,
+ NetLog::EventTypeToString(entry.type()), entry.source().id,
"source_type", NetLog::SourceTypeToString(entry.source().type),
"params", scoped_refptr<base::debug::ConvertableToTraceFormat>(
new TracedValue(params.Pass())));
diff --git a/net/base/trace_net_log_observer_unittest.cc b/net/base/trace_net_log_observer_unittest.cc
index c1a8803..2e20707 100644
--- a/net/base/trace_net_log_observer_unittest.cc
+++ b/net/base/trace_net_log_observer_unittest.cc
@@ -27,6 +27,9 @@
namespace {
+// TraceLog category for NetLog events.
+const char kNetLogTracingCategory[] = TRACE_DISABLED_BY_DEFAULT("netlog");
+
struct TraceEntryInfo {
std::string category;
std::string id;
@@ -86,9 +89,10 @@
}
static void EnableTraceLog() {
- TraceLog::GetInstance()->SetEnabled(base::debug::CategoryFilter("netlog"),
- TraceLog::RECORDING_MODE,
- base::debug::TraceOptions());
+ TraceLog::GetInstance()->SetEnabled(
+ base::debug::CategoryFilter(kNetLogTracingCategory),
+ TraceLog::RECORDING_MODE,
+ base::debug::TraceOptions());
}
void EndTraceAndFlush() {
@@ -120,7 +124,7 @@
<< "Unexpected item without a category field in trace_events";
continue;
}
- if (category != "netlog")
+ if (category != kNetLogTracingCategory)
continue;
filtered_trace_events->Append(dict->DeepCopy());
}
@@ -185,7 +189,7 @@
TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(*item2);
TraceEntryInfo actual_item3 = GetTraceEntryInfoFromValue(*item3);
- EXPECT_EQ("netlog", actual_item1.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
@@ -194,7 +198,7 @@
EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
actual_item1.source_type);
- EXPECT_EQ("netlog", actual_item2.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item2.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[1].source.id), actual_item2.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_BEGIN),
actual_item2.phase);
@@ -203,7 +207,7 @@
EXPECT_EQ(NetLog::SourceTypeToString(entries[1].source.type),
actual_item2.source_type);
- EXPECT_EQ("netlog", actual_item3.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item3.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[2].source.id), actual_item3.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_END),
actual_item3.phase);
@@ -236,7 +240,7 @@
TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(*item2);
- EXPECT_EQ("netlog", actual_item1.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
@@ -245,7 +249,7 @@
EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
actual_item1.source_type);
- EXPECT_EQ("netlog", actual_item2.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item2.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[2].source.id), actual_item2.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item2.phase);
@@ -274,7 +278,7 @@
ASSERT_TRUE(trace_events()->GetDictionary(0, &item1));
TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
- EXPECT_EQ("netlog", actual_item1.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
@@ -342,7 +346,7 @@
TraceEntryInfo actual_item1 = GetTraceEntryInfoFromValue(*item1);
TraceEntryInfo actual_item2 = GetTraceEntryInfoFromValue(*item2);
- EXPECT_EQ("netlog", actual_item1.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item1.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[0].source.id), actual_item1.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item1.phase);
@@ -351,7 +355,7 @@
EXPECT_EQ(NetLog::SourceTypeToString(entries[0].source.type),
actual_item1.source_type);
- EXPECT_EQ("netlog", actual_item2.category);
+ EXPECT_EQ(kNetLogTracingCategory, actual_item2.category);
EXPECT_EQ(base::StringPrintf("0x%d", entries[1].source.id), actual_item2.id);
EXPECT_EQ(std::string(1, TRACE_EVENT_PHASE_NESTABLE_ASYNC_INSTANT),
actual_item2.phase);
diff --git a/net/http/disk_cache_based_quic_server_info.cc b/net/http/disk_cache_based_quic_server_info.cc
index d55349e..44332c9 100644
--- a/net/http/disk_cache_based_quic_server_info.cc
+++ b/net/http/disk_cache_based_quic_server_info.cc
@@ -78,6 +78,7 @@
void DiskCacheBasedQuicServerInfo::Start() {
DCHECK(CalledOnValidThread());
DCHECK_EQ(GET_BACKEND, state_);
+ load_start_time_ = base::TimeTicks::Now();
DoLoop(OK);
}
@@ -312,6 +313,8 @@
}
entry_ = NULL;
Parse(data_);
+ UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheLoadTime",
+ base::TimeTicks::Now() - load_start_time_);
return OK;
}
diff --git a/net/http/disk_cache_based_quic_server_info.h b/net/http/disk_cache_based_quic_server_info.h
index e5ced3f..f904042 100644
--- a/net/http/disk_cache_based_quic_server_info.h
+++ b/net/http/disk_cache_based_quic_server_info.h
@@ -10,6 +10,7 @@
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/non_thread_safe.h"
+#include "base/time/time.h"
#include "net/base/completion_callback.h"
#include "net/disk_cache/disk_cache.h"
#include "net/quic/crypto/quic_server_info.h"
@@ -98,6 +99,7 @@
scoped_refptr<IOBuffer> read_buffer_;
scoped_refptr<IOBuffer> write_buffer_;
std::string data_;
+ base::TimeTicks load_start_time_;
base::WeakPtrFactory<DiskCacheBasedQuicServerInfo> weak_factory_;
};
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index b5ca18b..27afbea 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -339,6 +339,8 @@
num_incorrect_connection_ids_(0),
num_undecryptable_packets_(0),
num_duplicate_packets_(0),
+ num_blocked_frames_received_(0),
+ num_blocked_frames_sent_(0),
connection_description_(GetConnectionDescriptionString()) {
}
@@ -355,6 +357,10 @@
num_undecryptable_packets_);
UMA_HISTOGRAM_COUNTS("Net.QuicSession.DuplicatePacketsReceived",
num_duplicate_packets_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.BlockedFrames.Received",
+ num_blocked_frames_received_);
+ UMA_HISTOGRAM_COUNTS("Net.QuicSession.BlockedFrames.Sent",
+ num_blocked_frames_sent_);
if (num_frames_received_ > 0) {
int duplicate_stream_frame_per_thousand =
@@ -442,6 +448,7 @@
frame.window_update_frame));
break;
case BLOCKED_FRAME:
+ ++num_blocked_frames_sent_;
net_log_.AddEvent(
NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_SENT,
base::Bind(&NetLogQuicBlockedFrameCallback,
@@ -636,6 +643,7 @@
}
void QuicConnectionLogger::OnBlockedFrame(const QuicBlockedFrame& frame) {
+ ++num_blocked_frames_received_;
net_log_.AddEvent(
NetLog::TYPE_QUIC_SESSION_BLOCKED_FRAME_RECEIVED,
base::Bind(&NetLogQuicBlockedFrameCallback, &frame));
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 1d38049..29acfdc 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -151,6 +151,10 @@
int num_undecryptable_packets_;
// Count of the number of duplicate packets received.
int num_duplicate_packets_;
+ // Count of the number of BLOCKED frames received.
+ int num_blocked_frames_received_;
+ // Count of the number of BLOCKED frames sent.
+ int num_blocked_frames_sent_;
// Vector of inital packets status' indexed by packet sequence numbers, where
// false means never received. Zero is not a valid packet sequence number, so
// that offset is never used, and we'll track 150 packets.
diff --git a/net/quic/quic_reliable_client_stream.cc b/net/quic/quic_reliable_client_stream.cc
index b1a82d1..e186b03 100644
--- a/net/quic/quic_reliable_client_stream.cc
+++ b/net/quic/quic_reliable_client_stream.cc
@@ -42,12 +42,12 @@
return data_len;
}
-void QuicReliableClientStream::OnFinRead() {
+void QuicReliableClientStream::OnClose() {
if (delegate_) {
delegate_->OnClose(connection_error());
delegate_ = nullptr;
}
- ReliableQuicStream::OnFinRead();
+ ReliableQuicStream::OnClose();
}
void QuicReliableClientStream::OnCanWrite() {
diff --git a/net/quic/quic_reliable_client_stream.h b/net/quic/quic_reliable_client_stream.h
index 9ed6601..48f5cc9 100644
--- a/net/quic/quic_reliable_client_stream.h
+++ b/net/quic/quic_reliable_client_stream.h
@@ -55,7 +55,7 @@
// QuicDataStream
uint32 ProcessData(const char* data, uint32 data_len) override;
- void OnFinRead() override;
+ void OnClose() override;
void OnCanWrite() override;
QuicPriority EffectivePriority() const override;
diff --git a/net/quic/quic_session_test.cc b/net/quic/quic_session_test.cc
index 0a5032e..4712620 100644
--- a/net/quic/quic_session_test.cc
+++ b/net/quic/quic_session_test.cc
@@ -729,23 +729,26 @@
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
QuicStreamId stream_id = 5;
// Write until the header stream is flow control blocked.
+ SpdyHeaderBlock headers;
while (!headers_stream->flow_controller()->IsBlocked() && stream_id < 2010) {
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_FALSE(session_.IsStreamFlowControlBlocked());
- SpdyHeaderBlock headers;
headers["header"] = base::Uint64ToString(base::RandUint64()) +
base::Uint64ToString(base::RandUint64()) +
base::Uint64ToString(base::RandUint64());
headers_stream->WriteHeaders(stream_id, headers, true, nullptr);
stream_id += 2;
}
+ // Write one more to ensure that the headers stream has buffered data. The
+ // random headers may have exactly filled the flow control window.
+ headers_stream->WriteHeaders(stream_id, headers, true, nullptr);
+ EXPECT_TRUE(headers_stream->HasBufferedData());
+
EXPECT_TRUE(headers_stream->flow_controller()->IsBlocked());
EXPECT_FALSE(crypto_stream->flow_controller()->IsBlocked());
EXPECT_FALSE(session_.IsConnectionFlowControlBlocked());
EXPECT_TRUE(session_.IsStreamFlowControlBlocked());
EXPECT_FALSE(session_.HasDataToWrite());
- // TODO(rtenneti): crbug.com/423586 headers_stream->HasBufferedData is flaky.
- // EXPECT_TRUE(headers_stream->HasBufferedData());
// Now complete the crypto handshake, resulting in an increased flow control
// send window.
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc
index dac3096..046c0a1 100644
--- a/net/quic/quic_stream_factory.cc
+++ b/net/quic/quic_stream_factory.cc
@@ -312,7 +312,6 @@
int QuicStreamFactory::Job::DoResolveHost() {
// Start loading the data now, and wait for it after we resolve the host.
if (server_info_) {
- disk_cache_load_start_time_ = base::TimeTicks::Now();
server_info_->Start();
}
@@ -351,6 +350,7 @@
if (!server_info_)
return OK;
+ disk_cache_load_start_time_ = base::TimeTicks::Now();
return server_info_->WaitForDataReady(
base::Bind(&QuicStreamFactory::Job::OnIOComplete,
weak_factory_.GetWeakPtr()));
@@ -358,7 +358,7 @@
int QuicStreamFactory::Job::DoLoadServerInfoComplete(int rv) {
if (server_info_) {
- UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheReadTime",
+ UMA_HISTOGRAM_TIMES("Net.QuicServerInfo.DiskCacheWaitForDataReadyTime",
base::TimeTicks::Now() - disk_cache_load_start_time_);
}
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 13a3863..1dd9fb4 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -1822,7 +1822,7 @@
SynchronousErrorStreamSocket* raw_transport = transport.get();
scoped_ptr<SSLClientSocket> sock(
- CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
+ CreateSSLClientSocket(transport.Pass(),
test_server.host_port_pair(),
kDefaultSSLConfig));
@@ -1859,7 +1859,7 @@
SynchronousErrorStreamSocket* raw_transport = transport.get();
scoped_ptr<SSLClientSocket> sock(
- CreateSSLClientSocket(transport.PassAs<StreamSocket>(),
+ CreateSSLClientSocket(transport.Pass(),
test_server.host_port_pair(),
ssl_config));
diff --git a/net/spdy/spdy_framer.cc b/net/spdy/spdy_framer.cc
index 9d7ea87..fae97e8 100644
--- a/net/spdy/spdy_framer.cc
+++ b/net/spdy/spdy_framer.cc
@@ -70,6 +70,9 @@
const size_t kPriorityDependencyPayloadSize = 4;
const size_t kPriorityWeightPayloadSize = 1;
+// Wire size of pad length field.
+const size_t kPadLengthFieldSize = 1;
+
} // namespace
const SpdyStreamId SpdyFramer::kInvalidStream = static_cast<SpdyStreamId>(-1);
@@ -379,8 +382,8 @@
return "READING_COMMON_HEADER";
case SPDY_CONTROL_FRAME_PAYLOAD:
return "CONTROL_FRAME_PAYLOAD";
- case SPDY_READ_PADDING_LENGTH:
- return "SPDY_READ_PADDING_LENGTH";
+ case SPDY_READ_DATA_FRAME_PADDING_LENGTH:
+ return "SPDY_READ_DATA_FRAME_PADDING_LENGTH";
case SPDY_CONSUME_PADDING:
return "SPDY_CONSUME_PADDING";
case SPDY_IGNORE_REMAINING_PAYLOAD:
@@ -601,8 +604,8 @@
break;
}
- case SPDY_READ_PADDING_LENGTH: {
- size_t bytes_read = ProcessFramePaddingLength(data, len);
+ case SPDY_READ_DATA_FRAME_PADDING_LENGTH: {
+ size_t bytes_read = ProcessDataFramePaddingLength(data, len);
len -= bytes_read;
data += bytes_read;
break;
@@ -809,7 +812,7 @@
remaining_data_length_,
current_frame_flags_ & DATA_FLAG_FIN);
if (remaining_data_length_ > 0) {
- CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
+ CHANGE_STATE(SPDY_READ_DATA_FRAME_PADDING_LENGTH);
} else {
// Empty data frame.
if (current_frame_flags_ & DATA_FLAG_FIN) {
@@ -1083,15 +1086,23 @@
break;
case HEADERS:
frame_size_without_variable_data = GetHeadersMinimumSize();
- if (protocol_version() > SPDY3 &&
- current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
+ if (protocol_version() > SPDY3) {
+ if (current_frame_flags_ & HEADERS_FLAG_PADDED) {
+ frame_size_without_variable_data += kPadLengthFieldSize;
+ }
+ if (current_frame_flags_ & HEADERS_FLAG_PRIORITY) {
frame_size_without_variable_data +=
kPriorityDependencyPayloadSize +
kPriorityWeightPayloadSize;
+ }
}
break;
case PUSH_PROMISE:
frame_size_without_variable_data = GetPushPromiseMinimumSize();
+ if (protocol_version() > SPDY3 &&
+ current_frame_flags_ & PUSH_PROMISE_FLAG_PADDED) {
+ frame_size_without_variable_data += kPadLengthFieldSize;
+ }
break;
case CONTINUATION:
frame_size_without_variable_data = GetContinuationMinimumSize();
@@ -1457,6 +1468,14 @@
expect_continuation_ = current_frame_stream_id_;
end_stream_when_done_ = current_frame_flags_ & CONTROL_FLAG_FIN;
}
+ if (protocol_version() > SPDY3 &&
+ current_frame_flags_ & HEADERS_FLAG_PADDED) {
+ uint8 pad_payload_len = 0;
+ DCHECK_EQ(remaining_padding_payload_length_, 0u);
+ successful_read = reader.ReadUInt8(&pad_payload_len);
+ DCHECK(successful_read);
+ remaining_padding_payload_length_ = pad_payload_len;
+ }
const bool has_priority =
(current_frame_flags_ & HEADERS_FLAG_PRIORITY) != 0;
uint32 priority = 0;
@@ -1502,7 +1521,7 @@
expect_continuation_ == 0);
}
}
- CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
+ CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
break;
case PUSH_PROMISE:
{
@@ -1511,6 +1530,17 @@
set_error(SPDY_INVALID_CONTROL_FRAME);
break;
}
+ bool successful_read = true;
+ if (protocol_version() > SPDY3 &&
+ current_frame_flags_ & PUSH_PROMISE_FLAG_PADDED) {
+ DCHECK_EQ(remaining_padding_payload_length_, 0u);
+ uint8 pad_payload_len = 0;
+ successful_read = reader.ReadUInt8(&pad_payload_len);
+ DCHECK(successful_read);
+ remaining_padding_payload_length_ = pad_payload_len;
+ }
+ }
+ {
SpdyStreamId promised_stream_id = kInvalidStream;
bool successful_read = reader.ReadUInt31(&promised_stream_id);
DCHECK(successful_read);
@@ -1533,7 +1563,7 @@
(current_frame_flags_ &
PUSH_PROMISE_FLAG_END_PUSH_PROMISE) != 0);
}
- CHANGE_STATE(SPDY_READ_PADDING_LENGTH);
+ CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
break;
case CONTINUATION:
{
@@ -2120,11 +2150,10 @@
return processed_bytes;
}
-// TODO(raullenchai): ProcessFramePaddingLength should be able to deal with
-// HEADERS_FLAG_PADDED and PUSH_PROMISE_FLAG_PADDED as well (see b/15777051).
-size_t SpdyFramer::ProcessFramePaddingLength(const char* data, size_t len) {
- DCHECK_EQ(SPDY_READ_PADDING_LENGTH, state_);
- DCHECK_EQ(remaining_padding_payload_length_, 0u);
+size_t SpdyFramer::ProcessDataFramePaddingLength(const char* data, size_t len) {
+ DCHECK_EQ(SPDY_READ_DATA_FRAME_PADDING_LENGTH, state_);
+ DCHECK_EQ(0u, remaining_padding_payload_length_);
+ DCHECK_EQ(DATA, current_frame_type_);
size_t original_len = len;
if (current_frame_flags_ & DATA_FLAG_PADDED) {
@@ -2149,16 +2178,7 @@
set_error(SPDY_INVALID_DATA_FRAME_FLAGS);
return 0;
}
- if (current_frame_type_ == DATA) {
- CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
- } else {
- DCHECK(current_frame_type_ == HEADERS ||
- current_frame_type_ == PUSH_PROMISE ||
- current_frame_type_ == SYN_STREAM ||
- current_frame_type_ == SYN_REPLY)
- << current_frame_type_;
- CHANGE_STATE(SPDY_CONTROL_FRAME_HEADER_BLOCK);
- }
+ CHANGE_STATE(SPDY_FORWARD_STREAM_FRAME);
return original_len - len;
}
@@ -2606,11 +2626,20 @@
if (headers.has_priority()) {
flags |= HEADERS_FLAG_PRIORITY;
}
+ if (headers.padded()) {
+ flags |= HEADERS_FLAG_PADDED;
+ }
}
- // The size of this frame, including variable-length name-value block.
+ // The size of this frame, including padding (if there is any)
+ // and variable-length name-value block.
size_t size = GetHeadersMinimumSize();
+ if (protocol_version() > SPDY3 && headers.padded()) {
+ size += kPadLengthFieldSize;
+ size += headers.padding_payload_len();
+ }
+
uint32 priority = headers.priority();
if (headers.has_priority()) {
if (priority > GetLowestPriority()) {
@@ -2655,6 +2684,11 @@
DCHECK_EQ(GetHeadersMinimumSize(), builder.length());
if (protocol_version() > SPDY3) {
+ int padding_payload_len = 0;
+ if (headers.padded()) {
+ builder.WriteUInt8(headers.padding_payload_len());
+ padding_payload_len = headers.padding_payload_len();
+ }
if (headers.has_priority()) {
// TODO(jgraettinger): Plumb priorities and stream dependencies.
builder.WriteUInt32(0); // Non-exclusive bit and root stream ID.
@@ -2663,7 +2697,8 @@
WritePayloadWithContinuation(&builder,
hpack_encoding,
headers.stream_id(),
- HEADERS);
+ HEADERS,
+ padding_payload_len);
} else {
SerializeNameValueBlock(&builder, headers);
}
@@ -2717,6 +2752,12 @@
// The size of this frame, including variable-length name-value block.
size_t size = GetPushPromiseMinimumSize();
+ if (push_promise.padded()) {
+ flags |= PUSH_PROMISE_FLAG_PADDED;
+ size += kPadLengthFieldSize;
+ size += push_promise.padding_payload_len();
+ }
+
string hpack_encoding;
if (enable_compression_) {
GetHpackEncoder()->EncodeHeaderSet(
@@ -2737,13 +2778,24 @@
PUSH_PROMISE,
flags,
push_promise.stream_id());
- builder.WriteUInt32(push_promise.promised_stream_id());
- DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length());
+ int padding_payload_len = 0;
+ if (push_promise.padded()) {
+ builder.WriteUInt8(push_promise.padding_payload_len());
+ builder.WriteUInt32(push_promise.promised_stream_id());
+ DCHECK_EQ(GetPushPromiseMinimumSize() + kPadLengthFieldSize,
+ builder.length());
+
+ padding_payload_len = push_promise.padding_payload_len();
+ } else {
+ builder.WriteUInt32(push_promise.promised_stream_id());
+ DCHECK_EQ(GetPushPromiseMinimumSize(), builder.length());
+ }
WritePayloadWithContinuation(&builder,
hpack_encoding,
push_promise.stream_id(),
- PUSH_PROMISE);
+ PUSH_PROMISE,
+ padding_payload_len);
if (debug_visitor_) {
// SPDY4 uses HPACK for header compression. However, continue to
@@ -2923,32 +2975,34 @@
void SpdyFramer::WritePayloadWithContinuation(SpdyFrameBuilder* builder,
const string& hpack_encoding,
SpdyStreamId stream_id,
- SpdyFrameType type) {
+ SpdyFrameType type,
+ int padding_payload_len) {
const size_t kMaxControlFrameSize = GetHeaderFragmentMaxSize();
- // In addition to the prefix, fixed_field_size includes the size of
- // any fields that come before the variable-length name/value block.
- size_t fixed_field_size = 0;
uint8 end_flag = 0;
uint8 flags = 0;
if (type == HEADERS) {
- fixed_field_size = GetHeadersMinimumSize();
end_flag = HEADERS_FLAG_END_HEADERS;
} else if (type == PUSH_PROMISE) {
- fixed_field_size = GetPushPromiseMinimumSize();
end_flag = PUSH_PROMISE_FLAG_END_PUSH_PROMISE;
} else {
DLOG(FATAL) << "CONTINUATION frames cannot be used with frame type "
<< FrameTypeToString(type);
}
- // Write as much of the payload as possible into the initial frame.
- size_t bytes_remaining = hpack_encoding.size() -
- std::min(hpack_encoding.size(),
- kMaxControlFrameSize - fixed_field_size);
+ // Write all the padding payload and as much of the data payload as possible
+ // into the initial frame.
+ size_t bytes_remaining = 0;
+ bytes_remaining = hpack_encoding.size() -
+ std::min(hpack_encoding.size(),
+ kMaxControlFrameSize - builder->length() -
+ padding_payload_len);
builder->WriteBytes(&hpack_encoding[0],
hpack_encoding.size() - bytes_remaining);
-
+ if (padding_payload_len > 0) {
+ string padding = string(padding_payload_len, 0);
+ builder->WriteBytes(padding.data(), padding.length());
+ }
if (bytes_remaining > 0) {
builder->OverwriteLength(*this,
kMaxControlFrameSize - GetControlFrameHeaderSize());
diff --git a/net/spdy/spdy_framer.h b/net/spdy/spdy_framer.h
index 42711c2..99db36a 100644
--- a/net/spdy/spdy_framer.h
+++ b/net/spdy/spdy_framer.h
@@ -336,7 +336,7 @@
SPDY_AUTO_RESET,
SPDY_READING_COMMON_HEADER,
SPDY_CONTROL_FRAME_PAYLOAD,
- SPDY_READ_PADDING_LENGTH,
+ SPDY_READ_DATA_FRAME_PADDING_LENGTH,
SPDY_CONSUME_PADDING,
SPDY_IGNORE_REMAINING_PAYLOAD,
SPDY_FORWARD_STREAM_FRAME,
@@ -601,6 +601,8 @@
UnclosedStreamDataCompressorsOneByteAtATime);
FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
UncompressLargerThanFrameBufferInitialSize);
+ FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
+ CreatePushPromiseThenContinuationUncompressed);
FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest, ReadLargeSettingsFrame);
FRIEND_TEST_ALL_PREFIXES(SpdyFramerTest,
ReadLargeSettingsFrameInSmallChunks);
@@ -634,7 +636,7 @@
size_t ProcessControlFrameHeaderBlock(const char* data,
size_t len,
bool is_hpack_header_block);
- size_t ProcessFramePaddingLength(const char* data, size_t len);
+ size_t ProcessDataFramePaddingLength(const char* data, size_t len);
size_t ProcessFramePadding(const char* data, size_t len);
size_t ProcessDataFramePayload(const char* data, size_t len);
size_t ProcessGoAwayFramePayload(const char* data, size_t len);
@@ -672,7 +674,8 @@
void WritePayloadWithContinuation(SpdyFrameBuilder* builder,
const std::string& hpack_encoding,
SpdyStreamId stream_id,
- SpdyFrameType type);
+ SpdyFrameType type,
+ int padding_payload_len);
private:
// Deliver the given control frame's uncompressed headers block to the
diff --git a/net/spdy/spdy_framer_test.cc b/net/spdy/spdy_framer_test.cc
index 35b8a46..84ea0d7 100644
--- a/net/spdy/spdy_framer_test.cc
+++ b/net/spdy/spdy_framer_test.cc
@@ -2805,6 +2805,35 @@
CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
}
}
+
+ {
+ const char kDescription[] =
+ "HEADERS frame with a 0-length header name, FIN, max stream ID, padded";
+
+ const unsigned char kV4FrameData[] = {
+ 0x00, 0x00, 0x15, 0x01, // Headers
+ 0x0d, 0x7f, 0xff, 0xff, // FIN | END_HEADERS | PADDED, Stream
+ // 0x7fffffff
+ 0xff, 0x05, 0x00, 0x00, // Pad length field
+ 0x03, 0x66, 0x6f, 0x6f, // .foo
+ 0x00, 0x03, 0x66, 0x6f, // @.fo
+ 0x6f, 0x03, 0x62, 0x61, // o.ba
+ 0x72, // r
+ // Padding payload
+ 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+ SpdyHeadersIR headers_ir(0x7fffffff);
+ headers_ir.set_fin(true);
+ headers_ir.SetHeader("", "foo");
+ headers_ir.SetHeader("foo", "bar");
+ headers_ir.set_padding_len(6);
+ scoped_ptr<SpdyFrame> frame(framer.SerializeHeaders(headers_ir));
+ if (IsSpdy2() || IsSpdy3()) {
+ // Padding is not supported.
+ } else {
+ CompareFrame(kDescription, *frame, kV4FrameData, arraysize(kV4FrameData));
+ }
+ }
}
// TODO(phajdan.jr): Clean up after we no longer need
@@ -2982,27 +3011,98 @@
return;
}
- SpdyFramer framer(spdy_version_);
- framer.set_enable_compression(false);
- const char kDescription[] = "PUSH_PROMISE frame";
+ {
+ // Test framing PUSH_PROMISE without padding.
+ SpdyFramer framer(spdy_version_);
+ framer.set_enable_compression(false);
+ const char kDescription[] = "PUSH_PROMISE frame without padding";
- const unsigned char kFrameData[] = {
- 0x00, 0x00, 0x16, 0x05, 0x04, // PUSH_PROMISE: END_HEADERS
- 0x00, 0x00, 0x00, 0x2a, // Stream 42
- 0x00, 0x00, 0x00, 0x39, // Promised stream 57
- 0x00, 0x03, 0x62, 0x61, // @.ba
- 0x72, 0x03, 0x66, 0x6f, // r.fo
- 0x6f, 0x00, 0x03, 0x66, // o@.f
- 0x6f, 0x6f, 0x03, 0x62, // oo.b
- 0x61, 0x72, // ar
- };
+ const unsigned char kFrameData[] = {
+ 0x00, 0x00, 0x16, 0x05, // PUSH_PROMISE
+ 0x04, 0x00, 0x00, 0x00, // END_HEADERS
+ 0x2a, 0x00, 0x00, 0x00, // Stream 42
+ 0x39, 0x00, 0x03, 0x62, // Promised stream 57, @.b
+ 0x61, 0x72, 0x03, 0x66, // ar.f
+ 0x6f, 0x6f, 0x00, 0x03, // oo@.
+ 0x66, 0x6f, 0x6f, 0x03, // foo.
+ 0x62, 0x61, 0x72, // bar
+ };
- SpdyPushPromiseIR push_promise(42, 57);
- push_promise.SetHeader("bar", "foo");
- push_promise.SetHeader("foo", "bar");
- scoped_ptr<SpdySerializedFrame> frame(
- framer.SerializePushPromise(push_promise));
- CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ SpdyPushPromiseIR push_promise(42, 57);
+ push_promise.SetHeader("bar", "foo");
+ push_promise.SetHeader("foo", "bar");
+ scoped_ptr<SpdySerializedFrame> frame(
+ framer.SerializePushPromise(push_promise));
+ CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ }
+
+ {
+ // Test framing PUSH_PROMISE with one byte of padding.
+ SpdyFramer framer(spdy_version_);
+ framer.set_enable_compression(false);
+ const char kDescription[] = "PUSH_PROMISE frame with one byte of padding";
+
+ const unsigned char kFrameData[] = {
+ 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE
+ 0x0c, 0x00, 0x00, 0x00, // END_HEADERS | PADDED
+ 0x2a, 0x00, 0x00, 0x00, // Stream 42, Pad length field
+ 0x00, 0x39, 0x00, 0x03, // Promised stream 57
+ 0x62, 0x61, 0x72, 0x03, // bar.
+ 0x66, 0x6f, 0x6f, 0x00, // foo@
+ 0x03, 0x66, 0x6f, 0x6f, // .foo
+ 0x03, 0x62, 0x61, 0x72, // .bar
+ };
+
+ SpdyPushPromiseIR push_promise(42, 57);
+ push_promise.set_padding_len(1);
+ push_promise.SetHeader("bar", "foo");
+ push_promise.SetHeader("foo", "bar");
+ scoped_ptr<SpdySerializedFrame> frame(
+ framer.SerializePushPromise(push_promise));
+ CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ }
+
+ {
+ // Test framing PUSH_PROMISE with 177 bytes of padding.
+ SpdyFramer framer(spdy_version_);
+ framer.set_enable_compression(false);
+ const char kDescription[] = "PUSH_PROMISE frame with 177 bytes of padding";
+
+ const unsigned char kFrameData[] = {
+ 0x00, 0x00, 0xc7, 0x05, // PUSH_PROMISE
+ 0x0c, 0x00, 0x00, 0x00, // END_HEADERS | PADDED
+ 0x2a, 0xb0, 0x00, 0x00, // Stream 42, Pad length field
+ 0x00, 0x39, 0x00, 0x03, // Promised stream 57
+ 0x62, 0x61, 0x72, 0x03, // bar.
+ 0x66, 0x6f, 0x6f, 0x00, // foo@
+ 0x03, 0x66, 0x6f, 0x6f, // .foo
+ 0x03, 0x62, 0x61, 0x72, // .bar
+ // Padding of 176 0x00(s).
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ };
+
+ SpdyPushPromiseIR push_promise(42, 57);
+ push_promise.set_padding_len(177);
+ push_promise.SetHeader("bar", "foo");
+ push_promise.SetHeader("foo", "bar");
+ scoped_ptr<SpdySerializedFrame> frame(
+ framer.SerializePushPromise(push_promise));
+ CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
+ }
}
TEST_P(SpdyFramerTest, CreateContinuationUncompressed) {
@@ -3032,6 +3132,107 @@
CompareFrame(kDescription, *frame, kFrameData, arraysize(kFrameData));
}
+TEST_P(SpdyFramerTest, CreatePushPromiseThenContinuationUncompressed) {
+ if (spdy_version_ <= SPDY3) {
+ return;
+ }
+
+ {
+ // Test framing in a case such that a PUSH_PROMISE frame, with one byte of
+ // padding, cannot hold all the data payload, which is overflowed to the
+ // consecutive CONTINUATION frame.
+ SpdyFramer framer(spdy_version_);
+ framer.set_enable_compression(false);
+ const char kDescription[] =
+ "PUSH_PROMISE and CONTINUATION frames with one byte of padding";
+
+ const unsigned char kPartialPushPromiseFrameData[] = {
+ 0x00, 0x03, 0xf6, 0x05, // PUSH_PROMISE
+ 0x08, 0x00, 0x00, 0x00, // PADDED
+ 0x2a, 0x00, 0x00, 0x00, // Stream 42
+ 0x00, 0x39, 0x00, 0x03, // Promised stream 57
+ 0x78, 0x78, 0x78, 0x7f, // xxx.
+ 0x80, 0x07, 0x78, 0x78, // ..xx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, // xx
+ };
+
+ const unsigned char kContinuationFrameData[] = {
+ 0x00, 0x00, 0x16, 0x09, // CONTINUATION
+ 0x04, 0x00, 0x00, 0x00, // END_HEADERS
+ 0x2a, 0x78, 0x78, 0x78, // Stream 42, xxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78, 0x78, 0x78, // xxxx
+ 0x78, 0x78,
+ };
+
+ SpdyPushPromiseIR push_promise(42, 57);
+ push_promise.set_padding_len(1);
+ string big_value(framer.GetHeaderFragmentMaxSize(), 'x');
+ push_promise.SetHeader("xxx", big_value);
+ scoped_ptr<SpdySerializedFrame> frame(
+ framer.SerializePushPromise(push_promise));
+
+ // The entire frame should look like below:
+ // Name Length in Byte
+ // ------------------------------------------- Begin of PUSH_PROMISE frame
+ // PUSH_PROMISE header 9
+ // Pad length field 1
+ // Promised stream 4
+ // Length field of key 2
+ // Content of key 3
+ // Length field of value 3
+ // Part of big_value 16361
+ // ------------------------------------------- Begin of CONTINUATION frame
+ // CONTINUATION header 9
+ // Remaining of big_value 22
+ // ------------------------------------------- End
+
+ // Length of everything listed above except big_value.
+ int len_non_data_payload = 31;
+ EXPECT_EQ(framer.GetHeaderFragmentMaxSize() + len_non_data_payload,
+ frame->size());
+
+ // Partially compare the PUSH_PROMISE frame against the template.
+ const unsigned char* frame_data =
+ reinterpret_cast<const unsigned char*>(frame->data());
+ CompareCharArraysWithHexError(kDescription,
+ frame_data,
+ arraysize(kPartialPushPromiseFrameData),
+ kPartialPushPromiseFrameData,
+ arraysize(kPartialPushPromiseFrameData));
+
+ // Compare the CONTINUATION frame against the template.
+ frame_data += framer.GetHeaderFragmentMaxSize();
+ CompareCharArraysWithHexError(kDescription,
+ frame_data,
+ arraysize(kContinuationFrameData),
+ kContinuationFrameData,
+ arraysize(kContinuationFrameData));
+ }
+}
+
TEST_P(SpdyFramerTest, CreateAltSvc) {
if (spdy_version_ <= SPDY3) {
return;
@@ -3263,6 +3464,7 @@
SpdyFramer framer(spdy_version_);
framer.set_enable_compression(false);
SpdyHeadersIR headers(1);
+ headers.set_padding_len(256);
// Exact payload length will change with HPACK, but this should be long
// enough to cause an overflow.
@@ -3291,6 +3493,7 @@
SpdyFramer framer(spdy_version_);
framer.set_enable_compression(false);
SpdyPushPromiseIR push_promise(1, 2);
+ push_promise.set_padding_len(256);
// Exact payload length will change with HPACK, but this should be long
// enough to cause an overflow.
@@ -3729,7 +3932,7 @@
CHECK_EQ(framer.GetDataFrameMinimumSize(),
framer.ProcessInput(frame->data(),
framer.GetDataFrameMinimumSize()));
- CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_PADDING_LENGTH);
+ CHECK_EQ(framer.state(), SpdyFramer::SPDY_READ_DATA_FRAME_PADDING_LENGTH);
CHECK_EQ(framer.error_code(), SpdyFramer::SPDY_NO_ERROR);
bytes_consumed += framer.GetDataFrameMinimumSize();
@@ -3966,31 +4169,31 @@
}
const unsigned char kInput[] = {
- 0x00, 0x00, 0x17, 0x05, 0x08, // PUSH_PROMISE: PADDED
- 0x00, 0x00, 0x00, 0x01, // Stream 1
- 0x00, 0x00, 0x00, 0x2A, // Promised stream 42
- 0x02, // Padding of 2.
- 0x00, 0x06, 0x63, 0x6f,
- 0x6f, 0x6b, 0x69, 0x65,
- 0x07, 0x66, 0x6f, 0x6f,
- 0x3d, 0x62, 0x61, 0x72,
- 0x00, 0x00,
+ 0x00, 0x00, 0x17, 0x05, // PUSH_PROMISE
+ 0x08, 0x00, 0x00, 0x00, // PADDED
+ 0x01, 0x02, 0x00, 0x00, // Stream 1, Pad length field
+ 0x00, 0x2A, 0x00, 0x06, // Promised stream 42
+ 0x63, 0x6f, 0x6f, 0x6b,
+ 0x69, 0x65, 0x07, 0x66,
+ 0x6f, 0x6f, 0x3d, 0x62,
+ 0x61, 0x72, 0x00, 0x00,
- 0x00, 0x00, 0x14, 0x09, 0x00, // CONTINUATION
- 0x00, 0x00, 0x00, 0x01, // Stream 1
- 0x00, 0x06, 0x63, 0x6f,
- 0x6f, 0x6b, 0x69, 0x65,
- 0x08, 0x62, 0x61, 0x7a,
- 0x3d, 0x62, 0x69, 0x6e,
- 0x67, 0x00, 0x06, 0x63,
-
- 0x00, 0x00, 0x12, 0x09, 0x04, // CONTINUATION: END_HEADERS
- 0x00, 0x00, 0x00, 0x01, // Stream 1
+ 0x00, 0x00, 0x14, 0x09, // CONTINUATION
+ 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x06, 0x63, // Stream 1
0x6f, 0x6f, 0x6b, 0x69,
- 0x65, 0x00, 0x00, 0x04,
- 0x6e, 0x61, 0x6d, 0x65,
- 0x05, 0x76, 0x61, 0x6c,
- 0x75, 0x65,
+ 0x65, 0x08, 0x62, 0x61,
+ 0x7a, 0x3d, 0x62, 0x69,
+ 0x6e, 0x67, 0x00, 0x06,
+ 0x63,
+
+ 0x00, 0x00, 0x12, 0x09, // CONTINUATION
+ 0x04, 0x00, 0x00, 0x00, // END_HEADERS
+ 0x01, 0x6f, 0x6f, 0x6b, // Stream 1
+ 0x69, 0x65, 0x00, 0x00,
+ 0x04, 0x6e, 0x61, 0x6d,
+ 0x65, 0x05, 0x76, 0x61,
+ 0x6c, 0x75, 0x65,
};
SpdyFramer framer(spdy_version_);
diff --git a/net/spdy/spdy_protocol.h b/net/spdy/spdy_protocol.h
index c408f0a..3a979b9 100644
--- a/net/spdy/spdy_protocol.h
+++ b/net/spdy/spdy_protocol.h
@@ -845,9 +845,11 @@
class NET_EXPORT_PRIVATE SpdyHeadersIR : public SpdyFrameWithNameValueBlockIR {
public:
explicit SpdyHeadersIR(SpdyStreamId stream_id)
- : SpdyFrameWithNameValueBlockIR(stream_id),
- has_priority_(false),
- priority_(0) {}
+ : SpdyFrameWithNameValueBlockIR(stream_id),
+ has_priority_(false),
+ priority_(0),
+ padded_(false),
+ padding_payload_len_(0) {}
void Visit(SpdyFrameVisitor* visitor) const override;
@@ -856,10 +858,24 @@
uint32 priority() const { return priority_; }
void set_priority(SpdyPriority priority) { priority_ = priority; }
+ bool padded() const { return padded_; }
+ int padding_payload_len() const { return padding_payload_len_; }
+ void set_padding_len(int padding_len) {
+ DCHECK_GT(padding_len, 0);
+ DCHECK_LE(padding_len, kPaddingSizePerFrame);
+ padded_ = true;
+ // The pad field takes one octet on the wire.
+ padding_payload_len_ = padding_len - 1;
+ }
+
private:
bool has_priority_;
// 31-bit priority.
uint32 priority_;
+
+ bool padded_;
+ int padding_payload_len_;
+
DISALLOW_COPY_AND_ASSIGN(SpdyHeadersIR);
};
@@ -901,14 +917,30 @@
public:
SpdyPushPromiseIR(SpdyStreamId stream_id, SpdyStreamId promised_stream_id)
: SpdyFrameWithNameValueBlockIR(stream_id),
- promised_stream_id_(promised_stream_id) {}
+ promised_stream_id_(promised_stream_id),
+ padded_(false),
+ padding_payload_len_(0) {}
SpdyStreamId promised_stream_id() const { return promised_stream_id_; }
void set_promised_stream_id(SpdyStreamId id) { promised_stream_id_ = id; }
void Visit(SpdyFrameVisitor* visitor) const override;
+ bool padded() const { return padded_; }
+ int padding_payload_len() const { return padding_payload_len_; }
+ void set_padding_len(int padding_len) {
+ DCHECK_GT(padding_len, 0);
+ DCHECK_LE(padding_len, kPaddingSizePerFrame);
+ padded_ = true;
+ // The pad field takes one octet on the wire.
+ padding_payload_len_ = padding_len - 1;
+ }
+
private:
SpdyStreamId promised_stream_id_;
+
+ bool padded_;
+ int padding_payload_len_;
+
DISALLOW_COPY_AND_ASSIGN(SpdyPushPromiseIR);
};
diff --git a/net/ssl/default_channel_id_store.cc b/net/ssl/default_channel_id_store.cc
index b71d7b3..60e06ed 100644
--- a/net/ssl/default_channel_id_store.cc
+++ b/net/ssl/default_channel_id_store.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "base/metrics/histogram.h"
+#include "base/profiler/scoped_profile.h"
#include "net/base/net_errors.h"
namespace net {
@@ -61,6 +62,11 @@
void DefaultChannelIDStore::GetChannelIDTask::Run(
DefaultChannelIDStore* store) {
+ // TODO(vadimt): Remove ScopedProfile below once crbug.com/425814 is fixed.
+ tracked_objects::ScopedProfile tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "425814 DefaultChannelIDStore::GetChannelIDTask::Run"));
+
base::Time expiration_time;
std::string private_key_result;
std::string cert_result;
@@ -112,6 +118,11 @@
void DefaultChannelIDStore::SetChannelIDTask::Run(
DefaultChannelIDStore* store) {
+ // TODO(vadimt): Remove ScopedProfile below once crbug.com/425814 is fixed.
+ tracked_objects::ScopedProfile tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "425814 DefaultChannelIDStore::SetChannelIDTask::Run"));
+
store->SyncSetChannelID(server_identifier_, creation_time_,
expiration_time_, private_key_, cert_);
}
@@ -145,6 +156,11 @@
void DefaultChannelIDStore::DeleteChannelIDTask::Run(
DefaultChannelIDStore* store) {
+ // TODO(vadimt): Remove ScopedProfile below once crbug.com/425814 is fixed.
+ tracked_objects::ScopedProfile tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "425814 DefaultChannelIDStore::DeleteChannelIDTask::Run"));
+
store->SyncDeleteChannelID(server_identifier_);
InvokeCallback(callback_);
@@ -183,6 +199,11 @@
void DefaultChannelIDStore::DeleteAllCreatedBetweenTask::Run(
DefaultChannelIDStore* store) {
+ // TODO(vadimt): Remove ScopedProfile below once crbug.com/425814 is fixed.
+ tracked_objects::ScopedProfile tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "425814 DefaultChannelIDStore::DeleteAllCreatedBetweenTask::Run"));
+
store->SyncDeleteAllCreatedBetween(delete_begin_, delete_end_);
InvokeCallback(callback_);
@@ -213,6 +234,11 @@
void DefaultChannelIDStore::GetAllChannelIDsTask::Run(
DefaultChannelIDStore* store) {
+ // TODO(vadimt): Remove ScopedProfile below once crbug.com/425814 is fixed.
+ tracked_objects::ScopedProfile tracking_profile(
+ FROM_HERE_WITH_EXPLICIT_FUNCTION(
+ "425814 DefaultChannelIDStore::GetAllChannelIDsTask::Run"));
+
ChannelIDList cert_list;
store->SyncGetAllChannelIDs(&cert_list);
diff --git a/skia/ext/SkDiscardableMemory_chrome.h b/skia/ext/SkDiscardableMemory_chrome.h
index 18088c5..50946e6 100644
--- a/skia/ext/SkDiscardableMemory_chrome.h
+++ b/skia/ext/SkDiscardableMemory_chrome.h
@@ -13,12 +13,12 @@
// base::DiscardableMemory.
class SK_API SkDiscardableMemoryChrome : public SkDiscardableMemory {
public:
- virtual ~SkDiscardableMemoryChrome();
+ ~SkDiscardableMemoryChrome() override;
// SkDiscardableMemory:
- virtual bool lock() override;
- virtual void* data() override;
- virtual void unlock() override;
+ bool lock() override;
+ void* data() override;
+ void unlock() override;
private:
friend class SkDiscardableMemory;
diff --git a/skia/ext/analysis_canvas.h b/skia/ext/analysis_canvas.h
index d3d3b80..abedcaf 100644
--- a/skia/ext/analysis_canvas.h
+++ b/skia/ext/analysis_canvas.h
@@ -18,7 +18,7 @@
class SK_API AnalysisCanvas : public SkCanvas, public SkDrawPictureCallback {
public:
AnalysisCanvas(int width, int height);
- virtual ~AnalysisCanvas();
+ ~AnalysisCanvas() override;
// Returns true when a SkColor can be used to represent result.
bool GetColorIfSolid(SkColor* color) const;
@@ -27,92 +27,93 @@
void SetForceNotTransparent(bool flag);
// SkDrawPictureCallback override.
- virtual bool abortDrawing() override;
+ bool abortDrawing() override;
// SkCanvas overrides.
- virtual void clear(SkColor) override;
- virtual void drawPaint(const SkPaint& paint) override;
- virtual void drawPoints(PointMode,
- size_t count,
- const SkPoint pts[],
- const SkPaint&) override;
- virtual void drawOval(const SkRect&, const SkPaint&) override;
- virtual void drawRect(const SkRect&, const SkPaint&) override;
- virtual void drawRRect(const SkRRect&, const SkPaint&) override;
- virtual void drawPath(const SkPath& path, const SkPaint&) override;
- virtual void drawBitmap(const SkBitmap&,
- SkScalar left,
- SkScalar top,
- const SkPaint* paint = NULL) override;
- virtual void drawBitmapRectToRect(const SkBitmap&,
- const SkRect* src,
- const SkRect& dst,
- const SkPaint* paint,
- DrawBitmapRectFlags flags) override;
- virtual void drawBitmapMatrix(const SkBitmap&,
- const SkMatrix&,
- const SkPaint* paint = NULL) override;
- virtual void drawBitmapNine(const SkBitmap& bitmap,
- const SkIRect& center,
- const SkRect& dst,
- const SkPaint* paint = NULL) override;
- virtual void drawSprite(const SkBitmap&, int left, int top,
- const SkPaint* paint = NULL) override;
- virtual void drawVertices(VertexMode,
- int vertexCount,
- const SkPoint vertices[],
- const SkPoint texs[],
- const SkColor colors[],
- SkXfermode*,
- const uint16_t indices[],
- int indexCount,
- const SkPaint&) override;
+ void clear(SkColor) override;
+ void drawPaint(const SkPaint& paint) override;
+ void drawPoints(PointMode,
+ size_t count,
+ const SkPoint pts[],
+ const SkPaint&) override;
+ void drawOval(const SkRect&, const SkPaint&) override;
+ void drawRect(const SkRect&, const SkPaint&) override;
+ void drawRRect(const SkRRect&, const SkPaint&) override;
+ void drawPath(const SkPath& path, const SkPaint&) override;
+ void drawBitmap(const SkBitmap&,
+ SkScalar left,
+ SkScalar top,
+ const SkPaint* paint = NULL) override;
+ void drawBitmapRectToRect(const SkBitmap&,
+ const SkRect* src,
+ const SkRect& dst,
+ const SkPaint* paint,
+ DrawBitmapRectFlags flags) override;
+ void drawBitmapMatrix(const SkBitmap&,
+ const SkMatrix&,
+ const SkPaint* paint = NULL) override;
+ void drawBitmapNine(const SkBitmap& bitmap,
+ const SkIRect& center,
+ const SkRect& dst,
+ const SkPaint* paint = NULL) override;
+ void drawSprite(const SkBitmap&,
+ int left,
+ int top,
+ const SkPaint* paint = NULL) override;
+ void drawVertices(VertexMode,
+ int vertexCount,
+ const SkPoint vertices[],
+ const SkPoint texs[],
+ const SkColor colors[],
+ SkXfermode*,
+ const uint16_t indices[],
+ int indexCount,
+ const SkPaint&) override;
protected:
- virtual void willSave() override;
- virtual SaveLayerStrategy willSaveLayer(const SkRect*,
- const SkPaint*,
- SaveFlags) override;
- virtual void willRestore() override;
+ void willSave() override;
+ SaveLayerStrategy willSaveLayer(const SkRect*,
+ const SkPaint*,
+ SaveFlags) override;
+ void willRestore() override;
- virtual void onClipRect(const SkRect& rect,
- SkRegion::Op op,
- ClipEdgeStyle edge_style) override;
- virtual void onClipRRect(const SkRRect& rrect,
- SkRegion::Op op,
- ClipEdgeStyle edge_style) override;
- virtual void onClipPath(const SkPath& path,
- SkRegion::Op op,
- ClipEdgeStyle edge_style) override;
- virtual void onClipRegion(const SkRegion& deviceRgn,
- SkRegion::Op op) override;
+ void onClipRect(const SkRect& rect,
+ SkRegion::Op op,
+ ClipEdgeStyle edge_style) override;
+ void onClipRRect(const SkRRect& rrect,
+ SkRegion::Op op,
+ ClipEdgeStyle edge_style) override;
+ void onClipPath(const SkPath& path,
+ SkRegion::Op op,
+ ClipEdgeStyle edge_style) override;
+ void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) override;
- virtual void onDrawText(const void* text,
- size_t byteLength,
- SkScalar x,
- SkScalar y,
- const SkPaint&) override;
- virtual void onDrawPosText(const void* text,
- size_t byteLength,
- const SkPoint pos[],
- const SkPaint&) override;
- virtual void onDrawPosTextH(const void* text,
- size_t byteLength,
- const SkScalar xpos[],
- SkScalar constY,
- const SkPaint&) override;
- virtual void onDrawTextOnPath(const void* text,
- size_t byteLength,
- const SkPath& path,
- const SkMatrix* matrix,
- const SkPaint&) override;
- virtual void onDrawTextBlob(const SkTextBlob* blob,
- SkScalar x,
- SkScalar y,
- const SkPaint& paint) override;
- virtual void onDrawDRRect(const SkRRect& outer,
- const SkRRect& inner,
- const SkPaint&) override;
+ void onDrawText(const void* text,
+ size_t byteLength,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint&) override;
+ void onDrawPosText(const void* text,
+ size_t byteLength,
+ const SkPoint pos[],
+ const SkPaint&) override;
+ void onDrawPosTextH(const void* text,
+ size_t byteLength,
+ const SkScalar xpos[],
+ SkScalar constY,
+ const SkPaint&) override;
+ void onDrawTextOnPath(const void* text,
+ size_t byteLength,
+ const SkPath& path,
+ const SkMatrix* matrix,
+ const SkPaint&) override;
+ void onDrawTextBlob(const SkTextBlob* blob,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) override;
+ void onDrawDRRect(const SkRRect& outer,
+ const SkRRect& inner,
+ const SkPaint&) override;
void OnComplexClip();
diff --git a/skia/ext/benchmarking_canvas.cc b/skia/ext/benchmarking_canvas.cc
index f3f8cc5..64d3f6c 100644
--- a/skia/ext/benchmarking_canvas.cc
+++ b/skia/ext/benchmarking_canvas.cc
@@ -29,8 +29,7 @@
setProxy(canvas_.get());
}
- virtual ~TimingCanvas() {
- }
+ ~TimingCanvas() override {}
double GetTime(size_t index) {
TimingsMap::const_iterator timing_info = timings_map_.find(index);
@@ -40,149 +39,172 @@
}
// SkCanvas overrides.
- virtual void willSave() override {
+ void willSave() override {
AutoStamper stamper(this);
SkProxyCanvas::willSave();
}
- virtual SaveLayerStrategy willSaveLayer(const SkRect* bounds,
- const SkPaint* paint,
- SaveFlags flags) override {
+ SaveLayerStrategy willSaveLayer(const SkRect* bounds,
+ const SkPaint* paint,
+ SaveFlags flags) override {
AutoStamper stamper(this);
return SkProxyCanvas::willSaveLayer(bounds, paint, flags);
}
- virtual void willRestore() override {
+ void willRestore() override {
AutoStamper stamper(this);
SkProxyCanvas::willRestore();
}
- virtual void drawPaint(const SkPaint& paint) override {
+ void drawPaint(const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::drawPaint(paint);
}
- virtual void drawPoints(PointMode mode, size_t count, const SkPoint pts[],
- const SkPaint& paint) override {
+ void drawPoints(PointMode mode,
+ size_t count,
+ const SkPoint pts[],
+ const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::drawPoints(mode, count, pts, paint);
}
- virtual void drawOval(const SkRect& rect, const SkPaint& paint) override {
+ void drawOval(const SkRect& rect, const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::drawOval(rect, paint);
}
- virtual void drawRect(const SkRect& rect, const SkPaint& paint) override {
+ void drawRect(const SkRect& rect, const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::drawRect(rect, paint);
}
- virtual void drawRRect(const SkRRect& rrect, const SkPaint& paint) override {
+ void drawRRect(const SkRRect& rrect, const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::drawRRect(rrect, paint);
}
- virtual void drawPath(const SkPath& path, const SkPaint& paint) override {
+ void drawPath(const SkPath& path, const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::drawPath(path, paint);
}
- virtual void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top,
- const SkPaint* paint = NULL) override {
+ void drawBitmap(const SkBitmap& bitmap,
+ SkScalar left,
+ SkScalar top,
+ const SkPaint* paint = NULL) override {
AutoStamper stamper(this);
SkProxyCanvas::drawBitmap(bitmap, left, top, paint);
}
- virtual void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src,
- const SkRect& dst,
- const SkPaint* paint,
- DrawBitmapRectFlags flags) override {
+ void drawBitmapRectToRect(const SkBitmap& bitmap,
+ const SkRect* src,
+ const SkRect& dst,
+ const SkPaint* paint,
+ DrawBitmapRectFlags flags) override {
AutoStamper stamper(this);
SkProxyCanvas::drawBitmapRectToRect(bitmap, src, dst, paint, flags);
}
- virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
- const SkPaint* paint = NULL) override {
+ void drawBitmapMatrix(const SkBitmap& bitmap,
+ const SkMatrix& m,
+ const SkPaint* paint = NULL) override {
AutoStamper stamper(this);
SkProxyCanvas::drawBitmapMatrix(bitmap, m, paint);
}
- virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
- const SkPaint* paint = NULL) override {
+ void drawSprite(const SkBitmap& bitmap,
+ int left,
+ int top,
+ const SkPaint* paint = NULL) override {
AutoStamper stamper(this);
SkProxyCanvas::drawSprite(bitmap, left, top, paint);
}
- virtual void drawVertices(VertexMode vmode, int vertexCount,
- const SkPoint vertices[], const SkPoint texs[],
- const SkColor colors[], SkXfermode* xmode,
- const uint16_t indices[], int indexCount,
- const SkPaint& paint) override {
+ void drawVertices(VertexMode vmode,
+ int vertexCount,
+ const SkPoint vertices[],
+ const SkPoint texs[],
+ const SkColor colors[],
+ SkXfermode* xmode,
+ const uint16_t indices[],
+ int indexCount,
+ const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::drawVertices(vmode, vertexCount, vertices, texs, colors,
xmode, indices, indexCount, paint);
}
- virtual void drawData(const void* data, size_t length) override {
+ void drawData(const void* data, size_t length) override {
AutoStamper stamper(this);
SkProxyCanvas::drawData(data, length);
}
protected:
- virtual void onDrawText(const void* text, size_t byteLength, SkScalar x,
- SkScalar y, const SkPaint& paint) override {
+ void onDrawText(const void* text,
+ size_t byteLength,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::onDrawText(text, byteLength, x, y, paint);
}
- virtual void onDrawPosText(const void* text, size_t byteLength,
- const SkPoint pos[],
- const SkPaint& paint) override {
+ void onDrawPosText(const void* text,
+ size_t byteLength,
+ const SkPoint pos[],
+ const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::onDrawPosText(text, byteLength, pos, paint);
}
- virtual void onDrawPosTextH(const void* text, size_t byteLength,
- const SkScalar xpos[], SkScalar constY,
- const SkPaint& paint) override {
+ void onDrawPosTextH(const void* text,
+ size_t byteLength,
+ const SkScalar xpos[],
+ SkScalar constY,
+ const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::onDrawPosTextH(text, byteLength, xpos, constY, paint);
}
- virtual void onDrawTextOnPath(const void* text, size_t byteLength,
- const SkPath& path, const SkMatrix* matrix,
- const SkPaint& paint) override {
+ void onDrawTextOnPath(const void* text,
+ size_t byteLength,
+ const SkPath& path,
+ const SkMatrix* matrix,
+ const SkPaint& paint) override {
AutoStamper stamper(this);
SkProxyCanvas::onDrawTextOnPath(text, byteLength, path, matrix, paint);
}
- virtual void onClipRect(const SkRect& rect, SkRegion::Op op,
- ClipEdgeStyle edge_style) override {
+ void onClipRect(const SkRect& rect,
+ SkRegion::Op op,
+ ClipEdgeStyle edge_style) override {
AutoStamper stamper(this);
SkProxyCanvas::onClipRect(rect, op, edge_style);
}
- virtual void onClipRRect(const SkRRect& rrect, SkRegion::Op op,
- ClipEdgeStyle edge_style) override {
+ void onClipRRect(const SkRRect& rrect,
+ SkRegion::Op op,
+ ClipEdgeStyle edge_style) override {
AutoStamper stamper(this);
SkProxyCanvas::onClipRRect(rrect, op, edge_style);
}
- virtual void onClipPath(const SkPath& path, SkRegion::Op op,
- ClipEdgeStyle edge_style) override {
+ void onClipPath(const SkPath& path,
+ SkRegion::Op op,
+ ClipEdgeStyle edge_style) override {
AutoStamper stamper(this);
SkProxyCanvas::onClipPath(path, op, edge_style);
}
- virtual void onClipRegion(const SkRegion& region,
- SkRegion::Op op) override {
+ void onClipRegion(const SkRegion& region, SkRegion::Op op) override {
AutoStamper stamper(this);
SkProxyCanvas::onClipRegion(region, op);
}
- virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
- const SkPaint* paint) override {
+ void onDrawPicture(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint) override {
AutoStamper stamper(this);
SkProxyCanvas::onDrawPicture(picture, matrix, paint);
}
diff --git a/skia/ext/benchmarking_canvas.h b/skia/ext/benchmarking_canvas.h
index 7ef8204..50289a5 100644
--- a/skia/ext/benchmarking_canvas.h
+++ b/skia/ext/benchmarking_canvas.h
@@ -17,7 +17,7 @@
class SK_API BenchmarkingCanvas : public SkNWayCanvas {
public:
BenchmarkingCanvas(int width, int height);
- virtual ~BenchmarkingCanvas();
+ ~BenchmarkingCanvas() override;
// Returns the number of draw commands executed on this canvas.
size_t CommandCount() const;
diff --git a/skia/ext/bitmap_platform_device_mac.h b/skia/ext/bitmap_platform_device_mac.h
index eb142e2..dc78562 100644
--- a/skia/ext/bitmap_platform_device_mac.h
+++ b/skia/ext/bitmap_platform_device_mac.h
@@ -48,23 +48,25 @@
int width, int height,
bool is_opaque);
- virtual ~BitmapPlatformDevice();
+ ~BitmapPlatformDevice() override;
// PlatformDevice overrides
- virtual CGContextRef GetBitmapContext() override;
- virtual void DrawToNativeContext(CGContextRef context, int x, int y,
- const CGRect* src_rect) override;
+ CGContextRef GetBitmapContext() override;
+ void DrawToNativeContext(CGContextRef context,
+ int x,
+ int y,
+ const CGRect* src_rect) override;
// SkBaseDevice overrides
- virtual void setMatrixClip(const SkMatrix& transform, const SkRegion& region,
- const SkClipStack&) override;
+ void setMatrixClip(const SkMatrix& transform,
+ const SkRegion& region,
+ const SkClipStack&) override;
protected:
BitmapPlatformDevice(CGContextRef context,
const SkBitmap& bitmap);
- virtual SkBaseDevice* onCreateDevice(const SkImageInfo& info,
- Usage usage) override;
+ SkBaseDevice* onCreateDevice(const SkImageInfo& info, Usage usage) override;
private:
void ReleaseBitmapContext();
diff --git a/skia/ext/event_tracer_impl.cc b/skia/ext/event_tracer_impl.cc
index f5e081d..53ddf2b 100644
--- a/skia/ext/event_tracer_impl.cc
+++ b/skia/ext/event_tracer_impl.cc
@@ -9,23 +9,20 @@
namespace skia {
class SkChromiumEventTracer: public SkEventTracer {
- virtual const uint8_t* getCategoryGroupEnabled(const char* name) override;
- virtual const char* getCategoryGroupName(
- const uint8_t* categoryEnabledFlag) override;
- virtual SkEventTracer::Handle
- addTraceEvent(char phase,
- const uint8_t* categoryEnabledFlag,
- const char* name,
- uint64_t id,
- int32_t numArgs,
- const char** argNames,
- const uint8_t* argTypes,
- const uint64_t* argValues,
- uint8_t flags) override;
- virtual void
- updateTraceEventDuration(const uint8_t* categoryEnabledFlag,
- const char *name,
- SkEventTracer::Handle handle) override;
+ const uint8_t* getCategoryGroupEnabled(const char* name) override;
+ const char* getCategoryGroupName(const uint8_t* categoryEnabledFlag) override;
+ SkEventTracer::Handle addTraceEvent(char phase,
+ const uint8_t* categoryEnabledFlag,
+ const char* name,
+ uint64_t id,
+ int32_t numArgs,
+ const char** argNames,
+ const uint8_t* argTypes,
+ const uint64_t* argValues,
+ uint8_t flags) override;
+ void updateTraceEventDuration(const uint8_t* categoryEnabledFlag,
+ const char* name,
+ SkEventTracer::Handle handle) override;
};
const uint8_t*
diff --git a/skia/ext/lazy_pixel_ref.h b/skia/ext/lazy_pixel_ref.h
index b3f704d..2335fdf 100644
--- a/skia/ext/lazy_pixel_ref.h
+++ b/skia/ext/lazy_pixel_ref.h
@@ -15,7 +15,7 @@
class SK_API LazyPixelRef : public SkPixelRef {
public:
explicit LazyPixelRef(const SkImageInfo& info);
- virtual ~LazyPixelRef();
+ ~LazyPixelRef() override;
struct PrepareParams {
// Clipping rect for this pixel ref.
diff --git a/skia/ext/opacity_draw_filter.h b/skia/ext/opacity_draw_filter.h
index 9789cc2..7d11d68 100644
--- a/skia/ext/opacity_draw_filter.h
+++ b/skia/ext/opacity_draw_filter.h
@@ -19,8 +19,8 @@
class SK_API OpacityDrawFilter : public SkDrawFilter {
public:
OpacityDrawFilter(float opacity, bool disable_image_filtering);
- virtual ~OpacityDrawFilter();
- virtual bool filter(SkPaint* paint, SkDrawFilter::Type type) override;
+ ~OpacityDrawFilter() override;
+ bool filter(SkPaint* paint, SkDrawFilter::Type type) override;
private:
int alpha_;
diff --git a/skia/ext/pixel_ref_utils.cc b/skia/ext/pixel_ref_utils.cc
index 6eb7361..4e85f7a 100644
--- a/skia/ext/pixel_ref_utils.cc
+++ b/skia/ext/pixel_ref_utils.cc
@@ -51,8 +51,8 @@
DiscardablePixelRefSet* pixel_ref_set)
: SkBitmapDevice(bm), pixel_ref_set_(pixel_ref_set) {}
- virtual void clear(SkColor color) override {}
- virtual void drawPaint(const SkDraw& draw, const SkPaint& paint) override {
+ void clear(SkColor color) override {}
+ void drawPaint(const SkDraw& draw, const SkPaint& paint) override {
SkBitmap bitmap;
if (GetBitmapFromPaint(paint, &bitmap)) {
SkRect clip_rect = SkRect::Make(draw.fRC->getBounds());
@@ -60,11 +60,11 @@
}
}
- virtual void drawPoints(const SkDraw& draw,
- SkCanvas::PointMode mode,
- size_t count,
- const SkPoint points[],
- const SkPaint& paint) override {
+ void drawPoints(const SkDraw& draw,
+ SkCanvas::PointMode mode,
+ size_t count,
+ const SkPoint points[],
+ const SkPaint& paint) override {
SkBitmap bitmap;
if (!GetBitmapFromPaint(paint, &bitmap))
return;
@@ -87,9 +87,9 @@
GatherPixelRefDevice::drawRect(draw, bounds, paint);
}
- virtual void drawRect(const SkDraw& draw,
- const SkRect& rect,
- const SkPaint& paint) override {
+ void drawRect(const SkDraw& draw,
+ const SkRect& rect,
+ const SkPaint& paint) override {
SkBitmap bitmap;
if (GetBitmapFromPaint(paint, &bitmap)) {
SkRect mapped_rect;
@@ -98,21 +98,21 @@
AddBitmap(bitmap, mapped_rect);
}
}
- virtual void drawOval(const SkDraw& draw,
- const SkRect& rect,
- const SkPaint& paint) override {
+ void drawOval(const SkDraw& draw,
+ const SkRect& rect,
+ const SkPaint& paint) override {
GatherPixelRefDevice::drawRect(draw, rect, paint);
}
- virtual void drawRRect(const SkDraw& draw,
- const SkRRect& rect,
- const SkPaint& paint) override {
+ void drawRRect(const SkDraw& draw,
+ const SkRRect& rect,
+ const SkPaint& paint) override {
GatherPixelRefDevice::drawRect(draw, rect.rect(), paint);
}
- virtual void drawPath(const SkDraw& draw,
- const SkPath& path,
- const SkPaint& paint,
- const SkMatrix* pre_path_matrix,
- bool path_is_mutable) override {
+ void drawPath(const SkDraw& draw,
+ const SkPath& path,
+ const SkPaint& paint,
+ const SkMatrix* pre_path_matrix,
+ bool path_is_mutable) override {
SkBitmap bitmap;
if (!GetBitmapFromPaint(paint, &bitmap))
return;
@@ -126,10 +126,10 @@
GatherPixelRefDevice::drawRect(draw, final_rect, paint);
}
- virtual void drawBitmap(const SkDraw& draw,
- const SkBitmap& bitmap,
- const SkMatrix& matrix,
- const SkPaint& paint) override {
+ void drawBitmap(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkMatrix& matrix,
+ const SkPaint& paint) override {
SkMatrix total_matrix;
total_matrix.setConcat(*draw.fMatrix, matrix);
@@ -142,22 +142,22 @@
if (GetBitmapFromPaint(paint, &paint_bitmap))
AddBitmap(paint_bitmap, mapped_rect);
}
- virtual void drawBitmapRect(const SkDraw& draw,
- const SkBitmap& bitmap,
- const SkRect* src_or_null,
- const SkRect& dst,
- const SkPaint& paint,
- SkCanvas::DrawBitmapRectFlags flags) override {
+ void drawBitmapRect(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ const SkRect* src_or_null,
+ const SkRect& dst,
+ const SkPaint& paint,
+ SkCanvas::DrawBitmapRectFlags flags) override {
SkRect bitmap_rect = SkRect::MakeWH(bitmap.width(), bitmap.height());
SkMatrix matrix;
matrix.setRectToRect(bitmap_rect, dst, SkMatrix::kFill_ScaleToFit);
GatherPixelRefDevice::drawBitmap(draw, bitmap, matrix, paint);
}
- virtual void drawSprite(const SkDraw& draw,
- const SkBitmap& bitmap,
- int x,
- int y,
- const SkPaint& paint) override {
+ void drawSprite(const SkDraw& draw,
+ const SkBitmap& bitmap,
+ int x,
+ int y,
+ const SkPaint& paint) override {
// Sprites aren't affected by current matrix, so we can't reuse drawRect.
SkMatrix matrix;
matrix.setTranslate(x, y);
@@ -171,12 +171,12 @@
if (GetBitmapFromPaint(paint, &paint_bitmap))
AddBitmap(paint_bitmap, mapped_rect);
}
- virtual void drawText(const SkDraw& draw,
- const void* text,
- size_t len,
- SkScalar x,
- SkScalar y,
- const SkPaint& paint) override {
+ void drawText(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ SkScalar x,
+ SkScalar y,
+ const SkPaint& paint) override {
SkBitmap bitmap;
if (!GetBitmapFromPaint(paint, &bitmap))
return;
@@ -218,13 +218,13 @@
GatherPixelRefDevice::drawRect(draw, bounds, paint);
}
- virtual void drawPosText(const SkDraw& draw,
- const void* text,
- size_t len,
- const SkScalar pos[],
- int scalars_per_pos,
- const SkPoint& offset,
- const SkPaint& paint) override {
+ void drawPosText(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ const SkScalar pos[],
+ int scalars_per_pos,
+ const SkPoint& offset,
+ const SkPaint& paint) override {
SkBitmap bitmap;
if (!GetBitmapFromPaint(paint, &bitmap))
return;
@@ -263,12 +263,12 @@
GatherPixelRefDevice::drawRect(draw, bounds, paint);
}
- virtual void drawTextOnPath(const SkDraw& draw,
- const void* text,
- size_t len,
- const SkPath& path,
- const SkMatrix* matrix,
- const SkPaint& paint) override {
+ void drawTextOnPath(const SkDraw& draw,
+ const void* text,
+ size_t len,
+ const SkPath& path,
+ const SkMatrix* matrix,
+ const SkPaint& paint) override {
SkBitmap bitmap;
if (!GetBitmapFromPaint(paint, &bitmap))
return;
@@ -286,39 +286,39 @@
GatherPixelRefDevice::drawRect(draw, bounds, paint);
}
- virtual void drawVertices(const SkDraw& draw,
- SkCanvas::VertexMode,
- int vertex_count,
- const SkPoint verts[],
- const SkPoint texs[],
- const SkColor colors[],
- SkXfermode* xmode,
- const uint16_t indices[],
- int index_count,
- const SkPaint& paint) override {
+ void drawVertices(const SkDraw& draw,
+ SkCanvas::VertexMode,
+ int vertex_count,
+ const SkPoint verts[],
+ const SkPoint texs[],
+ const SkColor colors[],
+ SkXfermode* xmode,
+ const uint16_t indices[],
+ int index_count,
+ const SkPaint& paint) override {
GatherPixelRefDevice::drawPoints(
draw, SkCanvas::kPolygon_PointMode, vertex_count, verts, paint);
}
- virtual void drawDevice(const SkDraw&,
- SkBaseDevice*,
- int x,
- int y,
- const SkPaint&) override {}
+ void drawDevice(const SkDraw&,
+ SkBaseDevice*,
+ int x,
+ int y,
+ const SkPaint&) override {}
protected:
- virtual bool onReadPixels(const SkImageInfo& info,
- void* pixels,
- size_t rowBytes,
- int x,
- int y) override {
+ bool onReadPixels(const SkImageInfo& info,
+ void* pixels,
+ size_t rowBytes,
+ int x,
+ int y) override {
return false;
}
- virtual bool onWritePixels(const SkImageInfo& info,
- const void* pixels,
- size_t rowBytes,
- int x,
- int y) override {
+ bool onWritePixels(const SkImageInfo& info,
+ const void* pixels,
+ size_t rowBytes,
+ int x,
+ int y) override {
return false;
}
diff --git a/skia/ext/pixel_ref_utils_unittest.cc b/skia/ext/pixel_ref_utils_unittest.cc
index aef5766..656ef5c 100644
--- a/skia/ext/pixel_ref_utils_unittest.cc
+++ b/skia/ext/pixel_ref_utils_unittest.cc
@@ -34,20 +34,18 @@
CreateBitmap(gfx::Size(50, 50), "discardable", &bitmap_);
}
- virtual SkShader::BitmapType asABitmap(SkBitmap* bitmap,
- SkMatrix* matrix,
- TileMode xy[2]) const override {
+ SkShader::BitmapType asABitmap(SkBitmap* bitmap,
+ SkMatrix* matrix,
+ TileMode xy[2]) const override {
if (bitmap)
*bitmap = bitmap_;
return SkShader::kDefault_BitmapType;
}
// not indended to return an actual context. Just need to supply this.
- virtual size_t contextSize() const override {
- return sizeof(SkShader::Context);
- }
+ size_t contextSize() const override { return sizeof(SkShader::Context); }
- virtual void flatten(SkWriteBuffer&) const override {}
+ void flatten(SkWriteBuffer&) const override {}
SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(TestDiscardableShader);
diff --git a/skia/ext/vector_platform_device_skia.h b/skia/ext/vector_platform_device_skia.h
index fc88904..528eac9 100644
--- a/skia/ext/vector_platform_device_skia.h
+++ b/skia/ext/vector_platform_device_skia.h
@@ -23,24 +23,24 @@
SK_API VectorPlatformDeviceSkia(const SkISize& pageSize,
const SkISize& contentSize,
const SkMatrix& initialTransform);
- virtual ~VectorPlatformDeviceSkia();
+ ~VectorPlatformDeviceSkia() override;
// PlatformDevice methods.
- virtual bool SupportsPlatformPaint() override;
+ bool SupportsPlatformPaint() override;
- virtual PlatformSurface BeginPlatformPaint() override;
- virtual void EndPlatformPaint() override;
+ PlatformSurface BeginPlatformPaint() override;
+ void EndPlatformPaint() override;
#if defined(OS_WIN)
virtual void DrawToNativeContext(HDC dc,
int x,
int y,
const RECT* src_rect) override;
#elif defined(OS_MACOSX)
- virtual void DrawToNativeContext(CGContext* context,
- int x,
- int y,
- const CGRect* src_rect) override;
- virtual CGContextRef GetBitmapContext() override;
+ void DrawToNativeContext(CGContext* context,
+ int x,
+ int y,
+ const CGRect* src_rect) override;
+ CGContextRef GetBitmapContext() override;
#elif defined(OS_POSIX)
virtual void DrawToNativeContext(PlatformSurface surface,
int x,
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index a0187b9..a184a12 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -42,15 +42,12 @@
"browser_tests",
"content_browsertests",
"mojo_apps_js_unittests",
- "mojo_clipboard_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
"mojo_public_bindings_unittests",
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
@@ -99,15 +96,12 @@
"browser_tests",
"content_browsertests",
"mojo_apps_js_unittests",
- "mojo_clipboard_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
"mojo_public_bindings_unittests",
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
@@ -156,15 +150,12 @@
"browser_tests",
"content_browsertests",
"mojo_apps_js_unittests",
- "mojo_clipboard_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
"mojo_public_bindings_unittests",
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
@@ -213,15 +204,12 @@
"browser_tests",
"content_browsertests",
"mojo_apps_js_unittests",
- "mojo_clipboard_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
"mojo_public_bindings_unittests",
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_surfaces_lib_unittests",
"mojo_system_unittests",
"nacl_loader_unittests"
@@ -259,15 +247,12 @@
"media_unittests",
"message_center_unittests",
"mojo_apps_js_unittests",
- "mojo_clipboard_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
"mojo_public_bindings_unittests",
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
"net_unittests",
"ppapi_unittests",
@@ -341,7 +326,6 @@
"ipc_tests",
"jingle_unittests",
"media_unittests",
- "mojo_application_manager_unittests",
"mojo_apps_js_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
@@ -349,7 +333,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
"nacl_loader_unittests",
"net_unittests",
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index 9f814d3..ecce684 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -57,7 +57,6 @@
"ipc_tests",
"jingle_unittests",
"media_unittests",
- "mojo_application_manager_unittests",
"mojo_apps_js_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
@@ -65,9 +64,7 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
- "mojo_view_manager_unittests",
"nacl_loader_unittests",
{
"test": "net_unittests",
@@ -157,7 +154,6 @@
"ipc_tests",
"jingle_unittests",
"media_unittests",
- "mojo_application_manager_unittests",
"mojo_apps_js_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
@@ -165,9 +161,7 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
- "mojo_view_manager_unittests",
"nacl_loader_unittests",
{
"test": "net_unittests",
@@ -258,7 +252,6 @@
"ipc_tests",
"jingle_unittests",
"media_unittests",
- "mojo_application_manager_unittests",
"mojo_apps_js_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
@@ -266,9 +259,7 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
- "mojo_view_manager_unittests",
"nacl_loader_unittests",
{
"test": "net_unittests",
@@ -317,7 +308,6 @@
"google_apis_unittests",
"ipc_mojo_unittests",
"ipc_tests",
- "mojo_application_manager_unittests",
"mojo_apps_js_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
@@ -325,9 +315,7 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
- "mojo_view_manager_unittests",
"nacl_loader_unittests",
"sandbox_linux_unittests",
"sql_unittests",
diff --git a/testing/buildbot/chromium.mac.json b/testing/buildbot/chromium.mac.json
index ef5867d..018a2e3 100644
--- a/testing/buildbot/chromium.mac.json
+++ b/testing/buildbot/chromium.mac.json
@@ -56,8 +56,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
{
"test": "net_unittests",
@@ -144,8 +142,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
{
"test": "net_unittests",
@@ -232,8 +228,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
{
"test": "net_unittests",
@@ -321,8 +315,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_application_manager_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
{
"test": "net_unittests",
diff --git a/testing/buildbot/chromium.memory.fyi.json b/testing/buildbot/chromium.memory.fyi.json
index c2e560e..3f9acc0 100644
--- a/testing/buildbot/chromium.memory.fyi.json
+++ b/testing/buildbot/chromium.memory.fyi.json
@@ -28,7 +28,6 @@
"ipc_tests",
"jingle_unittests",
"media_unittests",
- "mojo_application_manager_unittests",
"mojo_apps_js_unittests",
"mojo_common_unittests",
"mojo_js_unittests",
@@ -36,7 +35,6 @@
"mojo_public_environment_unittests",
"mojo_public_system_unittests",
"mojo_public_utility_unittests",
- "mojo_shell_tests",
"mojo_system_unittests",
"nacl_loader_unittests",
"net_unittests",
diff --git a/third_party/android_testrunner/LICENSE b/third_party/android_testrunner/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/third_party/android_testrunner/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/third_party/android_testrunner/OWNERS b/third_party/android_testrunner/OWNERS
new file mode 100644
index 0000000..9281d8a
--- /dev/null
+++ b/third_party/android_testrunner/OWNERS
@@ -0,0 +1,3 @@
+craigdh@chromium.org
+frankf@chromium.org
+jbudorick@chromium.org
diff --git a/third_party/android_testrunner/README.chromium b/third_party/android_testrunner/README.chromium
new file mode 100644
index 0000000..7d382a1
--- /dev/null
+++ b/third_party/android_testrunner/README.chromium
@@ -0,0 +1,34 @@
+Name: Android Test runner script
+URL: http://source.android.com
+Version: 3.1.4
+License: Apache Version 2.0
+License File: NOT_SHIPPED
+Security Critical: no
+
+Description:
+This package is the scripts used to run the unit test for Android and from
+Android Gingerbread.
+
+Local Modifications:
+1. Added |silent_log| argument to |StartInstrumentation| so that output can be
+ suppressed.
+2. Changed error message handling in |StartInstrumentation| from |shortMsg| to
+ |longMsg| to provide more information when debugging.
+3. Applied the patch file patch.diff to fix a race condition and subproccess
+ bugs in run_command.py.
+4. Fixed a bug where wait_time wasn't properly respected in
+ _WaitForShellCommandContents.
+
+Here is the detail steps
+1. Checkout Android source code
+
+$ repo init -u git://android.git.kernel.org/platform/manifest.git -b gingerbread
+$ repo sync
+$ cd development
+$ git reset --hard 76f63551d36b1de63c63f357e5f0646ed8c306bb
+
+2. Copy the related files from
+ <android_gingerbread_tree>/development/testrunner/
+
+More information can be found in
+http://source.android.com/source/downloading.html
diff --git a/third_party/android_testrunner/adb_interface.py b/third_party/android_testrunner/adb_interface.py
new file mode 100644
index 0000000..93e1963
--- /dev/null
+++ b/third_party/android_testrunner/adb_interface.py
@@ -0,0 +1,514 @@
+#!/usr/bin/python2.4
+#
+#
+# Copyright 2008, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Provides an interface to communicate with the device via the adb command.
+
+Assumes adb binary is currently on system path.
+"""
+# Python imports
+import os
+import string
+import time
+
+# local imports
+import am_instrument_parser
+import errors
+import logger
+import run_command
+
+
+class AdbInterface:
+ """Helper class for communicating with Android device via adb."""
+
+ # argument to pass to adb, to direct command to specific device
+ _target_arg = ""
+
+ DEVICE_TRACE_DIR = "/data/test_results/"
+
+ def SetEmulatorTarget(self):
+ """Direct all future commands to the only running emulator."""
+ self._target_arg = "-e"
+
+ def SetDeviceTarget(self):
+ """Direct all future commands to the only connected USB device."""
+ self._target_arg = "-d"
+
+ def SetTargetSerial(self, serial):
+ """Direct all future commands to Android target with the given serial."""
+ self._target_arg = "-s %s" % serial
+
+ def SendCommand(self, command_string, timeout_time=20, retry_count=3):
+ """Send a command via adb.
+
+ Args:
+ command_string: adb command to run
+ timeout_time: number of seconds to wait for command to respond before
+ retrying
+ retry_count: number of times to retry command before raising
+ WaitForResponseTimedOutError
+ Returns:
+ string output of command
+
+ Raises:
+ WaitForResponseTimedOutError if device does not respond to command within time
+ """
+ adb_cmd = "adb %s %s" % (self._target_arg, command_string)
+ logger.SilentLog("about to run %s" % adb_cmd)
+ return run_command.RunCommand(adb_cmd, timeout_time=timeout_time,
+ retry_count=retry_count)
+
+ def SendShellCommand(self, cmd, timeout_time=20, retry_count=3):
+ """Send a adb shell command.
+
+ Args:
+ cmd: adb shell command to run
+ timeout_time: number of seconds to wait for command to respond before
+ retrying
+ retry_count: number of times to retry command before raising
+ WaitForResponseTimedOutError
+
+ Returns:
+ string output of command
+
+ Raises:
+ WaitForResponseTimedOutError: if device does not respond to command
+ """
+ return self.SendCommand("shell %s" % cmd, timeout_time=timeout_time,
+ retry_count=retry_count)
+
+ def BugReport(self, path):
+ """Dumps adb bugreport to the file specified by the path.
+
+ Args:
+ path: Path of the file where adb bugreport is dumped to.
+ """
+ bug_output = self.SendShellCommand("bugreport", timeout_time=60)
+ bugreport_file = open(path, "w")
+ bugreport_file.write(bug_output)
+ bugreport_file.close()
+
+ def Push(self, src, dest):
+ """Pushes the file src onto the device at dest.
+
+ Args:
+ src: file path of host file to push
+ dest: destination absolute file path on device
+ """
+ self.SendCommand("push %s %s" % (src, dest), timeout_time=60)
+
+ def Pull(self, src, dest):
+ """Pulls the file src on the device onto dest on the host.
+
+ Args:
+ src: absolute file path of file on device to pull
+ dest: destination file path on host
+
+ Returns:
+ True if success and False otherwise.
+ """
+ # Create the base dir if it doesn't exist already
+ if not os.path.exists(os.path.dirname(dest)):
+ os.makedirs(os.path.dirname(dest))
+
+ if self.DoesFileExist(src):
+ self.SendCommand("pull %s %s" % (src, dest), timeout_time=60)
+ return True
+ else:
+ logger.Log("ADB Pull Failed: Source file %s does not exist." % src)
+ return False
+
+ def DoesFileExist(self, src):
+ """Checks if the given path exists on device target.
+
+ Args:
+ src: file path to be checked.
+
+ Returns:
+ True if file exists
+ """
+
+ output = self.SendShellCommand("ls %s" % src)
+ error = "No such file or directory"
+
+ if error in output:
+ return False
+ return True
+
+ def EnableAdbRoot(self):
+ """Enable adb root on device."""
+ output = self.SendCommand("root")
+ if "adbd is already running as root" in output:
+ return True
+ elif "restarting adbd as root" in output:
+ # device will disappear from adb, wait for it to come back
+ self.SendCommand("wait-for-device")
+ return True
+ else:
+ logger.Log("Unrecognized output from adb root: %s" % output)
+ return False
+
+ def StartInstrumentationForPackage(
+ self, package_name, runner_name, timeout_time=60*10,
+ no_window_animation=False, instrumentation_args={}):
+ """Run instrumentation test for given package and runner.
+
+ Equivalent to StartInstrumentation, except instrumentation path is
+ separated into its package and runner components.
+ """
+ instrumentation_path = "%s/%s" % (package_name, runner_name)
+ return self.StartInstrumentation(instrumentation_path, timeout_time=timeout_time,
+ no_window_animation=no_window_animation,
+ instrumentation_args=instrumentation_args)
+
+ def StartInstrumentation(
+ self, instrumentation_path, timeout_time=60*10, no_window_animation=False,
+ profile=False, instrumentation_args={}, silent_log=False):
+
+ """Runs an instrumentation class on the target.
+
+ Returns a dictionary containing the key value pairs from the
+ instrumentations result bundle and a list of TestResults. Also handles the
+ interpreting of error output from the device and raises the necessary
+ exceptions.
+
+ Args:
+ instrumentation_path: string. It should be the fully classified package
+ name, and instrumentation test runner, separated by "/"
+ e.g. com.android.globaltimelaunch/.GlobalTimeLaunch
+ timeout_time: Timeout value for the am command.
+ no_window_animation: boolean, Whether you want window animations enabled
+ or disabled
+ profile: If True, profiling will be turned on for the instrumentation.
+ instrumentation_args: Dictionary of key value bundle arguments to pass to
+ instrumentation.
+ silent_log: If True, the invocation of the instrumentation test runner
+ will not be logged.
+
+ Returns:
+ (test_results, inst_finished_bundle)
+
+ test_results: a list of TestResults
+ inst_finished_bundle (dict): Key/value pairs contained in the bundle that
+ is passed into ActivityManager.finishInstrumentation(). Included in this
+ bundle is the return code of the Instrumentation process, any error
+ codes reported by the activity manager, and any results explicitly added
+ by the instrumentation code.
+
+ Raises:
+ WaitForResponseTimedOutError: if timeout occurred while waiting for
+ response to adb instrument command
+ DeviceUnresponsiveError: if device system process is not responding
+ InstrumentationError: if instrumentation failed to run
+ """
+
+ command_string = self._BuildInstrumentationCommandPath(
+ instrumentation_path, no_window_animation=no_window_animation,
+ profile=profile, raw_mode=True,
+ instrumentation_args=instrumentation_args)
+ if silent_log:
+ logger.SilentLog(command_string)
+ else:
+ logger.Log(command_string)
+ (test_results, inst_finished_bundle) = (
+ am_instrument_parser.ParseAmInstrumentOutput(
+ self.SendShellCommand(command_string, timeout_time=timeout_time,
+ retry_count=2)))
+ if "code" not in inst_finished_bundle:
+ logger.Log('No code available. inst_finished_bundle contains: %s '
+ % inst_finished_bundle)
+ raise errors.InstrumentationError("no test results... device setup "
+ "correctly?")
+
+ if inst_finished_bundle["code"] == "0":
+ long_msg_result = "no error message"
+ if "longMsg" in inst_finished_bundle:
+ long_msg_result = inst_finished_bundle["longMsg"]
+ logger.Log("Error! Test run failed: %s" % long_msg_result)
+ raise errors.InstrumentationError(long_msg_result)
+
+ if "INSTRUMENTATION_ABORTED" in inst_finished_bundle:
+ logger.Log("INSTRUMENTATION ABORTED!")
+ raise errors.DeviceUnresponsiveError
+
+ return (test_results, inst_finished_bundle)
+
+ def StartInstrumentationNoResults(
+ self, package_name, runner_name, no_window_animation=False,
+ raw_mode=False, instrumentation_args={}):
+ """Runs instrumentation and dumps output to stdout.
+
+ Equivalent to StartInstrumentation, but will dump instrumentation
+ 'normal' output to stdout, instead of parsing return results. Command will
+ never timeout.
+ """
+ adb_command_string = self.PreviewInstrumentationCommand(
+ package_name, runner_name, no_window_animation=no_window_animation,
+ raw_mode=raw_mode, instrumentation_args=instrumentation_args)
+ logger.Log(adb_command_string)
+ run_command.RunCommand(adb_command_string, return_output=False)
+
+ def PreviewInstrumentationCommand(
+ self, package_name, runner_name, no_window_animation=False,
+ raw_mode=False, instrumentation_args={}):
+ """Returns a string of adb command that will be executed."""
+ inst_command_string = self._BuildInstrumentationCommand(
+ package_name, runner_name, no_window_animation=no_window_animation,
+ raw_mode=raw_mode, instrumentation_args=instrumentation_args)
+ command_string = "adb %s shell %s" % (self._target_arg, inst_command_string)
+ return command_string
+
+ def _BuildInstrumentationCommand(
+ self, package, runner_name, no_window_animation=False, profile=False,
+ raw_mode=True, instrumentation_args={}):
+ instrumentation_path = "%s/%s" % (package, runner_name)
+
+ return self._BuildInstrumentationCommandPath(
+ instrumentation_path, no_window_animation=no_window_animation,
+ profile=profile, raw_mode=raw_mode,
+ instrumentation_args=instrumentation_args)
+
+ def _BuildInstrumentationCommandPath(
+ self, instrumentation_path, no_window_animation=False, profile=False,
+ raw_mode=True, instrumentation_args={}):
+ command_string = "am instrument"
+ if no_window_animation:
+ command_string += " --no_window_animation"
+ if profile:
+ self._CreateTraceDir()
+ command_string += (
+ " -p %s/%s.dmtrace" %
+ (self.DEVICE_TRACE_DIR, instrumentation_path.split(".")[-1]))
+
+ for key, value in instrumentation_args.items():
+ command_string += " -e %s '%s'" % (key, value)
+ if raw_mode:
+ command_string += " -r"
+ command_string += " -w %s" % instrumentation_path
+ return command_string
+
+ def _CreateTraceDir(self):
+ ls_response = self.SendShellCommand("ls /data/trace")
+ if ls_response.strip("#").strip(string.whitespace) != "":
+ self.SendShellCommand("create /data/trace", "mkdir /data/trace")
+ self.SendShellCommand("make /data/trace world writeable",
+ "chmod 777 /data/trace")
+
+ def WaitForDevicePm(self, wait_time=120):
+ """Waits for targeted device's package manager to be up.
+
+ Args:
+ wait_time: time in seconds to wait
+
+ Raises:
+ WaitForResponseTimedOutError if wait_time elapses and pm still does not
+ respond.
+ """
+ logger.Log("Waiting for device package manager...")
+ self.SendCommand("wait-for-device", timeout_time=wait_time, retry_count=0)
+ # Now the device is there, but may not be running.
+ # Query the package manager with a basic command
+ try:
+ self._WaitForShellCommandContents("pm path android", "package:",
+ wait_time)
+ except errors.WaitForResponseTimedOutError:
+ raise errors.WaitForResponseTimedOutError(
+ "Package manager did not respond after %s seconds" % wait_time)
+
+ def WaitForInstrumentation(self, package_name, runner_name, wait_time=120):
+ """Waits for given instrumentation to be present on device
+
+ Args:
+ wait_time: time in seconds to wait
+
+ Raises:
+ WaitForResponseTimedOutError if wait_time elapses and instrumentation
+ still not present.
+ """
+ instrumentation_path = "%s/%s" % (package_name, runner_name)
+ logger.Log("Waiting for instrumentation to be present")
+ # Query the package manager
+ try:
+ command = "pm list instrumentation | grep %s" % instrumentation_path
+ self._WaitForShellCommandContents(command, "instrumentation:", wait_time,
+ raise_abort=False)
+ except errors.WaitForResponseTimedOutError :
+ logger.Log(
+ "Could not find instrumentation %s on device. Does the "
+ "instrumentation in test's AndroidManifest.xml match definition"
+ "in test_defs.xml?" % instrumentation_path)
+ raise
+
+ def WaitForProcess(self, name, wait_time=120):
+ """Wait until a process is running on the device.
+
+ Args:
+ name: the process name as it appears in `ps`
+ wait_time: time in seconds to wait
+
+ Raises:
+ WaitForResponseTimedOutError if wait_time elapses and the process is
+ still not running
+ """
+ logger.Log("Waiting for process %s" % name)
+ self.SendCommand("wait-for-device")
+ self._WaitForShellCommandContents("ps", name, wait_time)
+
+ def WaitForProcessEnd(self, name, wait_time=120):
+ """Wait until a process is no longer running on the device.
+
+ Args:
+ name: the process name as it appears in `ps`
+ wait_time: time in seconds to wait
+
+ Raises:
+ WaitForResponseTimedOutError if wait_time elapses and the process is
+ still running
+ """
+ logger.Log("Waiting for process %s to end" % name)
+ self._WaitForShellCommandContents("ps", name, wait_time, invert=True)
+
+ def _WaitForShellCommandContents(self, command, expected, wait_time,
+ raise_abort=True, invert=False):
+ """Wait until the response to a command contains a given output.
+
+ Assumes that a only successful execution of "adb shell <command>" contains
+ the substring expected. Assumes that a device is present.
+
+ Args:
+ command: adb shell command to execute
+ expected: the string that should appear to consider the
+ command successful.
+ wait_time: time in seconds to wait
+ raise_abort: if False, retry when executing the command raises an
+ AbortError, rather than failing.
+ invert: if True, wait until the command output no longer contains the
+ expected contents.
+
+ Raises:
+ WaitForResponseTimedOutError: If wait_time elapses and the command has not
+ returned an output containing expected yet.
+ """
+ # Query the device with the command
+ success = False
+ attempts = 0
+ wait_period = 5
+ while not success and (attempts*wait_period) < wait_time:
+ # assume the command will always contain expected in the success case
+ try:
+ output = self.SendShellCommand(command, retry_count=1,
+ timeout_time=wait_time)
+ if ((not invert and expected in output)
+ or (invert and expected not in output)):
+ success = True
+ except errors.AbortError, e:
+ if raise_abort:
+ raise
+ # ignore otherwise
+
+ if not success:
+ time.sleep(wait_period)
+ attempts += 1
+
+ if not success:
+ raise errors.WaitForResponseTimedOutError()
+
+ def WaitForBootComplete(self, wait_time=120):
+ """Waits for targeted device's bootcomplete flag to be set.
+
+ Args:
+ wait_time: time in seconds to wait
+
+ Raises:
+ WaitForResponseTimedOutError if wait_time elapses and pm still does not
+ respond.
+ """
+ logger.Log("Waiting for boot complete...")
+ self.SendCommand("wait-for-device")
+ # Now the device is there, but may not be running.
+ # Query the package manager with a basic command
+ boot_complete = False
+ attempts = 0
+ wait_period = 5
+ while not boot_complete and (attempts*wait_period) < wait_time:
+ output = self.SendShellCommand("getprop dev.bootcomplete", retry_count=1)
+ output = output.strip()
+ if output == "1":
+ boot_complete = True
+ else:
+ time.sleep(wait_period)
+ attempts += 1
+ if not boot_complete:
+ raise errors.WaitForResponseTimedOutError(
+ "dev.bootcomplete flag was not set after %s seconds" % wait_time)
+
+ def Sync(self, retry_count=3, runtime_restart=False):
+ """Perform a adb sync.
+
+ Blocks until device package manager is responding.
+
+ Args:
+ retry_count: number of times to retry sync before failing
+ runtime_restart: stop runtime during sync and restart afterwards, useful
+ for syncing system libraries (core, framework etc)
+
+ Raises:
+ WaitForResponseTimedOutError if package manager does not respond
+ AbortError if unrecoverable error occurred
+ """
+ output = ""
+ error = None
+ if runtime_restart:
+ self.SendShellCommand("setprop ro.monkey 1", retry_count=retry_count)
+ # manual rest bootcomplete flag
+ self.SendShellCommand("setprop dev.bootcomplete 0",
+ retry_count=retry_count)
+ self.SendShellCommand("stop", retry_count=retry_count)
+
+ try:
+ output = self.SendCommand("sync", retry_count=retry_count)
+ except errors.AbortError, e:
+ error = e
+ output = e.msg
+ if "Read-only file system" in output:
+ logger.SilentLog(output)
+ logger.Log("Remounting read-only filesystem")
+ self.SendCommand("remount")
+ output = self.SendCommand("sync", retry_count=retry_count)
+ elif "No space left on device" in output:
+ logger.SilentLog(output)
+ logger.Log("Restarting device runtime")
+ self.SendShellCommand("stop", retry_count=retry_count)
+ output = self.SendCommand("sync", retry_count=retry_count)
+ self.SendShellCommand("start", retry_count=retry_count)
+ elif error is not None:
+ # exception occurred that cannot be recovered from
+ raise error
+ logger.SilentLog(output)
+ if runtime_restart:
+ # start runtime and wait till boot complete flag is set
+ self.SendShellCommand("start", retry_count=retry_count)
+ self.WaitForBootComplete()
+ # press the MENU key, this will disable key guard if runtime is started
+ # with ro.monkey set to 1
+ self.SendShellCommand("input keyevent 82", retry_count=retry_count)
+ else:
+ self.WaitForDevicePm()
+ return output
+
+ def GetSerialNumber(self):
+ """Returns the serial number of the targeted device."""
+ return self.SendCommand("get-serialno").strip()
diff --git a/third_party/android_testrunner/am_instrument_parser.py b/third_party/android_testrunner/am_instrument_parser.py
new file mode 100644
index 0000000..4554c4d
--- /dev/null
+++ b/third_party/android_testrunner/am_instrument_parser.py
@@ -0,0 +1,169 @@
+#!/usr/bin/python2.4
+#
+#
+# Copyright 2008, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module that assists in parsing the output of "am instrument" commands run on
+the device."""
+
+import re
+import string
+
+
+def ParseAmInstrumentOutput(result):
+ """Given the raw output of an "am instrument" command that targets and
+ InstrumentationTestRunner, return structured data.
+
+ Args:
+ result (string): Raw output of "am instrument"
+
+ Return
+ (test_results, inst_finished_bundle)
+
+ test_results (list of am_output_parser.TestResult)
+ inst_finished_bundle (dict): Key/value pairs contained in the bundle that is
+ passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return
+ code of the Instrumentation process, any error codes reported by the
+ activity manager, and any results explicity added by the instrumentation
+ code.
+ """
+
+ re_status_code = re.compile(r'INSTRUMENTATION_STATUS_CODE: (?P<status_code>-?\d)$')
+ test_results = []
+ inst_finished_bundle = {}
+
+ result_block_string = ""
+ for line in result.splitlines():
+ result_block_string += line + '\n'
+
+ if "INSTRUMENTATION_STATUS_CODE:" in line:
+ test_result = TestResult(result_block_string)
+ if test_result.GetStatusCode() == 1: # The test started
+ pass
+ elif test_result.GetStatusCode() in [0, -1, -2]:
+ test_results.append(test_result)
+ else:
+ pass
+ result_block_string = ""
+ if "INSTRUMENTATION_CODE:" in line:
+ inst_finished_bundle = _ParseInstrumentationFinishedBundle(result_block_string)
+ result_block_string = ""
+
+ return (test_results, inst_finished_bundle)
+
+
+def _ParseInstrumentationFinishedBundle(result):
+ """Given the raw output of "am instrument" returns a dictionary of the
+ key/value pairs from the bundle passed into
+ ActivityManager.finishInstrumentation().
+
+ Args:
+ result (string): Raw output of "am instrument"
+
+ Return:
+ inst_finished_bundle (dict): Key/value pairs contained in the bundle that is
+ passed into ActivityManager.finishInstrumentation(). Included in this bundle is the return
+ code of the Instrumentation process, any error codes reported by the
+ activity manager, and any results explicity added by the instrumentation
+ code.
+ """
+
+ re_result = re.compile(r'INSTRUMENTATION_RESULT: ([^=]+)=(.*)$')
+ re_code = re.compile(r'INSTRUMENTATION_CODE: (\-?\d)$')
+ result_dict = {}
+ key = ''
+ val = ''
+ last_tag = ''
+
+ for line in result.split('\n'):
+ line = line.strip(string.whitespace)
+ if re_result.match(line):
+ last_tag = 'INSTRUMENTATION_RESULT'
+ key = re_result.search(line).group(1).strip(string.whitespace)
+ if key.startswith('performance.'):
+ key = key[len('performance.'):]
+ val = re_result.search(line).group(2).strip(string.whitespace)
+ try:
+ result_dict[key] = float(val)
+ except ValueError:
+ result_dict[key] = val
+ except TypeError:
+ result_dict[key] = val
+ elif re_code.match(line):
+ last_tag = 'INSTRUMENTATION_CODE'
+ key = 'code'
+ val = re_code.search(line).group(1).strip(string.whitespace)
+ result_dict[key] = val
+ elif 'INSTRUMENTATION_ABORTED:' in line:
+ last_tag = 'INSTRUMENTATION_ABORTED'
+ key = 'INSTRUMENTATION_ABORTED'
+ val = ''
+ result_dict[key] = val
+ elif last_tag == 'INSTRUMENTATION_RESULT':
+ result_dict[key] += '\n' + line
+
+ if not result_dict.has_key('code'):
+ result_dict['code'] = '0'
+ result_dict['shortMsg'] = "No result returned from instrumentation"
+
+ return result_dict
+
+
+class TestResult(object):
+ """A class that contains information about a single test result."""
+
+ def __init__(self, result_block_string):
+ """
+ Args:
+ result_block_string (string): Is a single "block" of output. A single
+ "block" would be either a "test started" status report, or a "test
+ finished" status report.
+ """
+
+ self._test_name = None
+ self._status_code = None
+ self._failure_reason = None
+ self._fields_map = {}
+
+ re_status_code = re.search(r'INSTRUMENTATION_STATUS_CODE: '
+ '(?P<status_code>1|0|-1|-2)', result_block_string)
+ re_fields = re.compile(r'INSTRUMENTATION_STATUS: '
+ '(?P<key>[\w.]+)=(?P<value>.*?)(?=\nINSTRUMENTATION_STATUS)', re.DOTALL)
+
+ for field in re_fields.finditer(result_block_string):
+ key, value = (field.group('key').strip(), field.group('value').strip())
+ if key.startswith('performance.'):
+ key = key[len('performance.'):]
+ self._fields_map[key] = value
+ self._fields_map.setdefault('class')
+ self._fields_map.setdefault('test')
+
+ self._test_name = '%s:%s' % (self._fields_map['class'],
+ self._fields_map['test'])
+ self._status_code = int(re_status_code.group('status_code'))
+ if 'stack' in self._fields_map:
+ self._failure_reason = self._fields_map['stack']
+
+ def GetTestName(self):
+ return self._test_name
+
+ def GetStatusCode(self):
+ return self._status_code
+
+ def GetFailureReason(self):
+ return self._failure_reason
+
+ def GetResultFields(self):
+ return self._fields_map
diff --git a/third_party/android_testrunner/errors.py b/third_party/android_testrunner/errors.py
new file mode 100644
index 0000000..e163dd4
--- /dev/null
+++ b/third_party/android_testrunner/errors.py
@@ -0,0 +1,46 @@
+#!/usr/bin/python2.4
+#
+#
+# Copyright 2008, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Defines common exception classes for this package."""
+
+
+class MsgException(Exception):
+ """Generic exception with an optional string msg."""
+ def __init__(self, msg=""):
+ self.msg = msg
+
+
+class WaitForResponseTimedOutError(Exception):
+ """We sent a command and had to wait too long for response."""
+
+
+class DeviceUnresponsiveError(Exception):
+ """Device is unresponsive to command."""
+
+
+class InstrumentationError(Exception):
+ """Failed to run instrumentation."""
+
+
+class AbortError(MsgException):
+ """Generic exception that indicates a fatal error has occurred and program
+ execution should be aborted."""
+
+
+class ParseError(MsgException):
+ """Raised when xml data to parse has unrecognized format."""
+
diff --git a/third_party/android_testrunner/logger.py b/third_party/android_testrunner/logger.py
new file mode 100644
index 0000000..61463a1
--- /dev/null
+++ b/third_party/android_testrunner/logger.py
@@ -0,0 +1,96 @@
+#!/usr/bin/python2.4
+#
+#
+# Copyright 2007, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Simple logging utility. Dumps log messages to stdout, and optionally, to a
+log file.
+
+Init(path) must be called to enable logging to a file
+"""
+
+import datetime
+
+_LOG_FILE = None
+_verbose = False
+_log_time = True
+
+def Init(log_file_path):
+ """Set the path to the log file"""
+ global _LOG_FILE
+ _LOG_FILE = log_file_path
+ print "Using log file: %s" % _LOG_FILE
+
+def GetLogFilePath():
+ """Returns the path and name of the Log file"""
+ global _LOG_FILE
+ return _LOG_FILE
+
+def Log(new_str):
+ """Appends new_str to the end of _LOG_FILE and prints it to stdout.
+
+ Args:
+ # new_str is a string.
+ new_str: 'some message to log'
+ """
+ msg = _PrependTimeStamp(new_str)
+ print msg
+ _WriteLog(msg)
+
+def _WriteLog(msg):
+ global _LOG_FILE
+ if _LOG_FILE is not None:
+ file_handle = file(_LOG_FILE, 'a')
+ file_handle.write('\n' + str(msg))
+ file_handle.close()
+
+def _PrependTimeStamp(log_string):
+ """Returns the log_string prepended with current timestamp """
+ global _log_time
+ if _log_time:
+ return "# %s: %s" % (datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"),
+ log_string)
+ else:
+ # timestamp logging disabled
+ return log_string
+
+def SilentLog(new_str):
+ """Silently log new_str. Unless verbose mode is enabled, will log new_str
+ only to the log file
+ Args:
+ # new_str is a string.
+ new_str: 'some message to log'
+ """
+ global _verbose
+ msg = _PrependTimeStamp(new_str)
+ if _verbose:
+ print msg
+ _WriteLog(msg)
+
+def SetVerbose(new_verbose=True):
+ """ Enable or disable verbose logging"""
+ global _verbose
+ _verbose = new_verbose
+
+def SetTimestampLogging(new_timestamp=True):
+ """ Enable or disable outputting a timestamp with each log entry"""
+ global _log_time
+ _log_time = new_timestamp
+
+def main():
+ pass
+
+if __name__ == '__main__':
+ main()
diff --git a/third_party/android_testrunner/patch.diff b/third_party/android_testrunner/patch.diff
new file mode 100644
index 0000000..9b067cd
--- /dev/null
+++ b/third_party/android_testrunner/patch.diff
@@ -0,0 +1,104 @@
+diff --git a/third_party/android_testrunner/run_command.py b/third_party/android_testrunner/run_command.py
+index d398daa..6b84156 100644
+--- a/third_party/android_testrunner/run_command.py
++++ b/third_party/android_testrunner/run_command.py
+@@ -19,6 +19,7 @@
+ import os
+ import signal
+ import subprocess
++import tempfile
+ import threading
+ import time
+
+@@ -80,31 +81,36 @@ def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
+ """
+ start_time = time.time()
+ so = []
+- pid = []
+ global _abort_on_error, error_occurred
+ error_occurred = False
+
++ if return_output:
++ output_dest = tempfile.TemporaryFile(bufsize=0)
++ else:
++ # None means direct to stdout
++ output_dest = None
++ if stdin_input:
++ stdin_dest = subprocess.PIPE
++ else:
++ stdin_dest = None
++ pipe = subprocess.Popen(
++ cmd,
++ executable='/bin/bash',
++ stdin=stdin_dest,
++ stdout=output_dest,
++ stderr=subprocess.STDOUT,
++ shell=True, close_fds=True,
++ preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
++
+ def Run():
+ global error_occurred
+- if return_output:
+- output_dest = subprocess.PIPE
+- else:
+- # None means direct to stdout
+- output_dest = None
+- if stdin_input:
+- stdin_dest = subprocess.PIPE
+- else:
+- stdin_dest = None
+- pipe = subprocess.Popen(
+- cmd,
+- executable='/bin/bash',
+- stdin=stdin_dest,
+- stdout=output_dest,
+- stderr=subprocess.STDOUT,
+- shell=True)
+- pid.append(pipe.pid)
+ try:
+- output = pipe.communicate(input=stdin_input)[0]
++ pipe.communicate(input=stdin_input)
++ output = None
++ if return_output:
++ output_dest.seek(0)
++ output = output_dest.read()
++ output_dest.close()
+ if output is not None and len(output) > 0:
+ so.append(output)
+ except OSError, e:
+@@ -119,27 +125,17 @@ def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
+
+ t = threading.Thread(target=Run)
+ t.start()
+-
+- break_loop = False
+- while not break_loop:
+- if not t.isAlive():
+- break_loop = True
+-
+- # Check the timeout
+- if (not break_loop and timeout_time is not None
+- and time.time() > start_time + timeout_time):
+- try:
+- os.kill(pid[0], signal.SIGKILL)
+- except OSError:
+- # process already dead. No action required.
+- pass
+-
++ t.join(timeout_time)
++ if t.isAlive():
++ try:
++ pipe.kill()
++ except OSError:
++ # Can't kill a dead process.
++ pass
++ finally:
+ logger.SilentLog("about to raise a timeout for: %s" % cmd)
+ raise errors.WaitForResponseTimedOutError
+- if not break_loop:
+- time.sleep(0.1)
+
+- t.join()
+ output = "".join(so)
+ if _abort_on_error and error_occurred:
+ raise errors.AbortError(msg=output)
diff --git a/third_party/android_testrunner/run_command.py b/third_party/android_testrunner/run_command.py
new file mode 100644
index 0000000..6b84156
--- /dev/null
+++ b/third_party/android_testrunner/run_command.py
@@ -0,0 +1,192 @@
+#!/usr/bin/python2.4
+#
+#
+# Copyright 2007, The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# System imports
+import os
+import signal
+import subprocess
+import tempfile
+import threading
+import time
+
+# local imports
+import errors
+import logger
+
+_abort_on_error = False
+
+def SetAbortOnError(abort=True):
+ """Sets behavior of RunCommand to throw AbortError if command process returns
+ a negative error code"""
+ global _abort_on_error
+ _abort_on_error = abort
+
+def RunCommand(cmd, timeout_time=None, retry_count=3, return_output=True,
+ stdin_input=None):
+ """Spawn and retry a subprocess to run the given shell command.
+
+ Args:
+ cmd: shell command to run
+ timeout_time: time in seconds to wait for command to run before aborting.
+ retry_count: number of times to retry command
+ return_output: if True return output of command as string. Otherwise,
+ direct output of command to stdout.
+ stdin_input: data to feed to stdin
+ Returns:
+ output of command
+ """
+ result = None
+ while True:
+ try:
+ result = RunOnce(cmd, timeout_time=timeout_time,
+ return_output=return_output, stdin_input=stdin_input)
+ except errors.WaitForResponseTimedOutError:
+ if retry_count == 0:
+ raise
+ retry_count -= 1
+ logger.Log("No response for %s, retrying" % cmd)
+ else:
+ # Success
+ return result
+
+def RunOnce(cmd, timeout_time=None, return_output=True, stdin_input=None):
+ """Spawns a subprocess to run the given shell command.
+
+ Args:
+ cmd: shell command to run
+ timeout_time: time in seconds to wait for command to run before aborting.
+ return_output: if True return output of command as string. Otherwise,
+ direct output of command to stdout.
+ stdin_input: data to feed to stdin
+ Returns:
+ output of command
+ Raises:
+ errors.WaitForResponseTimedOutError if command did not complete within
+ timeout_time seconds.
+ errors.AbortError is command returned error code and SetAbortOnError is on.
+ """
+ start_time = time.time()
+ so = []
+ global _abort_on_error, error_occurred
+ error_occurred = False
+
+ if return_output:
+ output_dest = tempfile.TemporaryFile(bufsize=0)
+ else:
+ # None means direct to stdout
+ output_dest = None
+ if stdin_input:
+ stdin_dest = subprocess.PIPE
+ else:
+ stdin_dest = None
+ pipe = subprocess.Popen(
+ cmd,
+ executable='/bin/bash',
+ stdin=stdin_dest,
+ stdout=output_dest,
+ stderr=subprocess.STDOUT,
+ shell=True, close_fds=True,
+ preexec_fn=lambda: signal.signal(signal.SIGPIPE, signal.SIG_DFL))
+
+ def Run():
+ global error_occurred
+ try:
+ pipe.communicate(input=stdin_input)
+ output = None
+ if return_output:
+ output_dest.seek(0)
+ output = output_dest.read()
+ output_dest.close()
+ if output is not None and len(output) > 0:
+ so.append(output)
+ except OSError, e:
+ logger.SilentLog("failed to retrieve stdout from: %s" % cmd)
+ logger.Log(e)
+ so.append("ERROR")
+ error_occurred = True
+ if pipe.returncode:
+ logger.SilentLog("Error: %s returned %d error code" %(cmd,
+ pipe.returncode))
+ error_occurred = True
+
+ t = threading.Thread(target=Run)
+ t.start()
+ t.join(timeout_time)
+ if t.isAlive():
+ try:
+ pipe.kill()
+ except OSError:
+ # Can't kill a dead process.
+ pass
+ finally:
+ logger.SilentLog("about to raise a timeout for: %s" % cmd)
+ raise errors.WaitForResponseTimedOutError
+
+ output = "".join(so)
+ if _abort_on_error and error_occurred:
+ raise errors.AbortError(msg=output)
+
+ return "".join(so)
+
+
+def RunHostCommand(binary, valgrind=False):
+ """Run a command on the host (opt using valgrind).
+
+ Runs the host binary and returns the exit code.
+ If successfull, the output (stdout and stderr) are discarded,
+ but printed in case of error.
+ The command can be run under valgrind in which case all the
+ output are always discarded.
+
+ Args:
+ binary: full path of the file to be run.
+ valgrind: If True the command will be run under valgrind.
+
+ Returns:
+ The command exit code (int)
+ """
+ if not valgrind:
+ subproc = subprocess.Popen(binary, stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ subproc.wait()
+ if subproc.returncode != 0: # In case of error print the output
+ print subproc.communicate()[0]
+ return subproc.returncode
+ else:
+ # Need the full path to valgrind to avoid other versions on the system.
+ subproc = subprocess.Popen(["/usr/bin/valgrind", "--tool=memcheck",
+ "--leak-check=yes", "-q", binary],
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ # Cannot rely on the retcode of valgrind. Instead look for an empty output.
+ valgrind_out = subproc.communicate()[0].strip()
+ if valgrind_out:
+ print valgrind_out
+ return 1
+ else:
+ return 0
+
+
+def HasValgrind():
+ """Check that /usr/bin/valgrind exists.
+
+ We look for the fullpath to avoid picking up 'alternative' valgrind
+ on the system.
+
+ Returns:
+ True if a system valgrind was found.
+ """
+ return os.path.exists("/usr/bin/valgrind")
diff --git a/third_party/libevent/BUILD.gn b/third_party/libevent/BUILD.gn
index a1bd0c5..648dae3 100644
--- a/third_party/libevent/BUILD.gn
+++ b/third_party/libevent/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("libevent") {
+static_library("libevent") {
sources = [
"buffer.c",
"evbuffer.c",
diff --git a/third_party/modp_b64/BUILD.gn b/third_party/modp_b64/BUILD.gn
index 2ec992b..539abe1 100644
--- a/third_party/modp_b64/BUILD.gn
+++ b/third_party/modp_b64/BUILD.gn
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-source_set("modp_b64") {
+static_library("modp_b64") {
sources = [
"modp_b64.cc",
"modp_b64.h",
diff --git a/third_party/pymock/LICENSE.txt b/third_party/pymock/LICENSE.txt
new file mode 100644
index 0000000..7891703
--- /dev/null
+++ b/third_party/pymock/LICENSE.txt
@@ -0,0 +1,26 @@
+Copyright (c) 2003-2012, Michael Foord
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/third_party/pymock/OWNERS b/third_party/pymock/OWNERS
new file mode 100644
index 0000000..9946560
--- /dev/null
+++ b/third_party/pymock/OWNERS
@@ -0,0 +1 @@
+sbc@chromium.org
diff --git a/third_party/pymock/README.chromium b/third_party/pymock/README.chromium
new file mode 100644
index 0000000..aaf355d
--- /dev/null
+++ b/third_party/pymock/README.chromium
@@ -0,0 +1,10 @@
+Name: mock
+URL: http://pypi.python.org/pypi/mock
+Version: 1.0.1
+Security Critical: no
+License: BSD
+License File: LICENSE.txt
+Description:
+Python mock library, currently used by native_client_sdk. This is the
+same mock library that is now part of python 3.3 where it is know as
+unittest.mock.
diff --git a/third_party/pymock/mock.py b/third_party/pymock/mock.py
new file mode 100644
index 0000000..c8fc5d1
--- /dev/null
+++ b/third_party/pymock/mock.py
@@ -0,0 +1,2367 @@
+# mock.py
+# Test tools for mocking and patching.
+# Copyright (C) 2007-2012 Michael Foord & the mock team
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+
+# mock 1.0
+# http://www.voidspace.org.uk/python/mock/
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# Comments, suggestions and bug reports welcome.
+
+
+__all__ = (
+ 'Mock',
+ 'MagicMock',
+ 'patch',
+ 'sentinel',
+ 'DEFAULT',
+ 'ANY',
+ 'call',
+ 'create_autospec',
+ 'FILTER_DIR',
+ 'NonCallableMock',
+ 'NonCallableMagicMock',
+ 'mock_open',
+ 'PropertyMock',
+)
+
+
+__version__ = '1.0.1'
+
+
+import pprint
+import sys
+
+try:
+ import inspect
+except ImportError:
+ # for alternative platforms that
+ # may not have inspect
+ inspect = None
+
+try:
+ from functools import wraps as original_wraps
+except ImportError:
+ # Python 2.4 compatibility
+ def wraps(original):
+ def inner(f):
+ f.__name__ = original.__name__
+ f.__doc__ = original.__doc__
+ f.__module__ = original.__module__
+ f.__wrapped__ = original
+ return f
+ return inner
+else:
+ if sys.version_info[:2] >= (3, 3):
+ wraps = original_wraps
+ else:
+ def wraps(func):
+ def inner(f):
+ f = original_wraps(func)(f)
+ f.__wrapped__ = func
+ return f
+ return inner
+
+try:
+ unicode
+except NameError:
+ # Python 3
+ basestring = unicode = str
+
+try:
+ long
+except NameError:
+ # Python 3
+ long = int
+
+try:
+ BaseException
+except NameError:
+ # Python 2.4 compatibility
+ BaseException = Exception
+
+try:
+ next
+except NameError:
+ def next(obj):
+ return obj.next()
+
+
+BaseExceptions = (BaseException,)
+if 'java' in sys.platform:
+ # jython
+ import java
+ BaseExceptions = (BaseException, java.lang.Throwable)
+
+try:
+ _isidentifier = str.isidentifier
+except AttributeError:
+ # Python 2.X
+ import keyword
+ import re
+ regex = re.compile(r'^[a-z_][a-z0-9_]*$', re.I)
+ def _isidentifier(string):
+ if string in keyword.kwlist:
+ return False
+ return regex.match(string)
+
+
+inPy3k = sys.version_info[0] == 3
+
+# Needed to work around Python 3 bug where use of "super" interferes with
+# defining __class__ as a descriptor
+_super = super
+
+self = 'im_self'
+builtin = '__builtin__'
+if inPy3k:
+ self = '__self__'
+ builtin = 'builtins'
+
+FILTER_DIR = True
+
+
+def _is_instance_mock(obj):
+ # can't use isinstance on Mock objects because they override __class__
+ # The base class for all mocks is NonCallableMock
+ return issubclass(type(obj), NonCallableMock)
+
+
+def _is_exception(obj):
+ return (
+ isinstance(obj, BaseExceptions) or
+ isinstance(obj, ClassTypes) and issubclass(obj, BaseExceptions)
+ )
+
+
+class _slotted(object):
+ __slots__ = ['a']
+
+
+DescriptorTypes = (
+ type(_slotted.a),
+ property,
+)
+
+
+def _getsignature(func, skipfirst, instance=False):
+ if inspect is None:
+ raise ImportError('inspect module not available')
+
+ if isinstance(func, ClassTypes) and not instance:
+ try:
+ func = func.__init__
+ except AttributeError:
+ return
+ skipfirst = True
+ elif not isinstance(func, FunctionTypes):
+ # for classes where instance is True we end up here too
+ try:
+ func = func.__call__
+ except AttributeError:
+ return
+
+ if inPy3k:
+ try:
+ argspec = inspect.getfullargspec(func)
+ except TypeError:
+ # C function / method, possibly inherited object().__init__
+ return
+ regargs, varargs, varkw, defaults, kwonly, kwonlydef, ann = argspec
+ else:
+ try:
+ regargs, varargs, varkwargs, defaults = inspect.getargspec(func)
+ except TypeError:
+ # C function / method, possibly inherited object().__init__
+ return
+
+ # instance methods and classmethods need to lose the self argument
+ if getattr(func, self, None) is not None:
+ regargs = regargs[1:]
+ if skipfirst:
+ # this condition and the above one are never both True - why?
+ regargs = regargs[1:]
+
+ if inPy3k:
+ signature = inspect.formatargspec(
+ regargs, varargs, varkw, defaults,
+ kwonly, kwonlydef, ann, formatvalue=lambda value: "")
+ else:
+ signature = inspect.formatargspec(
+ regargs, varargs, varkwargs, defaults,
+ formatvalue=lambda value: "")
+ return signature[1:-1], func
+
+
+def _check_signature(func, mock, skipfirst, instance=False):
+ if not _callable(func):
+ return
+
+ result = _getsignature(func, skipfirst, instance)
+ if result is None:
+ return
+ signature, func = result
+
+ # can't use self because "self" is common as an argument name
+ # unfortunately even not in the first place
+ src = "lambda _mock_self, %s: None" % signature
+ checksig = eval(src, {})
+ _copy_func_details(func, checksig)
+ type(mock)._mock_check_sig = checksig
+
+
+def _copy_func_details(func, funcopy):
+ funcopy.__name__ = func.__name__
+ funcopy.__doc__ = func.__doc__
+ #funcopy.__dict__.update(func.__dict__)
+ funcopy.__module__ = func.__module__
+ if not inPy3k:
+ funcopy.func_defaults = func.func_defaults
+ return
+ funcopy.__defaults__ = func.__defaults__
+ funcopy.__kwdefaults__ = func.__kwdefaults__
+
+
+def _callable(obj):
+ if isinstance(obj, ClassTypes):
+ return True
+ if getattr(obj, '__call__', None) is not None:
+ return True
+ return False
+
+
+def _is_list(obj):
+ # checks for list or tuples
+ # XXXX badly named!
+ return type(obj) in (list, tuple)
+
+
+def _instance_callable(obj):
+ """Given an object, return True if the object is callable.
+ For classes, return True if instances would be callable."""
+ if not isinstance(obj, ClassTypes):
+ # already an instance
+ return getattr(obj, '__call__', None) is not None
+
+ klass = obj
+ # uses __bases__ instead of __mro__ so that we work with old style classes
+ if klass.__dict__.get('__call__') is not None:
+ return True
+
+ for base in klass.__bases__:
+ if _instance_callable(base):
+ return True
+ return False
+
+
+def _set_signature(mock, original, instance=False):
+ # creates a function with signature (*args, **kwargs) that delegates to a
+ # mock. It still does signature checking by calling a lambda with the same
+ # signature as the original.
+ if not _callable(original):
+ return
+
+ skipfirst = isinstance(original, ClassTypes)
+ result = _getsignature(original, skipfirst, instance)
+ if result is None:
+ # was a C function (e.g. object().__init__ ) that can't be mocked
+ return
+
+ signature, func = result
+
+ src = "lambda %s: None" % signature
+ checksig = eval(src, {})
+ _copy_func_details(func, checksig)
+
+ name = original.__name__
+ if not _isidentifier(name):
+ name = 'funcopy'
+ context = {'_checksig_': checksig, 'mock': mock}
+ src = """def %s(*args, **kwargs):
+ _checksig_(*args, **kwargs)
+ return mock(*args, **kwargs)""" % name
+ exec (src, context)
+ funcopy = context[name]
+ _setup_func(funcopy, mock)
+ return funcopy
+
+
+def _setup_func(funcopy, mock):
+ funcopy.mock = mock
+
+ # can't use isinstance with mocks
+ if not _is_instance_mock(mock):
+ return
+
+ def assert_called_with(*args, **kwargs):
+ return mock.assert_called_with(*args, **kwargs)
+ def assert_called_once_with(*args, **kwargs):
+ return mock.assert_called_once_with(*args, **kwargs)
+ def assert_has_calls(*args, **kwargs):
+ return mock.assert_has_calls(*args, **kwargs)
+ def assert_any_call(*args, **kwargs):
+ return mock.assert_any_call(*args, **kwargs)
+ def reset_mock():
+ funcopy.method_calls = _CallList()
+ funcopy.mock_calls = _CallList()
+ mock.reset_mock()
+ ret = funcopy.return_value
+ if _is_instance_mock(ret) and not ret is mock:
+ ret.reset_mock()
+
+ funcopy.called = False
+ funcopy.call_count = 0
+ funcopy.call_args = None
+ funcopy.call_args_list = _CallList()
+ funcopy.method_calls = _CallList()
+ funcopy.mock_calls = _CallList()
+
+ funcopy.return_value = mock.return_value
+ funcopy.side_effect = mock.side_effect
+ funcopy._mock_children = mock._mock_children
+
+ funcopy.assert_called_with = assert_called_with
+ funcopy.assert_called_once_with = assert_called_once_with
+ funcopy.assert_has_calls = assert_has_calls
+ funcopy.assert_any_call = assert_any_call
+ funcopy.reset_mock = reset_mock
+
+ mock._mock_delegate = funcopy
+
+
+def _is_magic(name):
+ return '__%s__' % name[2:-2] == name
+
+
+class _SentinelObject(object):
+ "A unique, named, sentinel object."
+ def __init__(self, name):
+ self.name = name
+
+ def __repr__(self):
+ return 'sentinel.%s' % self.name
+
+
+class _Sentinel(object):
+ """Access attributes to return a named object, usable as a sentinel."""
+ def __init__(self):
+ self._sentinels = {}
+
+ def __getattr__(self, name):
+ if name == '__bases__':
+ # Without this help(mock) raises an exception
+ raise AttributeError
+ return self._sentinels.setdefault(name, _SentinelObject(name))
+
+
+sentinel = _Sentinel()
+
+DEFAULT = sentinel.DEFAULT
+_missing = sentinel.MISSING
+_deleted = sentinel.DELETED
+
+
+class OldStyleClass:
+ pass
+ClassType = type(OldStyleClass)
+
+
+def _copy(value):
+ if type(value) in (dict, list, tuple, set):
+ return type(value)(value)
+ return value
+
+
+ClassTypes = (type,)
+if not inPy3k:
+ ClassTypes = (type, ClassType)
+
+_allowed_names = set(
+ [
+ 'return_value', '_mock_return_value', 'side_effect',
+ '_mock_side_effect', '_mock_parent', '_mock_new_parent',
+ '_mock_name', '_mock_new_name'
+ ]
+)
+
+
+def _delegating_property(name):
+ _allowed_names.add(name)
+ _the_name = '_mock_' + name
+ def _get(self, name=name, _the_name=_the_name):
+ sig = self._mock_delegate
+ if sig is None:
+ return getattr(self, _the_name)
+ return getattr(sig, name)
+ def _set(self, value, name=name, _the_name=_the_name):
+ sig = self._mock_delegate
+ if sig is None:
+ self.__dict__[_the_name] = value
+ else:
+ setattr(sig, name, value)
+
+ return property(_get, _set)
+
+
+
+class _CallList(list):
+
+ def __contains__(self, value):
+ if not isinstance(value, list):
+ return list.__contains__(self, value)
+ len_value = len(value)
+ len_self = len(self)
+ if len_value > len_self:
+ return False
+
+ for i in range(0, len_self - len_value + 1):
+ sub_list = self[i:i+len_value]
+ if sub_list == value:
+ return True
+ return False
+
+ def __repr__(self):
+ return pprint.pformat(list(self))
+
+
+def _check_and_set_parent(parent, value, name, new_name):
+ if not _is_instance_mock(value):
+ return False
+ if ((value._mock_name or value._mock_new_name) or
+ (value._mock_parent is not None) or
+ (value._mock_new_parent is not None)):
+ return False
+
+ _parent = parent
+ while _parent is not None:
+ # setting a mock (value) as a child or return value of itself
+ # should not modify the mock
+ if _parent is value:
+ return False
+ _parent = _parent._mock_new_parent
+
+ if new_name:
+ value._mock_new_parent = parent
+ value._mock_new_name = new_name
+ if name:
+ value._mock_parent = parent
+ value._mock_name = name
+ return True
+
+
+
+class Base(object):
+ _mock_return_value = DEFAULT
+ _mock_side_effect = None
+ def __init__(self, *args, **kwargs):
+ pass
+
+
+
+class NonCallableMock(Base):
+ """A non-callable version of `Mock`"""
+
+ def __new__(cls, *args, **kw):
+ # every instance has its own class
+ # so we can create magic methods on the
+ # class without stomping on other mocks
+ new = type(cls.__name__, (cls,), {'__doc__': cls.__doc__})
+ instance = object.__new__(new)
+ return instance
+
+
+ def __init__(
+ self, spec=None, wraps=None, name=None, spec_set=None,
+ parent=None, _spec_state=None, _new_name='', _new_parent=None,
+ **kwargs
+ ):
+ if _new_parent is None:
+ _new_parent = parent
+
+ __dict__ = self.__dict__
+ __dict__['_mock_parent'] = parent
+ __dict__['_mock_name'] = name
+ __dict__['_mock_new_name'] = _new_name
+ __dict__['_mock_new_parent'] = _new_parent
+
+ if spec_set is not None:
+ spec = spec_set
+ spec_set = True
+
+ self._mock_add_spec(spec, spec_set)
+
+ __dict__['_mock_children'] = {}
+ __dict__['_mock_wraps'] = wraps
+ __dict__['_mock_delegate'] = None
+
+ __dict__['_mock_called'] = False
+ __dict__['_mock_call_args'] = None
+ __dict__['_mock_call_count'] = 0
+ __dict__['_mock_call_args_list'] = _CallList()
+ __dict__['_mock_mock_calls'] = _CallList()
+
+ __dict__['method_calls'] = _CallList()
+
+ if kwargs:
+ self.configure_mock(**kwargs)
+
+ _super(NonCallableMock, self).__init__(
+ spec, wraps, name, spec_set, parent,
+ _spec_state
+ )
+
+
+ def attach_mock(self, mock, attribute):
+ """
+ Attach a mock as an attribute of this one, replacing its name and
+ parent. Calls to the attached mock will be recorded in the
+ `method_calls` and `mock_calls` attributes of this one."""
+ mock._mock_parent = None
+ mock._mock_new_parent = None
+ mock._mock_name = ''
+ mock._mock_new_name = None
+
+ setattr(self, attribute, mock)
+
+
+ def mock_add_spec(self, spec, spec_set=False):
+ """Add a spec to a mock. `spec` can either be an object or a
+ list of strings. Only attributes on the `spec` can be fetched as
+ attributes from the mock.
+
+ If `spec_set` is True then only attributes on the spec can be set."""
+ self._mock_add_spec(spec, spec_set)
+
+
+ def _mock_add_spec(self, spec, spec_set):
+ _spec_class = None
+
+ if spec is not None and not _is_list(spec):
+ if isinstance(spec, ClassTypes):
+ _spec_class = spec
+ else:
+ _spec_class = _get_class(spec)
+
+ spec = dir(spec)
+
+ __dict__ = self.__dict__
+ __dict__['_spec_class'] = _spec_class
+ __dict__['_spec_set'] = spec_set
+ __dict__['_mock_methods'] = spec
+
+
+ def __get_return_value(self):
+ ret = self._mock_return_value
+ if self._mock_delegate is not None:
+ ret = self._mock_delegate.return_value
+
+ if ret is DEFAULT:
+ ret = self._get_child_mock(
+ _new_parent=self, _new_name='()'
+ )
+ self.return_value = ret
+ return ret
+
+
+ def __set_return_value(self, value):
+ if self._mock_delegate is not None:
+ self._mock_delegate.return_value = value
+ else:
+ self._mock_return_value = value
+ _check_and_set_parent(self, value, None, '()')
+
+ __return_value_doc = "The value to be returned when the mock is called."
+ return_value = property(__get_return_value, __set_return_value,
+ __return_value_doc)
+
+
+ @property
+ def __class__(self):
+ if self._spec_class is None:
+ return type(self)
+ return self._spec_class
+
+ called = _delegating_property('called')
+ call_count = _delegating_property('call_count')
+ call_args = _delegating_property('call_args')
+ call_args_list = _delegating_property('call_args_list')
+ mock_calls = _delegating_property('mock_calls')
+
+
+ def __get_side_effect(self):
+ sig = self._mock_delegate
+ if sig is None:
+ return self._mock_side_effect
+ return sig.side_effect
+
+ def __set_side_effect(self, value):
+ value = _try_iter(value)
+ sig = self._mock_delegate
+ if sig is None:
+ self._mock_side_effect = value
+ else:
+ sig.side_effect = value
+
+ side_effect = property(__get_side_effect, __set_side_effect)
+
+
+ def reset_mock(self):
+ "Restore the mock object to its initial state."
+ self.called = False
+ self.call_args = None
+ self.call_count = 0
+ self.mock_calls = _CallList()
+ self.call_args_list = _CallList()
+ self.method_calls = _CallList()
+
+ for child in self._mock_children.values():
+ if isinstance(child, _SpecState):
+ continue
+ child.reset_mock()
+
+ ret = self._mock_return_value
+ if _is_instance_mock(ret) and ret is not self:
+ ret.reset_mock()
+
+
+ def configure_mock(self, **kwargs):
+ """Set attributes on the mock through keyword arguments.
+
+ Attributes plus return values and side effects can be set on child
+ mocks using standard dot notation and unpacking a dictionary in the
+ method call:
+
+ >>> attrs = {'method.return_value': 3, 'other.side_effect': KeyError}
+ >>> mock.configure_mock(**attrs)"""
+ for arg, val in sorted(kwargs.items(),
+ # we sort on the number of dots so that
+ # attributes are set before we set attributes on
+ # attributes
+ key=lambda entry: entry[0].count('.')):
+ args = arg.split('.')
+ final = args.pop()
+ obj = self
+ for entry in args:
+ obj = getattr(obj, entry)
+ setattr(obj, final, val)
+
+
+ def __getattr__(self, name):
+ if name == '_mock_methods':
+ raise AttributeError(name)
+ elif self._mock_methods is not None:
+ if name not in self._mock_methods or name in _all_magics:
+ raise AttributeError("Mock object has no attribute %r" % name)
+ elif _is_magic(name):
+ raise AttributeError(name)
+
+ result = self._mock_children.get(name)
+ if result is _deleted:
+ raise AttributeError(name)
+ elif result is None:
+ wraps = None
+ if self._mock_wraps is not None:
+ # XXXX should we get the attribute without triggering code
+ # execution?
+ wraps = getattr(self._mock_wraps, name)
+
+ result = self._get_child_mock(
+ parent=self, name=name, wraps=wraps, _new_name=name,
+ _new_parent=self
+ )
+ self._mock_children[name] = result
+
+ elif isinstance(result, _SpecState):
+ result = create_autospec(
+ result.spec, result.spec_set, result.instance,
+ result.parent, result.name
+ )
+ self._mock_children[name] = result
+
+ return result
+
+
+ def __repr__(self):
+ _name_list = [self._mock_new_name]
+ _parent = self._mock_new_parent
+ last = self
+
+ dot = '.'
+ if _name_list == ['()']:
+ dot = ''
+ seen = set()
+ while _parent is not None:
+ last = _parent
+
+ _name_list.append(_parent._mock_new_name + dot)
+ dot = '.'
+ if _parent._mock_new_name == '()':
+ dot = ''
+
+ _parent = _parent._mock_new_parent
+
+ # use ids here so as not to call __hash__ on the mocks
+ if id(_parent) in seen:
+ break
+ seen.add(id(_parent))
+
+ _name_list = list(reversed(_name_list))
+ _first = last._mock_name or 'mock'
+ if len(_name_list) > 1:
+ if _name_list[1] not in ('()', '().'):
+ _first += '.'
+ _name_list[0] = _first
+ name = ''.join(_name_list)
+
+ name_string = ''
+ if name not in ('mock', 'mock.'):
+ name_string = ' name=%r' % name
+
+ spec_string = ''
+ if self._spec_class is not None:
+ spec_string = ' spec=%r'
+ if self._spec_set:
+ spec_string = ' spec_set=%r'
+ spec_string = spec_string % self._spec_class.__name__
+ return "<%s%s%s id='%s'>" % (
+ type(self).__name__,
+ name_string,
+ spec_string,
+ id(self)
+ )
+
+
+ def __dir__(self):
+ """Filter the output of `dir(mock)` to only useful members.
+ XXXX
+ """
+ extras = self._mock_methods or []
+ from_type = dir(type(self))
+ from_dict = list(self.__dict__)
+
+ if FILTER_DIR:
+ from_type = [e for e in from_type if not e.startswith('_')]
+ from_dict = [e for e in from_dict if not e.startswith('_') or
+ _is_magic(e)]
+ return sorted(set(extras + from_type + from_dict +
+ list(self._mock_children)))
+
+
+ def __setattr__(self, name, value):
+ if name in _allowed_names:
+ # property setters go through here
+ return object.__setattr__(self, name, value)
+ elif (self._spec_set and self._mock_methods is not None and
+ name not in self._mock_methods and
+ name not in self.__dict__):
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+ elif name in _unsupported_magics:
+ msg = 'Attempting to set unsupported magic method %r.' % name
+ raise AttributeError(msg)
+ elif name in _all_magics:
+ if self._mock_methods is not None and name not in self._mock_methods:
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+
+ if not _is_instance_mock(value):
+ setattr(type(self), name, _get_method(name, value))
+ original = value
+ value = lambda *args, **kw: original(self, *args, **kw)
+ else:
+ # only set _new_name and not name so that mock_calls is tracked
+ # but not method calls
+ _check_and_set_parent(self, value, None, name)
+ setattr(type(self), name, value)
+ self._mock_children[name] = value
+ elif name == '__class__':
+ self._spec_class = value
+ return
+ else:
+ if _check_and_set_parent(self, value, name, name):
+ self._mock_children[name] = value
+ return object.__setattr__(self, name, value)
+
+
+ def __delattr__(self, name):
+ if name in _all_magics and name in type(self).__dict__:
+ delattr(type(self), name)
+ if name not in self.__dict__:
+ # for magic methods that are still MagicProxy objects and
+ # not set on the instance itself
+ return
+
+ if name in self.__dict__:
+ object.__delattr__(self, name)
+
+ obj = self._mock_children.get(name, _missing)
+ if obj is _deleted:
+ raise AttributeError(name)
+ if obj is not _missing:
+ del self._mock_children[name]
+ self._mock_children[name] = _deleted
+
+
+
+ def _format_mock_call_signature(self, args, kwargs):
+ name = self._mock_name or 'mock'
+ return _format_call_signature(name, args, kwargs)
+
+
+ def _format_mock_failure_message(self, args, kwargs):
+ message = 'Expected call: %s\nActual call: %s'
+ expected_string = self._format_mock_call_signature(args, kwargs)
+ call_args = self.call_args
+ if len(call_args) == 3:
+ call_args = call_args[1:]
+ actual_string = self._format_mock_call_signature(*call_args)
+ return message % (expected_string, actual_string)
+
+
+ def assert_called_with(_mock_self, *args, **kwargs):
+ """assert that the mock was called with the specified arguments.
+
+ Raises an AssertionError if the args and keyword args passed in are
+ different to the last call to the mock."""
+ self = _mock_self
+ if self.call_args is None:
+ expected = self._format_mock_call_signature(args, kwargs)
+ raise AssertionError('Expected call: %s\nNot called' % (expected,))
+
+ if self.call_args != (args, kwargs):
+ msg = self._format_mock_failure_message(args, kwargs)
+ raise AssertionError(msg)
+
+
+ def assert_called_once_with(_mock_self, *args, **kwargs):
+ """assert that the mock was called exactly once and with the specified
+ arguments."""
+ self = _mock_self
+ if not self.call_count == 1:
+ msg = ("Expected to be called once. Called %s times." %
+ self.call_count)
+ raise AssertionError(msg)
+ return self.assert_called_with(*args, **kwargs)
+
+
+ def assert_has_calls(self, calls, any_order=False):
+ """assert the mock has been called with the specified calls.
+ The `mock_calls` list is checked for the calls.
+
+ If `any_order` is False (the default) then the calls must be
+ sequential. There can be extra calls before or after the
+ specified calls.
+
+ If `any_order` is True then the calls can be in any order, but
+ they must all appear in `mock_calls`."""
+ if not any_order:
+ if calls not in self.mock_calls:
+ raise AssertionError(
+ 'Calls not found.\nExpected: %r\n'
+ 'Actual: %r' % (calls, self.mock_calls)
+ )
+ return
+
+ all_calls = list(self.mock_calls)
+
+ not_found = []
+ for kall in calls:
+ try:
+ all_calls.remove(kall)
+ except ValueError:
+ not_found.append(kall)
+ if not_found:
+ raise AssertionError(
+ '%r not all found in call list' % (tuple(not_found),)
+ )
+
+
+ def assert_any_call(self, *args, **kwargs):
+ """assert the mock has been called with the specified arguments.
+
+ The assert passes if the mock has *ever* been called, unlike
+ `assert_called_with` and `assert_called_once_with` that only pass if
+ the call is the most recent one."""
+ kall = call(*args, **kwargs)
+ if kall not in self.call_args_list:
+ expected_string = self._format_mock_call_signature(args, kwargs)
+ raise AssertionError(
+ '%s call not found' % expected_string
+ )
+
+
+ def _get_child_mock(self, **kw):
+ """Create the child mocks for attributes and return value.
+ By default child mocks will be the same type as the parent.
+ Subclasses of Mock may want to override this to customize the way
+ child mocks are made.
+
+ For non-callable mocks the callable variant will be used (rather than
+ any custom subclass)."""
+ _type = type(self)
+ if not issubclass(_type, CallableMixin):
+ if issubclass(_type, NonCallableMagicMock):
+ klass = MagicMock
+ elif issubclass(_type, NonCallableMock) :
+ klass = Mock
+ else:
+ klass = _type.__mro__[1]
+ return klass(**kw)
+
+
+
+def _try_iter(obj):
+ if obj is None:
+ return obj
+ if _is_exception(obj):
+ return obj
+ if _callable(obj):
+ return obj
+ try:
+ return iter(obj)
+ except TypeError:
+ # XXXX backwards compatibility
+ # but this will blow up on first call - so maybe we should fail early?
+ return obj
+
+
+
+class CallableMixin(Base):
+
+ def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
+ wraps=None, name=None, spec_set=None, parent=None,
+ _spec_state=None, _new_name='', _new_parent=None, **kwargs):
+ self.__dict__['_mock_return_value'] = return_value
+
+ _super(CallableMixin, self).__init__(
+ spec, wraps, name, spec_set, parent,
+ _spec_state, _new_name, _new_parent, **kwargs
+ )
+
+ self.side_effect = side_effect
+
+
+ def _mock_check_sig(self, *args, **kwargs):
+ # stub method that can be replaced with one with a specific signature
+ pass
+
+
+ def __call__(_mock_self, *args, **kwargs):
+ # can't use self in-case a function / method we are mocking uses self
+ # in the signature
+ _mock_self._mock_check_sig(*args, **kwargs)
+ return _mock_self._mock_call(*args, **kwargs)
+
+
+ def _mock_call(_mock_self, *args, **kwargs):
+ self = _mock_self
+ self.called = True
+ self.call_count += 1
+ self.call_args = _Call((args, kwargs), two=True)
+ self.call_args_list.append(_Call((args, kwargs), two=True))
+
+ _new_name = self._mock_new_name
+ _new_parent = self._mock_new_parent
+ self.mock_calls.append(_Call(('', args, kwargs)))
+
+ seen = set()
+ skip_next_dot = _new_name == '()'
+ do_method_calls = self._mock_parent is not None
+ name = self._mock_name
+ while _new_parent is not None:
+ this_mock_call = _Call((_new_name, args, kwargs))
+ if _new_parent._mock_new_name:
+ dot = '.'
+ if skip_next_dot:
+ dot = ''
+
+ skip_next_dot = False
+ if _new_parent._mock_new_name == '()':
+ skip_next_dot = True
+
+ _new_name = _new_parent._mock_new_name + dot + _new_name
+
+ if do_method_calls:
+ if _new_name == name:
+ this_method_call = this_mock_call
+ else:
+ this_method_call = _Call((name, args, kwargs))
+ _new_parent.method_calls.append(this_method_call)
+
+ do_method_calls = _new_parent._mock_parent is not None
+ if do_method_calls:
+ name = _new_parent._mock_name + '.' + name
+
+ _new_parent.mock_calls.append(this_mock_call)
+ _new_parent = _new_parent._mock_new_parent
+
+ # use ids here so as not to call __hash__ on the mocks
+ _new_parent_id = id(_new_parent)
+ if _new_parent_id in seen:
+ break
+ seen.add(_new_parent_id)
+
+ ret_val = DEFAULT
+ effect = self.side_effect
+ if effect is not None:
+ if _is_exception(effect):
+ raise effect
+
+ if not _callable(effect):
+ result = next(effect)
+ if _is_exception(result):
+ raise result
+ return result
+
+ ret_val = effect(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+
+ if (self._mock_wraps is not None and
+ self._mock_return_value is DEFAULT):
+ return self._mock_wraps(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+ return ret_val
+
+
+
+class Mock(CallableMixin, NonCallableMock):
+ """
+ Create a new `Mock` object. `Mock` takes several optional arguments
+ that specify the behaviour of the Mock object:
+
+ * `spec`: This can be either a list of strings or an existing object (a
+ class or instance) that acts as the specification for the mock object. If
+ you pass in an object then a list of strings is formed by calling dir on
+ the object (excluding unsupported magic attributes and methods). Accessing
+ any attribute not in this list will raise an `AttributeError`.
+
+ If `spec` is an object (rather than a list of strings) then
+ `mock.__class__` returns the class of the spec object. This allows mocks
+ to pass `isinstance` tests.
+
+ * `spec_set`: A stricter variant of `spec`. If used, attempting to *set*
+ or get an attribute on the mock that isn't on the object passed as
+ `spec_set` will raise an `AttributeError`.
+
+ * `side_effect`: A function to be called whenever the Mock is called. See
+ the `side_effect` attribute. Useful for raising exceptions or
+ dynamically changing return values. The function is called with the same
+ arguments as the mock, and unless it returns `DEFAULT`, the return
+ value of this function is used as the return value.
+
+ Alternatively `side_effect` can be an exception class or instance. In
+ this case the exception will be raised when the mock is called.
+
+ If `side_effect` is an iterable then each call to the mock will return
+ the next value from the iterable. If any of the members of the iterable
+ are exceptions they will be raised instead of returned.
+
+ * `return_value`: The value returned when the mock is called. By default
+ this is a new Mock (created on first access). See the
+ `return_value` attribute.
+
+ * `wraps`: Item for the mock object to wrap. If `wraps` is not None then
+ calling the Mock will pass the call through to the wrapped object
+ (returning the real result). Attribute access on the mock will return a
+ Mock object that wraps the corresponding attribute of the wrapped object
+ (so attempting to access an attribute that doesn't exist will raise an
+ `AttributeError`).
+
+ If the mock has an explicit `return_value` set then calls are not passed
+ to the wrapped object and the `return_value` is returned instead.
+
+ * `name`: If the mock has a name then it will be used in the repr of the
+ mock. This can be useful for debugging. The name is propagated to child
+ mocks.
+
+ Mocks can also be called with arbitrary keyword arguments. These will be
+ used to set attributes on the mock after it is created.
+ """
+
+
+
+def _dot_lookup(thing, comp, import_path):
+ try:
+ return getattr(thing, comp)
+ except AttributeError:
+ __import__(import_path)
+ return getattr(thing, comp)
+
+
+def _importer(target):
+ components = target.split('.')
+ import_path = components.pop(0)
+ thing = __import__(import_path)
+
+ for comp in components:
+ import_path += ".%s" % comp
+ thing = _dot_lookup(thing, comp, import_path)
+ return thing
+
+
+def _is_started(patcher):
+ # XXXX horrible
+ return hasattr(patcher, 'is_local')
+
+
+class _patch(object):
+
+ attribute_name = None
+ _active_patches = set()
+
+ def __init__(
+ self, getter, attribute, new, spec, create,
+ spec_set, autospec, new_callable, kwargs
+ ):
+ if new_callable is not None:
+ if new is not DEFAULT:
+ raise ValueError(
+ "Cannot use 'new' and 'new_callable' together"
+ )
+ if autospec is not None:
+ raise ValueError(
+ "Cannot use 'autospec' and 'new_callable' together"
+ )
+
+ self.getter = getter
+ self.attribute = attribute
+ self.new = new
+ self.new_callable = new_callable
+ self.spec = spec
+ self.create = create
+ self.has_local = False
+ self.spec_set = spec_set
+ self.autospec = autospec
+ self.kwargs = kwargs
+ self.additional_patchers = []
+
+
+ def copy(self):
+ patcher = _patch(
+ self.getter, self.attribute, self.new, self.spec,
+ self.create, self.spec_set,
+ self.autospec, self.new_callable, self.kwargs
+ )
+ patcher.attribute_name = self.attribute_name
+ patcher.additional_patchers = [
+ p.copy() for p in self.additional_patchers
+ ]
+ return patcher
+
+
+ def __call__(self, func):
+ if isinstance(func, ClassTypes):
+ return self.decorate_class(func)
+ return self.decorate_callable(func)
+
+
+ def decorate_class(self, klass):
+ for attr in dir(klass):
+ if not attr.startswith(patch.TEST_PREFIX):
+ continue
+
+ attr_value = getattr(klass, attr)
+ if not hasattr(attr_value, "__call__"):
+ continue
+
+ patcher = self.copy()
+ setattr(klass, attr, patcher(attr_value))
+ return klass
+
+
+ def decorate_callable(self, func):
+ if hasattr(func, 'patchings'):
+ func.patchings.append(self)
+ return func
+
+ @wraps(func)
+ def patched(*args, **keywargs):
+ # don't use a with here (backwards compatability with Python 2.4)
+ extra_args = []
+ entered_patchers = []
+
+ # can't use try...except...finally because of Python 2.4
+ # compatibility
+ exc_info = tuple()
+ try:
+ try:
+ for patching in patched.patchings:
+ arg = patching.__enter__()
+ entered_patchers.append(patching)
+ if patching.attribute_name is not None:
+ keywargs.update(arg)
+ elif patching.new is DEFAULT:
+ extra_args.append(arg)
+
+ args += tuple(extra_args)
+ return func(*args, **keywargs)
+ except:
+ if (patching not in entered_patchers and
+ _is_started(patching)):
+ # the patcher may have been started, but an exception
+ # raised whilst entering one of its additional_patchers
+ entered_patchers.append(patching)
+ # Pass the exception to __exit__
+ exc_info = sys.exc_info()
+ # re-raise the exception
+ raise
+ finally:
+ for patching in reversed(entered_patchers):
+ patching.__exit__(*exc_info)
+
+ patched.patchings = [self]
+ if hasattr(func, 'func_code'):
+ # not in Python 3
+ patched.compat_co_firstlineno = getattr(
+ func, "compat_co_firstlineno",
+ func.func_code.co_firstlineno
+ )
+ return patched
+
+
+ def get_original(self):
+ target = self.getter()
+ name = self.attribute
+
+ original = DEFAULT
+ local = False
+
+ try:
+ original = target.__dict__[name]
+ except (AttributeError, KeyError):
+ original = getattr(target, name, DEFAULT)
+ else:
+ local = True
+
+ if not self.create and original is DEFAULT:
+ raise AttributeError(
+ "%s does not have the attribute %r" % (target, name)
+ )
+ return original, local
+
+
+ def __enter__(self):
+ """Perform the patch."""
+ new, spec, spec_set = self.new, self.spec, self.spec_set
+ autospec, kwargs = self.autospec, self.kwargs
+ new_callable = self.new_callable
+ self.target = self.getter()
+
+ # normalise False to None
+ if spec is False:
+ spec = None
+ if spec_set is False:
+ spec_set = None
+ if autospec is False:
+ autospec = None
+
+ if spec is not None and autospec is not None:
+ raise TypeError("Can't specify spec and autospec")
+ if ((spec is not None or autospec is not None) and
+ spec_set not in (True, None)):
+ raise TypeError("Can't provide explicit spec_set *and* spec or autospec")
+
+ original, local = self.get_original()
+
+ if new is DEFAULT and autospec is None:
+ inherit = False
+ if spec is True:
+ # set spec to the object we are replacing
+ spec = original
+ if spec_set is True:
+ spec_set = original
+ spec = None
+ elif spec is not None:
+ if spec_set is True:
+ spec_set = spec
+ spec = None
+ elif spec_set is True:
+ spec_set = original
+
+ if spec is not None or spec_set is not None:
+ if original is DEFAULT:
+ raise TypeError("Can't use 'spec' with create=True")
+ if isinstance(original, ClassTypes):
+ # If we're patching out a class and there is a spec
+ inherit = True
+
+ Klass = MagicMock
+ _kwargs = {}
+ if new_callable is not None:
+ Klass = new_callable
+ elif spec is not None or spec_set is not None:
+ this_spec = spec
+ if spec_set is not None:
+ this_spec = spec_set
+ if _is_list(this_spec):
+ not_callable = '__call__' not in this_spec
+ else:
+ not_callable = not _callable(this_spec)
+ if not_callable:
+ Klass = NonCallableMagicMock
+
+ if spec is not None:
+ _kwargs['spec'] = spec
+ if spec_set is not None:
+ _kwargs['spec_set'] = spec_set
+
+ # add a name to mocks
+ if (isinstance(Klass, type) and
+ issubclass(Klass, NonCallableMock) and self.attribute):
+ _kwargs['name'] = self.attribute
+
+ _kwargs.update(kwargs)
+ new = Klass(**_kwargs)
+
+ if inherit and _is_instance_mock(new):
+ # we can only tell if the instance should be callable if the
+ # spec is not a list
+ this_spec = spec
+ if spec_set is not None:
+ this_spec = spec_set
+ if (not _is_list(this_spec) and not
+ _instance_callable(this_spec)):
+ Klass = NonCallableMagicMock
+
+ _kwargs.pop('name')
+ new.return_value = Klass(_new_parent=new, _new_name='()',
+ **_kwargs)
+ elif autospec is not None:
+ # spec is ignored, new *must* be default, spec_set is treated
+ # as a boolean. Should we check spec is not None and that spec_set
+ # is a bool?
+ if new is not DEFAULT:
+ raise TypeError(
+ "autospec creates the mock for you. Can't specify "
+ "autospec and new."
+ )
+ if original is DEFAULT:
+ raise TypeError("Can't use 'autospec' with create=True")
+ spec_set = bool(spec_set)
+ if autospec is True:
+ autospec = original
+
+ new = create_autospec(autospec, spec_set=spec_set,
+ _name=self.attribute, **kwargs)
+ elif kwargs:
+ # can't set keyword args when we aren't creating the mock
+ # XXXX If new is a Mock we could call new.configure_mock(**kwargs)
+ raise TypeError("Can't pass kwargs to a mock we aren't creating")
+
+ new_attr = new
+
+ self.temp_original = original
+ self.is_local = local
+ setattr(self.target, self.attribute, new_attr)
+ if self.attribute_name is not None:
+ extra_args = {}
+ if self.new is DEFAULT:
+ extra_args[self.attribute_name] = new
+ for patching in self.additional_patchers:
+ arg = patching.__enter__()
+ if patching.new is DEFAULT:
+ extra_args.update(arg)
+ return extra_args
+
+ return new
+
+
+ def __exit__(self, *exc_info):
+ """Undo the patch."""
+ if not _is_started(self):
+ raise RuntimeError('stop called on unstarted patcher')
+
+ if self.is_local and self.temp_original is not DEFAULT:
+ setattr(self.target, self.attribute, self.temp_original)
+ else:
+ delattr(self.target, self.attribute)
+ if not self.create and not hasattr(self.target, self.attribute):
+ # needed for proxy objects like django settings
+ setattr(self.target, self.attribute, self.temp_original)
+
+ del self.temp_original
+ del self.is_local
+ del self.target
+ for patcher in reversed(self.additional_patchers):
+ if _is_started(patcher):
+ patcher.__exit__(*exc_info)
+
+
+ def start(self):
+ """Activate a patch, returning any created mock."""
+ result = self.__enter__()
+ self._active_patches.add(self)
+ return result
+
+
+ def stop(self):
+ """Stop an active patch."""
+ self._active_patches.discard(self)
+ return self.__exit__()
+
+
+
+def _get_target(target):
+ try:
+ target, attribute = target.rsplit('.', 1)
+ except (TypeError, ValueError):
+ raise TypeError("Need a valid target to patch. You supplied: %r" %
+ (target,))
+ getter = lambda: _importer(target)
+ return getter, attribute
+
+
+def _patch_object(
+ target, attribute, new=DEFAULT, spec=None,
+ create=False, spec_set=None, autospec=None,
+ new_callable=None, **kwargs
+ ):
+ """
+ patch.object(target, attribute, new=DEFAULT, spec=None, create=False,
+ spec_set=None, autospec=None, new_callable=None, **kwargs)
+
+ patch the named member (`attribute`) on an object (`target`) with a mock
+ object.
+
+ `patch.object` can be used as a decorator, class decorator or a context
+ manager. Arguments `new`, `spec`, `create`, `spec_set`,
+ `autospec` and `new_callable` have the same meaning as for `patch`. Like
+ `patch`, `patch.object` takes arbitrary keyword arguments for configuring
+ the mock object it creates.
+
+ When used as a class decorator `patch.object` honours `patch.TEST_PREFIX`
+ for choosing which methods to wrap.
+ """
+ getter = lambda: target
+ return _patch(
+ getter, attribute, new, spec, create,
+ spec_set, autospec, new_callable, kwargs
+ )
+
+
+def _patch_multiple(target, spec=None, create=False, spec_set=None,
+ autospec=None, new_callable=None, **kwargs):
+ """Perform multiple patches in a single call. It takes the object to be
+ patched (either as an object or a string to fetch the object by importing)
+ and keyword arguments for the patches::
+
+ with patch.multiple(settings, FIRST_PATCH='one', SECOND_PATCH='two'):
+ ...
+
+ Use `DEFAULT` as the value if you want `patch.multiple` to create
+ mocks for you. In this case the created mocks are passed into a decorated
+ function by keyword, and a dictionary is returned when `patch.multiple` is
+ used as a context manager.
+
+ `patch.multiple` can be used as a decorator, class decorator or a context
+ manager. The arguments `spec`, `spec_set`, `create`,
+ `autospec` and `new_callable` have the same meaning as for `patch`. These
+ arguments will be applied to *all* patches done by `patch.multiple`.
+
+ When used as a class decorator `patch.multiple` honours `patch.TEST_PREFIX`
+ for choosing which methods to wrap.
+ """
+ if type(target) in (unicode, str):
+ getter = lambda: _importer(target)
+ else:
+ getter = lambda: target
+
+ if not kwargs:
+ raise ValueError(
+ 'Must supply at least one keyword argument with patch.multiple'
+ )
+ # need to wrap in a list for python 3, where items is a view
+ items = list(kwargs.items())
+ attribute, new = items[0]
+ patcher = _patch(
+ getter, attribute, new, spec, create, spec_set,
+ autospec, new_callable, {}
+ )
+ patcher.attribute_name = attribute
+ for attribute, new in items[1:]:
+ this_patcher = _patch(
+ getter, attribute, new, spec, create, spec_set,
+ autospec, new_callable, {}
+ )
+ this_patcher.attribute_name = attribute
+ patcher.additional_patchers.append(this_patcher)
+ return patcher
+
+
+def patch(
+ target, new=DEFAULT, spec=None, create=False,
+ spec_set=None, autospec=None, new_callable=None, **kwargs
+ ):
+ """
+ `patch` acts as a function decorator, class decorator or a context
+ manager. Inside the body of the function or with statement, the `target`
+ is patched with a `new` object. When the function/with statement exits
+ the patch is undone.
+
+ If `new` is omitted, then the target is replaced with a
+ `MagicMock`. If `patch` is used as a decorator and `new` is
+ omitted, the created mock is passed in as an extra argument to the
+ decorated function. If `patch` is used as a context manager the created
+ mock is returned by the context manager.
+
+ `target` should be a string in the form `'package.module.ClassName'`. The
+ `target` is imported and the specified object replaced with the `new`
+ object, so the `target` must be importable from the environment you are
+ calling `patch` from. The target is imported when the decorated function
+ is executed, not at decoration time.
+
+ The `spec` and `spec_set` keyword arguments are passed to the `MagicMock`
+ if patch is creating one for you.
+
+ In addition you can pass `spec=True` or `spec_set=True`, which causes
+ patch to pass in the object being mocked as the spec/spec_set object.
+
+ `new_callable` allows you to specify a different class, or callable object,
+ that will be called to create the `new` object. By default `MagicMock` is
+ used.
+
+ A more powerful form of `spec` is `autospec`. If you set `autospec=True`
+ then the mock with be created with a spec from the object being replaced.
+ All attributes of the mock will also have the spec of the corresponding
+ attribute of the object being replaced. Methods and functions being
+ mocked will have their arguments checked and will raise a `TypeError` if
+ they are called with the wrong signature. For mocks replacing a class,
+ their return value (the 'instance') will have the same spec as the class.
+
+ Instead of `autospec=True` you can pass `autospec=some_object` to use an
+ arbitrary object as the spec instead of the one being replaced.
+
+ By default `patch` will fail to replace attributes that don't exist. If
+ you pass in `create=True`, and the attribute doesn't exist, patch will
+ create the attribute for you when the patched function is called, and
+ delete it again afterwards. This is useful for writing tests against
+ attributes that your production code creates at runtime. It is off by by
+ default because it can be dangerous. With it switched on you can write
+ passing tests against APIs that don't actually exist!
+
+ Patch can be used as a `TestCase` class decorator. It works by
+ decorating each test method in the class. This reduces the boilerplate
+ code when your test methods share a common patchings set. `patch` finds
+ tests by looking for method names that start with `patch.TEST_PREFIX`.
+ By default this is `test`, which matches the way `unittest` finds tests.
+ You can specify an alternative prefix by setting `patch.TEST_PREFIX`.
+
+ Patch can be used as a context manager, with the with statement. Here the
+ patching applies to the indented block after the with statement. If you
+ use "as" then the patched object will be bound to the name after the
+ "as"; very useful if `patch` is creating a mock object for you.
+
+ `patch` takes arbitrary keyword arguments. These will be passed to
+ the `Mock` (or `new_callable`) on construction.
+
+ `patch.dict(...)`, `patch.multiple(...)` and `patch.object(...)` are
+ available for alternate use-cases.
+ """
+ getter, attribute = _get_target(target)
+ return _patch(
+ getter, attribute, new, spec, create,
+ spec_set, autospec, new_callable, kwargs
+ )
+
+
+class _patch_dict(object):
+ """
+ Patch a dictionary, or dictionary like object, and restore the dictionary
+ to its original state after the test.
+
+ `in_dict` can be a dictionary or a mapping like container. If it is a
+ mapping then it must at least support getting, setting and deleting items
+ plus iterating over keys.
+
+ `in_dict` can also be a string specifying the name of the dictionary, which
+ will then be fetched by importing it.
+
+ `values` can be a dictionary of values to set in the dictionary. `values`
+ can also be an iterable of `(key, value)` pairs.
+
+ If `clear` is True then the dictionary will be cleared before the new
+ values are set.
+
+ `patch.dict` can also be called with arbitrary keyword arguments to set
+ values in the dictionary::
+
+ with patch.dict('sys.modules', mymodule=Mock(), other_module=Mock()):
+ ...
+
+ `patch.dict` can be used as a context manager, decorator or class
+ decorator. When used as a class decorator `patch.dict` honours
+ `patch.TEST_PREFIX` for choosing which methods to wrap.
+ """
+
+ def __init__(self, in_dict, values=(), clear=False, **kwargs):
+ if isinstance(in_dict, basestring):
+ in_dict = _importer(in_dict)
+ self.in_dict = in_dict
+ # support any argument supported by dict(...) constructor
+ self.values = dict(values)
+ self.values.update(kwargs)
+ self.clear = clear
+ self._original = None
+
+
+ def __call__(self, f):
+ if isinstance(f, ClassTypes):
+ return self.decorate_class(f)
+ @wraps(f)
+ def _inner(*args, **kw):
+ self._patch_dict()
+ try:
+ return f(*args, **kw)
+ finally:
+ self._unpatch_dict()
+
+ return _inner
+
+
+ def decorate_class(self, klass):
+ for attr in dir(klass):
+ attr_value = getattr(klass, attr)
+ if (attr.startswith(patch.TEST_PREFIX) and
+ hasattr(attr_value, "__call__")):
+ decorator = _patch_dict(self.in_dict, self.values, self.clear)
+ decorated = decorator(attr_value)
+ setattr(klass, attr, decorated)
+ return klass
+
+
+ def __enter__(self):
+ """Patch the dict."""
+ self._patch_dict()
+
+
+ def _patch_dict(self):
+ values = self.values
+ in_dict = self.in_dict
+ clear = self.clear
+
+ try:
+ original = in_dict.copy()
+ except AttributeError:
+ # dict like object with no copy method
+ # must support iteration over keys
+ original = {}
+ for key in in_dict:
+ original[key] = in_dict[key]
+ self._original = original
+
+ if clear:
+ _clear_dict(in_dict)
+
+ try:
+ in_dict.update(values)
+ except AttributeError:
+ # dict like object with no update method
+ for key in values:
+ in_dict[key] = values[key]
+
+
+ def _unpatch_dict(self):
+ in_dict = self.in_dict
+ original = self._original
+
+ _clear_dict(in_dict)
+
+ try:
+ in_dict.update(original)
+ except AttributeError:
+ for key in original:
+ in_dict[key] = original[key]
+
+
+ def __exit__(self, *args):
+ """Unpatch the dict."""
+ self._unpatch_dict()
+ return False
+
+ start = __enter__
+ stop = __exit__
+
+
+def _clear_dict(in_dict):
+ try:
+ in_dict.clear()
+ except AttributeError:
+ keys = list(in_dict)
+ for key in keys:
+ del in_dict[key]
+
+
+def _patch_stopall():
+ """Stop all active patches."""
+ for patch in list(_patch._active_patches):
+ patch.stop()
+
+
+patch.object = _patch_object
+patch.dict = _patch_dict
+patch.multiple = _patch_multiple
+patch.stopall = _patch_stopall
+patch.TEST_PREFIX = 'test'
+
+magic_methods = (
+ "lt le gt ge eq ne "
+ "getitem setitem delitem "
+ "len contains iter "
+ "hash str sizeof "
+ "enter exit "
+ "divmod neg pos abs invert "
+ "complex int float index "
+ "trunc floor ceil "
+)
+
+numerics = "add sub mul div floordiv mod lshift rshift and xor or pow "
+inplace = ' '.join('i%s' % n for n in numerics.split())
+right = ' '.join('r%s' % n for n in numerics.split())
+extra = ''
+if inPy3k:
+ extra = 'bool next '
+else:
+ extra = 'unicode long nonzero oct hex truediv rtruediv '
+
+# not including __prepare__, __instancecheck__, __subclasscheck__
+# (as they are metaclass methods)
+# __del__ is not supported at all as it causes problems if it exists
+
+_non_defaults = set('__%s__' % method for method in [
+ 'cmp', 'getslice', 'setslice', 'coerce', 'subclasses',
+ 'format', 'get', 'set', 'delete', 'reversed',
+ 'missing', 'reduce', 'reduce_ex', 'getinitargs',
+ 'getnewargs', 'getstate', 'setstate', 'getformat',
+ 'setformat', 'repr', 'dir'
+])
+
+
+def _get_method(name, func):
+ "Turns a callable object (like a mock) into a real function"
+ def method(self, *args, **kw):
+ return func(self, *args, **kw)
+ method.__name__ = name
+ return method
+
+
+_magics = set(
+ '__%s__' % method for method in
+ ' '.join([magic_methods, numerics, inplace, right, extra]).split()
+)
+
+_all_magics = _magics | _non_defaults
+
+_unsupported_magics = set([
+ '__getattr__', '__setattr__',
+ '__init__', '__new__', '__prepare__'
+ '__instancecheck__', '__subclasscheck__',
+ '__del__'
+])
+
+_calculate_return_value = {
+ '__hash__': lambda self: object.__hash__(self),
+ '__str__': lambda self: object.__str__(self),
+ '__sizeof__': lambda self: object.__sizeof__(self),
+ '__unicode__': lambda self: unicode(object.__str__(self)),
+}
+
+_return_values = {
+ '__lt__': NotImplemented,
+ '__gt__': NotImplemented,
+ '__le__': NotImplemented,
+ '__ge__': NotImplemented,
+ '__int__': 1,
+ '__contains__': False,
+ '__len__': 0,
+ '__exit__': False,
+ '__complex__': 1j,
+ '__float__': 1.0,
+ '__bool__': True,
+ '__nonzero__': True,
+ '__oct__': '1',
+ '__hex__': '0x1',
+ '__long__': long(1),
+ '__index__': 1,
+}
+
+
+def _get_eq(self):
+ def __eq__(other):
+ ret_val = self.__eq__._mock_return_value
+ if ret_val is not DEFAULT:
+ return ret_val
+ return self is other
+ return __eq__
+
+def _get_ne(self):
+ def __ne__(other):
+ if self.__ne__._mock_return_value is not DEFAULT:
+ return DEFAULT
+ return self is not other
+ return __ne__
+
+def _get_iter(self):
+ def __iter__():
+ ret_val = self.__iter__._mock_return_value
+ if ret_val is DEFAULT:
+ return iter([])
+ # if ret_val was already an iterator, then calling iter on it should
+ # return the iterator unchanged
+ return iter(ret_val)
+ return __iter__
+
+_side_effect_methods = {
+ '__eq__': _get_eq,
+ '__ne__': _get_ne,
+ '__iter__': _get_iter,
+}
+
+
+
+def _set_return_value(mock, method, name):
+ fixed = _return_values.get(name, DEFAULT)
+ if fixed is not DEFAULT:
+ method.return_value = fixed
+ return
+
+ return_calulator = _calculate_return_value.get(name)
+ if return_calulator is not None:
+ try:
+ return_value = return_calulator(mock)
+ except AttributeError:
+ # XXXX why do we return AttributeError here?
+ # set it as a side_effect instead?
+ return_value = AttributeError(name)
+ method.return_value = return_value
+ return
+
+ side_effector = _side_effect_methods.get(name)
+ if side_effector is not None:
+ method.side_effect = side_effector(mock)
+
+
+
+class MagicMixin(object):
+ def __init__(self, *args, **kw):
+ _super(MagicMixin, self).__init__(*args, **kw)
+ self._mock_set_magics()
+
+
+ def _mock_set_magics(self):
+ these_magics = _magics
+
+ if self._mock_methods is not None:
+ these_magics = _magics.intersection(self._mock_methods)
+
+ remove_magics = set()
+ remove_magics = _magics - these_magics
+
+ for entry in remove_magics:
+ if entry in type(self).__dict__:
+ # remove unneeded magic methods
+ delattr(self, entry)
+
+ # don't overwrite existing attributes if called a second time
+ these_magics = these_magics - set(type(self).__dict__)
+
+ _type = type(self)
+ for entry in these_magics:
+ setattr(_type, entry, MagicProxy(entry, self))
+
+
+
+class NonCallableMagicMock(MagicMixin, NonCallableMock):
+ """A version of `MagicMock` that isn't callable."""
+ def mock_add_spec(self, spec, spec_set=False):
+ """Add a spec to a mock. `spec` can either be an object or a
+ list of strings. Only attributes on the `spec` can be fetched as
+ attributes from the mock.
+
+ If `spec_set` is True then only attributes on the spec can be set."""
+ self._mock_add_spec(spec, spec_set)
+ self._mock_set_magics()
+
+
+
+class MagicMock(MagicMixin, Mock):
+ """
+ MagicMock is a subclass of Mock with default implementations
+ of most of the magic methods. You can use MagicMock without having to
+ configure the magic methods yourself.
+
+ If you use the `spec` or `spec_set` arguments then *only* magic
+ methods that exist in the spec will be created.
+
+ Attributes and the return value of a `MagicMock` will also be `MagicMocks`.
+ """
+ def mock_add_spec(self, spec, spec_set=False):
+ """Add a spec to a mock. `spec` can either be an object or a
+ list of strings. Only attributes on the `spec` can be fetched as
+ attributes from the mock.
+
+ If `spec_set` is True then only attributes on the spec can be set."""
+ self._mock_add_spec(spec, spec_set)
+ self._mock_set_magics()
+
+
+
+class MagicProxy(object):
+ def __init__(self, name, parent):
+ self.name = name
+ self.parent = parent
+
+ def __call__(self, *args, **kwargs):
+ m = self.create_mock()
+ return m(*args, **kwargs)
+
+ def create_mock(self):
+ entry = self.name
+ parent = self.parent
+ m = parent._get_child_mock(name=entry, _new_name=entry,
+ _new_parent=parent)
+ setattr(parent, entry, m)
+ _set_return_value(parent, m, entry)
+ return m
+
+ def __get__(self, obj, _type=None):
+ return self.create_mock()
+
+
+
+class _ANY(object):
+ "A helper object that compares equal to everything."
+
+ def __eq__(self, other):
+ return True
+
+ def __ne__(self, other):
+ return False
+
+ def __repr__(self):
+ return '<ANY>'
+
+ANY = _ANY()
+
+
+
+def _format_call_signature(name, args, kwargs):
+ message = '%s(%%s)' % name
+ formatted_args = ''
+ args_string = ', '.join([repr(arg) for arg in args])
+ kwargs_string = ', '.join([
+ '%s=%r' % (key, value) for key, value in kwargs.items()
+ ])
+ if args_string:
+ formatted_args = args_string
+ if kwargs_string:
+ if formatted_args:
+ formatted_args += ', '
+ formatted_args += kwargs_string
+
+ return message % formatted_args
+
+
+
+class _Call(tuple):
+ """
+ A tuple for holding the results of a call to a mock, either in the form
+ `(args, kwargs)` or `(name, args, kwargs)`.
+
+ If args or kwargs are empty then a call tuple will compare equal to
+ a tuple without those values. This makes comparisons less verbose::
+
+ _Call(('name', (), {})) == ('name',)
+ _Call(('name', (1,), {})) == ('name', (1,))
+ _Call(((), {'a': 'b'})) == ({'a': 'b'},)
+
+ The `_Call` object provides a useful shortcut for comparing with call::
+
+ _Call(((1, 2), {'a': 3})) == call(1, 2, a=3)
+ _Call(('foo', (1, 2), {'a': 3})) == call.foo(1, 2, a=3)
+
+ If the _Call has no name then it will match any name.
+ """
+ def __new__(cls, value=(), name=None, parent=None, two=False,
+ from_kall=True):
+ name = ''
+ args = ()
+ kwargs = {}
+ _len = len(value)
+ if _len == 3:
+ name, args, kwargs = value
+ elif _len == 2:
+ first, second = value
+ if isinstance(first, basestring):
+ name = first
+ if isinstance(second, tuple):
+ args = second
+ else:
+ kwargs = second
+ else:
+ args, kwargs = first, second
+ elif _len == 1:
+ value, = value
+ if isinstance(value, basestring):
+ name = value
+ elif isinstance(value, tuple):
+ args = value
+ else:
+ kwargs = value
+
+ if two:
+ return tuple.__new__(cls, (args, kwargs))
+
+ return tuple.__new__(cls, (name, args, kwargs))
+
+
+ def __init__(self, value=(), name=None, parent=None, two=False,
+ from_kall=True):
+ self.name = name
+ self.parent = parent
+ self.from_kall = from_kall
+
+
+ def __eq__(self, other):
+ if other is ANY:
+ return True
+ try:
+ len_other = len(other)
+ except TypeError:
+ return False
+
+ self_name = ''
+ if len(self) == 2:
+ self_args, self_kwargs = self
+ else:
+ self_name, self_args, self_kwargs = self
+
+ other_name = ''
+ if len_other == 0:
+ other_args, other_kwargs = (), {}
+ elif len_other == 3:
+ other_name, other_args, other_kwargs = other
+ elif len_other == 1:
+ value, = other
+ if isinstance(value, tuple):
+ other_args = value
+ other_kwargs = {}
+ elif isinstance(value, basestring):
+ other_name = value
+ other_args, other_kwargs = (), {}
+ else:
+ other_args = ()
+ other_kwargs = value
+ else:
+ # len 2
+ # could be (name, args) or (name, kwargs) or (args, kwargs)
+ first, second = other
+ if isinstance(first, basestring):
+ other_name = first
+ if isinstance(second, tuple):
+ other_args, other_kwargs = second, {}
+ else:
+ other_args, other_kwargs = (), second
+ else:
+ other_args, other_kwargs = first, second
+
+ if self_name and other_name != self_name:
+ return False
+
+ # this order is important for ANY to work!
+ return (other_args, other_kwargs) == (self_args, self_kwargs)
+
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+
+ def __call__(self, *args, **kwargs):
+ if self.name is None:
+ return _Call(('', args, kwargs), name='()')
+
+ name = self.name + '()'
+ return _Call((self.name, args, kwargs), name=name, parent=self)
+
+
+ def __getattr__(self, attr):
+ if self.name is None:
+ return _Call(name=attr, from_kall=False)
+ name = '%s.%s' % (self.name, attr)
+ return _Call(name=name, parent=self, from_kall=False)
+
+
+ def __repr__(self):
+ if not self.from_kall:
+ name = self.name or 'call'
+ if name.startswith('()'):
+ name = 'call%s' % name
+ return name
+
+ if len(self) == 2:
+ name = 'call'
+ args, kwargs = self
+ else:
+ name, args, kwargs = self
+ if not name:
+ name = 'call'
+ elif not name.startswith('()'):
+ name = 'call.%s' % name
+ else:
+ name = 'call%s' % name
+ return _format_call_signature(name, args, kwargs)
+
+
+ def call_list(self):
+ """For a call object that represents multiple calls, `call_list`
+ returns a list of all the intermediate calls as well as the
+ final call."""
+ vals = []
+ thing = self
+ while thing is not None:
+ if thing.from_kall:
+ vals.append(thing)
+ thing = thing.parent
+ return _CallList(reversed(vals))
+
+
+call = _Call(from_kall=False)
+
+
+
+def create_autospec(spec, spec_set=False, instance=False, _parent=None,
+ _name=None, **kwargs):
+ """Create a mock object using another object as a spec. Attributes on the
+ mock will use the corresponding attribute on the `spec` object as their
+ spec.
+
+ Functions or methods being mocked will have their arguments checked
+ to check that they are called with the correct signature.
+
+ If `spec_set` is True then attempting to set attributes that don't exist
+ on the spec object will raise an `AttributeError`.
+
+ If a class is used as a spec then the return value of the mock (the
+ instance of the class) will have the same spec. You can use a class as the
+ spec for an instance object by passing `instance=True`. The returned mock
+ will only be callable if instances of the mock are callable.
+
+ `create_autospec` also takes arbitrary keyword arguments that are passed to
+ the constructor of the created mock."""
+ if _is_list(spec):
+ # can't pass a list instance to the mock constructor as it will be
+ # interpreted as a list of strings
+ spec = type(spec)
+
+ is_type = isinstance(spec, ClassTypes)
+
+ _kwargs = {'spec': spec}
+ if spec_set:
+ _kwargs = {'spec_set': spec}
+ elif spec is None:
+ # None we mock with a normal mock without a spec
+ _kwargs = {}
+
+ _kwargs.update(kwargs)
+
+ Klass = MagicMock
+ if type(spec) in DescriptorTypes:
+ # descriptors don't have a spec
+ # because we don't know what type they return
+ _kwargs = {}
+ elif not _callable(spec):
+ Klass = NonCallableMagicMock
+ elif is_type and instance and not _instance_callable(spec):
+ Klass = NonCallableMagicMock
+
+ _new_name = _name
+ if _parent is None:
+ # for a top level object no _new_name should be set
+ _new_name = ''
+
+ mock = Klass(parent=_parent, _new_parent=_parent, _new_name=_new_name,
+ name=_name, **_kwargs)
+
+ if isinstance(spec, FunctionTypes):
+ # should only happen at the top level because we don't
+ # recurse for functions
+ mock = _set_signature(mock, spec)
+ else:
+ _check_signature(spec, mock, is_type, instance)
+
+ if _parent is not None and not instance:
+ _parent._mock_children[_name] = mock
+
+ if is_type and not instance and 'return_value' not in kwargs:
+ mock.return_value = create_autospec(spec, spec_set, instance=True,
+ _name='()', _parent=mock)
+
+ for entry in dir(spec):
+ if _is_magic(entry):
+ # MagicMock already does the useful magic methods for us
+ continue
+
+ if isinstance(spec, FunctionTypes) and entry in FunctionAttributes:
+ # allow a mock to actually be a function
+ continue
+
+ # XXXX do we need a better way of getting attributes without
+ # triggering code execution (?) Probably not - we need the actual
+ # object to mock it so we would rather trigger a property than mock
+ # the property descriptor. Likewise we want to mock out dynamically
+ # provided attributes.
+ # XXXX what about attributes that raise exceptions other than
+ # AttributeError on being fetched?
+ # we could be resilient against it, or catch and propagate the
+ # exception when the attribute is fetched from the mock
+ try:
+ original = getattr(spec, entry)
+ except AttributeError:
+ continue
+
+ kwargs = {'spec': original}
+ if spec_set:
+ kwargs = {'spec_set': original}
+
+ if not isinstance(original, FunctionTypes):
+ new = _SpecState(original, spec_set, mock, entry, instance)
+ mock._mock_children[entry] = new
+ else:
+ parent = mock
+ if isinstance(spec, FunctionTypes):
+ parent = mock.mock
+
+ new = MagicMock(parent=parent, name=entry, _new_name=entry,
+ _new_parent=parent, **kwargs)
+ mock._mock_children[entry] = new
+ skipfirst = _must_skip(spec, entry, is_type)
+ _check_signature(original, new, skipfirst=skipfirst)
+
+ # so functions created with _set_signature become instance attributes,
+ # *plus* their underlying mock exists in _mock_children of the parent
+ # mock. Adding to _mock_children may be unnecessary where we are also
+ # setting as an instance attribute?
+ if isinstance(new, FunctionTypes):
+ setattr(mock, entry, new)
+
+ return mock
+
+
+def _must_skip(spec, entry, is_type):
+ if not isinstance(spec, ClassTypes):
+ if entry in getattr(spec, '__dict__', {}):
+ # instance attribute - shouldn't skip
+ return False
+ spec = spec.__class__
+ if not hasattr(spec, '__mro__'):
+ # old style class: can't have descriptors anyway
+ return is_type
+
+ for klass in spec.__mro__:
+ result = klass.__dict__.get(entry, DEFAULT)
+ if result is DEFAULT:
+ continue
+ if isinstance(result, (staticmethod, classmethod)):
+ return False
+ return is_type
+
+ # shouldn't get here unless function is a dynamically provided attribute
+ # XXXX untested behaviour
+ return is_type
+
+
+def _get_class(obj):
+ try:
+ return obj.__class__
+ except AttributeError:
+ # in Python 2, _sre.SRE_Pattern objects have no __class__
+ return type(obj)
+
+
+class _SpecState(object):
+
+ def __init__(self, spec, spec_set=False, parent=None,
+ name=None, ids=None, instance=False):
+ self.spec = spec
+ self.ids = ids
+ self.spec_set = spec_set
+ self.parent = parent
+ self.instance = instance
+ self.name = name
+
+
+FunctionTypes = (
+ # python function
+ type(create_autospec),
+ # instance method
+ type(ANY.__eq__),
+ # unbound method
+ type(_ANY.__eq__),
+)
+
+FunctionAttributes = set([
+ 'func_closure',
+ 'func_code',
+ 'func_defaults',
+ 'func_dict',
+ 'func_doc',
+ 'func_globals',
+ 'func_name',
+])
+
+
+file_spec = None
+
+
+def mock_open(mock=None, read_data=''):
+ """
+ A helper function to create a mock to replace the use of `open`. It works
+ for `open` called directly or used as a context manager.
+
+ The `mock` argument is the mock object to configure. If `None` (the
+ default) then a `MagicMock` will be created for you, with the API limited
+ to methods or attributes available on standard file handles.
+
+ `read_data` is a string for the `read` method of the file handle to return.
+ This is an empty string by default.
+ """
+ global file_spec
+ if file_spec is None:
+ # set on first use
+ if inPy3k:
+ import _io
+ file_spec = list(set(dir(_io.TextIOWrapper)).union(set(dir(_io.BytesIO))))
+ else:
+ file_spec = file
+
+ if mock is None:
+ mock = MagicMock(name='open', spec=open)
+
+ handle = MagicMock(spec=file_spec)
+ handle.write.return_value = None
+ handle.__enter__.return_value = handle
+ handle.read.return_value = read_data
+
+ mock.return_value = handle
+ return mock
+
+
+class PropertyMock(Mock):
+ """
+ A mock intended to be used as a property, or other descriptor, on a class.
+ `PropertyMock` provides `__get__` and `__set__` methods so you can specify
+ a return value when it is fetched.
+
+ Fetching a `PropertyMock` instance from an object calls the mock, with
+ no args. Setting it calls the mock with the value being set.
+ """
+ def _get_child_mock(self, **kwargs):
+ return MagicMock(**kwargs)
+
+ def __get__(self, obj, obj_type):
+ return self()
+ def __set__(self, obj, val):
+ self(val)
diff --git a/tools/android/checkstyle/chromium-style-5.0.xml b/tools/android/checkstyle/chromium-style-5.0.xml
index 17b44b4..351b5b3 100644
--- a/tools/android/checkstyle/chromium-style-5.0.xml
+++ b/tools/android/checkstyle/chromium-style-5.0.xml
@@ -164,6 +164,17 @@
<property name="throwsIndent" value="8"/>
<property name="lineWrappingIndentation" value="8"/>
</module>
+ <!-- TODO(aurimas): make OperatorWrap into an error once all the warnings are fixed. -->
+ <module name="OperatorWrap">
+ <property name="severity" value="warning"/>
+ <property name="option" value="NL" />
+ <property name="tokens" value="BAND, BOR, BSR, BXOR, DIV, EQUAL, GE, GT, LAND, LE, LITERAL_INSTANCEOF, LOR, LT, MINUS, MOD, NOT_EQUAL, PLUS, QUESTION, SL, SR, STAR " />
+ </module>
+ <module name="OperatorWrap">
+ <property name="severity" value="warning"/>
+ <property name="option" value="eol"/>
+ <property name="tokens" value="ASSIGN"/>
+ </module>
</module>
<module name="FileTabCharacter">
<property name="severity" value="error"/>
diff --git a/tools/android/forwarder2/device_forwarder_main.cc b/tools/android/forwarder2/device_forwarder_main.cc
index cad46f4..aeb2853 100644
--- a/tools/android/forwarder2/device_forwarder_main.cc
+++ b/tools/android/forwarder2/device_forwarder_main.cc
@@ -68,7 +68,7 @@
}
// Daemon::ServerDelegate:
- virtual void Init() OVERRIDE {
+ virtual void Init() override {
DCHECK(!g_notifier);
g_notifier = new forwarder2::PipeNotifier();
signal(SIGTERM, KillHandler);
@@ -77,7 +77,7 @@
controller_thread_->Start();
}
- virtual void OnClientConnected(scoped_ptr<Socket> client_socket) OVERRIDE {
+ virtual void OnClientConnected(scoped_ptr<Socket> client_socket) override {
if (initialized_) {
client_socket->WriteString("OK");
return;
@@ -119,7 +119,7 @@
bool has_failed() const { return has_failed_; }
// Daemon::ClientDelegate:
- virtual void OnDaemonReady(Socket* daemon_socket) OVERRIDE {
+ virtual void OnDaemonReady(Socket* daemon_socket) override {
char buf[kBufSize];
const int bytes_read = daemon_socket->Read(
buf, sizeof(buf) - 1 /* leave space for null terminator */);
diff --git a/tools/android/forwarder2/host_forwarder_main.cc b/tools/android/forwarder2/host_forwarder_main.cc
index 59571b6..514ad93 100644
--- a/tools/android/forwarder2/host_forwarder_main.cc
+++ b/tools/android/forwarder2/host_forwarder_main.cc
@@ -311,7 +311,7 @@
}
// Daemon::ServerDelegate:
- virtual void Init() OVERRIDE {
+ virtual void Init() override {
LOG(INFO) << "Starting host process daemon (pid=" << getpid() << ")";
DCHECK(!g_notifier);
g_notifier = new PipeNotifier();
@@ -319,7 +319,7 @@
signal(SIGINT, KillHandler);
}
- virtual void OnClientConnected(scoped_ptr<Socket> client_socket) OVERRIDE {
+ virtual void OnClientConnected(scoped_ptr<Socket> client_socket) override {
char buf[kBufSize];
const int bytes_read = client_socket->Read(buf, sizeof(buf));
if (bytes_read <= 0) {
@@ -362,7 +362,7 @@
bool has_failed() const { return has_failed_; }
// Daemon::ClientDelegate:
- virtual void OnDaemonReady(Socket* daemon_socket) OVERRIDE {
+ virtual void OnDaemonReady(Socket* daemon_socket) override {
// Send the forward command to the daemon.
CHECK_EQ(command_pickle_.size(),
daemon_socket->WriteNumBytes(command_pickle_.data(),
diff --git a/tools/android/heap_profiler/heap_profiler_unittest.cc b/tools/android/heap_profiler/heap_profiler_unittest.cc
index 65c2700..d69af5f 100644
--- a/tools/android/heap_profiler/heap_profiler_unittest.cc
+++ b/tools/android/heap_profiler/heap_profiler_unittest.cc
@@ -14,9 +14,9 @@
class HeapProfilerTest : public testing::Test {
public:
- virtual void SetUp() OVERRIDE { heap_profiler_init(&stats_); }
+ virtual void SetUp() override { heap_profiler_init(&stats_); }
- virtual void TearDown() OVERRIDE {
+ virtual void TearDown() override {
CheckAllocVsStacktaceConsistency();
heap_profiler_cleanup();
}
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index d5f3d18..9b0b52f 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -475,6 +475,9 @@
return 0;
return self.SimpleTest("chrome", "unit_tests")
+ def TestUIBaseUnit(self):
+ return self.SimpleTest("chrome", "ui_base_unittests")
+
def TestUIUnit(self):
return self.SimpleTest("chrome", "ui_unittests")
@@ -723,6 +726,7 @@
"sync": TestSync, "sync_unit_tests": TestSync,
"sync_integration_tests": TestSyncIntegration,
"sync_integration": TestSyncIntegration,
+ "ui_base_unit": TestUIBaseUnit, "ui_base_unittests": TestUIBaseUnit,
"ui_unit": TestUIUnit, "ui_unittests": TestUIUnit,
"unit": TestUnit, "unit_tests": TestUnit,
"url": TestURL, "url_unittests": TestURL,
diff --git a/url/url_canon_icu.h b/url/url_canon_icu.h
index 18b1f09..80d7953 100644
--- a/url/url_canon_icu.h
+++ b/url/url_canon_icu.h
@@ -24,11 +24,11 @@
// be managed by the creator such that it is alive as long as this is.
ICUCharsetConverter(UConverter* converter);
- virtual ~ICUCharsetConverter();
+ ~ICUCharsetConverter() override;
- virtual void ConvertFromUTF16(const base::char16* input,
- int input_len,
- CanonOutput* output) override;
+ void ConvertFromUTF16(const base::char16* input,
+ int input_len,
+ CanonOutput* output) override;
private:
// The ICU converter, not owned by this class.
diff --git a/url/url_canon_stdstring.h b/url/url_canon_stdstring.h
index 62622b4..c3d8ba1 100644
--- a/url/url_canon_stdstring.h
+++ b/url/url_canon_stdstring.h
@@ -36,12 +36,12 @@
class URL_EXPORT StdStringCanonOutput : public CanonOutput {
public:
StdStringCanonOutput(std::string* str);
- virtual ~StdStringCanonOutput();
+ ~StdStringCanonOutput() override;
// Must be called after writing has completed but before the string is used.
void Complete();
- virtual void Resize(int sz) override;
+ void Resize(int sz) override;
protected:
std::string* str_;