Update from https://crrev.com/317530
TBR=qsr@chromium.org
BUG=461092
Review URL: https://codereview.chromium.org/952893003
diff --git a/.gitignore b/.gitignore
index a0262de..223119c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,7 +51,6 @@
/third_party/lss/
/third_party/mesa/src/
/third_party/nss/
-/third_party/ots/
/third_party/pdfium/
/third_party/pywebsocket/src/
/third_party/requests/src/
diff --git a/DEPS b/DEPS
index ecc3b17..ab58ade 100644
--- a/DEPS
+++ b/DEPS
@@ -21,19 +21,19 @@
'chromium_git': 'https://chromium.googlesource.com',
'dart_svn': 'https://dart.googlecode.com',
'sfntly_revision': '1bdaae8fc788a5ac8936d68bf24f37d977a13dac',
- 'skia_revision': 'd1371a6019189820653aaf20f72ee8f5d0ee3fef',
+ 'skia_revision': '792c80f5a7b66e75d42664ccb298f31962c6654c',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Skia
# and V8 without interference from each other.
- 'v8_revision': '055b865a326cdf6a28d2bbb0f197b36e09069fc1',
+ 'v8_revision': '3dfd929ea07487f2295553df397720d8d75d227c',
# 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': '73edef0a2a162e943d5be7715f53bee5d9452b2e',
+ 'angle_revision': '6df9b37d8e3aed3aea12058900b7932f911a152a',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling build tools
# and whatever else without interference from each other.
- 'buildtools_revision': '5c5e924788fe40f7d6e0a3841ac572de2475e689',
+ 'buildtools_revision': '93b3d0af1b30db55ee42bd2e983f7753153217db',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling Dart
# and whatever else without interference from each other.
@@ -45,7 +45,7 @@
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling BoringSSL
# and whatever else without interference from each other.
- 'boringssl_revision': 'd306f165a462f47c2c0e8f3a0f2b4ae6950f70ed',
+ 'boringssl_revision': 'b180ee98a60149dd3fd07cce4e834494c9d5b31c',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling lss
# and whatever else without interference from each other.
@@ -82,7 +82,7 @@
Var('chromium_git') + '/angle/angle.git' + '@' + Var('angle_revision'),
'src/third_party/icu':
- Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '4e3266f32c62d30a3f9e2232a753c60129d1e670',
+ Var('chromium_git') + '/chromium/deps/icu.git' + '@' + '2081ee6abfa118003fd559cb72393f5df561dba7',
'src/tools/grit':
Var('chromium_git') + '/external/grit-i18n.git' + '@' + 'a5890a8118c0c80cc0560e6d8d5cf65e5d725509', # from svn revision 185
@@ -105,9 +105,6 @@
'src/third_party/skia':
Var('chromium_git') + '/skia.git' + '@' + Var('skia_revision'),
- 'src/third_party/ots':
- Var('chromium_git') + '/external/ots.git' + '@' + '98897009f3ea8a5fa3e20a4a74977da7aaa8e61a',
-
'src/third_party/brotli/src':
Var('chromium_git') + '/external/font-compression-reference.git' + '@' + '8c9c83426beb4a58da34be76ea1fccb4054c4703',
@@ -133,7 +130,7 @@
'https://boringssl.googlesource.com/boringssl.git' + '@' + Var('boringssl_revision'),
'src/tools/gyp':
- Var('chromium_git') + '/external/gyp.git' + '@' + '4d7c139b1820c5fcb993868c61f170a02cda8a40', # from svn revision 2028
+ Var('chromium_git') + '/external/gyp.git' + '@' + '34640080d08ab2a37665512e52142947def3056d', # from svn revision 2028
}
diff --git a/base/BUILD.gn b/base/BUILD.gn
index e417681..c63d377 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -42,7 +42,6 @@
"android/jni_android.h",
"android/jni_array.cc",
"android/jni_array.h",
- "android/jni_onload_delegate.h",
"android/jni_registrar.cc",
"android/jni_registrar.h",
"android/jni_string.cc",
@@ -676,6 +675,10 @@
"trace_event/memory_dump_provider.h",
"trace_event/process_memory_dump.cc",
"trace_event/process_memory_dump.h",
+ "trace_event/process_memory_totals.cc",
+ "trace_event/process_memory_totals.h",
+ "trace_event/process_memory_totals_dump_provider.cc",
+ "trace_event/process_memory_totals_dump_provider.h",
"trace_event/trace_event.h",
"trace_event/trace_event_android.cc",
"trace_event/trace_event_argument.cc",
@@ -869,7 +872,7 @@
]
# TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
libs = [
"cfgmgr32.lib",
@@ -1028,10 +1031,8 @@
configs += [ "//build/config/compiler:optimize_max" ]
}
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
- }
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
source_set("prefs") {
@@ -1335,6 +1336,7 @@
"timer/timer_unittest.cc",
"tools_sanity_unittest.cc",
"trace_event/memory_dump_manager_unittest.cc",
+ "trace_event/process_memory_totals_dump_provider_unittest.cc",
"trace_event/trace_event_argument_unittest.cc",
"trace_event/trace_event_memory_unittest.cc",
"trace_event/trace_event_synthetic_delay_unittest.cc",
@@ -1439,10 +1441,8 @@
set_sources_assignment_filter(sources_assignment_filter)
}
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
- }
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
if (is_android) {
diff --git a/base/allocator/BUILD.gn b/base/allocator/BUILD.gn
index e931b1c..a07a356 100644
--- a/base/allocator/BUILD.gn
+++ b/base/allocator/BUILD.gn
@@ -36,7 +36,7 @@
args = [
visual_studio_path + "/vc/lib",
rebase_path("$target_gen_dir/allocator"),
- cpu_arch,
+ current_cpu,
]
}
}
diff --git a/base/android/base_jni_onload.cc b/base/android/base_jni_onload.cc
index ae64120..c3a65d4 100644
--- a/base/android/base_jni_onload.cc
+++ b/base/android/base_jni_onload.cc
@@ -5,59 +5,51 @@
#include "base/android/base_jni_onload.h"
#include "base/android/jni_android.h"
-#include "base/android/jni_onload_delegate.h"
+#include "base/android/jni_utils.h"
#include "base/android/library_loader/library_loader_hooks.h"
+#include "base/bind.h"
namespace base {
namespace android {
namespace {
-// The JNIOnLoadDelegate implementation in base.
-class BaseJNIOnLoadDelegate : public JNIOnLoadDelegate {
- public:
- bool RegisterJNI(JNIEnv* env) override;
- bool Init() override;
-};
-
-bool BaseJNIOnLoadDelegate::RegisterJNI(JNIEnv* env) {
+bool RegisterJNI(JNIEnv* env) {
return RegisterLibraryLoaderEntryHook(env);
}
-bool BaseJNIOnLoadDelegate::Init() {
+bool Init() {
+ JNIEnv* env = base::android::AttachCurrentThread();
+ base::android::InitReplacementClassLoader(env,
+ base::android::GetClassLoader(env));
return true;
}
} // namespace
-bool OnJNIOnLoad(JavaVM* vm,
- std::vector<JNIOnLoadDelegate*>* delegates) {
+bool OnJNIOnLoadRegisterJNI(JavaVM* vm,
+ std::vector<RegisterCallback> callbacks) {
base::android::InitVM(vm);
JNIEnv* env = base::android::AttachCurrentThread();
- BaseJNIOnLoadDelegate delegate;
- delegates->push_back(&delegate);
- bool ret = true;
- for (std::vector<JNIOnLoadDelegate*>::reverse_iterator i =
- delegates->rbegin(); i != delegates->rend(); ++i) {
- if (!(*i)->RegisterJNI(env)) {
- ret = false;
- break;
- }
+ callbacks.push_back(base::Bind(&RegisterJNI));
+ for (std::vector<RegisterCallback>::reverse_iterator i =
+ callbacks.rbegin(); i != callbacks.rend(); ++i) {
+ if (!i->Run(env))
+ return false;
}
+ return true;
+}
- if (ret) {
- for (std::vector<JNIOnLoadDelegate*>::reverse_iterator i =
- delegates->rbegin(); i != delegates->rend(); ++i) {
- if (!(*i)->Init()) {
- ret = false;
- break;
- }
- }
+bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks) {
+ callbacks.push_back(base::Bind(&Init));
+ for (std::vector<InitCallback>::reverse_iterator i =
+ callbacks.rbegin(); i != callbacks.rend(); ++i) {
+ if (!i->Run())
+ return false;
}
- delegates->pop_back();
- return ret;
+ return true;
}
} // namespace android
diff --git a/base/android/base_jni_onload.h b/base/android/base_jni_onload.h
index f3f05fa..dcc7756 100644
--- a/base/android/base_jni_onload.h
+++ b/base/android/base_jni_onload.h
@@ -9,17 +9,22 @@
#include <vector>
#include "base/base_export.h"
+#include "base/callback.h"
namespace base {
namespace android {
-class JNIOnLoadDelegate;
+// Returns whether JNI registration succeeded. Caller shall put the
+// RegisterCallback into |callbacks| in reverse order.
+typedef base::Callback<bool(JNIEnv*)> RegisterCallback;
+BASE_EXPORT bool OnJNIOnLoadRegisterJNI(
+ JavaVM* vm,
+ std::vector<RegisterCallback> callbacks);
-// Returns whether JNI registration and initialization succeeded. Caller shall
-// put the JNIOnLoadDelegate into |delegates| in reverse order. Refer
-// JNIOnLoadDelegate for more information.
-BASE_EXPORT bool OnJNIOnLoad(JavaVM* vm,
- std::vector<JNIOnLoadDelegate*>* delegates);
+// Returns whether initialization succeeded. Caller shall put the
+// InitCallback into |callbacks| in reverse order.
+typedef base::Callback<bool(void)> InitCallback;
+BASE_EXPORT bool OnJNIOnLoadInit(std::vector<InitCallback> callbacks);
} // namespace android
} // namespace base
diff --git a/base/android/java/src/org/chromium/base/ResourceExtractor.java b/base/android/java/src/org/chromium/base/ResourceExtractor.java
index 9252b4d..d44f2fc 100644
--- a/base/android/java/src/org/chromium/base/ResourceExtractor.java
+++ b/base/android/java/src/org/chromium/base/ResourceExtractor.java
@@ -12,6 +12,8 @@
import android.content.res.AssetManager;
import android.os.AsyncTask;
import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Trace;
import android.preference.PreferenceManager;
import android.util.Log;
@@ -57,6 +59,8 @@
private class ExtractTask extends AsyncTask<Void, Void, Void> {
private static final int BUFFER_SIZE = 16 * 1024;
+ private final List<Runnable> mCompletionCallbacks = new ArrayList<Runnable>();
+
public ExtractTask() {
}
@@ -211,6 +215,23 @@
return null;
}
+ private void onPostExecuteImpl() {
+ for (int i = 0; i < mCompletionCallbacks.size(); i++) {
+ mCompletionCallbacks.get(i).run();
+ }
+ mCompletionCallbacks.clear();
+ }
+
+ @Override
+ protected void onPostExecute(Void result) {
+ beginTraceSection("ResourceExtractor.ExtractTask.onPostExecute");
+ try {
+ onPostExecuteImpl();
+ } finally {
+ endTraceSection();
+ }
+ }
+
// Looks for a timestamp file on disk that indicates the version of the APK that
// the resource paks were extracted from. Returns null if a timestamp was found
// and it indicates that the resources match the current APK. Otherwise returns
@@ -335,6 +356,13 @@
mContext = context.getApplicationContext();
}
+ /**
+ * Synchronously wait for the resource extraction to be completed.
+ * <p>
+ * This method is bad and you should feel bad for using it.
+ *
+ * @see #addCompletionCallback(Runnable)
+ */
public void waitForCompletion() {
if (shouldSkipPakExtraction()) {
return;
@@ -355,6 +383,35 @@
}
/**
+ * Adds a callback to be notified upon the completion of resource extraction.
+ * <p>
+ * If the resource task has already completed, the callback will be posted to the UI message
+ * queue. Otherwise, it will be executed after all the resources have been extracted.
+ * <p>
+ * This must be called on the UI thread. The callback will also always be executed on
+ * the UI thread.
+ *
+ * @param callback The callback to be enqueued.
+ */
+ public void addCompletionCallback(Runnable callback) {
+ ThreadUtils.assertOnUiThread();
+
+ Handler handler = new Handler(Looper.getMainLooper());
+ if (shouldSkipPakExtraction()) {
+ handler.post(callback);
+ return;
+ }
+
+ assert mExtractTask != null;
+ assert !mExtractTask.isCancelled();
+ if (mExtractTask.getStatus() == AsyncTask.Status.FINISHED) {
+ handler.post(callback);
+ } else {
+ mExtractTask.mCompletionCallbacks.add(callback);
+ }
+ }
+
+ /**
* This will extract the application pak resources in an
* AsyncTask. Call waitForCompletion() at the point resources
* are needed to block until the task completes.
diff --git a/base/android/java/src/org/chromium/base/library_loader/Linker.java b/base/android/java/src/org/chromium/base/library_loader/Linker.java
index 23f953c..bbf76cb 100644
--- a/base/android/java/src/org/chromium/base/library_loader/Linker.java
+++ b/base/android/java/src/org/chromium/base/library_loader/Linker.java
@@ -1039,7 +1039,7 @@
mLoadSize = in.readLong();
mRelroStart = in.readLong();
mRelroSize = in.readLong();
- ParcelFileDescriptor fd = in.readFileDescriptor();
+ ParcelFileDescriptor fd = ParcelFileDescriptor.CREATOR.createFromParcel(in);
// If CreateSharedRelro fails, the OS file descriptor will be -1 and |fd| will be null.
mRelroFd = (fd == null) ? -1 : fd.detachFd();
}
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
index e09c2d5..a2de00a 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -17,6 +17,8 @@
using base::android::MethodID;
using base::android::ScopedJavaLocalRef;
+bool g_disable_manual_jni_registration = false;
+
JavaVM* g_jvm = NULL;
// Leak the global app context, as it is used from a non-joinable worker thread
// that may still be running at shutdown. There is no harm in doing this.
@@ -77,6 +79,15 @@
namespace base {
namespace android {
+bool IsManualJniRegistrationDisabled() {
+ return g_disable_manual_jni_registration;
+}
+
+void DisableManualJniRegistration() {
+ DCHECK(!g_disable_manual_jni_registration);
+ g_disable_manual_jni_registration = true;
+}
+
JNIEnv* AttachCurrentThread() {
DCHECK(g_jvm);
JNIEnv* env = NULL;
diff --git a/base/android/jni_android.h b/base/android/jni_android.h
index b5e5526..504eb85 100644
--- a/base/android/jni_android.h
+++ b/base/android/jni_android.h
@@ -21,6 +21,13 @@
// Used to mark symbols to be exported in a shared library's symbol table.
#define JNI_EXPORT __attribute__ ((visibility("default")))
+// Used to disable manual JNI registration in binaries that prefer to use native
+// JNI exports for startup performance. This is not compatible with the crazy
+// linker and so defaults to off. Call DisableManualJniRegistration at the very
+// beginning of JNI_OnLoad to use this.
+BASE_EXPORT bool IsManualJniRegistrationDisabled();
+BASE_EXPORT void DisableManualJniRegistration();
+
// Contains the registration method information for initializing JNI bindings.
struct RegistrationMethod {
const char* name;
diff --git a/base/android/jni_generator/jni_generator.py b/base/android/jni_generator/jni_generator.py
index 6e39c13..54fea6b 100755
--- a/base/android/jni_generator/jni_generator.py
+++ b/base/android/jni_generator/jni_generator.py
@@ -889,7 +889,7 @@
def GetJNINativeMethodsString(self):
"""Returns the implementation of the array of native methods."""
- if self.options.native_exports:
+ if self.options.native_exports and not self.options.native_exports_optional:
return ''
template = Template("""\
static const JNINativeMethod kMethods${JAVA_CLASS}[] = {
@@ -922,7 +922,7 @@
"""Returns the code for RegisterNatives."""
template = Template("""\
${REGISTER_NATIVES_SIGNATURE} {
-${CLASSES}
+${EARLY_EXIT}${CLASSES}
${NATIVES}
${CALLED_BY_NATIVES}
return true;
@@ -934,9 +934,16 @@
else:
signature += ')'
+ early_exit = ''
+ if self.options.native_exports_optional:
+ early_exit = """\
+ if (base::android::IsManualJniRegistrationDisabled()) return true;
+"""
+
natives = self.GetRegisterNativesImplString()
called_by_natives = self.GetRegisterCalledByNativesImplString()
values = {'REGISTER_NATIVES_SIGNATURE': signature,
+ 'EARLY_EXIT': early_exit,
'CLASSES': self.GetFindClasses(),
'NATIVES': natives,
'CALLED_BY_NATIVES': called_by_natives,
@@ -945,7 +952,7 @@
def GetRegisterNativesImplString(self):
"""Returns the shared implementation for RegisterNatives."""
- if self.options.native_exports:
+ if self.options.native_exports and not self.options.native_exports_optional:
return ''
template = Template("""\
@@ -1035,6 +1042,31 @@
param.name
for param in called_by_native.params])
+ def GetStubName(self, native):
+ """Return the name of the stub function for this native method.
+
+ Args:
+ native: the native dictionary describing the method.
+
+ Returns:
+ A string with the stub function name. For native exports mode this is the
+ Java_* symbol name required by the JVM; otherwise it is just the name of
+ the native method itself.
+ """
+ if self.options.native_exports:
+ template = Template("Java_${JAVA_NAME}_native${NAME}")
+
+ java_name = JniParams.RemapClassName(self.fully_qualified_class)
+ java_name = java_name.replace('_', '_1').replace('/', '_')
+ if native.java_class_name:
+ java_name += '_00024' + native.java_class_name
+
+ values = {'NAME': native.name,
+ 'JAVA_NAME': java_name}
+ return template.substitute(values)
+ else:
+ return native.name
+
def GetForwardDeclaration(self, native):
template_str = """
static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS});
@@ -1042,7 +1074,7 @@
if self.options.native_exports:
template_str += """
__attribute__((visibility("default"), alias("${NAME}")))
-${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env, ${PARAMS});
+${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS});
"""
template = Template(template_str)
params_in_call = []
@@ -1050,16 +1082,11 @@
params_in_call = ['env', 'jcaller']
params_in_call = ', '.join(params_in_call + [p.name for p in native.params])
- java_name = JniParams.RemapClassName(self.fully_qualified_class)
- java_name = java_name.replace('_', '_1').replace('/', '_')
- if native.java_class_name:
- java_name += '_00024' + native.java_class_name
-
values = {'RETURN': JavaDataTypeToC(native.return_type),
'NAME': native.name,
- 'JAVA_NAME': java_name,
'PARAMS': self.GetParamsInDeclaration(native),
- 'PARAMS_IN_CALL': params_in_call}
+ 'PARAMS_IN_CALL': params_in_call,
+ 'STUB_NAME': self.GetStubName(native)}
return template.substitute(values)
def GetNativeMethodStubString(self, native):
@@ -1067,11 +1094,11 @@
if self.options.native_exports:
template_str = """\
__attribute__((visibility("default")))
-${RETURN} Java_${JAVA_NAME}_native${NAME}(JNIEnv* env,
+${RETURN} ${STUB_NAME}(JNIEnv* env,
${PARAMS_IN_DECLARATION}) {"""
else:
template_str = """\
-static ${RETURN} ${NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
+static ${RETURN} ${STUB_NAME}(JNIEnv* env, ${PARAMS_IN_DECLARATION}) {"""
template_str += """
${P0_TYPE}* native = reinterpret_cast<${P0_TYPE}*>(${PARAM0_NAME});
CHECK_NATIVE_PTR(env, jcaller, native, "${NAME}"${OPTIONAL_ERROR_RETURN});
@@ -1093,24 +1120,16 @@
if re.match(RE_SCOPED_JNI_RETURN_TYPES, return_type):
post_call = '.Release()'
- if self.options.native_exports:
- java_name = JniParams.RemapClassName(self.fully_qualified_class)
- java_name = java_name.replace('_', '_1').replace('/', '_')
- if native.java_class_name:
- java_name += '_00024' + native.java_class_name
- else:
- java_name = ''
-
values = {
'RETURN': return_type,
'OPTIONAL_ERROR_RETURN': optional_error_return,
- 'JAVA_NAME': java_name,
'NAME': native.name,
'PARAMS_IN_DECLARATION': self.GetParamsInDeclaration(native),
'PARAM0_NAME': native.params[0].name,
'P0_TYPE': native.p0_type,
'PARAMS_IN_CALL': params_in_call,
- 'POST_CALL': post_call
+ 'POST_CALL': post_call,
+ 'STUB_NAME': self.GetStubName(native),
}
return template.substitute(values)
@@ -1225,12 +1244,13 @@
return template.substitute(values)
def GetKMethodArrayEntry(self, native):
- template = Template("""\
- { "native${NAME}", ${JNI_SIGNATURE}, reinterpret_cast<void*>(${NAME}) },""")
+ template = Template(' { "native${NAME}", ${JNI_SIGNATURE}, ' +
+ 'reinterpret_cast<void*>(${STUB_NAME}) },')
values = {'NAME': native.name,
'JNI_SIGNATURE': JniParams.Signature(native.params,
native.return_type,
- True)}
+ True),
+ 'STUB_NAME': self.GetStubName(native)}
return template.substitute(values)
def GetUniqueClasses(self, origin):
@@ -1500,7 +1520,12 @@
option_parser.add_option('--native_exports', action='store_true',
help='Native method registration through .so '
'exports.')
+ option_parser.add_option('--native_exports_optional', action='store_true',
+ help='Support both explicit and native method'
+ 'registration.')
options, args = option_parser.parse_args(argv)
+ if options.native_exports_optional:
+ options.native_exports = True
if options.jar_file:
input_file = ExtractJarInputFile(options.jar_file, options.input_file,
options.output_dir)
diff --git a/base/android/jni_generator/jni_generator_tests.py b/base/android/jni_generator/jni_generator_tests.py
index 7e39cda..e29bc0c 100755
--- a/base/android/jni_generator/jni_generator_tests.py
+++ b/base/android/jni_generator/jni_generator_tests.py
@@ -43,6 +43,7 @@
self.cpp = 'cpp'
self.javap = 'javap'
self.native_exports = False
+ self.native_exports_optional = False
class TestGenerator(unittest.TestCase):
def assertObjEquals(self, first, second):
@@ -1019,7 +1020,7 @@
test_data, 'org/chromium/example/jni_generator/Test', options)
self.assertGoldenTextEquals(jni_from_java.GetContent())
- def testNativeExportsOption(self):
+ def runNativeExportsOption(self, optional):
test_data = """
package org.chromium.example.jni_generator;
@@ -1054,9 +1055,18 @@
options = TestOptions()
options.jni_init_native_name = 'nativeInitNativeClass'
options.native_exports = True
+ options.native_exports_optional = optional
jni_from_java = jni_generator.JNIFromJavaSource(
test_data, 'org/chromium/example/jni_generator/SampleForTests', options)
- self.assertGoldenTextEquals(jni_from_java.GetContent())
+ return jni_from_java.GetContent()
+
+ def testNativeExportsOption(self):
+ content = self.runNativeExportsOption(False)
+ self.assertGoldenTextEquals(content)
+
+ def testNativeExportsOptionalOption(self):
+ content = self.runNativeExportsOption(True)
+ self.assertGoldenTextEquals(content)
def testOuterInnerRaises(self):
test_data = """
diff --git a/base/android/jni_generator/testNativeExportsOptionalOption.golden b/base/android/jni_generator/testNativeExportsOptionalOption.golden
new file mode 100644
index 0000000..2a3b172
--- /dev/null
+++ b/base/android/jni_generator/testNativeExportsOptionalOption.golden
@@ -0,0 +1,283 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file is autogenerated by
+// base/android/jni_generator/jni_generator.py
+// For
+// org/chromium/example/jni_generator/SampleForTests
+
+#ifndef org_chromium_example_jni_generator_SampleForTests_JNI
+#define org_chromium_example_jni_generator_SampleForTests_JNI
+
+#include <jni.h>
+
+#include "base/android/jni_generator/jni_generator_helper.h"
+
+#include "base/android/jni_int_wrapper.h"
+
+// Step 1: forward declarations.
+namespace {
+const char kSampleForTestsClassPath[] =
+ "org/chromium/example/jni_generator/SampleForTests";
+// Leaking this jclass as we cannot use LazyInstance from some threads.
+base::subtle::AtomicWord g_SampleForTests_clazz __attribute__((unused)) = 0;
+#define SampleForTests_clazz(env) base::android::LazyGetClass(env, kSampleForTestsClassPath, &g_SampleForTests_clazz)
+
+} // namespace
+
+extern "C" {
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default"), alias("Init")))
+jint
+ Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit(JNIEnv*
+ env, jobject jcaller);
+
+static jint Init(JNIEnv* env, jobject jcaller);
+
+__attribute__((visibility("default"), alias("Init")))
+jint
+ Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit(JNIEnv*
+ env, jobject jcaller);
+
+}; // extern "C"
+
+// Step 2: method stubs.
+
+extern "C" {
+__attribute__((visibility("default")))
+jint
+ Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod(JNIEnv*
+ env,
+ jobject jcaller,
+ jlong nativeTest,
+ jint arg1) {
+ Test* native = reinterpret_cast<Test*>(nativeTest);
+ CHECK_NATIVE_PTR(env, jcaller, native, "StaticMethod", 0);
+ return native->StaticMethod(env, jcaller, arg1);
+}
+
+__attribute__((visibility("default")))
+jint
+ Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod(JNIEnv*
+ env,
+ jobject jcaller,
+ jlong nativeTest,
+ jint arg1) {
+ Test* native = reinterpret_cast<Test*>(nativeTest);
+ CHECK_NATIVE_PTR(env, jcaller, native, "Method", 0);
+ return native->Method(env, jcaller, arg1);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParam = 0;
+static void Java_SampleForTests_testMethodWithParam(JNIEnv* env, jobject obj,
+ JniIntWrapper iParam) {
+ /* Must call RegisterNativesImpl() */
+ CHECK_CLAZZ(env, obj,
+ SampleForTests_clazz(env));
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, SampleForTests_clazz(env),
+ "testMethodWithParam",
+
+"("
+"I"
+")"
+"V",
+ &g_SampleForTests_testMethodWithParam);
+
+ env->CallVoidMethod(obj,
+ method_id, as_jint(iParam));
+ jni_generator::CheckException(env);
+
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithParamAndReturn =
+ 0;
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_SampleForTests_testMethodWithParamAndReturn(JNIEnv* env, jobject obj,
+ JniIntWrapper iParam) {
+ /* Must call RegisterNativesImpl() */
+ CHECK_CLAZZ(env, obj,
+ SampleForTests_clazz(env), NULL);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_INSTANCE>(
+ env, SampleForTests_clazz(env),
+ "testMethodWithParamAndReturn",
+
+"("
+"I"
+")"
+"Ljava/lang/String;",
+ &g_SampleForTests_testMethodWithParamAndReturn);
+
+ jstring ret =
+ static_cast<jstring>(env->CallObjectMethod(obj,
+ method_id, as_jint(iParam)));
+ jni_generator::CheckException(env);
+ return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithParam = 0;
+static jint Java_SampleForTests_testStaticMethodWithParam(JNIEnv* env,
+ JniIntWrapper iParam) {
+ /* Must call RegisterNativesImpl() */
+ CHECK_CLAZZ(env, SampleForTests_clazz(env),
+ SampleForTests_clazz(env), 0);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, SampleForTests_clazz(env),
+ "testStaticMethodWithParam",
+
+"("
+"I"
+")"
+"I",
+ &g_SampleForTests_testStaticMethodWithParam);
+
+ jint ret =
+ env->CallStaticIntMethod(SampleForTests_clazz(env),
+ method_id, as_jint(iParam));
+ jni_generator::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testMethodWithNoParam = 0;
+static jdouble Java_SampleForTests_testMethodWithNoParam(JNIEnv* env) {
+ /* Must call RegisterNativesImpl() */
+ CHECK_CLAZZ(env, SampleForTests_clazz(env),
+ SampleForTests_clazz(env), 0);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, SampleForTests_clazz(env),
+ "testMethodWithNoParam",
+
+"("
+")"
+"D",
+ &g_SampleForTests_testMethodWithNoParam);
+
+ jdouble ret =
+ env->CallStaticDoubleMethod(SampleForTests_clazz(env),
+ method_id);
+ jni_generator::CheckException(env);
+ return ret;
+}
+
+static base::subtle::AtomicWord g_SampleForTests_testStaticMethodWithNoParam =
+ 0;
+static base::android::ScopedJavaLocalRef<jstring>
+ Java_SampleForTests_testStaticMethodWithNoParam(JNIEnv* env) {
+ /* Must call RegisterNativesImpl() */
+ CHECK_CLAZZ(env, SampleForTests_clazz(env),
+ SampleForTests_clazz(env), NULL);
+ jmethodID method_id =
+ base::android::MethodID::LazyGet<
+ base::android::MethodID::TYPE_STATIC>(
+ env, SampleForTests_clazz(env),
+ "testStaticMethodWithNoParam",
+
+"("
+")"
+"Ljava/lang/String;",
+ &g_SampleForTests_testStaticMethodWithNoParam);
+
+ jstring ret =
+static_cast<jstring>(env->CallStaticObjectMethod(SampleForTests_clazz(env),
+ method_id));
+ jni_generator::CheckException(env);
+ return base::android::ScopedJavaLocalRef<jstring>(env, ret);
+}
+}; // extern "C"
+
+// Step 3: RegisterNatives.
+
+static const JNINativeMethod kMethodsMyOtherInnerClass[] = {
+ { "nativeInit",
+"("
+")"
+"I",
+ reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyOtherInnerClass_nativeInit)
+ },
+};
+
+static const JNINativeMethod kMethodsMyInnerClass[] = {
+ { "nativeInit",
+"("
+")"
+"I",
+ reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_00024MyInnerClass_nativeInit)
+ },
+};
+
+static const JNINativeMethod kMethodsSampleForTests[] = {
+ { "nativeStaticMethod",
+"("
+"J"
+"I"
+")"
+"I",
+ reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeStaticMethod)
+ },
+ { "nativeMethod",
+"("
+"J"
+"I"
+")"
+"I",
+ reinterpret_cast<void*>(Java_org_chromium_example_jni_1generator_SampleForTests_nativeMethod)
+ },
+};
+
+static bool RegisterNativesImpl(JNIEnv* env, jclass clazz) {
+ if (base::android::IsManualJniRegistrationDisabled()) return true;
+ base::subtle::Release_Store(&g_SampleForTests_clazz,
+ static_cast<base::subtle::AtomicWord>(env->NewWeakGlobalRef(clazz));
+
+ const int kMethodsMyOtherInnerClassSize =
+ arraysize(kMethodsMyOtherInnerClass);
+
+ if (env->RegisterNatives(MyOtherInnerClass_clazz(env),
+ kMethodsMyOtherInnerClass,
+ kMethodsMyOtherInnerClassSize) < 0) {
+ jni_generator::HandleRegistrationError(
+ env, MyOtherInnerClass_clazz(env), __FILE__);
+ return false;
+ }
+
+ const int kMethodsMyInnerClassSize = arraysize(kMethodsMyInnerClass);
+
+ if (env->RegisterNatives(MyInnerClass_clazz(env),
+ kMethodsMyInnerClass,
+ kMethodsMyInnerClassSize) < 0) {
+ jni_generator::HandleRegistrationError(
+ env, MyInnerClass_clazz(env), __FILE__);
+ return false;
+ }
+
+ const int kMethodsSampleForTestsSize = arraysize(kMethodsSampleForTests);
+
+ if (env->RegisterNatives(SampleForTests_clazz(env),
+ kMethodsSampleForTests,
+ kMethodsSampleForTestsSize) < 0) {
+ jni_generator::HandleRegistrationError(
+ env, SampleForTests_clazz(env), __FILE__);
+ return false;
+ }
+
+ return true;
+}
+
+extern "C" JNIEXPORT bool JNICALL
+Java_org_chromium_example_jni_1generator_SampleForTests_nativeInitNativeClass(JNIEnv*
+ env, jclass clazz) {
+ return RegisterNativesImpl(env, clazz);
+}
+
+#endif // org_chromium_example_jni_generator_SampleForTests_JNI
diff --git a/base/android/jni_onload_delegate.h b/base/android/jni_onload_delegate.h
deleted file mode 100644
index ef1b137..0000000
--- a/base/android/jni_onload_delegate.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef BASE_ANDROID_JNI_ONLOAD_DELEGATE_H_
-#define BASE_ANDROID_JNI_ONLOAD_DELEGATE_H_
-
-#include <jni.h>
-
-#include "base/base_export.h"
-
-namespace base {
-namespace android {
-
-// This delegate class is used to implement component specific JNI registration
-// and initialization. All methods are called in JNI_OnLoad().
-//
-// Both RegisterJNI() and Init() methods are called if the shared library
-// is loaded by crazy linker that can't find JNI methods without JNI
-// registration, otherwise, only Init() is invoked where dynamic lookup is
-// used to find the JNI methods.
-//
-// It is important to make sure the JNI registration code is only in
-// RegisterJNI(), so it could be stripped out when JNI registration isn't
-// needed.
-class BASE_EXPORT JNIOnLoadDelegate {
- public:
- virtual ~JNIOnLoadDelegate() {}
-
- // Returns whether the JNI registration succeeded.
- virtual bool RegisterJNI(JNIEnv* env) = 0;
-
- // Returns whether the initialization succeeded. This method is called after
- // RegisterJNI(), all JNI methods shall ready to be used.
- virtual bool Init() = 0;
-};
-
-} // namespace android
-} // namespace base
-
-#endif // BASE_ANDROID_JNI_ONLOAD_DELEGATE_H_
diff --git a/base/base.gyp b/base/base.gyp
index 8cd5d6a..213e62d 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -645,6 +645,7 @@
'timer/timer_unittest.cc',
'tools_sanity_unittest.cc',
'trace_event/memory_dump_manager_unittest.cc',
+ 'trace_event/process_memory_totals_dump_provider_unittest.cc',
'trace_event/trace_event_argument_unittest.cc',
'trace_event/trace_event_memory_unittest.cc',
'trace_event/trace_event_synthetic_delay_unittest.cc',
diff --git a/base/base.gypi b/base/base.gypi
index 37a8171..b7c33b8 100644
--- a/base/base.gypi
+++ b/base/base.gypi
@@ -44,7 +44,6 @@
'android/jni_android.h',
'android/jni_array.cc',
'android/jni_array.h',
- 'android/jni_onload_delegate.h',
'android/jni_registrar.cc',
'android/jni_registrar.h',
'android/jni_string.cc',
@@ -672,6 +671,10 @@
'trace_event/memory_dump_provider.h',
'trace_event/process_memory_dump.cc',
'trace_event/process_memory_dump.h',
+ 'trace_event/process_memory_totals.cc',
+ 'trace_event/process_memory_totals.h',
+ 'trace_event/process_memory_totals_dump_provider.cc',
+ 'trace_event/process_memory_totals_dump_provider.h',
'trace_event/trace_event.h',
'trace_event/trace_event_android.cc',
'trace_event/trace_event_argument.cc',
diff --git a/base/i18n/break_iterator.cc b/base/i18n/break_iterator.cc
index e3aaa2b..e2ed667 100644
--- a/base/i18n/break_iterator.cc
+++ b/base/i18n/break_iterator.cc
@@ -74,7 +74,8 @@
static_cast<int32_t>(string_.size()),
&status);
if (U_FAILURE(status)) {
- NOTREACHED() << "ubrk_open failed";
+ NOTREACHED() << "ubrk_open failed for type " << break_type
+ << " with error " << status;
}
}
diff --git a/base/i18n/time_formatting_unittest.cc b/base/i18n/time_formatting_unittest.cc
index 4739b62..df0c1ed 100644
--- a/base/i18n/time_formatting_unittest.cc
+++ b/base/i18n/time_formatting_unittest.cc
@@ -158,11 +158,11 @@
EXPECT_EQ(ASCIIToUTF16("30 Apr 2011"), TimeFormatShortDate(time));
EXPECT_EQ(ASCIIToUTF16("30/04/2011"), TimeFormatShortDateNumeric(time));
- EXPECT_EQ(ASCIIToUTF16("30/04/2011 15:42:07"),
+ EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07"),
TimeFormatShortDateAndTime(time));
- EXPECT_EQ(ASCIIToUTF16("30/04/2011 15:42:07 ") + GetShortTimeZone(),
+ EXPECT_EQ(ASCIIToUTF16("30/04/2011, 15:42:07 ") + GetShortTimeZone(),
TimeFormatShortDateAndTimeWithTimeZone(time));
- EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 15:42:07"),
+ EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011 at 15:42:07"),
TimeFormatFriendlyDateAndTime(time));
EXPECT_EQ(ASCIIToUTF16("Saturday, 30 April 2011"),
TimeFormatFriendlyDate(time));
diff --git a/base/ios/device_util.mm b/base/ios/device_util.mm
index ff7be36..1234562 100644
--- a/base/ios/device_util.mm
+++ b/base/ios/device_util.mm
@@ -13,7 +13,6 @@
#include <sys/socket.h>
#include <sys/sysctl.h>
-#include "base/ios/ios_util.h"
#include "base/logging.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/scoped_ptr.h"
diff --git a/base/ios/device_util_unittest.mm b/base/ios/device_util_unittest.mm
index 3494e00..82d4217 100644
--- a/base/ios/device_util_unittest.mm
+++ b/base/ios/device_util_unittest.mm
@@ -5,7 +5,6 @@
#import <UIKit/UIKit.h>
#include "base/ios/device_util.h"
-#include "base/ios/ios_util.h"
#include "base/strings/sys_string_conversions.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "testing/gtest_mac.h"
diff --git a/base/memory/discardable_memory_android.cc b/base/memory/discardable_memory_android.cc
index 27b390f..5dcdfdc 100644
--- a/base/memory/discardable_memory_android.cc
+++ b/base/memory/discardable_memory_android.cc
@@ -53,8 +53,8 @@
std::vector<DiscardableMemoryType>* types) {
const DiscardableMemoryType supported_types[] = {
DISCARDABLE_MEMORY_TYPE_ASHMEM,
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
+ DISCARDABLE_MEMORY_TYPE_SHMEM,
+ DISCARDABLE_MEMORY_TYPE_EMULATED
};
types->assign(supported_types, supported_types + arraysize(supported_types));
}
diff --git a/base/memory/discardable_memory_linux.cc b/base/memory/discardable_memory_linux.cc
index 977b029..670ad7e 100644
--- a/base/memory/discardable_memory_linux.cc
+++ b/base/memory/discardable_memory_linux.cc
@@ -19,8 +19,8 @@
void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) {
const DiscardableMemoryType supported_types[] = {
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
+ DISCARDABLE_MEMORY_TYPE_SHMEM,
+ DISCARDABLE_MEMORY_TYPE_EMULATED
};
types->assign(supported_types, supported_types + arraysize(supported_types));
}
diff --git a/base/memory/discardable_memory_mac.cc b/base/memory/discardable_memory_mac.cc
index c8669a6..e0096e5 100644
--- a/base/memory/discardable_memory_mac.cc
+++ b/base/memory/discardable_memory_mac.cc
@@ -23,8 +23,8 @@
std::vector<DiscardableMemoryType>* types) {
const DiscardableMemoryType supported_types[] = {
DISCARDABLE_MEMORY_TYPE_MACH,
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
+ DISCARDABLE_MEMORY_TYPE_SHMEM,
+ DISCARDABLE_MEMORY_TYPE_EMULATED
};
types->assign(supported_types, supported_types + arraysize(supported_types));
}
diff --git a/base/memory/discardable_memory_win.cc b/base/memory/discardable_memory_win.cc
index 977b029..670ad7e 100644
--- a/base/memory/discardable_memory_win.cc
+++ b/base/memory/discardable_memory_win.cc
@@ -19,8 +19,8 @@
void DiscardableMemory::GetSupportedTypes(
std::vector<DiscardableMemoryType>* types) {
const DiscardableMemoryType supported_types[] = {
- DISCARDABLE_MEMORY_TYPE_EMULATED,
- DISCARDABLE_MEMORY_TYPE_SHMEM
+ DISCARDABLE_MEMORY_TYPE_SHMEM,
+ DISCARDABLE_MEMORY_TYPE_EMULATED
};
types->assign(supported_types, supported_types + arraysize(supported_types));
}
diff --git a/base/memory/scoped_ptr_unittest.cc b/base/memory/scoped_ptr_unittest.cc
index 0887a99..766f444 100644
--- a/base/memory/scoped_ptr_unittest.cc
+++ b/base/memory/scoped_ptr_unittest.cc
@@ -9,7 +9,6 @@
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/callback.h"
-#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
@@ -686,8 +685,11 @@
// value first.
TEST(ScopedPtrTest, LoggingDoesntConvertToBoolean) {
scoped_ptr<int> x(new int);
- std::stringstream s;
- s << x;
- std::string expected = base::StringPrintf("%p", x.get());
- EXPECT_EQ(expected, s.str());
+ std::stringstream s1;
+ s1 << x;
+
+ std::stringstream s2;
+ s2 << x.get();
+
+ EXPECT_EQ(s2.str(), s1.str());
}
diff --git a/base/memory/singleton.h b/base/memory/singleton.h
index e5e2e3e..e50bdc0 100644
--- a/base/memory/singleton.h
+++ b/base/memory/singleton.h
@@ -23,7 +23,6 @@
#include "base/atomicops.h"
#include "base/base_export.h"
#include "base/memory/aligned_memory.h"
-#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/threading/thread_restrictions.h"
namespace base {
@@ -237,8 +236,6 @@
// instance_ pointer must acquire visibility over the singleton data.
base::subtle::AtomicWord value = base::subtle::Acquire_Load(&instance_);
if (value != 0 && value != base::internal::kBeingCreatedMarker) {
- // See the corresponding HAPPENS_BEFORE below.
- ANNOTATE_HAPPENS_AFTER(&instance_);
return reinterpret_cast<Type*>(value);
}
@@ -250,10 +247,6 @@
// stop right after we do this store.
Type* newval = Traits::New();
- // This annotation helps race detectors recognize correct lock-less
- // synchronization between different threads calling get().
- // See the corresponding HAPPENS_AFTER below and above.
- ANNOTATE_HAPPENS_BEFORE(&instance_);
// Releases the visibility over instance_ to the readers.
base::subtle::Release_Store(
&instance_, reinterpret_cast<base::subtle::AtomicWord>(newval));
@@ -267,8 +260,6 @@
// We hit a race. Wait for the other thread to complete it.
value = base::internal::WaitForInstance(&instance_);
- // See the corresponding HAPPENS_BEFORE above.
- ANNOTATE_HAPPENS_AFTER(&instance_);
return reinterpret_cast<Type*>(value);
}
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
index 4e600f9..8e5360b 100644
--- a/base/process/process_win.cc
+++ b/base/process/process_win.cc
@@ -6,6 +6,7 @@
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "base/metrics/field_trial.h"
#include "base/process/kill.h"
#include "base/win/windows_version.h"
@@ -165,7 +166,21 @@
priority = value ? PROCESS_MODE_BACKGROUND_BEGIN :
PROCESS_MODE_BACKGROUND_END;
} else {
- priority = value ? BELOW_NORMAL_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS;
+ // Experiment (http://crbug.com/458594) with using IDLE_PRIORITY_CLASS as a
+ // background priority for background renderers (this code path is
+ // technically for more than just the renderers but they're the only use
+ // case in practice and experimenting here direclty is thus easier -- plus
+ // it doesn't really hurt as above we already state our intent of using
+ // PROCESS_MODE_BACKGROUND_BEGIN if available which is essentially
+ // IDLE_PRIORITY_CLASS plus lowered IO priority). Enabled by default in the
+ // asbence of field trials to get coverage on the perf waterfall.
+ DWORD background_priority = IDLE_PRIORITY_CLASS;
+ base::FieldTrial* trial =
+ base::FieldTrialList::Find("BackgroundRendererProcesses");
+ if (trial && trial->group_name() == "AllowBelowNormalFromBrowser")
+ background_priority = BELOW_NORMAL_PRIORITY_CLASS;
+
+ priority = value ? background_priority : NORMAL_PRIORITY_CLASS;
}
return (::SetPriorityClass(Handle(), priority) != 0);
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
index b6c103d..a104831 100644
--- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
+++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -4,19 +4,20 @@
package org.chromium.base.test;
-import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.test.AndroidTestRunner;
import android.test.InstrumentationTestRunner;
import android.util.Log;
-import junit.framework.Test;
import junit.framework.TestCase;
-import junit.framework.TestSuite;
+import junit.framework.TestResult;
import org.chromium.base.test.util.MinAndroidSdkLevel;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* An Instrumentation test runner that checks SDK level for tests with specific requirements.
*/
@@ -24,40 +25,94 @@
private static final String TAG = "BaseInstrumentationTestRunner";
- @Override
- protected AndroidTestRunner getAndroidTestRunner() {
- return new BaseAndroidTestRunner(getContext());
+ /**
+ * An interface for classes that check whether a test case should be skipped.
+ */
+ public interface SkipCheck {
+ /**
+ * Checks whether the given test case should be skipped.
+ *
+ * @param testCase The test case to check.
+ * @return Whether the test case should be skipped.
+ */
+ public boolean shouldSkip(TestCase testCase);
}
/**
- * Skips tests that don't meet the requirements of the current device.
+ * A test result that can skip tests.
*/
- public class BaseAndroidTestRunner extends AndroidTestRunner {
- private final Context mContext;
+ public class SkippingTestResult extends TestResult {
- public BaseAndroidTestRunner(Context context) {
- mContext = context;
+ private final List<SkipCheck> mSkipChecks;
+
+ /**
+ * Creates an instance of SkippingTestResult.
+ */
+ public SkippingTestResult() {
+ mSkipChecks = new ArrayList<SkipCheck>();
+ }
+
+ /**
+ * Adds a check for whether a test should run.
+ *
+ * @param skipCheck The check to add.
+ */
+ public void addSkipCheck(SkipCheck skipCheck) {
+ mSkipChecks.add(skipCheck);
+ }
+
+ private boolean shouldSkip(final TestCase test) {
+ for (SkipCheck s : mSkipChecks) {
+ if (s.shouldSkip(test)) return true;
+ }
+ return false;
}
@Override
- public void setTest(Test test) {
- super.setTest(test);
- TestSuite revisedTestSuite = new TestSuite();
- for (TestCase testCase : this.getTestCases()) {
- Class<?> testClass = testCase.getClass();
- if (shouldSkip(testClass, testCase)) {
- revisedTestSuite.addTest(new SkippedTest(testCase));
- Bundle skipResult = new Bundle();
- skipResult.putBoolean("test_skipped", true);
- sendStatus(0, skipResult);
- } else {
- revisedTestSuite.addTest(testCase);
- }
- }
- super.setTest(revisedTestSuite);
- }
+ protected void run(final TestCase test) {
+ if (shouldSkip(test)) {
+ startTest(test);
- protected boolean shouldSkip(Class<?> testClass, TestCase testCase) {
+ Bundle skipResult = new Bundle();
+ skipResult.putString("class", test.getClass().getName());
+ skipResult.putString("test", test.getName());
+ skipResult.putBoolean("test_skipped", true);
+ sendStatus(0, skipResult);
+
+ endTest(test);
+ } else {
+ super.run(test);
+ }
+ }
+ }
+
+ @Override
+ protected AndroidTestRunner getAndroidTestRunner() {
+ return new AndroidTestRunner() {
+ @Override
+ protected TestResult createTestResult() {
+ SkippingTestResult r = new SkippingTestResult();
+ r.addSkipCheck(new MinAndroidSdkLevelSkipCheck());
+ return r;
+ }
+ };
+ }
+
+ /**
+ * Checks the device's SDK level against any specified minimum requirement.
+ */
+ public static class MinAndroidSdkLevelSkipCheck implements SkipCheck {
+
+ /**
+ * If {@link org.chromium.base.test.util.MinAndroidSdkLevel} is present, checks its value
+ * against the device's SDK level.
+ *
+ * @param testCase The test to check.
+ * @return true if the device's SDK level is below the specified minimum.
+ */
+ @Override
+ public boolean shouldSkip(TestCase testCase) {
+ Class<?> testClass = testCase.getClass();
if (testClass.isAnnotationPresent(MinAndroidSdkLevel.class)) {
MinAndroidSdkLevel v = testClass.getAnnotation(MinAndroidSdkLevel.class);
if (Build.VERSION.SDK_INT < v.value()) {
@@ -69,28 +124,6 @@
}
return false;
}
-
- protected Context getContext() {
- return mContext;
- }
}
- /**
- * Replaces a TestCase that should be skipped.
- */
- public static class SkippedTest extends TestCase {
-
- public SkippedTest(TestCase skipped) {
- super(skipped.getClass().getName() + "#" + skipped.getName());
- }
-
- @Override
- protected void runTest() throws Throwable {
- }
-
- @Override
- public String toString() {
- return "SKIPPED " + super.toString();
- }
- }
}
diff --git a/base/test/test_suite.cc b/base/test/test_suite.cc
index 903e93e..d40dd98 100644
--- a/base/test/test_suite.cc
+++ b/base/test/test_suite.cc
@@ -35,6 +35,14 @@
#endif // OS_IOS
#endif // OS_MACOSX
+#if !defined(OS_WIN)
+#include "base/i18n/rtl.h"
+#if !defined(OS_IOS)
+#include "base/strings/string_util.h"
+#include "third_party/icu/source/common/unicode/uloc.h"
+#endif
+#endif
+
#if defined(OS_ANDROID)
#include "base/test/test_support_android.h"
#endif
@@ -321,6 +329,22 @@
}
base::i18n::InitializeICU();
+ // On the Mac OS X command line, the default locale is *_POSIX. In Chromium,
+ // the locale is set via an OS X locale API and is never *_POSIX.
+ // Some tests (such as those involving word break iterator) will behave
+ // differently and fail if we use *POSIX locale. Setting it to en_US here
+ // does not affect tests that explicitly overrides the locale for testing.
+ // This can be an issue on all platforms other than Windows.
+ // TODO(jshin): Should we set the locale via an OS X locale API here?
+#if !defined(OS_WIN)
+#if defined(OS_IOS)
+ base::i18n::SetICUDefaultLocale("en_US");
+#else
+ std::string default_locale(uloc_getDefault());
+ if (EndsWith(default_locale, "POSIX", false))
+ base::i18n::SetICUDefaultLocale("en_US");
+#endif
+#endif
CatchMaybeTests();
ResetCommandLine();
diff --git a/base/time/time.h b/base/time/time.h
index 18de085..6d61861 100644
--- a/base/time/time.h
+++ b/base/time/time.h
@@ -178,6 +178,14 @@
return delta_ / a.delta_;
}
+ // Multiplicative computations with floats.
+ TimeDelta multiply_by(double a) const {
+ return TimeDelta(delta_ * a);
+ }
+ TimeDelta divide_by(double a) const {
+ return TimeDelta(delta_ / a);
+ }
+
// Defined below because it depends on the definition of the other classes.
Time operator+(Time t) const;
TimeTicks operator+(TimeTicks t) const;
diff --git a/base/time/time_unittest.cc b/base/time/time_unittest.cc
index fdac59d..6387ec7 100644
--- a/base/time/time_unittest.cc
+++ b/base/time/time_unittest.cc
@@ -867,6 +867,15 @@
TimeDelta::FromMicroseconds(min_int64_plus_two).magnitude());
}
+
+TEST(TimeDelta, multiply_by) {
+ double d = 0.5;
+ EXPECT_EQ(TimeDelta::FromMilliseconds(500),
+ TimeDelta::FromMilliseconds(1000).multiply_by(d));
+ EXPECT_EQ(TimeDelta::FromMilliseconds(2000),
+ TimeDelta::FromMilliseconds(1000).divide_by(d));
+}
+
TEST(TimeDeltaLogging, DCheckEqCompiles) {
DCHECK_EQ(TimeDelta(), TimeDelta());
}
diff --git a/base/trace_event/memory_dump_manager.cc b/base/trace_event/memory_dump_manager.cc
index bf631b3..c8be8f8 100644
--- a/base/trace_event/memory_dump_manager.cc
+++ b/base/trace_event/memory_dump_manager.cc
@@ -9,22 +9,15 @@
#include "base/compiler_specific.h"
#include "base/trace_event/memory_dump_provider.h"
#include "base/trace_event/process_memory_dump.h"
-
-// TODO(primiano): in a separate CL rename DeleteTraceLogForTesting into
-// something like base::internal::TeardownSingletonForTesting so we don't have
-// to add a new friend to singleton each time.
-class DeleteTraceLogForTesting {
- public:
- static void Delete() {
- Singleton<
- base::trace_event::MemoryDumpManager,
- LeakySingletonTraits<base::trace_event::MemoryDumpManager>>::OnExit(0);
- }
-};
+#include "base/trace_event/trace_event_argument.h"
namespace base {
namespace trace_event {
+namespace {
+MemoryDumpManager* g_instance_for_testing = nullptr;
+}
+
// TODO(primiano): this should be smarter and should do something similar to
// trace event synthetic delays.
const char MemoryDumpManager::kTraceCategory[] =
@@ -32,13 +25,16 @@
// static
MemoryDumpManager* MemoryDumpManager::GetInstance() {
+ if (g_instance_for_testing)
+ return g_instance_for_testing;
+
return Singleton<MemoryDumpManager,
LeakySingletonTraits<MemoryDumpManager>>::get();
}
// static
-void MemoryDumpManager::DeleteForTesting() {
- DeleteTraceLogForTesting::Delete();
+void MemoryDumpManager::SetInstanceForTesting(MemoryDumpManager* instance) {
+ g_instance_for_testing = instance;
}
MemoryDumpManager::MemoryDumpManager() : memory_tracing_enabled_(0) {
@@ -96,15 +92,14 @@
// Creates a dump point for the current process and appends it to the trace.
void MemoryDumpManager::CreateLocalDumpPoint() {
AutoLock lock(lock_);
- // TRACE_EVENT_* macros don't induce scoped_refptr type inference, hence we
- // need the base ConvertableToTraceFormat and the upcast below. The
- // alternative would be unnecessarily expensive (double Acquire/Release).
- scoped_refptr<ConvertableToTraceFormat> pmd(new ProcessMemoryDump());
+ scoped_ptr<ProcessMemoryDump> pmd(new ProcessMemoryDump());
for (MemoryDumpProvider* dump_provider : dump_providers_enabled_) {
- dump_provider->DumpInto(static_cast<ProcessMemoryDump*>(pmd.get()));
+ dump_provider->DumpInto(pmd.get());
}
+ scoped_refptr<TracedValue> value(new TracedValue());
+ pmd->AsValueInto(value.get());
// TODO(primiano): add the dump point to the trace at this point.
}
diff --git a/base/trace_event/memory_dump_manager.h b/base/trace_event/memory_dump_manager.h
index fbc71d5..1a22e61 100644
--- a/base/trace_event/memory_dump_manager.h
+++ b/base/trace_event/memory_dump_manager.h
@@ -50,17 +50,17 @@
void OnTraceLogDisabled() override;
private:
+ friend struct DefaultDeleter<MemoryDumpManager>; // For the testing instance.
friend struct DefaultSingletonTraits<MemoryDumpManager>;
friend class MemoryDumpManagerTest;
static const char kTraceCategory[];
+ static void SetInstanceForTesting(MemoryDumpManager* instance);
+
MemoryDumpManager();
virtual ~MemoryDumpManager();
- // Tears down the singleton instance.
- static void DeleteForTesting();
-
// Broadcasts the dump requests to the other processes.
void BroadcastDumpRequest();
diff --git a/base/trace_event/memory_dump_manager_unittest.cc b/base/trace_event/memory_dump_manager_unittest.cc
index b5337e9..1ba73e6 100644
--- a/base/trace_event/memory_dump_manager_unittest.cc
+++ b/base/trace_event/memory_dump_manager_unittest.cc
@@ -17,14 +17,16 @@
class MemoryDumpManagerTest : public testing::Test {
public:
void SetUp() override {
+ mdm_.reset(new MemoryDumpManager());
+ MemoryDumpManager::SetInstanceForTesting(mdm_.get());
+ ASSERT_EQ(mdm_, MemoryDumpManager::GetInstance());
MemoryDumpManager::GetInstance()->Initialize();
- mdm_ = MemoryDumpManager::GetInstance();
}
void TearDown() override {
- MemoryDumpManager::DeleteForTesting();
+ MemoryDumpManager::SetInstanceForTesting(nullptr);
+ mdm_.reset();
TraceLog::DeleteForTesting();
- mdm_ = NULL;
}
protected:
@@ -37,7 +39,7 @@
void DisableTracing() { TraceLog::GetInstance()->SetDisabled(); }
- MemoryDumpManager* mdm_;
+ scoped_ptr<MemoryDumpManager> mdm_;
private:
// We want our singleton torn down after each test.
diff --git a/base/trace_event/process_memory_dump.cc b/base/trace_event/process_memory_dump.cc
index 0a3e096..6da9132 100644
--- a/base/trace_event/process_memory_dump.cc
+++ b/base/trace_event/process_memory_dump.cc
@@ -4,25 +4,25 @@
#include "base/trace_event/process_memory_dump.h"
-#include "base/json/json_writer.h"
-#include "base/values.h"
+#include "base/trace_event/process_memory_totals.h"
+#include "base/trace_event/trace_event_argument.h"
namespace base {
namespace trace_event {
-ProcessMemoryDump::ProcessMemoryDump() {
+ProcessMemoryDump::ProcessMemoryDump() : has_process_totals_(false) {
}
ProcessMemoryDump::~ProcessMemoryDump() {
}
-void ProcessMemoryDump::AppendAsTraceFormat(std::string* out) const {
- // Build up the [dumper name] -> [serialized snapshot] JSON dictionary.
- DictionaryValue dict;
- std::string json_dict;
- // TODO(primiano): this will append here the actual dumps from the dumpers.
- base::JSONWriter::Write(&dict, &json_dict);
- *out += json_dict;
+void ProcessMemoryDump::AsValueInto(TracedValue* value) const {
+ // Build up the [dumper name] -> [value] dictionary.
+ if (has_process_totals_) {
+ value->BeginDictionary("process_totals");
+ process_totals_.AsValueInto(value);
+ value->EndDictionary();
+ }
}
} // namespace trace_event
diff --git a/base/trace_event/process_memory_dump.h b/base/trace_event/process_memory_dump.h
index ae42987..f70537b 100644
--- a/base/trace_event/process_memory_dump.h
+++ b/base/trace_event/process_memory_dump.h
@@ -6,27 +6,34 @@
#define BASE_TRACE_EVENT_PROCESS_MEMORY_DUMP_H_
#include "base/base_export.h"
-#include "base/basictypes.h"
-#include "base/trace_event/trace_event_impl.h"
+#include "base/trace_event/process_memory_totals.h"
namespace base {
namespace trace_event {
-// A container which holds the dumps produced by the MemoryDumpProvider(s)
-// for a specific process. ProcessMemoryDump is as a strongly typed container
-// which enforces the data model for each memory dump point.
-// At trace generation time (i.e. when AppendAsTraceFormat is called) the
-// ProcessMemoryDump will compose a key-value dictionary of the various dumps
-// obtained during at trace dump point time.
-class BASE_EXPORT ProcessMemoryDump : public ConvertableToTraceFormat {
+class ConvertableToTraceFormat;
+
+// ProcessMemoryDump is as a strongly typed container which enforces the data
+// model for each memory dump point and holds the dumps produced by the
+// MemoryDumpProvider(s) for a specific process.
+// At trace generation time (i.e. when AsValue() is called), ProcessMemoryDump
+// will compose a key-value dictionary of the various dumps obtained at trace
+// dump point time.
+class BASE_EXPORT ProcessMemoryDump {
public:
ProcessMemoryDump();
+ ~ProcessMemoryDump();
- // ConvertableToTraceFormat implementation.
- void AppendAsTraceFormat(std::string* out) const override;
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ ProcessMemoryTotals* process_totals() { return &process_totals_; }
+ bool has_process_totals() const { return has_process_totals_; }
+ void set_has_process_totals() { has_process_totals_ = true; }
private:
- ~ProcessMemoryDump() override;
+ ProcessMemoryTotals process_totals_;
+ bool has_process_totals_;
DISALLOW_COPY_AND_ASSIGN(ProcessMemoryDump);
};
diff --git a/base/trace_event/process_memory_totals.cc b/base/trace_event/process_memory_totals.cc
new file mode 100644
index 0000000..41ad788
--- /dev/null
+++ b/base/trace_event/process_memory_totals.cc
@@ -0,0 +1,17 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals.h"
+
+#include "base/trace_event/trace_event_argument.h"
+
+namespace base {
+namespace trace_event {
+
+void ProcessMemoryTotals::AsValueInto(TracedValue* value) const {
+ value->SetDouble("resident_set_bytes", resident_set_bytes_);
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/process_memory_totals.h b/base/trace_event/process_memory_totals.h
new file mode 100644
index 0000000..1c99152
--- /dev/null
+++ b/base/trace_event/process_memory_totals.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
+
+#include "base/base_export.h"
+#include "base/basictypes.h"
+
+namespace base {
+namespace trace_event {
+
+class TracedValue;
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotals {
+ public:
+ ProcessMemoryTotals() {}
+
+ // Called at trace generation time to populate the TracedValue.
+ void AsValueInto(TracedValue* value) const;
+
+ uint64 resident_set_bytes() const { return resident_set_bytes_; }
+ void set_resident_set_bytes(uint64 value) { resident_set_bytes_ = value; }
+
+ private:
+ uint64 resident_set_bytes_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotals);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_H_
diff --git a/base/trace_event/process_memory_totals_dump_provider.cc b/base/trace_event/process_memory_totals_dump_provider.cc
new file mode 100644
index 0000000..cda0ff1
--- /dev/null
+++ b/base/trace_event/process_memory_totals_dump_provider.cc
@@ -0,0 +1,53 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/process/process_metrics.h"
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+
+namespace base {
+namespace trace_event {
+
+// static
+uint64 ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+namespace {
+ProcessMetrics* CreateProcessMetricsForCurrentProcess() {
+#if !defined(OS_MACOSX) || defined(OS_IOS)
+ return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle());
+#else
+ return ProcessMetrics::CreateProcessMetrics(GetCurrentProcessHandle(), NULL);
+#endif
+}
+} // namespace
+
+// static
+ProcessMemoryTotalsDumpProvider*
+ProcessMemoryTotalsDumpProvider::GetInstance() {
+ return Singleton<
+ ProcessMemoryTotalsDumpProvider,
+ LeakySingletonTraits<ProcessMemoryTotalsDumpProvider>>::get();
+}
+
+ProcessMemoryTotalsDumpProvider::ProcessMemoryTotalsDumpProvider()
+ : process_metrics_(CreateProcessMetricsForCurrentProcess()) {
+}
+
+ProcessMemoryTotalsDumpProvider::~ProcessMemoryTotalsDumpProvider() {
+}
+
+// Called at trace dump point time. Creates a snapshot the memory counters for
+// the current process.
+void ProcessMemoryTotalsDumpProvider::DumpInto(ProcessMemoryDump* pmd) {
+ const uint64 rss_bytes = rss_bytes_for_testing
+ ? rss_bytes_for_testing
+ : process_metrics_->GetWorkingSetSize();
+ pmd->process_totals()->set_resident_set_bytes(rss_bytes);
+ pmd->set_has_process_totals();
+}
+
+} // namespace trace_event
+} // namespace base
diff --git a/base/trace_event/process_memory_totals_dump_provider.h b/base/trace_event/process_memory_totals_dump_provider.h
new file mode 100644
index 0000000..45917a8
--- /dev/null
+++ b/base/trace_event/process_memory_totals_dump_provider.h
@@ -0,0 +1,44 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+#define BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
+
+#include "base/gtest_prod_util.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/singleton.h"
+#include "base/trace_event/memory_dump_provider.h"
+
+namespace base {
+
+class ProcessMetrics;
+
+namespace trace_event {
+
+// Dump provider which collects process-wide memory stats.
+class BASE_EXPORT ProcessMemoryTotalsDumpProvider : public MemoryDumpProvider {
+ public:
+ static ProcessMemoryTotalsDumpProvider* GetInstance();
+
+ // MemoryDumpProvider implementation.
+ void DumpInto(ProcessMemoryDump* pmd) override;
+
+ private:
+ friend struct DefaultSingletonTraits<ProcessMemoryTotalsDumpProvider>;
+ FRIEND_TEST_ALL_PREFIXES(ProcessMemoryTotalsDumpProviderTest, DumpRSS);
+
+ static uint64 rss_bytes_for_testing;
+
+ ProcessMemoryTotalsDumpProvider();
+ ~ProcessMemoryTotalsDumpProvider() override;
+
+ scoped_ptr<ProcessMetrics> process_metrics_;
+
+ DISALLOW_COPY_AND_ASSIGN(ProcessMemoryTotalsDumpProvider);
+};
+
+} // namespace trace_event
+} // namespace base
+
+#endif // BASE_TRACE_EVENT_PROCESS_MEMORY_TOTALS_DUMP_PROVIDER_H_
diff --git a/base/trace_event/process_memory_totals_dump_provider_unittest.cc b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
new file mode 100644
index 0000000..4a60036
--- /dev/null
+++ b/base/trace_event/process_memory_totals_dump_provider_unittest.cc
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/trace_event/process_memory_totals_dump_provider.h"
+
+#include "base/trace_event/process_memory_dump.h"
+#include "base/trace_event/process_memory_totals.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace base {
+namespace trace_event {
+
+TEST(ProcessMemoryTotalsDumpProviderTest, DumpRSS) {
+ auto mdptp = ProcessMemoryTotalsDumpProvider::GetInstance();
+ scoped_ptr<ProcessMemoryDump> pmd_before(new ProcessMemoryDump());
+ scoped_ptr<ProcessMemoryDump> pmd_after(new ProcessMemoryDump());
+
+ ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 1024;
+ mdptp->DumpInto(pmd_before.get());
+
+ // Pretend that the RSS of the process increased of +1M.
+ const size_t kAllocSize = 1048576;
+ ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing += kAllocSize;
+
+ mdptp->DumpInto(pmd_after.get());
+
+ ProcessMemoryTotalsDumpProvider::rss_bytes_for_testing = 0;
+
+ ASSERT_TRUE(pmd_before->has_process_totals());
+ ASSERT_TRUE(pmd_after->has_process_totals());
+
+ const uint64 rss_before = pmd_before->process_totals()->resident_set_bytes();
+ const uint64 rss_after = pmd_after->process_totals()->resident_set_bytes();
+
+ EXPECT_NE(0U, rss_before);
+ EXPECT_NE(0U, rss_after);
+
+ EXPECT_EQ(rss_after - rss_before, kAllocSize);
+}
+
+} // namespace trace_Event
+} // namespace base
diff --git a/base/trace_event/trace_event_synthetic_delay.cc b/base/trace_event/trace_event_synthetic_delay.cc
index 4b957c3..bad79cc 100644
--- a/base/trace_event/trace_event_synthetic_delay.cc
+++ b/base/trace_event/trace_event_synthetic_delay.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/memory/singleton.h"
+#include "base/third_party/dynamic_annotations/dynamic_annotations.h"
#include "base/trace_event/trace_event_synthetic_delay.h"
namespace {
diff --git a/base/version.cc b/base/version.cc
index 6318b35..933356e 100644
--- a/base/version.cc
+++ b/base/version.cc
@@ -31,6 +31,8 @@
for (std::vector<std::string>::const_iterator it = numbers.begin();
it != numbers.end(); ++it) {
+ if (StartsWithASCII(*it, "+", false))
+ return false;
int num;
if (!StringToInt(*it, &num))
return false;
@@ -42,8 +44,8 @@
if (num > max)
return false;
- // This throws out things like +3, or 032.
- if (IntToString(num) != *it)
+ // This throws out leading zeros for the first item only.
+ if (it == numbers.begin() && IntToString(num) != *it)
return false;
parsed->push_back(static_cast<uint16>(num));
diff --git a/base/version_unittest.cc b/base/version_unittest.cc
index 3119c39..46d8255 100644
--- a/base/version_unittest.cc
+++ b/base/version_unittest.cc
@@ -41,16 +41,22 @@
{".", 0, false},
{" . ", 0, false},
{"0", 1, true},
+ {"0.", 0, false},
{"0.0", 2, true},
{"65537.0", 0, false},
{"-1.0", 0, false},
{"1.-1.0", 0, false},
+ {"1,--1.0", 0, false},
{"+1.0", 0, false},
{"1.+1.0", 0, false},
+ {"1+1.0", 0, false},
+ {"++1.0", 0, false},
{"1.0a", 0, false},
{"1.2.3.4.5.6.7.8.9.0", 10, true},
{"02.1", 0, false},
+ {"0.01", 2, true},
{"f.1", 0, false},
+ {"15.007.20011", 3, true},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
@@ -77,6 +83,7 @@
{"1.1", "1.0.1", 1},
{"1.0.0", "1.0", 0},
{"1.0.3", "1.0.20", -1},
+ {"11.0.10", "15.007.20011", -1},
};
for (size_t i = 0; i < arraysize(cases); ++i) {
Version lhs(cases[i].lhs);
diff --git a/base/win/pe_image.cc b/base/win/pe_image.cc
index 572b4d9..e226b6a 100644
--- a/base/win/pe_image.cc
+++ b/base/win/pe_image.cc
@@ -20,6 +20,9 @@
namespace {
+ // PdbInfo Signature
+ const DWORD kPdbInfoSignature = 'SDSR';
+
// Compare two strings byte by byte on an unsigned basis.
// if s1 == s2, return 0
// if s1 < s2, return negative
@@ -35,6 +38,12 @@
*reinterpret_cast<const unsigned char*>(s2));
}
+ struct PdbInfo {
+ DWORD Signature;
+ GUID Guid;
+ DWORD Age;
+ char PdbFileName[1];
+ };
} // namespace
// Callback used to enumerate imports. See EnumImportChunksFunction.
@@ -142,6 +151,36 @@
return ret;
}
+bool PEImage::GetDebugId(LPGUID guid, LPDWORD age) const {
+ if (NULL == guid || NULL == age) {
+ return false;
+ }
+
+ DWORD debug_directory_size =
+ GetImageDirectoryEntrySize(IMAGE_DIRECTORY_ENTRY_DEBUG);
+ PIMAGE_DEBUG_DIRECTORY debug_directory =
+ reinterpret_cast<PIMAGE_DEBUG_DIRECTORY>(
+ GetImageDirectoryEntryAddr(IMAGE_DIRECTORY_ENTRY_DEBUG));
+
+ size_t directory_count =
+ debug_directory_size / sizeof(IMAGE_DEBUG_DIRECTORY);
+
+ for (size_t index = 0; index < directory_count; ++index) {
+ if (debug_directory[index].Type == IMAGE_DEBUG_TYPE_CODEVIEW) {
+ PdbInfo* pdb_info = reinterpret_cast<PdbInfo*>(
+ RVAToAddr(debug_directory[index].AddressOfRawData));
+ if (pdb_info->Signature != kPdbInfoSignature) {
+ // Unsupported PdbInfo signature
+ return false;
+ }
+ *guid = pdb_info->Guid;
+ *age = pdb_info->Age;
+ return true;
+ }
+ }
+ return false;
+}
+
PDWORD PEImage::GetExportEntry(LPCSTR name) const {
PIMAGE_EXPORT_DIRECTORY exports = GetExportDirectory();
diff --git a/base/win/pe_image.h b/base/win/pe_image.h
index dde1b48..5cef537 100644
--- a/base/win/pe_image.h
+++ b/base/win/pe_image.h
@@ -132,6 +132,9 @@
// Returns the exports directory.
PIMAGE_EXPORT_DIRECTORY GetExportDirectory() const;
+ // Returns the debug id (guid+age).
+ bool GetDebugId(LPGUID guid, LPDWORD age) const;
+
// Returns a given export entry.
// Use: e = image.GetExportEntry(f);
// Pre: 'f' is either a zero terminated string or ordinal
diff --git a/base/win/pe_image_unittest.cc b/base/win/pe_image_unittest.cc
index 238c924..af4209b 100644
--- a/base/win/pe_image_unittest.cc
+++ b/base/win/pe_image_unittest.cc
@@ -267,5 +267,21 @@
FreeLibrary(module);
}
+// Test that we can get debug id out of a module.
+TEST(PEImageTest, GetDebugId) {
+ HMODULE module = LoadLibrary(L"advapi32.dll");
+ ASSERT_TRUE(NULL != module);
+
+ PEImage pe(module);
+ GUID guid = {0};
+ DWORD age = 0;
+ EXPECT_TRUE(pe.GetDebugId(&guid, &age));
+
+ GUID empty_guid = {0};
+ EXPECT_TRUE(!IsEqualGUID(empty_guid, guid));
+ EXPECT_NE(0U, age);
+ FreeLibrary(module);
+}
+
} // namespace win
} // namespace base
diff --git a/build/all.gyp b/build/all.gyp
index 93cac8c..8ad63b3 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -519,7 +519,6 @@
'target_name': 'chromium_builder_nacl_win_integration',
'type': 'none',
'dependencies': [
- 'chromium_builder_qa', # needed for pyauto
'chromium_builder_tests',
],
}, # target_name: chromium_builder_nacl_win_integration
@@ -636,42 +635,10 @@
],
}, # target_name: chromium_gpu_debug_builder
{
- 'target_name': 'chromium_builder_qa',
- 'type': 'none',
- 'dependencies': [
- '../chrome/chrome.gyp:chrome',
- # Dependencies of pyauto_functional tests.
- '../remoting/remoting.gyp:remoting_webapp',
- ],
- 'conditions': [
- ['OS=="mac"', {
- 'dependencies': [
- '../remoting/remoting.gyp:remoting_me2me_host_archive',
- ],
- }],
- ['OS=="win"', {
- 'dependencies': [
- '../chrome/chrome.gyp:crash_service',
- ],
- }],
- ['OS=="win" and target_arch=="ia32"', {
- 'dependencies': [
- '../chrome/chrome.gyp:crash_service_win64',
- ],
- }],
- ['OS=="win" and component != "shared_library" and wix_exists == "True" and sas_dll_exists == "True"', {
- 'dependencies': [
- '../remoting/remoting.gyp:remoting_host_installation',
- ],
- }],
- ],
- }, # target_name: chromium_builder_qa
- {
'target_name': 'chromium_builder_perf_av',
'type': 'none',
'dependencies': [
'blink_tests', # to run layout tests
- 'chromium_builder_qa', # needed for perf pyauto tests
],
}, # target_name: chromium_builder_perf_av
{
@@ -1093,10 +1060,6 @@
],
},
{
- 'target_name': 'chromium_builder_win_cf',
- 'type': 'none',
- },
- {
'target_name': 'chromium_builder_dbg_tsan_win',
'type': 'none',
'dependencies': [
diff --git a/build/android/android_exports.gyp b/build/android/android_exports.gyp
index c259eee..bf3424d 100644
--- a/build/android/android_exports.gyp
+++ b/build/android/android_exports.gyp
@@ -2,13 +2,20 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
+# This target is only used when android_webview_build==1 - it implements a
+# whitelist for exported symbols to minimise the binary size and prevent us
+# accidentally exposing things we don't mean to expose.
+
{
+ 'variables': {
+ 'android_linker_script%': '<(SHARED_INTERMEDIATE_DIR)/android_webview_export_whitelist.lst',
+ },
'targets': [
{
'target_name': 'android_exports',
'type': 'none',
'inputs': [
- '<(DEPTH)/build/android/android_exports.lst',
+ '<(DEPTH)/build/android/android_webview_export_whitelist.lst',
],
'outputs': [
'<(android_linker_script)',
@@ -28,9 +35,6 @@
# Only export symbols that are specified in version script.
'-Wl,--version-script=<(android_linker_script)',
],
- 'ldflags!': [
- '-Wl,--exclude-libs=ALL',
- ],
},
}],
],
diff --git a/build/android/android_no_jni_exports.lst b/build/android/android_no_jni_exports.lst
new file mode 100644
index 0000000..ffc6cf7
--- /dev/null
+++ b/build/android/android_no_jni_exports.lst
@@ -0,0 +1,17 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# This script makes all JNI exported symbols local, to prevent the JVM from
+# being able to find them, enforcing use of manual JNI function registration.
+# This is used for all Android binaries by default, unless they explicitly state
+# that they want JNI exported symbols to remain visible, as we need to ensure
+# the manual registration path is correct to maintain compatibility with the
+# crazy linker.
+# Check ld version script manual:
+# https://sourceware.org/binutils/docs-2.24/ld/VERSION.html#VERSION
+
+{
+ local:
+ Java_*;
+};
diff --git a/build/android/android_exports.lst b/build/android/android_webview_export_whitelist.lst
similarity index 72%
rename from build/android/android_exports.lst
rename to build/android/android_webview_export_whitelist.lst
index 6eee232..2a56a75 100644
--- a/build/android/android_exports.lst
+++ b/build/android/android_webview_export_whitelist.lst
@@ -2,7 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-# Default exports specification for chromium shared libraries on android.
+# Exports specification for android_webview_build==1, which uses a whitelist to
+# enforce only specific symbols being exported.
# Check ld version script manual:
# https://sourceware.org/binutils/docs-2.24/ld/VERSION.html#VERSION
diff --git a/build/android/buildbot/bb_device_status_check.py b/build/android/buildbot/bb_device_status_check.py
index 6de2723..3bec158 100755
--- a/build/android/buildbot/bb_device_status_check.py
+++ b/build/android/buildbot/bb_device_status_check.py
@@ -337,11 +337,12 @@
zip(*[DeviceInfo(dev, options) for dev in devices]))
# Write device info to file for buildbot info display.
- with open('/home/chrome-bot/.adb_device_info', 'w') as f:
- for device in json_data:
- f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'],
- device['build'], float(device['battery']['temperature']) / 10,
- device['battery']['level']))
+ if os.path.exists('/home/chrome-bot'):
+ with open('/home/chrome-bot/.adb_device_info', 'w') as f:
+ for device in json_data:
+ f.write('%s %s %s %.1fC %s%%\n' % (device['serial'], device['type'],
+ device['build'], float(device['battery']['temperature']) / 10,
+ device['battery']['level']))
err_msg = CheckForMissingDevices(options, devices) or []
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index 09c12b2..9afba51 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -5,3 +5,4 @@
M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.webContents In PendingDocumentData.java
M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.originalIntent In PendingDocumentData.java
M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.url In PendingDocumentData.java
+M D UuF: Unused public or protected field: org.chromium.chrome.browser.document.PendingDocumentData.requestId In PendingDocumentData.java
diff --git a/build/android/provision_devices.py b/build/android/provision_devices.py
index 65054fe..824e642 100755
--- a/build/android/provision_devices.py
+++ b/build/android/provision_devices.py
@@ -178,7 +178,7 @@
if options.disable_network:
device_settings.ConfigureContentSettings(
device, device_settings.NETWORK_DISABLED_SETTINGS)
- if options.wait_for_battery:
+ if options.min_battery_level is not None:
try:
battery_info = device.old_interface.GetBatteryInfo()
except Exception as e:
@@ -241,24 +241,11 @@
logging.getLogger().addHandler(custom_handler)
logging.getLogger().setLevel(logging.INFO)
- # TODO(perezju): This script used to rely on the builder name to determine
- # the desired device configuration for perf bots. To safely phase this out,
- # we now:
- # - expose these configuration settings as command line options
- # - set default values for these options based on the builder name, thus
- # matching the previous behaviour of the script on all bots.
- # - explicitly adding these options on the perf bots will also maintain the
- # script behaviour, namely:
- # --wait-for-battery --disable-network --disable-java-debug
- # - after all perf-bot recipes are updated, we can remove the following
- # builder-name-sniffing code and replace |is_perf| with |False|.
- is_perf = 'perf' in os.environ.get('BUILDBOT_BUILDERNAME', '').lower()
-
# Recommended options on perf bots:
# --disable-network
# TODO(tonyg): We eventually want network on. However, currently radios
# can cause perfbots to drain faster than they charge.
- # --wait-for-battery
+ # --min-battery-level 95
# Some perf bots run benchmarks with USB charging disabled which leads
# to gradual draining of the battery. We must wait for a full charge
# before starting a run in order to keep the devices online.
@@ -274,20 +261,15 @@
help='when wiping the device, max number of seconds to'
' wait after each reboot '
'(default: %s)' % _DEFAULT_TIMEOUTS.HELP_TEXT)
- parser.add_argument('--wait-for-battery', action='store_true',
- default=is_perf,
- help='wait for the battery on the devices to charge')
- parser.add_argument('--min-battery-level', default=95, type=int,
- metavar='NUM',
- help='when waiting for battery, minimum battery level'
- ' required to continue (default: %(default)s)')
+ parser.add_argument('--min-battery-level', type=int, metavar='NUM',
+ help='wait for the device to reach this minimum battery'
+ ' level before trying to continue')
parser.add_argument('--disable-location', action='store_true',
help='disable Google location services on devices')
parser.add_argument('--disable-network', action='store_true',
- default=is_perf,
help='disable network access on devices')
parser.add_argument('--disable-java-debug', action='store_false',
- dest='enable_java_debug', default=not is_perf,
+ dest='enable_java_debug', default=True,
help='disable Java property asserts and JNI checking')
parser.add_argument('-t', '--target', default='Debug',
help='the build target (default: %(default)s)')
diff --git a/build/android/pylib/base/base_test_result.py b/build/android/pylib/base/base_test_result.py
index 508b988..58200f6 100644
--- a/build/android/pylib/base/base_test_result.py
+++ b/build/android/pylib/base/base_test_result.py
@@ -77,6 +77,10 @@
"""Get the test duration."""
return self._duration
+ def SetLog(self, log):
+ """Set the test log."""
+ self._log = log
+
def GetLog(self):
"""Get the test log."""
return self._log
diff --git a/build/android/pylib/device/adb_wrapper.py b/build/android/pylib/device/adb_wrapper.py
index f29f5c7..c954508 100644
--- a/build/android/pylib/device/adb_wrapper.py
+++ b/build/android/pylib/device/adb_wrapper.py
@@ -299,14 +299,14 @@
cmd, 'path does not specify an accessible directory in the device',
device_serial=self._device_serial)
- def Logcat(self, clear=False, dump=False, filter_spec=None,
+ def Logcat(self, clear=False, dump=False, filter_specs=None,
logcat_format=None, timeout=None, retries=_DEFAULT_RETRIES):
"""Get an iterable over the logcat output.
Args:
clear: If true, clear the logcat.
dump: If true, dump the current logcat contents.
- filter_spec: If set, spec to filter the logcat.
+ filter_specs: If set, a list of specs to filter the logcat.
logcat_format: If set, the format in which the logcat should be output.
Options include "brief", "process", "tag", "thread", "raw", "time",
"threadtime", and "long"
@@ -328,14 +328,14 @@
use_iter = False
if logcat_format:
cmd.extend(['-v', logcat_format])
- if filter_spec is not None:
- cmd.append(filter_spec)
+ if filter_specs:
+ cmd.extend(filter_specs)
if use_iter:
return self._IterRunDeviceAdbCmd(cmd, timeout)
else:
timeout = timeout if timeout is not None else _DEFAULT_TIMEOUT
- return self._RunDeviceAdbCmd(cmd, timeout, retries)
+ return self._RunDeviceAdbCmd(cmd, timeout, retries).splitlines()
def Forward(self, local, remote, timeout=_DEFAULT_TIMEOUT,
retries=_DEFAULT_RETRIES):
diff --git a/build/android/pylib/device/device_utils.py b/build/android/pylib/device/device_utils.py
index eba5e02..fb882e7 100644
--- a/build/android/pylib/device/device_utils.py
+++ b/build/android/pylib/device/device_utils.py
@@ -8,6 +8,8 @@
"""
# pylint: disable=unused-argument
+import collections
+import itertools
import logging
import multiprocessing
import os
@@ -1306,14 +1308,54 @@
retries: number of retries
Returns:
- A 2-tuple containing:
- - A dict containing the overall memory usage statistics for the PID.
- - A dict containing memory usage statistics broken down by mapping.
+ A dict containing memory usage statistics for the PID. May include:
+ Size, Rss, Pss, Shared_Clean, Shared_Dirty, Private_Clean,
+ Private_Dirty, VmHWM
Raises:
CommandTimeoutError on timeout.
"""
- return self.old_interface.GetMemoryUsageForPid(pid)
+ result = collections.defaultdict(int)
+
+ try:
+ result.update(self._GetMemoryUsageForPidFromSmaps(pid))
+ except device_errors.CommandFailedError:
+ logging.exception('Error getting memory usage from smaps')
+
+ try:
+ result.update(self._GetMemoryUsageForPidFromStatus(pid))
+ except device_errors.CommandFailedError:
+ logging.exception('Error getting memory usage from status')
+
+ return result
+
+ def _GetMemoryUsageForPidFromSmaps(self, pid):
+ SMAPS_COLUMNS = (
+ 'Size', 'Rss', 'Pss', 'Shared_Clean', 'Shared_Dirty', 'Private_Clean',
+ 'Private_Dirty')
+
+ showmap_out = self.RunShellCommand(
+ ['showmap', str(pid)], as_root=True, check_return=True)
+ if not showmap_out:
+ raise device_errors.CommandFailedError('No output from showmap')
+
+ split_totals = showmap_out[-1].split()
+ if (not split_totals
+ or len(split_totals) != 9
+ or split_totals[-1] != 'TOTAL'):
+ raise device_errors.CommandFailedError(
+ 'Invalid output from showmap: %s' % '\n'.join(showmap_out))
+
+ return dict(itertools.izip(SMAPS_COLUMNS, (int(n) for n in split_totals)))
+
+ def _GetMemoryUsageForPidFromStatus(self, pid):
+ for line in self.ReadFile(
+ '/proc/%s/status' % str(pid), as_root=True).splitlines():
+ if line.startswith('VmHWM:'):
+ return {'VmHWM': int(line.split()[1])}
+ else:
+ raise device_errors.CommandFailedError(
+ 'Could not find memory peak value for pid %s', str(pid))
@decorators.WithTimeoutAndRetriesFromInstance()
def GetLogcatMonitor(self, timeout=None, retries=None, *args, **kwargs):
@@ -1386,6 +1428,8 @@
"""
if not devices:
devices = adb_wrapper.AdbWrapper.GetDevices()
+ if not devices:
+ raise device_errors.NoDevicesError()
devices = [d if isinstance(d, cls) else cls(d) for d in devices]
if async:
return parallelizer.Parallelizer(devices)
diff --git a/build/android/pylib/device/device_utils_test.py b/build/android/pylib/device/device_utils_test.py
index 8a25f25..3f4ef59 100755
--- a/build/android/pylib/device/device_utils_test.py
+++ b/build/android/pylib/device/device_utils_test.py
@@ -39,7 +39,7 @@
import mock # pylint: disable=F0401
-class DeviceUtilsTest(unittest.TestCase):
+class DeviceUtilsInitTest(unittest.TestCase):
def testInitWithStr(self):
serial_as_str = str('0123456789abcdef')
@@ -121,79 +121,6 @@
self.mocked = mocked
-class DeviceUtilsOldImplTest(unittest.TestCase):
-
- class AndroidCommandsCalls(object):
-
- def __init__(self, test_case, cmd_ret, comp):
- self._cmds = cmd_ret
- self._comp = comp
- self._run_command = _PatchedFunction()
- self._test_case = test_case
- self._total_received = 0
-
- def __enter__(self):
- self._run_command.patched = mock.patch(
- 'run_command.RunCommand',
- side_effect=lambda c, **kw: self._ret(c))
- self._run_command.mocked = self._run_command.patched.__enter__()
-
- def _ret(self, actual_cmd):
- if sys.exc_info()[0] is None:
- on_failure_fmt = ('\n'
- ' received command: %s\n'
- ' expected command: %s')
- self._test_case.assertGreater(
- len(self._cmds), self._total_received,
- msg=on_failure_fmt % (actual_cmd, None))
- expected_cmd, ret = self._cmds[self._total_received]
- self._total_received += 1
- self._test_case.assertTrue(
- self._comp(expected_cmd, actual_cmd),
- msg=on_failure_fmt % (actual_cmd, expected_cmd))
- return ret
- return ''
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self._run_command.patched.__exit__(exc_type, exc_val, exc_tb)
- if exc_type is None:
- on_failure = "adb commands don't match.\nExpected:%s\nActual:%s" % (
- ''.join('\n %s' % c for c, _ in self._cmds),
- ''.join('\n %s' % a[0]
- for _, a, kw in self._run_command.mocked.mock_calls))
- self._test_case.assertEqual(
- len(self._cmds), len(self._run_command.mocked.mock_calls),
- msg=on_failure)
- for (expected_cmd, _r), (_n, actual_args, actual_kwargs) in zip(
- self._cmds, self._run_command.mocked.mock_calls):
- self._test_case.assertEqual(1, len(actual_args), msg=on_failure)
- self._test_case.assertTrue(self._comp(expected_cmd, actual_args[0]),
- msg=on_failure)
- self._test_case.assertTrue('timeout_time' in actual_kwargs,
- msg=on_failure)
- self._test_case.assertTrue('retry_count' in actual_kwargs,
- msg=on_failure)
-
- def assertNoAdbCalls(self):
- return type(self).AndroidCommandsCalls(self, [], str.__eq__)
-
- def assertCalls(self, cmd, ret, comp=str.__eq__):
- return type(self).AndroidCommandsCalls(self, [(cmd, ret)], comp)
-
- def assertCallsSequence(self, cmd_ret, comp=str.__eq__):
- return type(self).AndroidCommandsCalls(self, cmd_ret, comp)
-
- def setUp(self):
- self._get_adb_path_patch = mock.patch('pylib.constants.GetAdbPath',
- mock.Mock(return_value='adb'))
- self._get_adb_path_patch.start()
- self.device = device_utils.DeviceUtils(
- '0123456789abcdef', default_timeout=1, default_retries=0)
-
- def tearDown(self):
- self._get_adb_path_patch.stop()
-
-
def _AdbWrapperMock(test_serial):
adb = mock.Mock(spec=adb_wrapper.AdbWrapper)
adb.__str__ = mock.Mock(return_value=test_serial)
@@ -201,7 +128,7 @@
return adb
-class DeviceUtilsNewImplTest(mock_calls.TestCase):
+class DeviceUtilsTest(mock_calls.TestCase):
def setUp(self):
self.adb = _AdbWrapperMock('0123456789abcdef')
@@ -230,7 +157,7 @@
msg, str(self.device)))
-class DeviceUtilsIsOnlineTest(DeviceUtilsNewImplTest):
+class DeviceUtilsIsOnlineTest(DeviceUtilsTest):
def testIsOnline_true(self):
with self.assertCall(self.call.adb.GetState(), 'device'):
@@ -245,7 +172,7 @@
self.assertFalse(self.device.IsOnline())
-class DeviceUtilsHasRootTest(DeviceUtilsNewImplTest):
+class DeviceUtilsHasRootTest(DeviceUtilsTest):
def testHasRoot_true(self):
with self.assertCall(self.call.adb.Shell('ls /root'), 'foo\n'):
@@ -256,7 +183,7 @@
self.assertFalse(self.device.HasRoot())
-class DeviceUtilsEnableRootTest(DeviceUtilsNewImplTest):
+class DeviceUtilsEnableRootTest(DeviceUtilsTest):
def testEnableRoot_succeeds(self):
with self.assertCalls(
@@ -279,7 +206,7 @@
self.device.EnableRoot()
-class DeviceUtilsIsUserBuildTest(DeviceUtilsNewImplTest):
+class DeviceUtilsIsUserBuildTest(DeviceUtilsTest):
def testIsUserBuild_yes(self):
with self.assertCall(
@@ -292,7 +219,7 @@
self.assertFalse(self.device.IsUserBuild())
-class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsNewImplTest):
+class DeviceUtilsGetExternalStoragePathTest(DeviceUtilsTest):
def testGetExternalStoragePath_succeeds(self):
with self.assertCall(
@@ -306,7 +233,7 @@
self.device.GetExternalStoragePath()
-class DeviceUtilsGetApplicationPathTest(DeviceUtilsNewImplTest):
+class DeviceUtilsGetApplicationPathTest(DeviceUtilsTest):
def testGetApplicationPath_exists(self):
with self.assertCalls(
@@ -333,7 +260,7 @@
@mock.patch('time.sleep', mock.Mock())
-class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsNewImplTest):
+class DeviceUtilsWaitUntilFullyBootedTest(DeviceUtilsTest):
def testWaitUntilFullyBooted_succeedsNoWifi(self):
with self.assertCalls(
@@ -443,7 +370,7 @@
@mock.patch('time.sleep', mock.Mock())
-class DeviceUtilsRebootTest(DeviceUtilsNewImplTest):
+class DeviceUtilsRebootTest(DeviceUtilsTest):
def testReboot_nonBlocking(self):
with self.assertCalls(
@@ -469,7 +396,7 @@
self.device.Reboot(block=True, wifi=True)
-class DeviceUtilsInstallTest(DeviceUtilsNewImplTest):
+class DeviceUtilsInstallTest(DeviceUtilsTest):
def testInstall_noPriorInstall(self):
with self.assertCalls(
@@ -526,7 +453,7 @@
self.device.Install('/fake/test/app.apk', retries=0)
-class DeviceUtilsRunShellCommandTest(DeviceUtilsNewImplTest):
+class DeviceUtilsRunShellCommandTest(DeviceUtilsTest):
def setUp(self):
super(DeviceUtilsRunShellCommandTest, self).setUp()
@@ -656,7 +583,7 @@
self.device.RunShellCommand(cmd, check_return=False))
-class DeviceUtilsGetDevicePieWrapper(DeviceUtilsNewImplTest):
+class DeviceUtilsGetDevicePieWrapper(DeviceUtilsTest):
def testGetDevicePieWrapper_jb(self):
with self.assertCall(
@@ -675,7 +602,7 @@
@mock.patch('time.sleep', mock.Mock())
-class DeviceUtilsKillAllTest(DeviceUtilsNewImplTest):
+class DeviceUtilsKillAllTest(DeviceUtilsTest):
def testKillAll_noMatchingProcesses(self):
with self.assertCall(self.call.adb.Shell('ps'),
@@ -726,7 +653,7 @@
self.device.KillAll('some.process', signum=signal.SIGTERM))
-class DeviceUtilsStartActivityTest(DeviceUtilsNewImplTest):
+class DeviceUtilsStartActivityTest(DeviceUtilsTest):
def testStartActivity_actionOnly(self):
test_intent = intent.Intent(action='android.intent.action.VIEW')
@@ -890,7 +817,7 @@
self.device.StartActivity(test_intent)
-class DeviceUtilsStartInstrumentationTest(DeviceUtilsNewImplTest):
+class DeviceUtilsStartInstrumentationTest(DeviceUtilsTest):
def testStartInstrumentation_nothing(self):
with self.assertCalls(
@@ -932,7 +859,7 @@
finish=False, raw=False, extras={'foo': 'Foo', 'bar': 'Bar'})
-class DeviceUtilsBroadcastIntentTest(DeviceUtilsNewImplTest):
+class DeviceUtilsBroadcastIntentTest(DeviceUtilsTest):
def testBroadcastIntent_noExtras(self):
test_intent = intent.Intent(action='test.package.with.an.INTENT')
@@ -960,7 +887,7 @@
self.device.BroadcastIntent(test_intent)
-class DeviceUtilsGoHomeTest(DeviceUtilsNewImplTest):
+class DeviceUtilsGoHomeTest(DeviceUtilsTest):
def testGoHome(self):
with self.assertCall(
@@ -970,7 +897,7 @@
self.device.GoHome()
-class DeviceUtilsForceStopTest(DeviceUtilsNewImplTest):
+class DeviceUtilsForceStopTest(DeviceUtilsTest):
def testForceStop(self):
with self.assertCall(
@@ -979,7 +906,7 @@
self.device.ForceStop('this.is.a.test.package')
-class DeviceUtilsClearApplicationStateTest(DeviceUtilsNewImplTest):
+class DeviceUtilsClearApplicationStateTest(DeviceUtilsTest):
def testClearApplicationState_packageDoesntExist(self):
with self.assertCalls(
@@ -1012,14 +939,14 @@
self.device.ClearApplicationState('this.package.exists')
-class DeviceUtilsSendKeyEventTest(DeviceUtilsNewImplTest):
+class DeviceUtilsSendKeyEventTest(DeviceUtilsTest):
def testSendKeyEvent(self):
with self.assertCall(self.call.adb.Shell('input keyevent 66'), ''):
self.device.SendKeyEvent(66)
-class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsNewImplTest):
+class DeviceUtilsPushChangedFilesIndividuallyTest(DeviceUtilsTest):
def testPushChangedFilesIndividually_empty(self):
test_files = []
@@ -1041,7 +968,7 @@
self.device._PushChangedFilesIndividually(test_files)
-class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsNewImplTest):
+class DeviceUtilsPushChangedFilesZippedTest(DeviceUtilsTest):
def testPushChangedFilesZipped_empty(self):
test_files = []
@@ -1080,7 +1007,7 @@
('/test/host/path/file2', '/test/device/path/file2')])
-class DeviceUtilsFileExistsTest(DeviceUtilsNewImplTest):
+class DeviceUtilsFileExistsTest(DeviceUtilsTest):
def testFileExists_usingTest_fileExists(self):
with self.assertCall(
@@ -1096,7 +1023,7 @@
self.assertFalse(self.device.FileExists('/does/not/exist'))
-class DeviceUtilsPullFileTest(DeviceUtilsNewImplTest):
+class DeviceUtilsPullFileTest(DeviceUtilsTest):
def testPullFile_existsOnDevice(self):
with mock.patch('os.path.exists', return_value=True):
@@ -1117,7 +1044,7 @@
'/test/file/host/path')
-class DeviceUtilsReadFileTest(DeviceUtilsNewImplTest):
+class DeviceUtilsReadFileTest(DeviceUtilsTest):
def testReadFile_exists(self):
with self.assertCall(
@@ -1145,7 +1072,7 @@
as_root=True))
-class DeviceUtilsWriteFileTest(DeviceUtilsNewImplTest):
+class DeviceUtilsWriteFileTest(DeviceUtilsTest):
def testWriteFileWithPush_success(self):
tmp_host = MockTempFile('/tmp/file/on.host')
@@ -1208,7 +1135,7 @@
self.device.WriteFile('/test/file', 'contents', as_root=True)
-class DeviceUtilsLsTest(DeviceUtilsNewImplTest):
+class DeviceUtilsLsTest(DeviceUtilsTest):
def testLs_directory(self):
result = [('.', adb_wrapper.DeviceStat(16889, 4096, 1417436123)),
@@ -1226,7 +1153,7 @@
self.device.Ls('/data/local/tmp/testfile.txt'))
-class DeviceUtilsStatTest(DeviceUtilsNewImplTest):
+class DeviceUtilsStatTest(DeviceUtilsTest):
def testStat_file(self):
result = [('.', adb_wrapper.DeviceStat(16889, 4096, 1417436123)),
@@ -1256,7 +1183,7 @@
self.device.Stat('/data/local/tmp/does.not.exist.txt')
-class DeviceUtilsSetJavaAssertsTest(DeviceUtilsNewImplTest):
+class DeviceUtilsSetJavaAssertsTest(DeviceUtilsTest):
def testSetJavaAsserts_enable(self):
with self.assertCalls(
@@ -1296,7 +1223,7 @@
self.assertFalse(self.device.SetJavaAsserts(True))
-class DeviceUtilsGetPropTest(DeviceUtilsNewImplTest):
+class DeviceUtilsGetPropTest(DeviceUtilsTest):
def testGetProp_exists(self):
with self.assertCall(
@@ -1330,7 +1257,7 @@
cache=True, retries=3))
-class DeviceUtilsSetPropTest(DeviceUtilsNewImplTest):
+class DeviceUtilsSetPropTest(DeviceUtilsTest):
def testSetProp(self):
with self.assertCall(
@@ -1351,7 +1278,7 @@
self.device.SetProp('test.property', 'new_value', check=True)
-class DeviceUtilsGetPidsTest(DeviceUtilsNewImplTest):
+class DeviceUtilsGetPidsTest(DeviceUtilsTest):
def testGetPids_noMatches(self):
with self.assertCall(self.call.adb.Shell('ps'),
@@ -1387,7 +1314,7 @@
self.device.GetPids('exact.match'))
-class DeviceUtilsTakeScreenshotTest(DeviceUtilsNewImplTest):
+class DeviceUtilsTakeScreenshotTest(DeviceUtilsTest):
def testTakeScreenshot_fileNameProvided(self):
with self.assertCalls(
@@ -1401,22 +1328,18 @@
self.device.TakeScreenshot('/test/host/screenshot.png')
-class DeviceUtilsGetMemoryUsageForPidTest(DeviceUtilsOldImplTest):
+class DeviceUtilsGetMemoryUsageForPidTest(DeviceUtilsTest):
def setUp(self):
super(DeviceUtilsGetMemoryUsageForPidTest, self).setUp()
- self.device.old_interface._privileged_command_runner = (
- self.device.old_interface.RunShellCommand)
- self.device.old_interface._protected_file_access_method_initialized = True
def testGetMemoryUsageForPid_validPid(self):
- with self.assertCallsSequence([
- ("adb -s 0123456789abcdef shell 'showmap 1234'",
- '100 101 102 103 104 105 106 107 TOTAL\r\n'),
- ("adb -s 0123456789abcdef shell "
- "'cat \"/proc/1234/status\" 2> /dev/null'",
- 'VmHWM: 1024 kB')
- ]):
+ with self.assertCalls(
+ (self.call.device.RunShellCommand(
+ ['showmap', '1234'], as_root=True, check_return=True),
+ ['100 101 102 103 104 105 106 107 TOTAL']),
+ (self.call.device.ReadFile('/proc/1234/status', as_root=True),
+ 'VmHWM: 1024 kB\n')):
self.assertEqual(
{
'Size': 100,
@@ -1430,14 +1353,36 @@
},
self.device.GetMemoryUsageForPid(1234))
- def testGetMemoryUsageForPid_invalidPid(self):
+ def testGetMemoryUsageForPid_noSmaps(self):
with self.assertCalls(
- "adb -s 0123456789abcdef shell 'showmap 4321'",
- 'cannot open /proc/4321/smaps: No such file or directory\r\n'):
- self.assertEqual({}, self.device.GetMemoryUsageForPid(4321))
+ (self.call.device.RunShellCommand(
+ ['showmap', '4321'], as_root=True, check_return=True),
+ ['cannot open /proc/4321/smaps: No such file or directory']),
+ (self.call.device.ReadFile('/proc/4321/status', as_root=True),
+ 'VmHWM: 1024 kb\n')):
+ self.assertEquals({'VmHWM': 1024}, self.device.GetMemoryUsageForPid(4321))
+
+ def testGetMemoryUsageForPid_noStatus(self):
+ with self.assertCalls(
+ (self.call.device.RunShellCommand(
+ ['showmap', '4321'], as_root=True, check_return=True),
+ ['100 101 102 103 104 105 106 107 TOTAL']),
+ (self.call.device.ReadFile('/proc/4321/status', as_root=True),
+ self.CommandError())):
+ self.assertEquals(
+ {
+ 'Size': 100,
+ 'Rss': 101,
+ 'Pss': 102,
+ 'Shared_Clean': 103,
+ 'Shared_Dirty': 104,
+ 'Private_Clean': 105,
+ 'Private_Dirty': 106,
+ },
+ self.device.GetMemoryUsageForPid(4321))
-class DeviceUtilsStrTest(DeviceUtilsNewImplTest):
+class DeviceUtilsStrTest(DeviceUtilsTest):
def testStr_returnsSerial(self):
with self.assertCalls(
@@ -1459,6 +1404,12 @@
and serial == str(device),
'Expected a DeviceUtils object with serial %s' % serial)
+ def testParallel_noDevices(self):
+ with self.assertCall(
+ mock.call.pylib.device.adb_wrapper.AdbWrapper.GetDevices(), []):
+ with self.assertRaises(device_errors.NoDevicesError):
+ device_utils.DeviceUtils.parallel()
+
if __name__ == '__main__':
logging.getLogger().setLevel(logging.DEBUG)
diff --git a/build/android/pylib/device/logcat_monitor.py b/build/android/pylib/device/logcat_monitor.py
index 7ede49c..1d4cc24 100644
--- a/build/android/pylib/device/logcat_monitor.py
+++ b/build/android/pylib/device/logcat_monitor.py
@@ -22,18 +22,20 @@
# Format: <DATE> <TIME> <PID> <TID> <LEVEL> <COMPONENT>: <MESSAGE>
_THREADTIME_RE_FORMAT = r'\S* +\S* +(%s) +(%s) +(%s) +(%s): +(%s)$'
- def __init__(self, adb, clear=True):
+ def __init__(self, adb, clear=True, filter_specs=None):
"""Create a LogcatMonitor instance.
Args:
adb: An instance of adb_wrapper.AdbWrapper.
clear: If True, clear the logcat when monitoring starts.
+ filter_specs: An optional list of '<tag>[:priority]' strings.
"""
if isinstance(adb, adb_wrapper.AdbWrapper):
self._adb = adb
else:
raise ValueError('Unsupported type passed for argument "device"')
self._clear = clear
+ self._filter_specs = filter_specs
self._logcat_out = None
self._logcat_out_file = None
self._logcat_proc = None
@@ -76,7 +78,7 @@
# returned.
# - failure_regex matches a line, in which case None is returned
# - the timeout is hit, in which case a CommandTimeoutError is raised.
- for l in self._adb.Logcat():
+ for l in self._adb.Logcat(filter_specs=self._filter_specs):
m = success_regex.search(l)
if m:
return m
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance.py b/build/android/pylib/instrumentation/instrumentation_test_instance.py
index 45e6ee4..3f56e6d 100644
--- a/build/android/pylib/instrumentation/instrumentation_test_instance.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance.py
@@ -23,6 +23,10 @@
os.path.join(constants.DIR_SOURCE_ROOT, 'build', 'util', 'lib', 'common'))
import unittest_util
+# Ref: http://developer.android.com/reference/android/app/Activity.html
+_ACTIVITY_RESULT_CANCELED = 0
+_ACTIVITY_RESULT_OK = -1
+
_DEFAULT_ANNOTATIONS = [
'Smoke', 'SmallTest', 'MediumTest', 'LargeTest',
'EnormousTest', 'IntegrationTest']
@@ -54,48 +58,69 @@
return (code, bundle, statuses)
-def GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms):
- """Generate the result of |test| from |instr_statuses|.
+def GenerateTestResults(
+ result_code, result_bundle, statuses, start_ms, duration_ms):
+ """Generate test results from |statuses|.
Args:
- test_name: The name of the test as "class#method"
- instr_statuses: A list of 2-tuples containing:
+ result_code: The overall status code as an integer.
+ result_bundle: The summary bundle dump as a dict.
+ statuses: A list of 2-tuples containing:
- the status code as an integer
- the bundle dump as a dict mapping string keys to string values
Note that this is the same as the third item in the 3-tuple returned by
|_ParseAmInstrumentRawOutput|.
start_ms: The start time of the test in milliseconds.
duration_ms: The duration of the test in milliseconds.
+
Returns:
- An InstrumentationTestResult object.
+ A list containing an instance of InstrumentationTestResult for each test
+ parsed.
"""
- log = ''
- result_type = base_test_result.ResultType.UNKNOWN
- for status_code, bundle in instr_statuses:
- if status_code == instrumentation_parser.STATUS_CODE_START:
- pass
- elif status_code == instrumentation_parser.STATUS_CODE_OK:
- bundle_test = '%s#%s' % (bundle.get('class', ''), bundle.get('test', ''))
- skipped = bundle.get('test_skipped', '')
+ results = []
- if (test_name == bundle_test and
- result_type == base_test_result.ResultType.UNKNOWN):
- result_type = base_test_result.ResultType.PASS
- elif skipped.lower() in ('true', '1', 'yes'):
- result_type = base_test_result.ResultType.SKIP
- logging.info('Skipped ' + test_name)
+ current_result = None
+
+ for status_code, bundle in statuses:
+ test_class = bundle.get('class', '')
+ test_method = bundle.get('test', '')
+ if test_class and test_method:
+ test_name = '%s#%s' % (test_class, test_method)
else:
- if status_code not in (instrumentation_parser.STATUS_CODE_ERROR,
- instrumentation_parser.STATUS_CODE_FAILURE):
- logging.error('Unrecognized status code %d. Handling as an error.',
- status_code)
- result_type = base_test_result.ResultType.FAIL
- if 'stack' in bundle:
- log = bundle['stack']
+ continue
- return test_result.InstrumentationTestResult(
- test_name, result_type, start_ms, duration_ms, log=log)
+ if status_code == instrumentation_parser.STATUS_CODE_START:
+ if current_result:
+ results.append(current_result)
+ current_result = test_result.InstrumentationTestResult(
+ test_name, base_test_result.ResultType.UNKNOWN, start_ms, duration_ms)
+ else:
+ if status_code == instrumentation_parser.STATUS_CODE_OK:
+ if bundle.get('test_skipped', '').lower() in ('true', '1', 'yes'):
+ current_result.SetType(base_test_result.ResultType.SKIP)
+ elif current_result.GetType() == base_test_result.ResultType.UNKNOWN:
+ current_result.SetType(base_test_result.ResultType.PASS)
+ else:
+ if status_code not in (instrumentation_parser.STATUS_CODE_ERROR,
+ instrumentation_parser.STATUS_CODE_FAILURE):
+ logging.error('Unrecognized status code %d. Handling as an error.',
+ status_code)
+ current_result.SetType(base_test_result.ResultType.FAIL)
+ if 'stack' in bundle:
+ current_result.SetLog(bundle['stack'])
+
+ if current_result:
+ if current_result.GetType() == base_test_result.ResultType.UNKNOWN:
+ crashed = (result_code == _ACTIVITY_RESULT_CANCELED
+ and any(_NATIVE_CRASH_RE.search(l)
+ for l in result_bundle.itervalues()))
+ if crashed:
+ current_result.SetType(base_test_result.ResultType.CRASH)
+
+ results.append(current_result)
+
+ return results
class InstrumentationTestInstance(test_instance.TestInstance):
@@ -421,37 +446,14 @@
return inflated_tests
@staticmethod
- def GenerateMultiTestResult(errors, statuses):
- results = []
- skip_counter = 1
- for status_code, bundle in statuses:
- if status_code != instrumentation_parser.STATUS_CODE_START:
- # TODO(rnephew): Make skipped tests still output test name. This is only
- # there to give skipped tests a unique name so they are counted
- if 'test_skipped' in bundle:
- test_name = str(skip_counter)
- skip_counter += 1
- else:
- test_name = '%s#%s' % (bundle.get('class', ''),
- bundle.get('test', ''))
-
- results.append(
- GenerateTestResult(test_name, [(status_code, bundle)], 0, 0))
- for error in errors.itervalues():
- if _NATIVE_CRASH_RE.search(error):
- results.append(
- base_test_result.BaseTestResult(
- 'Crash detected', base_test_result.ResultType.CRASH))
-
- return results
-
- @staticmethod
def ParseAmInstrumentRawOutput(raw_output):
return ParseAmInstrumentRawOutput(raw_output)
@staticmethod
- def GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms):
- return GenerateTestResult(test_name, instr_statuses, start_ms, duration_ms)
+ def GenerateTestResults(
+ result_code, result_bundle, statuses, start_ms, duration_ms):
+ return GenerateTestResults(result_code, result_bundle, statuses,
+ start_ms, duration_ms)
#override
def TearDown(self):
diff --git a/build/android/pylib/instrumentation/instrumentation_test_instance_test.py b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
index 693f175..752e4d3 100755
--- a/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
+++ b/build/android/pylib/instrumentation/instrumentation_test_instance_test.py
@@ -27,15 +27,12 @@
options = mock.Mock()
options.tool = ''
- def testGenerateTestResult_noStatus(self):
- result = instrumentation_test_instance.GenerateTestResult(
- 'test.package.TestClass#testMethod', [], 0, 1000)
- self.assertEqual('test.package.TestClass#testMethod', result.GetName())
- self.assertEqual(base_test_result.ResultType.UNKNOWN, result.GetType())
- self.assertEqual('', result.GetLog())
- self.assertEqual(1000, result.GetDuration())
+ def testGenerateTestResults_noStatus(self):
+ results = instrumentation_test_instance.GenerateTestResults(
+ None, None, [], 0, 1000)
+ self.assertEqual([], results)
- def testGenerateTestResult_testPassed(self):
+ def testGenerateTestResults_testPassed(self):
statuses = [
(1, {
'class': 'test.package.TestClass',
@@ -46,65 +43,52 @@
'test': 'testMethod',
}),
]
- result = instrumentation_test_instance.GenerateTestResult(
- 'test.package.TestClass#testMethod', statuses, 0, 1000)
- self.assertEqual(base_test_result.ResultType.PASS, result.GetType())
+ results = instrumentation_test_instance.GenerateTestResults(
+ None, None, statuses, 0, 1000)
+ self.assertEqual(1, len(results))
+ self.assertEqual(base_test_result.ResultType.PASS, results[0].GetType())
- def testGenerateTestResult_testSkipped_first(self):
- statuses = [
- (0, {
- 'test_skipped': 'true',
- }),
- (1, {
- 'class': 'test.package.TestClass',
- 'test': 'testMethod',
- }),
- (0, {
- 'class': 'test.package.TestClass',
- 'test': 'testMethod',
- }),
- ]
- result = instrumentation_test_instance.GenerateTestResult(
- 'test.package.TestClass#testMethod', statuses, 0, 1000)
- self.assertEqual(base_test_result.ResultType.SKIP, result.GetType())
-
- def testGenerateTestResult_testSkipped_last(self):
+ def testGenerateTestResults_testSkipped_true(self):
statuses = [
(1, {
'class': 'test.package.TestClass',
'test': 'testMethod',
}),
(0, {
- 'class': 'test.package.TestClass',
- 'test': 'testMethod',
- }),
- (0, {
'test_skipped': 'true',
+ 'class': 'test.package.TestClass',
+ 'test': 'testMethod',
+ }),
+ (0, {
+ 'class': 'test.package.TestClass',
+ 'test': 'testMethod',
}),
]
- result = instrumentation_test_instance.GenerateTestResult(
- 'test.package.TestClass#testMethod', statuses, 0, 1000)
- self.assertEqual(base_test_result.ResultType.SKIP, result.GetType())
+ results = instrumentation_test_instance.GenerateTestResults(
+ None, None, statuses, 0, 1000)
+ self.assertEqual(1, len(results))
+ self.assertEqual(base_test_result.ResultType.SKIP, results[0].GetType())
- def testGenerateTestResult_testSkipped_false(self):
+ def testGenerateTestResults_testSkipped_false(self):
statuses = [
+ (1, {
+ 'class': 'test.package.TestClass',
+ 'test': 'testMethod',
+ }),
(0, {
'test_skipped': 'false',
}),
- (1, {
- 'class': 'test.package.TestClass',
- 'test': 'testMethod',
- }),
(0, {
'class': 'test.package.TestClass',
'test': 'testMethod',
}),
]
- result = instrumentation_test_instance.GenerateTestResult(
- 'test.package.TestClass#testMethod', statuses, 0, 1000)
- self.assertEqual(base_test_result.ResultType.PASS, result.GetType())
+ results = instrumentation_test_instance.GenerateTestResults(
+ None, None, statuses, 0, 1000)
+ self.assertEqual(1, len(results))
+ self.assertEqual(base_test_result.ResultType.PASS, results[0].GetType())
- def testGenerateTestResult_testFailed(self):
+ def testGenerateTestResults_testFailed(self):
statuses = [
(1, {
'class': 'test.package.TestClass',
@@ -115,9 +99,10 @@
'test': 'testMethod',
}),
]
- result = instrumentation_test_instance.GenerateTestResult(
- 'test.package.TestClass#testMethod', statuses, 0, 1000)
- self.assertEqual(base_test_result.ResultType.FAIL, result.GetType())
+ results = instrumentation_test_instance.GenerateTestResults(
+ None, None, statuses, 0, 1000)
+ self.assertEqual(1, len(results))
+ self.assertEqual(base_test_result.ResultType.FAIL, results[0].GetType())
if __name__ == '__main__':
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py
index 5f095a5..f3983fd 100644
--- a/build/android/pylib/instrumentation/test_runner.py
+++ b/build/android/pylib/instrumentation/test_runner.py
@@ -320,9 +320,16 @@
'%s/%s' % (self.test_pkg.GetPackageName(), self.options.test_runner),
raw=True, extras=extras, timeout=timeout, retries=3)
- def _GenerateTestResult(self, test, instr_statuses, start_ms, duration_ms):
- return instrumentation_test_instance.GenerateTestResult(
- test, instr_statuses, start_ms, duration_ms)
+ def _GenerateTestResult(self, test, instr_result_code, instr_result_bundle,
+ statuses, start_ms, duration_ms):
+ results = instrumentation_test_instance.GenerateTestResults(
+ instr_result_code, instr_result_bundle, statuses, start_ms, duration_ms)
+ for r in results:
+ if r.GetName() == test:
+ return r
+ logging.error('Could not find result for test: %s', test)
+ return test_result.InstrumentationTestResult(
+ test, base_test_result.ResultType.UNKNOWN, start_ms, duration_ms)
#override
def RunTest(self, test):
@@ -345,9 +352,10 @@
duration_ms = time_ms() - start_ms
# Parse the test output
- _, _, statuses = (
+ result_code, result_bundle, statuses = (
instrumentation_test_instance.ParseAmInstrumentRawOutput(raw_output))
- result = self._GenerateTestResult(test, statuses, start_ms, duration_ms)
+ result = self._GenerateTestResult(
+ test, result_code, result_bundle, statuses, start_ms, duration_ms)
if local_device_instrumentation_test_run.DidPackageCrashOnDevice(
self.test_pkg.GetPackageName(), self.device):
result.SetType(base_test_result.ResultType.CRASH)
diff --git a/build/android/pylib/linker/test_case.py b/build/android/pylib/linker/test_case.py
index 8ebf803..c7b0f50 100644
--- a/build/android/pylib/linker/test_case.py
+++ b/build/android/pylib/linker/test_case.py
@@ -123,7 +123,7 @@
"""
# 1. Start recording logcat with appropriate filters.
- with device.GetLogcatMonitor(filters=_LOGCAT_FILTERS) as logmon:
+ with device.GetLogcatMonitor(filter_specs=_LOGCAT_FILTERS) as logmon:
# 2. Force-start activity.
device.StartActivity(
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
index 2ed16ee..ac3f5b1 100644
--- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py
+++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -124,16 +124,19 @@
# TODO(jbudorick): Make instrumentation tests output a JSON so this
# doesn't have to parse the output.
- logging.info('output from %s:' % test_name)
+ logging.debug('output from %s:', test_name)
for l in output:
- logging.info(' %s' % l)
+ logging.debug(' %s', l)
- _, _, statuses = self._test_instance.ParseAmInstrumentRawOutput(output)
- result = self._test_instance.GenerateTestResult(
- test_name, statuses, start_ms, duration_ms)
+ result_code, result_bundle, statuses = (
+ self._test_instance.ParseAmInstrumentRawOutput(output))
+ results = self._test_instance.GenerateTestResults(
+ result_code, result_bundle, statuses, start_ms, duration_ms)
if DidPackageCrashOnDevice(self._test_instance.test_package, device):
- result.SetType(base_test_result.ResultType.CRASH)
- return result
+ for r in results:
+ if r.GetType() == base_test_result.ResultType.UNKNOWN:
+ r.SetType(base_test_result.ResultType.CRASH)
+ return results
#override
def _ShouldShard(self):
diff --git a/build/android/pylib/local/device/local_device_test_run.py b/build/android/pylib/local/device/local_device_test_run.py
index 8c322cb..fa24eb1 100644
--- a/build/android/pylib/local/device/local_device_test_run.py
+++ b/build/android/pylib/local/device/local_device_test_run.py
@@ -70,10 +70,11 @@
if unknown_tests:
results.AddResults(
base_test_result.BaseTestResult(
- t, base_test_result.ResultType.UNKNOWN)
- for t in tests)
+ u, base_test_result.ResultType.UNKNOWN)
+ for u in unknown_tests)
if failed_tests:
results.AddResults(all_fail_results[f] for f in failed_tests)
+
return results
def GetTool(self, device):
diff --git a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
index 5138d46..709a30c 100644
--- a/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
+++ b/build/android/pylib/remote/device/remote_device_instrumentation_test_run.py
@@ -40,10 +40,11 @@
base_test_result.ResultType.FAIL))
return r
- _, errors, parsed_output = self._test_instance.ParseAmInstrumentRawOutput(
- self._results['results']['output'].splitlines())
- logging.debug(errors)
- result = self._test_instance.GenerateMultiTestResult(errors, parsed_output)
+ result_code, result_bundle, statuses = (
+ self._test_instance.ParseAmInstrumentRawOutput(
+ self._results['results']['output'].splitlines()))
+ result = self._test_instance.GenerateTestResults(
+ result_code, result_bundle, statuses, 0, 0)
if isinstance(result, base_test_result.BaseTestResult):
r.AddResult(result)
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
index 02f5d6a..d7a4bdf 100644
--- a/build/android/pylib/uiautomator/test_runner.py
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -79,8 +79,11 @@
return self.device.RunShellCommand(cmd, timeout=timeout, retries=0)
#override
- def _GenerateTestResult(self, test, instr_statuses, start_ms, duration_ms):
+ def _GenerateTestResult(self, test, _result_code, _result_bundle, statuses,
+ start_ms, duration_ms):
# uiautomator emits its summary status with INSTRUMENTATION_STATUS_CODE,
# not INSTRUMENTATION_CODE, so we have to drop if off the list of statuses.
+ summary_code, summary_bundle = statuses[-1]
return super(TestRunner, self)._GenerateTestResult(
- test, instr_statuses[:-1], start_ms, duration_ms)
+ test, summary_code, summary_bundle, statuses[:-1], start_ms,
+ duration_ms)
diff --git a/build/common.gypi b/build/common.gypi
index 3a071c8..55dad68 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -584,9 +584,6 @@
# If no directory is specified then a temporary directory will be used.
'test_isolation_outdir%': '',
- # True if isolate should fail if the isolate files refer to files
- # that are missing.
- 'test_isolation_fail_on_missing': 1,
'wix_path%': '<(DEPTH)/third_party/wix',
@@ -630,6 +627,9 @@
# Enable LTO on code compiled with -O2.
'use_lto_o2%': 0,
+ # Allowed level of identical code folding in the gold linker.
+ 'gold_icf_level%': 'safe',
+
# Libxkbcommon usage.
'use_xkbcommon%': 0,
@@ -1157,7 +1157,6 @@
'use_canvas_skia%': '<(use_canvas_skia)',
'test_isolation_mode%': '<(test_isolation_mode)',
'test_isolation_outdir%': '<(test_isolation_outdir)',
- 'test_isolation_fail_on_missing': '<(test_isolation_fail_on_missing)',
'enable_basic_printing%': '<(enable_basic_printing)',
'enable_print_preview%': '<(enable_print_preview)',
'enable_spellcheck%': '<(enable_spellcheck)',
@@ -1199,6 +1198,7 @@
'gomadir%': '<(gomadir)',
'use_lto%': '<(use_lto)',
'use_lto_o2%': '<(use_lto_o2)',
+ 'gold_icf_level%': '<(gold_icf_level)',
'video_hole%': '<(video_hole)',
'support_pre_M6_history_database%': '<(support_pre_M6_history_database)',
'v8_use_external_startup_data%': '<(v8_use_external_startup_data)',
@@ -1802,9 +1802,6 @@
# Copy it out one scope.
'android_webview_build%': '<(android_webview_build)',
-
- # Default android linker script for shared library exports.
- 'android_linker_script%': '<(SHARED_INTERMEDIATE_DIR)/android_exports.lst',
}], # OS=="android"
['embedded==1', {
'use_system_fontconfig%': 0,
@@ -1831,7 +1828,6 @@
'jni_generator_jarjar_file': '../android_webview/build/jarjar-rules.txt',
}],
['OS=="linux" and target_arch!="mipsel"', {
- # TODO(thakis): This is here to measure perf for a while.
'clang%': 1,
}], # OS=="mac"
['OS=="mac"', {
@@ -2144,23 +2140,13 @@
'clang_chrome_plugins_flags': [
'<!@(<(DEPTH)/tools/clang/scripts/plugin_flags.sh)'
],
- 'conditions': [
- # TODO(dcheng): https://crbug.com/417463 -- work to enable this flag
- # on all platforms is currently underway.
- ['OS=="android" or OS=="linux" or OS=="mac" or OS=="ios"', {
- 'clang_chrome_plugins_flags': [
- '-Xclang',
- '-plugin-arg-find-bad-constructs',
- '-Xclang',
- 'strict-virtual-specifiers',
- ],
- }],
- ],
}],
['asan==1 or msan==1 or lsan==1 or tsan==1', {
'clang%': 1,
'use_allocator%': 'none',
'use_sanitizer_options%': 1,
+ # Disable ICF in the linker to avoid debug info loss.
+ 'gold_icf_level%': 'none',
}],
['asan==1 and OS=="linux" and chromeos==0', {
'use_custom_libcxx%': 1,
@@ -2475,6 +2461,14 @@
'-Wno-unnamed-type-template-args',
],
+ # By default, Android targets have their exported JNI symbols stripped,
+ # so we test the manual JNI registration code paths that are required
+ # when using the crazy linker. To allow use of native JNI exports (lazily
+ # resolved by the JVM), targets can enable this variable, which will stop
+ # the stripping from happening. Only targets which do not need to be
+ # compatible with the crazy linker are permitted to set this.
+ 'use_native_jni_exports%': 0,
+
'conditions': [
['OS=="win" and component=="shared_library"', {
# See http://msdn.microsoft.com/en-us/library/aa652367.aspx
@@ -3517,7 +3511,7 @@
],
},
}],
- # TODO(thakis): Enable this everywhere. http://crbug.com/371125
+ # -Wl,-z,-defs doesn't work with the sanitiziers, http://crbug.com/452065
['(OS=="linux" or OS=="android") and asan==0 and msan==0 and tsan==0 and ubsan==0 and ubsan_vptr==0', {
'target_defaults': {
'ldflags': [
@@ -4414,7 +4408,7 @@
'target_conditions': [
['_toolset=="target"', {
'ldflags': [
- '-Wl,--icf=safe',
+ '-Wl,--icf=<(gold_icf_level)',
],
}],
],
@@ -4594,9 +4588,15 @@
'-Wl,--no-undefined',
],
'conditions': [
- ['component=="static_library"', {
- 'ldflags': [
- '-Wl,--exclude-libs=ALL',
+ ['component=="static_library" and android_webview_build==0', {
+ 'target_conditions': [
+ ['use_native_jni_exports==0', {
+ # Use a linker version script to strip JNI exports from
+ # binaries which have not specifically asked to use them.
+ 'ldflags': [
+ '-Wl,--version-script=<!(cd <(DEPTH) && pwd -P)/build/android/android_no_jni_exports.lst',
+ ],
+ }],
],
}],
['clang==1', {
@@ -4656,6 +4656,20 @@
'ldflags': [
'--sysroot=<(android_ndk_sysroot)',
'-nostdlib',
+ # Don't allow visible symbols from libgcc or stlport to be
+ # re-exported.
+ '-Wl,--exclude-libs=libgcc.a',
+ '-Wl,--exclude-libs=libstlport_static.a',
+ # Don't allow visible symbols from libraries that contain
+ # assembly code with symbols that aren't hidden properly.
+ # http://crbug.com/448386
+ '-Wl,--exclude-libs=libcommon_audio.a',
+ '-Wl,--exclude-libs=libcommon_audio_neon.a',
+ '-Wl,--exclude-libs=libcommon_audio_sse2.a',
+ '-Wl,--exclude-libs=libiSACFix.a',
+ '-Wl,--exclude-libs=libisac_neon.a',
+ '-Wl,--exclude-libs=libopus.a',
+ '-Wl,--exclude-libs=libvpx.a',
],
'libraries': [
'-l<(android_stlport_library)',
@@ -4712,7 +4726,7 @@
['target_arch == "arm" and order_profiling==0', {
'ldflags': [
# Enable identical code folding to reduce size.
- '-Wl,--icf=safe',
+ '-Wl,--icf=<(gold_icf_level)',
],
}],
# NOTE: The stlport header include paths below are specified in
@@ -4772,9 +4786,6 @@
],
}],
['_type=="shared_library" or _type=="loadable_module"', {
- 'ldflags!': [
- '-Wl,--exclude-libs=ALL',
- ],
'ldflags': [
'-Wl,-shared,-Bsymbolic',
],
diff --git a/build/compiled_action.gni b/build/compiled_action.gni
index e5059aa..b6d0c4d 100644
--- a/build/compiled_action.gni
+++ b/build/compiled_action.gni
@@ -66,7 +66,7 @@
# saves unnecessarily compiling your tool for the target platform. But if you
# need a target build of your tool as well, just leave off the if statement.
-if (build_os == "win") {
+if (host_os == "win") {
_host_executable_suffix = ".exe"
} else {
_host_executable_suffix = ""
diff --git a/build/config/BUILD.gn b/build/config/BUILD.gn
index 5f93dd9..49b5cfe 100644
--- a/build/config/BUILD.gn
+++ b/build/config/BUILD.gn
@@ -231,7 +231,7 @@
# have to tell it to turn it off.
defines += [ "_HAS_ITERATOR_DEBUGGING=0" ]
}
- } else if (is_linux && !is_android && cpu_arch == "x64" &&
+ } else if (is_linux && !is_android && current_cpu == "x64" &&
!disable_iterator_debugging) {
# Enable libstdc++ debugging facilities to help catch problems early, see
# http://crbug.com/65151 .
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index d806a17..cd10730 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -16,7 +16,53 @@
# KEEP IN ALPHABETICAL ORDER and write a good description for everything.
# Use "is_*" names for intrinsic platform descriptions and build modes, and
# "use_*" names for optional features libraries, and configurations.
+
+# TODO(dpranke): The os and cpu_arch variables exist for backwards
+# compatibility and should be deleted once all of the build files and
+# bots have been updated to use current_cpu/target_cpu and
+# current_os/target_os instead.
+
+if (target_os == "") {
+ if (defined(os)) {
+ # If os is defined, it was set in an args file and needs to be
+ # used for backwards-compatibility.
+ target_os = os
+ } else {
+ target_os = host_os
+ }
+}
+
+if (target_cpu == "") {
+ if (defined(cpu_arch)) {
+ # If cpu_arch is defined, it was set in an args file and needs to be
+ # used for backwards-compatibility.
+ target_cpu = cpu_arch
+ } else if (target_os == "android") {
+ # If we're building for Android, we should assume that we want to
+ # build for ARM by default, not the host_cpu (which is likely x64).
+ # This allows us to not have to specify both target_os and target_cpu
+ # on the command line.
+ target_cpu = "arm"
+ } else {
+ target_cpu = host_cpu
+ }
+}
+
+if (current_cpu == "") {
+ current_cpu = target_cpu
+}
+if (current_os == "") {
+ current_os = target_os
+}
+
declare_args() {
+ # TODO(dpranke): These values are here for backwards compatibility and
+ # should be deleted when all of the builders and configs have been updated.
+ cpu_arch = target_cpu
+ os = target_os
+ build_cpu_arch = host_cpu
+ build_os = host_os
+
# How many symbols to include in the build. This affects the performance of
# the build since the symbols are large and dealing with them is slow.
# 2 means regular build with symbols.
@@ -32,11 +78,12 @@
is_debug = true
# Whether we're a traditional desktop unix.
- is_desktop_linux = os == "linux" && os != "chromeos"
+ is_desktop_linux = current_os == "linux" && current_os != "chromeos"
# Set to true when compiling with the Clang compiler. Typically this is used
# to configure warnings.
- is_clang = os == "mac" || os == "ios" || os == "linux" || os == "chromeos"
+ is_clang = current_os == "mac" || current_os == "ios" ||
+ current_os == "linux" || current_os == "chromeos"
# Selects the desired build flavor. Official builds get additional
# processing to prepare for release. Normally you will want to develop and
@@ -60,29 +107,22 @@
# Compile for Thread Sanitizer to find threading bugs.
is_tsan = false
- if (os == "chromeos") {
+ if (current_os == "chromeos") {
# Allows the target toolchain to be injected as arguments. This is needed
# to support the CrOS build system which supports per-build-configuration
# toolchains.
cros_use_custom_toolchain = false
}
- # TODO(cjhopman): Make target_arch work for all platforms.
-
- # Architecture of the target device. For Android builds, this will be equal to
- # the cpu_arch of the default toolchain. When checking the CPU architecture
- # for source files and build dependencies you should almost alway use cpu_arch
- # instead. cpu_arch is the architecture of the current toolchain and allows
- # cross-compiles (compiling the same target for multiple toolchains in the
- # same build) to work.
- target_arch = "arm"
-
# TODO(brettw) remove this flag (and therefore enable linking all targets) on
# Windows when we have sufficient bot capacity. In the meantime, you can
# enable linking for local compiles.
link_chrome_on_windows = true
}
+# TODO(dpranke): Remove these asserts when os and cpu_arch are removed.
+assert(current_os == os)
+
# =============================================================================
# OS DEFINITIONS
# =============================================================================
@@ -98,10 +138,10 @@
# generally too different despite being based on the Linux kernel).
#
# Do not add more is_* variants here for random lesser-used Unix systems like
-# aix or one of the BSDs. If you need to check these, just check the os value
-# directly.
+# aix or one of the BSDs. If you need to check these, just check the
+# current_os value directly.
-if (os == "win") {
+if (current_os == "win") {
is_android = false
is_chromeos = false
is_ios = false
@@ -110,7 +150,7 @@
is_nacl = false
is_posix = false
is_win = true
-} else if (os == "mac") {
+} else if (current_os == "mac") {
is_android = false
is_chromeos = false
is_ios = false
@@ -119,7 +159,7 @@
is_nacl = false
is_posix = true
is_win = false
-} else if (os == "android") {
+} else if (current_os == "android") {
is_android = true
is_chromeos = false
is_ios = false
@@ -128,7 +168,7 @@
is_nacl = false
is_posix = true
is_win = false
-} else if (os == "chromeos") {
+} else if (current_os == "chromeos") {
is_android = false
is_chromeos = true
is_ios = false
@@ -137,9 +177,10 @@
is_nacl = false
is_posix = true
is_win = false
-} else if (os == "nacl") {
- # os == "nacl" will be passed by the nacl toolchain definition. It is not
- # set by default or on the command line. We treat is as a Posix variant.
+} else if (current_os == "nacl") {
+ # current_os == "nacl" will be passed by the nacl toolchain definition.
+ # It is not set by default or on the command line. We treat is as a
+ # Posix variant.
is_android = false
is_chromeos = false
is_ios = false
@@ -148,7 +189,7 @@
is_nacl = true
is_posix = true
is_win = false
-} else if (os == "ios") {
+} else if (current_os == "ios") {
is_android = false
is_chromeos = false
is_ios = true
@@ -157,7 +198,7 @@
is_nacl = false
is_posix = true
is_win = false
-} else if (os == "linux") {
+} else if (current_os == "linux") {
is_android = false
is_chromeos = false
is_ios = false
@@ -169,18 +210,6 @@
}
# =============================================================================
-# CPU ARCHITECTURE
-# =============================================================================
-
-if (is_android) {
- # TODO(cjhopman): enable this assert once bots are updated to not set
- # cpu_arch.
- #assert(cpu_arch == build_cpu_arch, "Android device target architecture should
- # be set with 'target_arch', not 'cpu_arch'")
- cpu_arch = target_arch
-}
-
-# =============================================================================
# SOURCES FILTERS
# =============================================================================
#
@@ -441,6 +470,11 @@
_shared_library_configs += _windows_linker_configs
} else if (is_mac) {
_shared_library_configs += [ "//build/config/mac:mac_dynamic_flags" ]
+} else if (is_android) {
+ # Strip native JNI exports from shared libraries by default. Binaries that
+ # want this can remove this config.
+ _shared_library_configs +=
+ [ "//build/config/android:hide_native_jni_exports" ]
}
set_defaults("shared_library") {
configs = _shared_library_configs
@@ -481,28 +515,28 @@
if (is_win) {
# On windows we use the same toolchain for host and target by default.
- # TODO(dpranke): rename the toolchains to x64 and x86 to match cpu_arch.
- if (cpu_arch == "x64") {
+ # TODO(dpranke): rename the toolchains to x64 and x86 to match current_cpu.
+ if (current_cpu == "x64") {
host_toolchain = "//build/toolchain/win:64"
- } else if (cpu_arch == "x86") {
+ } else if (current_cpu == "x86") {
host_toolchain = "//build/toolchain/win:32"
}
set_default_toolchain("$host_toolchain")
} else if (is_android) {
# Use clang for the x86/64 Linux host builds.
- if (build_cpu_arch == "x86" || build_cpu_arch == "x64") {
- host_toolchain = "//build/toolchain/linux:clang_$build_cpu_arch"
+ if (host_cpu == "x86" || host_cpu == "x64") {
+ host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
} else {
- host_toolchain = "//build/toolchain/linux:$build_cpu_arch"
+ host_toolchain = "//build/toolchain/linux:$host_cpu"
}
- set_default_toolchain("//build/toolchain/android:$cpu_arch")
+ set_default_toolchain("//build/toolchain/android:$current_cpu")
} else if (is_linux) {
if (is_clang) {
- host_toolchain = "//build/toolchain/linux:clang_$build_cpu_arch"
- set_default_toolchain("//build/toolchain/linux:clang_$cpu_arch")
+ host_toolchain = "//build/toolchain/linux:clang_$host_cpu"
+ set_default_toolchain("//build/toolchain/linux:clang_$current_cpu")
} else {
- host_toolchain = "//build/toolchain/linux:$build_cpu_arch"
- set_default_toolchain("//build/toolchain/linux:$cpu_arch")
+ host_toolchain = "//build/toolchain/linux:$host_cpu"
+ set_default_toolchain("//build/toolchain/linux:$current_cpu")
}
if (is_chromeos && cros_use_custom_toolchain) {
set_default_toolchain("//build/toolchain/cros:target")
diff --git a/build/config/allocator.gni b/build/config/allocator.gni
index 9fcfe49..4c9ae67 100644
--- a/build/config/allocator.gni
+++ b/build/config/allocator.gni
@@ -3,7 +3,7 @@
# found in the LICENSE file.
# TODO(GYP): Make tcmalloc work on win.
-if (is_android || cpu_arch == "mipsel" || is_mac || is_asan || is_win) {
+if (is_android || current_cpu == "mipsel" || is_mac || is_asan || is_win) {
_default_allocator = "none"
} else {
_default_allocator = "tcmalloc"
diff --git a/build/config/android/BUILD.gn b/build/config/android/BUILD.gn
index 0cc38b7..5492693 100644
--- a/build/config/android/BUILD.gn
+++ b/build/config/android/BUILD.gn
@@ -25,3 +25,8 @@
cflags = [ "-fPIE" ]
ldflags = [ "-pie" ]
}
+
+config("hide_native_jni_exports") {
+ ldflags = [ "-Wl,--version-script=" +
+ rebase_path("//build/android/android_no_jni_exports.lst") ]
+}
diff --git a/build/config/android/config.gni b/build/config/android/config.gni
index 0105a64..cebf4de 100644
--- a/build/config/android/config.gni
+++ b/build/config/android/config.gni
@@ -50,9 +50,9 @@
# Defines the name the Android build gives to the current host CPU
# architecture, which is different than the names GN uses.
- if (build_cpu_arch == "x64") {
+ if (host_cpu == "x64") {
android_host_arch = "x86_64"
- } else if (build_cpu_arch == "x86") {
+ } else if (host_cpu == "x86") {
android_host_arch = "x86"
} else {
assert(false, "Need Android toolchain support for your build CPU arch.")
@@ -60,7 +60,7 @@
# Defines the name the Android build gives to the current host CPU
# architecture, which is different than the names GN uses.
- if (build_os == "linux") {
+ if (host_os == "linux") {
android_host_os = "linux"
} else {
assert(false, "Need Android toolchain support for your build OS.")
@@ -119,32 +119,32 @@
# Location of libgcc. This is only needed for the current GN toolchain, so we
# only need to define the current one, rather than one for every platform
# like the toolchain roots.
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
android_prebuilt_arch = "android-x86"
_binary_prefix = "i686-linux-android"
android_toolchain_root = "$x86_android_toolchain_root"
android_libgcc_file = "$android_toolchain_root/lib/gcc/i686-linux-android/${_android_toolchain_version}/libgcc.a"
- } else if (cpu_arch == "arm") {
+ } else if (current_cpu == "arm") {
android_prebuilt_arch = "android-arm"
_binary_prefix = "arm-linux-androideabi"
android_toolchain_root = "$arm_android_toolchain_root"
android_libgcc_file = "$android_toolchain_root/lib/gcc/arm-linux-androideabi/${_android_toolchain_version}/libgcc.a"
- } else if (cpu_arch == "mipsel") {
+ } else if (current_cpu == "mipsel") {
android_prebuilt_arch = "android-mips"
_binary_prefix = "mipsel-linux-android"
android_toolchain_root = "$mips_android_toolchain_root"
android_libgcc_file = "$android_toolchain_root/lib/gcc/mipsel-linux-android/${_android_toolchain_version}/libgcc.a"
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
android_prebuilt_arch = "android-x86_64"
_binary_prefix = "x86_64-linux-android"
android_toolchain_root = "$x86_64_android_toolchain_root"
android_libgcc_file = "$android_toolchain_root/lib/gcc/x86_64-linux-android/${_android_toolchain_version}/libgcc.a"
- } else if (cpu_arch == "arm64") {
+ } else if (current_cpu == "arm64") {
android_prebuilt_arch = "android-arm64"
_binary_prefix = "aarch64-linux-android"
android_toolchain_root = "$arm64_android_toolchain_root"
android_libgcc_file = "$android_toolchain_root/lib/gcc/aarch64-linux-android/${_android_toolchain_version}/libgcc.a"
- } else if (cpu_arch == "mips64el") {
+ } else if (current_cpu == "mips64el") {
android_prebuilt_arch = "android-mips64"
_binary_prefix = "mips64el-linux-android"
android_toolchain_root = "$mips64_android_toolchain_root"
@@ -169,25 +169,25 @@
# ABI ------------------------------------------------------------------------
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
android_app_abi = "x86"
- } else if (cpu_arch == "arm") {
+ } else if (current_cpu == "arm") {
import("//build/config/arm.gni")
if (arm_version < 7) {
android_app_abi = "armeabi"
} else {
android_app_abi = "armeabi-v7a"
}
- } else if (cpu_arch == "mipsel") {
+ } else if (current_cpu == "mipsel") {
android_app_abi = "mips"
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
android_app_abi = "x86_64"
- } else if (cpu_arch == "arm64") {
+ } else if (current_cpu == "arm64") {
android_app_abi = "arm64-v8a"
- } else if (cpu_arch == "mips64el") {
+ } else if (current_cpu == "mips64el") {
android_app_abi = "mips64"
} else {
- assert(false, "Unknown Android ABI: " + cpu_arch)
+ assert(false, "Unknown Android ABI: " + current_cpu)
}
} else {
if (!defined(is_android_webview_build)) {
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni
index 33dfa37..8ca0642 100644
--- a/build/config/android/rules.gni
+++ b/build/config/android/rules.gni
@@ -74,6 +74,12 @@
rebase_path(jni_generator_jarjar_file, root_build_dir),
]
}
+ if (!is_clang) {
+ # Clang builds currently fail with --native_exports_optional due to
+ # http://llvm.org/bugs/show_bug.cgi?id=22602 - only enable for gcc.
+ # http://crbug.com/442327
+ args += [ "--native_exports_optional" ]
+ }
}
config("jni_includes_${target_name}") {
@@ -184,6 +190,12 @@
"--includes",
rebase_path(jni_generator_include, root_build_dir),
]
+ if (!is_clang) {
+ # Clang builds currently fail with --native_exports_optional due to
+ # http://llvm.org/bugs/show_bug.cgi?id=22602 - only enable for gcc.
+ # http://crbug.com/442327
+ args += [ "--native_exports_optional" ]
+ }
}
}
@@ -346,9 +358,7 @@
action("${target_name}__generate_enum") {
# The sources aren't compiled so don't check their dependencies.
- # TODO(brettw) uncomment after GN binary rolled pas 314974 (which added
- # support for this value on actions).
- #check_includes = false
+ check_includes = false
sources = invoker.sources
script = "//build/android/gyp/java_cpp_enum.py"
diff --git a/build/config/arm.gni b/build/config/arm.gni
index d39c6e9..778ecc1 100644
--- a/build/config/arm.gni
+++ b/build/config/arm.gni
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-if (cpu_arch == "arm") {
+if (current_cpu == "arm") {
declare_args() {
# Version of the ARM processor when compiling on ARM. Ignored on non-ARM
# platforms.
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 164b97d..8cb4088 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -3,10 +3,10 @@
# found in the LICENSE file.
import("//build/config/android/config.gni")
-if (cpu_arch == "arm") {
+if (current_cpu == "arm") {
import("//build/config/arm.gni")
}
-if (cpu_arch == "mipsel" || cpu_arch == "mips64el") {
+if (current_cpu == "mipsel" || current_cpu == "mips64el") {
import("//build/config/mips.gni")
}
if (is_posix) {
@@ -24,7 +24,7 @@
# These are not multi-arch so cannot be used except on x86 and x86-64 (the
# only two architectures that are currently checked in). Turn this off when
# you are using a custom toolchain and need to control -B in cflags.
- linux_use_bundled_binutils = is_linux && cpu_arch == "x64"
+ linux_use_bundled_binutils = is_linux && current_cpu == "x64"
# Compile in such a way as to enable profiling of the generated code. For
# example, don't omit the frame pointer and leave in symbols.
@@ -39,7 +39,7 @@
# Use gold for linking on 64-bit Linux only (on 32-bit it runs out of
# address space, and it doesn't support cross-compiling).
- use_gold = is_linux && cpu_arch == "x64"
+ use_gold = is_linux && current_cpu == "x64"
# use_debug_fission: whether to use split DWARF debug info
# files. This can reduce link time significantly, but is incompatible
@@ -121,7 +121,7 @@
}
# Linker warnings.
- if (!(is_chromeos && cpu_arch == "arm") && !is_mac) {
+ if (!(is_chromeos && current_cpu == "arm") && !is_mac) {
# TODO(jochen): Enable this on chromeos on arm. http://crbug.com/356580
ldflags += [ "-Wl,--fatal-warnings" ]
}
@@ -172,12 +172,12 @@
common_mac_flags = []
# CPU architecture.
- if (cpu_arch == "x64") {
+ if (current_cpu == "x64") {
common_mac_flags += [
"-arch",
"x86_64",
]
- } else if (cpu_arch == "x86") {
+ } else if (current_cpu == "x86") {
common_mac_flags += [
"-arch",
"i386",
@@ -222,13 +222,13 @@
# CPU architecture. We may or may not be doing a cross compile now, so for
# simplicity we always explicitly set the architecture.
- if (cpu_arch == "x64") {
+ if (current_cpu == "x64") {
cflags += [
"-m64",
"-march=x86-64",
]
ldflags += [ "-m64" ]
- } else if (cpu_arch == "x86") {
+ } else if (current_cpu == "x86") {
cflags += [ "-m32" ]
ldflags += [ "-m32" ]
if (is_clang) {
@@ -242,7 +242,7 @@
"-mstackrealign",
]
}
- } else if (cpu_arch == "arm") {
+ } else if (current_cpu == "arm") {
# Don't set the compiler flags for the WebView build. These will come
# from the Android build system.
if (!is_android_webview_build) {
@@ -275,7 +275,7 @@
]
}
}
- } else if (cpu_arch == "mipsel") {
+ } else if (current_cpu == "mipsel") {
# Don't set the compiler flags for the WebView build. These will come
# from the Android build system.
if (!is_android_webview_build) {
@@ -302,7 +302,7 @@
]
}
}
- } else if (cpu_arch == "mips64el") {
+ } else if (current_cpu == "mips64el") {
# Don't set the compiler flags for the WebView build. These will come
# from the Android build system.
if (!is_android_webview_build) {
@@ -437,7 +437,7 @@
}
# Use gold for Android for most CPU architectures.
- if (cpu_arch == "x86" || cpu_arch == "x64" || cpu_arch == "arm") {
+ if (current_cpu == "x86" || current_cpu == "x64" || current_cpu == "arm") {
ldflags += [ "-fuse-ld=gold" ]
if (is_clang) {
# Let clang find the ld.gold in the NDK.
@@ -449,10 +449,17 @@
ldflags += [
"-Wl,--no-undefined",
- # Don't export symbols from statically linked libraries.
- "-Wl,--exclude-libs=ALL",
+ # Don't allow visible symbols from libgcc or stlport to be
+ # re-exported.
+ "-Wl,--exclude-libs=libgcc.a",
+ "-Wl,--exclude-libs=libstlport_static.a",
+
+ # Don't allow visible symbols from libraries that contain
+ # assembly code with symbols that aren't hidden properly.
+ # http://crbug.com/448386
+ "-Wl,--exclude-libs=libvpx_assembly_arm.a",
]
- if (cpu_arch == "arm") {
+ if (current_cpu == "arm") {
ldflags += [
# Enable identical code folding to reduce size.
"-Wl,--icf=safe",
@@ -460,10 +467,10 @@
}
if (is_clang) {
- if (cpu_arch == "arm") {
+ if (current_cpu == "arm") {
cflags += [ "-target arm-linux-androideabi" ]
ldflags += [ "-target arm-linux-androideabi" ]
- } else if (cpu_arch == "x86") {
+ } else if (current_cpu == "x86") {
cflags += [ "-target x86-linux-androideabi" ]
ldflags += [ "-target x86-linux-androideabi" ]
}
@@ -472,7 +479,7 @@
}
config("compiler_arm_fpu") {
- if (cpu_arch == "arm" && !is_android_webview_build) {
+ if (current_cpu == "arm" && !is_android_webview_build) {
cflags = [ "-mfpu=$arm_fpu" ]
}
}
@@ -570,7 +577,7 @@
libs += [ "stlport_static" ]
}
- if (cpu_arch == "mipsel") {
+ if (current_cpu == "mipsel") {
libs += [
# ld linker is used for mips Android, and ld does not accept library
# absolute path prefixed by "-l"; Since libgcc does not exist in mips
@@ -837,7 +844,7 @@
# Suppress warnings about ABI changes on ARM (Clang doesn't give this
# warning).
- if (cpu_arch == "arm" && !is_clang) {
+ if (current_cpu == "arm" && !is_clang) {
cflags += [ "-Wno-psabi" ]
}
@@ -881,6 +888,20 @@
}
}
+# On Windows compiling on x64, VC will issue a warning when converting
+# size_t to int because it will truncate the value. Our code should not have
+# these warnings and one should use a static_cast or a checked_cast for the
+# conversion depending on the case. However, a lot of code still needs to be
+# fixed. Apply this config to such targets to disable the warning.
+#
+# Note that this can be applied regardless of platform and architecture to
+# clean up the call sites. This will only apply the flag when necessary.
+config("no_size_t_to_int_warning") {
+ if (is_win && current_cpu == "x64") {
+ cflags = [ "/wd4267" ]
+ }
+}
+
# Optimization -----------------------------------------------------------------
#
# Note that BUILDCONFIG.gn sets up a variable "default_optimization_config"
diff --git a/build/config/features.gni b/build/config/features.gni
index 3811e27..ba69371 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -74,9 +74,9 @@
# currently.
# Do not disable seccomp_bpf anywhere without talking to
# security@chromium.org!
-use_seccomp_bpf =
- (is_linux || is_android) && (cpu_arch == "x86" || cpu_arch == "x64" ||
- cpu_arch == "arm" || cpu_arch == "mipsel")
+use_seccomp_bpf = (is_linux || is_android) &&
+ (current_cpu == "x86" || current_cpu == "x64" ||
+ current_cpu == "arm" || current_cpu == "mipsel")
# Enable notifications everywhere except iOS.
enable_notifications = !is_ios
diff --git a/build/config/linux/BUILD.gn b/build/config/linux/BUILD.gn
index 0453c84..202fd73 100644
--- a/build/config/linux/BUILD.gn
+++ b/build/config/linux/BUILD.gn
@@ -180,15 +180,17 @@
#ignore_libs = true # Loader generated below.
}
-# This generates a target named "gio".
-generate_library_loader("gio") {
- name = "LibGioLoader"
- output_h = "libgio.h"
- output_cc = "libgio_loader.cc"
- header = "<gio/gio.h>"
- config = ":gio_config"
+if (is_desktop_linux) {
+ # This generates a target named "gio".
+ generate_library_loader("gio") {
+ name = "LibGioLoader"
+ output_h = "libgio.h"
+ output_cc = "libgio_loader.cc"
+ header = "<gio/gio.h>"
+ config = ":gio_config"
- functions = gypi_values.libgio_functions
+ functions = gypi_values.libgio_functions
+ }
}
# This generates a target named "libpci".
diff --git a/build/config/linux/pkg_config.gni b/build/config/linux/pkg_config.gni
index 631d60a..34ed1af 100644
--- a/build/config/linux/pkg_config.gni
+++ b/build/config/linux/pkg_config.gni
@@ -43,7 +43,7 @@
"-s",
sysroot,
"-a",
- cpu_arch,
+ current_cpu,
]
} else if (pkg_config != "") {
pkg_config_args = [
diff --git a/build/config/mips.gni b/build/config/mips.gni
index f544d94..512552d 100644
--- a/build/config/mips.gni
+++ b/build/config/mips.gni
@@ -3,11 +3,11 @@
# found in the LICENSE file.
# MIPS arch variant.
-if (cpu_arch == "mipsel") {
+if (current_cpu == "mipsel") {
declare_args() {
mips_arch_variant = "r1"
}
-} else if (cpu_arch == "mips64el") {
+} else if (current_cpu == "mips64el") {
if (is_android) {
declare_args() {
mips_arch_variant = "r6"
diff --git a/build/config/sysroot.gni b/build/config/sysroot.gni
index a9b250c..941c77a 100644
--- a/build/config/sysroot.gni
+++ b/build/config/sysroot.gni
@@ -16,17 +16,17 @@
} else if (is_android) {
import("//build/config/android/config.gni")
if (!is_android_webview_build) {
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
sysroot = rebase_path("$android_ndk_root/$x86_android_sysroot_subdir")
- } else if (cpu_arch == "arm") {
+ } else if (current_cpu == "arm") {
sysroot = rebase_path("$android_ndk_root/$arm_android_sysroot_subdir")
- } else if (cpu_arch == "mipsel") {
+ } else if (current_cpu == "mipsel") {
sysroot = rebase_path("$android_ndk_root/$mips_android_sysroot_subdir")
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
sysroot = rebase_path("$android_ndk_root/$x86_64_android_sysroot_subdir")
- } else if (cpu_arch == "arm64") {
+ } else if (current_cpu == "arm64") {
sysroot = rebase_path("$android_ndk_root/$arm64_android_sysroot_subdir")
- } else if (cpu_arch == "mips64") {
+ } else if (current_cpu == "mips64") {
sysroot = rebase_path("$android_ndk_root/$mips64_android_sysroot_subdir")
} else {
sysroot = ""
@@ -37,17 +37,17 @@
} else if (is_linux && is_chrome_branded && is_official_build && !is_chromeos) {
# For official builds, use the sysroot checked into the internal source repo
# so that the builds work on older versions of Linux.
- if (cpu_arch == "x64") {
+ if (current_cpu == "x64") {
sysroot =
rebase_path("//chrome/installer/linux/debian_wheezy_amd64-sysroot")
- } else if (cpu_arch == "x86") {
+ } else if (current_cpu == "x86") {
sysroot = rebase_path("//chrome/installer/linux/debian_wheezy_i386-sysroot")
} else {
# Any other builds don't use a sysroot.
sysroot = ""
}
} else if (is_linux && !is_chromeos) {
- if (cpu_arch == "mipsel") {
+ if (current_cpu == "mipsel") {
sysroot = rebase_path("//mipsel-sysroot/sysroot")
} else {
sysroot = ""
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index 3f05108..201d45b 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -31,7 +31,7 @@
# Linker flags for Windows SDK setup, this is applied only to EXEs and DLLs.
config("sdk_link") {
- if (cpu_arch == "x64") {
+ if (current_cpu == "x64") {
ldflags = [ "/MACHINE:X64" ]
lib_dirs = [
"$windows_sdk_path\Lib\winv6.3\um\x64",
diff --git a/build/download_sdk_extras.py b/build/download_sdk_extras.py
index 45e7199..d22d885 100755
--- a/build/download_sdk_extras.py
+++ b/build/download_sdk_extras.py
@@ -9,6 +9,8 @@
bucket named: <dir in SDK extras>_<package name>_<version>.zip. The file will
be extracted in the android_tools/sdk/extras directory on the test bots. This
script will not do anything for developers.
+
+TODO(navabi): Move this script (crbug.com/459819).
"""
import json
@@ -54,8 +56,13 @@
local_zip = '%s/%s' % (SDK_EXTRAS_PATH, package['zip'])
if not os.path.exists(local_zip):
package_zip = '%s/%s' % (SDK_EXTRAS_BUCKET, package['zip'])
- subprocess.check_call(['python', GSUTIL_PATH, '--force-version', '4.7',
- 'cp', package_zip, local_zip])
+ try:
+ subprocess.check_call(['python', GSUTIL_PATH, '--force-version', '4.7',
+ 'cp', package_zip, local_zip])
+ except AccessDeniedException:
+ print ('WARNING: Bot does not have permission to download SDK packages.'
+ ' If this bot compiles for Android, it may have errors.')
+ return 0
# Always clean dir and extract zip to ensure correct contents.
clean_and_extract(package['dir_name'], package['package'], package['zip'])
diff --git a/build/get_landmines.py b/build/get_landmines.py
index 7a918c8..d7c98a5 100755
--- a/build/get_landmines.py
+++ b/build/get_landmines.py
@@ -62,6 +62,7 @@
print 'Clobber to fix missing NaCl gyp dependencies (crbug.com/427427).'
print 'Another clobber for missing NaCl gyp deps (crbug.com/427427).'
print 'Clobber to fix GN not picking up increased ID range (crbug.com/444902)'
+ print 'Remove NaCl toolchains from the output dir (crbug.com/456902)'
def main():
diff --git a/build/ios/OWNERS b/build/ios/OWNERS
index 1c3e6c8..4caf405 100644
--- a/build/ios/OWNERS
+++ b/build/ios/OWNERS
@@ -1,3 +1,4 @@
rohitrao@chromium.org
stuartmorgan@chromium.org
+per-file grit_whitelist.txt=*
diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt
index c1edfdf..484f806 100644
--- a/build/ios/grit_whitelist.txt
+++ b/build/ios/grit_whitelist.txt
@@ -130,6 +130,7 @@
IDS_AUTOFILL_ADDRESS_LINE_SEPARATOR
IDS_AUTOFILL_ADDRESS_SUMMARY_SEPARATOR
IDS_AUTOFILL_CC_AMEX
+IDS_AUTOFILL_CC_AMEX_SHORT
IDS_AUTOFILL_CC_DINERS
IDS_AUTOFILL_CC_DISCOVER
IDS_AUTOFILL_CC_GENERIC
@@ -719,6 +720,7 @@
IDS_LIBADDRESSINPUT_UNRECOGNIZED_FORMAT_ZIP_CODE_EXAMPLE_AND_URL
IDS_LIBADDRESSINPUT_VILLAGE_TOWNSHIP
IDS_LIBADDRESSINPUT_ZIP_CODE_LABEL
+IDS_LINK_FROM_CLIPBOARD
IDS_LOGIN_DIALOG_OK_BUTTON_LABEL
IDS_LOGIN_DIALOG_PASSWORD_FIELD
IDS_LOGIN_DIALOG_TITLE
diff --git a/build/isolate.gypi b/build/isolate.gypi
index d7070fe..fbb6d3c 100644
--- a/build/isolate.gypi
+++ b/build/isolate.gypi
@@ -109,9 +109,6 @@
["test_isolation_outdir!=''", {
'action': [ '--isolate-server', '<(test_isolation_outdir)' ],
}],
- ['test_isolation_fail_on_missing == 0', {
- 'action': ['--ignore_broken_items'],
- }],
["test_isolation_mode == 'prepare'", {
'outputs': [
'<(PRODUCT_DIR)/<(RULE_INPUT_ROOT).isolated.gen.json',
diff --git a/build/jar_file_jni_generator.gypi b/build/jar_file_jni_generator.gypi
index 4c01c8a..9472c10 100644
--- a/build/jar_file_jni_generator.gypi
+++ b/build/jar_file_jni_generator.gypi
@@ -73,5 +73,13 @@
'<(DEPTH)/build/android/android_exports.gyp:android_exports',
],
}],
+ ['clang==0', {
+ # Clang builds currently fail with --native_exports_optional due to
+ # http://llvm.org/bugs/show_bug.cgi?id=22602 - only enable for gcc.
+ # http://crbug.com/442327
+ 'variables': {
+ 'native_exports%': '--native_exports_optional',
+ },
+ }],
],
}
diff --git a/build/jni_generator.gypi b/build/jni_generator.gypi
index 6edc512..853b5f6 100644
--- a/build/jni_generator.gypi
+++ b/build/jni_generator.gypi
@@ -92,6 +92,14 @@
'<(DEPTH)/build/android/android_exports.gyp:android_exports',
],
}],
+ ['clang==0', {
+ # Clang builds currently fail with --native_exports_optional due to
+ # http://llvm.org/bugs/show_bug.cgi?id=22602 - only enable for gcc.
+ # http://crbug.com/442327
+ 'variables': {
+ 'native_exports%': '--native_exports_optional',
+ },
+ }],
],
}
diff --git a/build/json_schema_api.gni b/build/json_schema_api.gni
index 83846a2..68a9fdd 100644
--- a/build/json_schema_api.gni
+++ b/build/json_schema_api.gni
@@ -183,6 +183,7 @@
sources += get_target_outputs(":$schema_generator_name")
public_deps += [ ":$schema_generator_name" ]
deps += [ "//tools/json_schema_compiler:generated_api_util" ]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
}
if (bundle) {
diff --git a/build/sanitizers/tsan_suppressions.cc b/build/sanitizers/tsan_suppressions.cc
index 5704f2d..24c24d6 100644
--- a/build/sanitizers/tsan_suppressions.cc
+++ b/build/sanitizers/tsan_suppressions.cc
@@ -69,8 +69,8 @@
"race:v8::Locker::Initialize\n"
// http://crbug.com/223352
-"race:uprv_malloc_52\n"
-"race:uprv_realloc_52\n"
+"race:uprv_malloc_54\n"
+"race:uprv_realloc_54\n"
// http://crbug.com/239359
"race:media::TestInputCallback::OnData\n"
@@ -325,6 +325,15 @@
// https://crbug.com/455665
"race:mojo::common::*::tick_clock\n"
+// https://crbug.com/459429
+"race:randomnessPid\n"
+
+// https://crbug.com/460243
+"race:IPC::ChannelMojoHost::OnClientLaunched\n"
+
+// https://crbug.com/454655
+"race:content::BrowserTestBase::PostTaskToInProcessRendererAndWait\n"
+
// End of suppressions.
; // Please keep this semicolon.
diff --git a/build/secondary/third_party/cacheinvalidation/BUILD.gn b/build/secondary/third_party/cacheinvalidation/BUILD.gn
index 088f89a..feb93d7 100644
--- a/build/secondary/third_party/cacheinvalidation/BUILD.gn
+++ b/build/secondary/third_party/cacheinvalidation/BUILD.gn
@@ -77,17 +77,14 @@
"src/google/cacheinvalidation/include/types.h",
]
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
public_configs = [ ":cacheinvalidation_config" ]
deps = [
"src/google/cacheinvalidation:cacheinvalidation_proto_cpp",
"//base",
]
-
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
- }
}
test("cacheinvalidation_unittests") {
diff --git a/build/secondary/third_party/icu/BUILD.gn b/build/secondary/third_party/icu/BUILD.gn
index 8b64f70..53818c9 100644
--- a/build/secondary/third_party/icu/BUILD.gn
+++ b/build/secondary/third_party/icu/BUILD.gn
@@ -74,6 +74,26 @@
"source/i18n/chnsecal.cpp",
"source/i18n/choicfmt.cpp",
"source/i18n/coleitr.cpp",
+ "source/i18n/collationbasedatabuilder.cpp",
+ "source/i18n/collationbuilder.cpp",
+ "source/i18n/collationcompare.cpp",
+ "source/i18n/collation.cpp",
+ "source/i18n/collationdatabuilder.cpp",
+ "source/i18n/collationdata.cpp",
+ "source/i18n/collationdatareader.cpp",
+ "source/i18n/collationdatawriter.cpp",
+ "source/i18n/collationfastlatinbuilder.cpp",
+ "source/i18n/collationfastlatin.cpp",
+ "source/i18n/collationfcd.cpp",
+ "source/i18n/collationiterator.cpp",
+ "source/i18n/collationkeys.cpp",
+ "source/i18n/collationroot.cpp",
+ "source/i18n/collationrootelements.cpp",
+ "source/i18n/collationruleparser.cpp",
+ "source/i18n/collationsets.cpp",
+ "source/i18n/collationsettings.cpp",
+ "source/i18n/collationtailoring.cpp",
+ "source/i18n/collationweights.cpp",
"source/i18n/coll.cpp",
"source/i18n/compactdecimalformat.cpp",
"source/i18n/coptccal.cpp",
@@ -95,6 +115,7 @@
"source/i18n/dcfmtsym.cpp",
"source/i18n/decContext.c",
"source/i18n/decfmtst.cpp",
+ "source/i18n/decimalformatpattern.cpp",
"source/i18n/decimfmt.cpp",
"source/i18n/decNumber.c",
"source/i18n/digitlst.cpp",
@@ -105,6 +126,7 @@
"source/i18n/dtrule.cpp",
"source/i18n/esctrn.cpp",
"source/i18n/ethpccal.cpp",
+ "source/i18n/filteredbrk.cpp",
"source/i18n/fmtable_cnv.cpp",
"source/i18n/fmtable.cpp",
"source/i18n/format.cpp",
@@ -122,6 +144,7 @@
"source/i18n/japancal.cpp",
"source/i18n/locdspnm.cpp",
"source/i18n/measfmt.cpp",
+ "source/i18n/measunit.cpp",
"source/i18n/measure.cpp",
"source/i18n/msgfmt.cpp",
"source/i18n/name2uni.cpp",
@@ -137,6 +160,7 @@
"source/i18n/plurfmt.cpp",
"source/i18n/plurrule.cpp",
"source/i18n/quant.cpp",
+ "source/i18n/quantityformatter.cpp",
"source/i18n/rbnf.cpp",
"source/i18n/rbt.cpp",
"source/i18n/rbt_data.cpp",
@@ -149,13 +173,17 @@
"source/i18n/regexst.cpp",
"source/i18n/regextxt.cpp",
"source/i18n/region.cpp",
+ "source/i18n/reldatefmt.cpp",
"source/i18n/reldtfmt.cpp",
"source/i18n/rematch.cpp",
"source/i18n/remtrans.cpp",
"source/i18n/repattrn.cpp",
+ "source/i18n/rulebasedcollator.cpp",
+ "source/i18n/scientificformathelper.cpp",
"source/i18n/scriptset.cpp",
"source/i18n/search.cpp",
"source/i18n/selfmt.cpp",
+ "source/i18n/sharedbreakiterator.cpp",
"source/i18n/simpletz.cpp",
"source/i18n/smpdtfmt.cpp",
"source/i18n/smpdtfst.cpp",
@@ -164,7 +192,6 @@
"source/i18n/strrepl.cpp",
"source/i18n/stsearch.cpp",
"source/i18n/taiwncal.cpp",
- "source/i18n/tblcoll.cpp",
"source/i18n/timezone.cpp",
"source/i18n/titletrn.cpp",
"source/i18n/tmunit.cpp",
@@ -182,21 +209,17 @@
"source/i18n/tzrule.cpp",
"source/i18n/tztrans.cpp",
"source/i18n/ucal.cpp",
- "source/i18n/ucln_in.c",
- "source/i18n/ucol_bld.cpp",
- "source/i18n/ucol_cnt.cpp",
+ "source/i18n/ucln_in.cpp",
"source/i18n/ucol.cpp",
"source/i18n/ucoleitr.cpp",
- "source/i18n/ucol_elm.cpp",
"source/i18n/ucol_res.cpp",
"source/i18n/ucol_sit.cpp",
- "source/i18n/ucol_tok.cpp",
- "source/i18n/ucol_wgt.cpp",
"source/i18n/ucsdet.cpp",
"source/i18n/ucurr.cpp",
"source/i18n/udat.cpp",
"source/i18n/udateintervalformat.cpp",
"source/i18n/udatpg.cpp",
+ "source/i18n/uitercollationiterator.cpp",
"source/i18n/ulocdata.c",
"source/i18n/umsg.cpp",
"source/i18n/unesctrn.cpp",
@@ -213,6 +236,8 @@
"source/i18n/uspoof.cpp",
"source/i18n/uspoof_impl.cpp",
"source/i18n/uspoof_wsconf.cpp",
+ "source/i18n/utf16collationiterator.cpp",
+ "source/i18n/utf8collationiterator.cpp",
"source/i18n/utmscale.c",
"source/i18n/utrans.cpp",
"source/i18n/vtzone.cpp",
@@ -286,8 +311,9 @@
"source/common/errorcode.cpp",
"source/common/filterednormalizer2.cpp",
"source/common/icudataver.c",
- "source/common/icuplug.c",
+ "source/common/icuplug.cpp",
"source/common/listformatter.cpp",
+ "source/common/loadednormalizer2impl.cpp",
"source/common/locavailable.cpp",
"source/common/locbased.cpp",
"source/common/locdispnames.cpp",
@@ -325,6 +351,8 @@
"source/common/servnotf.cpp",
"source/common/servrbf.cpp",
"source/common/servslkf.cpp",
+ "source/common/sharedobject.cpp",
+ "source/common/simplepatternformatter.cpp",
"source/common/stringpiece.cpp",
"source/common/stringtriebuilder.cpp",
"source/common/uarrsort.c",
@@ -342,7 +370,7 @@
"source/common/ucharstrie.cpp",
"source/common/ucharstrieiterator.cpp",
"source/common/uchriter.cpp",
- "source/common/ucln_cmn.c",
+ "source/common/ucln_cmn.cpp",
"source/common/ucmndata.c",
"source/common/ucnv2022.cpp",
"source/common/ucnv_bld.cpp",
@@ -359,7 +387,7 @@
"source/common/ucnvisci.c",
"source/common/ucnvlat1.c",
"source/common/ucnv_lmb.c",
- "source/common/ucnvmbcs.c",
+ "source/common/ucnvmbcs.cpp",
"source/common/ucnvscsu.c",
"source/common/ucnvsel.cpp",
"source/common/ucnv_set.c",
@@ -380,11 +408,13 @@
"source/common/uiter.cpp",
"source/common/ulist.c",
"source/common/uloc.cpp",
+ "source/common/uloc_keytype.cpp",
"source/common/uloc_tag.c",
"source/common/umapfile.c",
"source/common/umath.c",
"source/common/umutex.cpp",
"source/common/unames.cpp",
+ "source/common/unifiedcache.cpp",
"source/common/unifilt.cpp",
"source/common/unifunct.cpp",
"source/common/uniset_closure.cpp",
@@ -399,7 +429,6 @@
"source/common/unistr_titlecase_brkiter.cpp",
"source/common/unormcmp.cpp",
"source/common/unorm.cpp",
- "source/common/unorm_it.c",
"source/common/uobject.cpp",
"source/common/uprops.cpp",
"source/common/uresbund.cpp",
@@ -416,7 +445,7 @@
"source/common/ustack.cpp",
"source/common/ustrcase.cpp",
"source/common/ustrcase_locale.cpp",
- "source/common/ustr_cnv.c",
+ "source/common/ustr_cnv.cpp",
"source/common/ustrenum.cpp",
"source/common/ustrfmt.c",
"source/common/ustring.cpp",
@@ -457,6 +486,7 @@
if (is_win || icu_use_data_file) {
sources += [ "source/stubdata/stubdata.c" ]
+ defines += [ "U_ICUDATAENTRY_IN_COMMON" ]
}
}
diff --git a/build/secondary/third_party/libjpeg_turbo/BUILD.gn b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
index be16302..bf35d07 100644
--- a/build/secondary/third_party/libjpeg_turbo/BUILD.gn
+++ b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
@@ -5,17 +5,17 @@
# Do not use the targets in this file unless you need a certain libjpeg
# implementation. Use the meta target //third_party:jpeg instead.
-if (cpu_arch == "arm") {
+if (current_cpu == "arm") {
import("//build/config/arm.gni")
}
-if (cpu_arch == "x86" || cpu_arch == "x64") {
+if (current_cpu == "x86" || current_cpu == "x64") {
import("//third_party/yasm/yasm_assemble.gni")
yasm_assemble("simd_asm") {
defines = []
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
sources = [
"simd/jccolmmx.asm",
"simd/jccolss2.asm",
@@ -52,7 +52,7 @@
"simd/jsimdcpu.asm",
]
defines += [ "__x86__" ]
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
sources = [
"simd/jccolss2-64.asm",
"simd/jcgrass2-64.asm",
@@ -76,7 +76,7 @@
if (is_win) {
defines += [ "MSVC" ]
include_dirs = [ "win" ]
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
defines += [ "WIN32" ]
} else {
defines += [ "WIN64" ]
@@ -92,7 +92,7 @@
}
source_set("simd") {
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
deps = [
":simd_asm",
]
@@ -102,14 +102,14 @@
if (is_win) {
cflags = [ "/wd4245" ]
}
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
deps = [
":simd_asm",
]
sources = [
"simd/jsimd_x86_64.c",
]
- } else if (cpu_arch == "arm" && arm_version >= 7 &&
+ } else if (current_cpu == "arm" && arm_version >= 7 &&
(arm_use_neon || arm_optionally_use_neon)) {
sources = [
"simd/jsimd_arm.c",
diff --git a/build/secondary/third_party/libsrtp/BUILD.gn b/build/secondary/third_party/libsrtp/BUILD.gn
index 506d19f..d9b658e 100644
--- a/build/secondary/third_party/libsrtp/BUILD.gn
+++ b/build/secondary/third_party/libsrtp/BUILD.gn
@@ -45,7 +45,7 @@
]
}
- if (cpu_arch == "x64" || cpu_arch == "x86" || cpu_arch == "arm") {
+ if (current_cpu == "x64" || current_cpu == "x86" || current_cpu == "arm") {
defines += [
# TODO(leozwang): CPU_RISC doesn"t work properly on android/arm
# platform for unknown reasons, need to investigate the root cause
@@ -56,7 +56,7 @@
]
}
- if (cpu_arch == "mipsel") {
+ if (current_cpu == "mipsel") {
defines += [ "CPU_RISC" ]
}
}
diff --git a/build/secondary/third_party/nss/BUILD.gn b/build/secondary/third_party/nss/BUILD.gn
index 768a85d..ee5f112 100644
--- a/build/secondary/third_party/nss/BUILD.gn
+++ b/build/secondary/third_party/nss/BUILD.gn
@@ -217,7 +217,10 @@
"//build/config/win:lean_and_mean", # Won"t compile with lean and mean.
]
}
- configs += [ "//build/config/compiler:no_chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//build/config/compiler:no_size_t_to_int_warning",
+ ]
cflags = []
defines = [
@@ -228,10 +231,7 @@
include_dirs = [ "nspr/pr/include/private" ]
if (is_win) {
- cflags = [
- "/wd4554", # Check precidence.
- "/wd4267", # Conversion from size_t to "type".
- ]
+ cflags = [ "/wd4554" ] # Check precidence.
defines += [
"XP_PC",
"WIN32",
@@ -281,9 +281,9 @@
]
}
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
defines += [ "_X86_" ]
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
defines += [ "_AMD64_" ]
}
@@ -474,7 +474,7 @@
]
}
- if (is_win && cpu_arch == "x86") {
+ if (is_win && current_cpu == "x86") {
source_set("nss_static_avx") {
sources = [
"nss/lib/freebl/intel-gcm-wrap.c",
@@ -882,7 +882,10 @@
if (is_win) {
configs -= [ "//build/config/win:unicode" ] # Requires 8-bit mode.
}
- configs += [ "//build/config/compiler:no_chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+ "//build/config/compiler:no_size_t_to_int_warning",
+ ]
public_configs = [ ":nss_static_config" ]
cflags = []
@@ -901,10 +904,7 @@
]
if (is_win) {
- cflags += [
- "/wd4101", # Unreferenced local variable.
- "/wd4267", # Conversion from size_t to "type".
- ]
+ cflags += [ "/wd4101" ] # Unreferenced local variable.
}
if (include_nss_libpkix) {
@@ -1094,7 +1094,7 @@
defines += [ "NSS_DISABLE_ROOT_CERTS" ]
}
- if (cpu_arch == "x64" && !is_win) {
+ if (current_cpu == "x64" && !is_win) {
sources -= [
"nss/lib/freebl/chacha20/chacha20.c",
"nss/lib/freebl/poly1305/poly1305.c",
@@ -1139,7 +1139,7 @@
"WIN95",
]
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
defines += [
"NSS_X86_OR_X64",
"NSS_X86",
@@ -1153,7 +1153,7 @@
"INTEL_GCM",
]
sources -= [ "nss/lib/freebl/mpi/mpi_amd64.c" ]
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
sources -= [
"nss/lib/freebl/intel-aes-x86-masm.asm",
"nss/lib/freebl/mpi/mpi_amd64.c",
@@ -1204,7 +1204,7 @@
"//third_party/sqlite",
]
- if (is_win && cpu_arch == "x86") {
+ if (is_win && current_cpu == "x86") {
deps += [ ":nss_static_avx" ]
}
}
diff --git a/build/toolchain/android/BUILD.gn b/build/toolchain/android/BUILD.gn
index e3d950a..53ad506 100644
--- a/build/toolchain/android/BUILD.gn
+++ b/build/toolchain/android/BUILD.gn
@@ -18,7 +18,7 @@
# Subdirectory inside of android_ndk_sysroot where libs go.
# - tool_prefix
# Prefix to be added to the tool names.
-# - toolchain_cpu_arch
+# - toolchain_cpu
# Same as gcc_toolchain
template("android_gcc_toolchain") {
gcc_toolchain(target_name) {
@@ -51,7 +51,7 @@
ld = cxx
toolchain_os = "android"
- toolchain_cpu_arch = invoker.toolchain_cpu_arch
+ toolchain_cpu = invoker.toolchain_cpu
# We make the assumption that the gcc_toolchain will produce a soname with
# the following definition.
@@ -85,7 +85,7 @@
android_ndk_lib_dir = "usr/lib"
tool_prefix = "$x86_android_toolchain_root/bin/i686-linux-android-"
- toolchain_cpu_arch = "x86"
+ toolchain_cpu = "x86"
}
android_gcc_toolchain("arm") {
@@ -93,7 +93,7 @@
android_ndk_lib_dir = "usr/lib"
tool_prefix = "$arm_android_toolchain_root/bin/arm-linux-androideabi-"
- toolchain_cpu_arch = "arm"
+ toolchain_cpu = "arm"
}
android_gcc_toolchain("mipsel") {
@@ -101,7 +101,7 @@
android_ndk_lib_dir = "usr/lib"
tool_prefix = "$mips_android_toolchain_root/bin/mipsel-linux-android-"
- toolchain_cpu_arch = "mipsel"
+ toolchain_cpu = "mipsel"
}
android_gcc_toolchain("x64") {
@@ -109,7 +109,7 @@
android_ndk_lib_dir = "usr/lib64"
tool_prefix = "$x86_64_android_toolchain_root/bin/x86_64-linux-android-"
- toolchain_cpu_arch = "x86_64"
+ toolchain_cpu = "x86_64"
}
android_gcc_toolchain("arm64") {
@@ -117,7 +117,7 @@
android_ndk_lib_dir = "usr/lib"
tool_prefix = "$arm64_android_toolchain_root/bin/arm-linux-androideabi-"
- toolchain_cpu_arch = "aarch64"
+ toolchain_cpu = "aarch64"
}
android_gcc_toolchain("mips64el") {
@@ -125,5 +125,5 @@
android_ndk_lib_dir = "usr/lib64"
tool_prefix = "$mips64_android_toolchain_root/bin/mipsel-linux-android-"
- toolchain_cpu_arch = "mipsel64el"
+ toolchain_cpu = "mipsel64el"
}
diff --git a/build/toolchain/cros/BUILD.gn b/build/toolchain/cros/BUILD.gn
index d360f72..140958b 100644
--- a/build/toolchain/cros/BUILD.gn
+++ b/build/toolchain/cros/BUILD.gn
@@ -29,7 +29,7 @@
ar = "${cros_target_ar}"
ld = cxx
- toolchain_cpu_arch = "${cpu_arch}"
+ toolchain_cpu = "${target_cpu}"
toolchain_os = "linux"
is_clang = is_clang
}
diff --git a/build/toolchain/gcc_toolchain.gni b/build/toolchain/gcc_toolchain.gni
index 5cca299..5f49f68 100644
--- a/build/toolchain/gcc_toolchain.gni
+++ b/build/toolchain/gcc_toolchain.gni
@@ -14,10 +14,10 @@
# - ar
# - ld
# and the following which is used in the toolchain_args
-# - toolchain_cpu_arch (What "cpu_arch" should be set to when invoking a
-# build using this toolchain.)
-# - toolchain_os (What "os" should be set to when invoking a build using this
-# toolchain.)
+# - toolchain_cpu (What "current_cpu" should be set to when invoking a
+# build using this toolchain.)
+# - toolchain_os (What "current_os" should be set to when invoking a
+# build using this toolchain.)
#
# Optional parameters:
# - libs_section_prefix
@@ -40,8 +40,8 @@
assert(defined(invoker.cxx), "gcc_toolchain() must specify a \"cxx\" value")
assert(defined(invoker.ar), "gcc_toolchain() must specify a \"ar\" value")
assert(defined(invoker.ld), "gcc_toolchain() must specify a \"ld\" value")
- assert(defined(invoker.toolchain_cpu_arch),
- "gcc_toolchain() must specify a \"toolchain_cpu_arch\"")
+ assert(defined(invoker.toolchain_cpu),
+ "gcc_toolchain() must specify a \"toolchain_cpu\"")
assert(defined(invoker.toolchain_os),
"gcc_toolchain() must specify a \"toolchain_os\"")
@@ -204,8 +204,19 @@
# When invoking this toolchain not as the default one, these args will be
# passed to the build. They are ignored when this is the default toolchain.
toolchain_args() {
- cpu_arch = invoker.toolchain_cpu_arch
- os = invoker.toolchain_os
+ current_cpu = invoker.toolchain_cpu
+ current_os = invoker.toolchain_os
+
+ # These values need to be passed through unchanged.
+ target_os = target_os
+ target_cpu = target_cpu
+
+ # TODO(dpranke): These values are here for backwards compatibility and
+ # should be deleted when all of the builders and configs have been
+ # updated.
+ cpu_arch = current_cpu
+ os = current_os
+
if (defined(invoker.is_clang)) {
is_clang = invoker.is_clang
}
diff --git a/build/toolchain/linux/BUILD.gn b/build/toolchain/linux/BUILD.gn
index 1d17772..7bcd9d0 100644
--- a/build/toolchain/linux/BUILD.gn
+++ b/build/toolchain/linux/BUILD.gn
@@ -24,7 +24,7 @@
ar = "arm-linux-gnueabi-ar"
ld = cxx
- toolchain_cpu_arch = "arm"
+ toolchain_cpu = "arm"
toolchain_os = "linux"
is_clang = false
}
@@ -43,7 +43,7 @@
ar = "ar"
ld = cxx
- toolchain_cpu_arch = "x86"
+ toolchain_cpu = "x86"
toolchain_os = "linux"
is_clang = true
}
@@ -55,7 +55,7 @@
ar = "ar"
ld = cxx
- toolchain_cpu_arch = "x86"
+ toolchain_cpu = "x86"
toolchain_os = "linux"
is_clang = false
}
@@ -74,7 +74,7 @@
ar = "ar"
ld = cxx
- toolchain_cpu_arch = "x64"
+ toolchain_cpu = "x64"
toolchain_os = "linux"
is_clang = true
}
@@ -86,7 +86,7 @@
ar = "ar"
ld = cxx
- toolchain_cpu_arch = "x64"
+ toolchain_cpu = "x64"
toolchain_os = "linux"
is_clang = false
}
@@ -97,7 +97,7 @@
ar = "mipsel-linux-gnu-ar"
ld = cxx
- toolchain_cpu_arch = "mipsel"
+ toolchain_cpu = "mipsel"
toolchain_os = "linux"
is_clang = false
}
diff --git a/build/toolchain/mac/BUILD.gn b/build/toolchain/mac/BUILD.gn
index 0560714..18ee8b8 100644
--- a/build/toolchain/mac/BUILD.gn
+++ b/build/toolchain/mac/BUILD.gn
@@ -194,14 +194,17 @@
}
toolchain_args() {
- os = invoker.toolchain_os
+ current_os = invoker.toolchain_os
+
+ # TODO(dpranke): os is here for backwards compatibility.
+ os = current_os
}
}
}
# Toolchain representing the target build (either mac or iOS).
mac_clang_toolchain("clang") {
- toolchain_os = os
+ toolchain_os = current_os
}
# This toolchain provides a way for iOS target compiles to reference targets
diff --git a/build/toolchain/nacl/BUILD.gn b/build/toolchain/nacl/BUILD.gn
index b923608..5fa637c 100644
--- a/build/toolchain/nacl/BUILD.gn
+++ b/build/toolchain/nacl/BUILD.gn
@@ -54,7 +54,7 @@
toolchain_args() {
# Override the default OS detection. The build config will set the is_*
# flags accordingly.
- os = "nacl"
+ current_os = "nacl"
# Component build not supported in NaCl, since it does not support shared
# libraries.
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn
index b8f87e7..e9461a4 100644
--- a/build/toolchain/win/BUILD.gn
+++ b/build/toolchain/win/BUILD.gn
@@ -31,7 +31,7 @@
gyp_win_tool_path,
windows_sdk_path,
visual_studio_runtime_dirs,
- cpu_arch,
+ current_cpu,
],
"scope")
@@ -43,7 +43,7 @@
concurrent_links = exec_script("../get_concurrent_links.py", [], "value")
# Parameters:
-# cpu_arch: cpu_arch to pass as a build arg
+# current_cpu: current_cpu to pass as a build arg
# environment: File name of environment file.
template("msvc_toolchain") {
if (defined(invoker.concurrent_links)) {
@@ -62,7 +62,7 @@
"copy_dlls",
rebase_path(root_build_dir),
configuration,
- invoker.cpu_arch,
+ invoker.current_cpu,
])
if (use_goma) {
@@ -200,7 +200,10 @@
# When invoking this toolchain not as the default one, these args will be
# passed to the build. They are ignored when this is the default toolchain.
toolchain_args() {
- cpu_arch = invoker.cpu_arch
+ current_cpu = invoker.current_cpu
+
+ # TODO(dpranke): cpu_arch is here for backwards compatibility.
+ cpu_arch = current_cpu
}
}
}
@@ -209,16 +212,18 @@
# get it sorted out how we want to support them both in a single build.
# Right now only one of these can be enabled at a time because the
# runtime libraries get copied to root_build_dir and would collide.
-if (cpu_arch == "x86") {
+if (current_cpu == "x86") {
msvc_toolchain("32") {
environment = "environment.x86"
- cpu_arch = "x86"
+
+ current_cpu = "x86"
}
}
-if (cpu_arch == "x64") {
+if (current_cpu == "x64") {
msvc_toolchain("64") {
environment = "environment.x64"
- cpu_arch = "x64"
+
+ current_cpu = "x64"
}
}
diff --git a/build/toolchain/win/midl.gni b/build/toolchain/win/midl.gni
index ce310d1..30bcbf7 100644
--- a/build/toolchain/win/midl.gni
+++ b/build/toolchain/win/midl.gni
@@ -56,10 +56,10 @@
"$out_dir/$proxy_file",
]
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
win_tool_arch = "environment.x86"
idl_target_platform = "win32"
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
win_tool_arch = "environment.x64"
idl_target_platform = "x64"
} else {
diff --git a/build/toolchain/win/setup_toolchain.py b/build/toolchain/win/setup_toolchain.py
index cc89638..bc9bd1e 100644
--- a/build/toolchain/win/setup_toolchain.py
+++ b/build/toolchain/win/setup_toolchain.py
@@ -51,23 +51,23 @@
return env
-def _SetupScript(target_arch, sdk_dir):
+def _SetupScript(target_cpu, sdk_dir):
"""Returns a command (with arguments) to be used to set up the
environment."""
# Check if we are running in the SDK command line environment and use
- # the setup script from the SDK if so. |target_arch| should be either
+ # the setup script from the SDK if so. |target_cpu| should be either
# 'x86' or 'x64'.
- assert target_arch in ('x86', 'x64')
+ assert target_cpu in ('x86', 'x64')
if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', 1))) and sdk_dir:
return [os.path.normpath(os.path.join(sdk_dir, 'Bin/SetEnv.Cmd')),
- '/' + target_arch]
+ '/' + target_cpu]
else:
# We only support x64-hosted tools.
# TODO(scottmg|dpranke): Non-depot_tools toolchain: need to get Visual
# Studio install location from registry.
return [os.path.normpath(os.path.join(os.environ['GYP_MSVS_OVERRIDE_PATH'],
'VC/vcvarsall.bat')),
- 'amd64_x86' if target_arch == 'x86' else 'amd64']
+ 'amd64_x86' if target_cpu == 'x86' else 'amd64']
def _FormatAsEnvironmentBlock(envvar_dict):
@@ -100,25 +100,25 @@
if len(sys.argv) != 6:
print('Usage setup_toolchain.py '
'<visual studio path> <win tool path> <win sdk path> '
- '<runtime dirs> <cpu_arch>')
+ '<runtime dirs> <target_cpu>')
sys.exit(2)
tool_source = sys.argv[2]
win_sdk_path = sys.argv[3]
runtime_dirs = sys.argv[4]
- cpu_arch = sys.argv[5]
+ target_cpu = sys.argv[5]
_CopyTool(tool_source)
- archs = ('x86', 'x64')
- assert cpu_arch in archs
+ cpus = ('x86', 'x64')
+ assert target_cpu in cpus
vc_bin_dir = ''
# TODO(scottmg|goma): Do we need an equivalent of
# ninja_use_custom_environment_files?
- for arch in archs:
+ for cpu in cpus:
# Extract environment variables for subprocesses.
- args = _SetupScript(arch, win_sdk_path)
+ args = _SetupScript(cpu, win_sdk_path)
args.extend(('&&', 'set'))
popen = subprocess.Popen(
args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
@@ -126,7 +126,7 @@
env = _ExtractImportantEnvironment(variables)
env['PATH'] = runtime_dirs + ';' + env['PATH']
- if arch == cpu_arch:
+ if cpu == target_cpu:
for path in env['PATH'].split(os.pathsep):
if os.path.exists(os.path.join(path, 'cl.exe')):
vc_bin_dir = os.path.realpath(path)
@@ -143,7 +143,7 @@
sdk_dir=win_sdk_path)
env['INCLUDE'] = additional_includes + env['INCLUDE']
env_block = _FormatAsEnvironmentBlock(env)
- with open('environment.' + arch, 'wb') as f:
+ with open('environment.' + cpu, 'wb') as f:
f.write(env_block)
assert vc_bin_dir
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 6f49e7c..5b175eb 100644
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -129,11 +129,11 @@
source_x64)
-def CopyDlls(target_dir, configuration, cpu_arch):
+def CopyDlls(target_dir, configuration, target_cpu):
"""Copy the VS runtime DLLs into the requested directory as needed.
configuration is one of 'Debug' or 'Release'.
- cpu_arch is one of 'x86' or 'x64'.
+ target_cpu is one of 'x86' or 'x64'.
The debug configuration gets both the debug and release DLLs; the
release config only the latter.
@@ -143,7 +143,7 @@
return
x64_runtime, x86_runtime = vs2013_runtime_dll_dirs
- runtime_dir = x64_runtime if cpu_arch == 'x64' else x86_runtime
+ runtime_dir = x64_runtime if target_cpu == 'x64' else x86_runtime
_CopyRuntime(target_dir, runtime_dir, 'msvc%s120.dll')
if configuration == 'Debug':
_CopyRuntime(target_dir, runtime_dir, 'msvc%s120d.dll')
diff --git a/build/win/install-build-deps.py b/build/win/install-build-deps.py
deleted file mode 100755
index d9e50b6..0000000
--- a/build/win/install-build-deps.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2012 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import shutil
-import sys
-import os
-
-def patch_msbuild():
- """VS2010 MSBuild has a ULDI bug that we patch here. See http://goo.gl/Pn8tj.
- """
- source_path = os.path.join(os.environ['ProgramFiles(x86)'],
- "MSBuild",
- "Microsoft.Cpp",
- "v4.0",
- "Microsoft.CppBuild.targets")
- backup_path = source_path + ".backup"
- if not os.path.exists(backup_path):
- try:
- print "Backing up %s..." % source_path
- shutil.copyfile(source_path, backup_path)
- except IOError:
- print "Could not back up %s to %s. Run as Administrator?" % (
- source_path, backup_path)
- return 1
-
- source = open(source_path).read()
- base = ('''<Target Name="GetResolvedLinkObjs" Returns="@(ObjFullPath)" '''
- '''DependsOnTargets="$(CommonBuildOnlyTargets);ComputeCLOutputs;'''
- '''ResolvedLinkObjs"''')
- find = base + '>'
- replace = base + ''' Condition="'$(ConfigurationType)'=='StaticLibrary'">'''
- result = source.replace(find, replace)
-
- if result != source:
- open(source_path, "w").write(result)
- print "Patched %s." % source_path
- return 0
-
-
-def main():
- return patch_msbuild()
-
-
-if __name__ == "__main__":
- sys.exit(main())
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index d6fd028..cffee57 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -26,8 +26,8 @@
"animation/layer_animation_value_provider.h",
"animation/scroll_offset_animation_curve.cc",
"animation/scroll_offset_animation_curve.h",
- "animation/scrollbar_animation_controller.h",
"animation/scrollbar_animation_controller.cc",
+ "animation/scrollbar_animation_controller.h",
"animation/scrollbar_animation_controller_linear_fade.cc",
"animation/scrollbar_animation_controller_linear_fade.h",
"animation/scrollbar_animation_controller_thinning.cc",
@@ -94,12 +94,12 @@
"debug/layer_tree_debug_state.h",
"debug/micro_benchmark.cc",
"debug/micro_benchmark.h",
- "debug/micro_benchmark_impl.cc",
- "debug/micro_benchmark_impl.h",
"debug/micro_benchmark_controller.cc",
"debug/micro_benchmark_controller.h",
"debug/micro_benchmark_controller_impl.cc",
"debug/micro_benchmark_controller_impl.h",
+ "debug/micro_benchmark_impl.cc",
+ "debug/micro_benchmark_impl.h",
"debug/paint_time_counter.cc",
"debug/paint_time_counter.h",
"debug/picture_debug_util.cc",
@@ -125,10 +125,10 @@
"debug/unittest_only_benchmark_impl.h",
"input/input_handler.cc",
"input/input_handler.h",
- "input/page_scale_animation.cc",
- "input/page_scale_animation.h",
"input/layer_selection_bound.cc",
"input/layer_selection_bound.h",
+ "input/page_scale_animation.cc",
+ "input/page_scale_animation.h",
"input/scroll_elasticity_helper.cc",
"input/scroll_elasticity_helper.h",
"input/selection_bound_type.h",
@@ -301,8 +301,8 @@
"quads/draw_quad.h",
"quads/io_surface_draw_quad.cc",
"quads/io_surface_draw_quad.h",
- "quads/largest_draw_quad.h",
"quads/largest_draw_quad.cc",
+ "quads/largest_draw_quad.h",
"quads/list_container.cc",
"quads/list_container.h",
"quads/picture_draw_quad.cc",
@@ -329,10 +329,10 @@
"quads/yuv_video_draw_quad.h",
"resources/bitmap_content_layer_updater.cc",
"resources/bitmap_content_layer_updater.h",
- "resources/bitmap_tile_task_worker_pool.cc",
- "resources/bitmap_tile_task_worker_pool.h",
"resources/bitmap_skpicture_content_layer_updater.cc",
"resources/bitmap_skpicture_content_layer_updater.h",
+ "resources/bitmap_tile_task_worker_pool.cc",
+ "resources/bitmap_tile_task_worker_pool.h",
"resources/clip_display_item.cc",
"resources/clip_display_item.h",
"resources/clip_path_display_item.cc",
@@ -396,19 +396,13 @@
"resources/raster_source.h",
"resources/raster_source_helper.cc",
"resources/raster_source_helper.h",
+ "resources/raster_tile_priority_queue.cc",
+ "resources/raster_tile_priority_queue.h",
"resources/raster_tile_priority_queue_all.cc",
"resources/raster_tile_priority_queue_all.h",
"resources/raster_tile_priority_queue_required.cc",
"resources/raster_tile_priority_queue_required.h",
- "resources/raster_tile_priority_queue.cc",
- "resources/raster_tile_priority_queue.h",
"resources/rasterizer.h",
- "resources/software_rasterizer.cc",
- "resources/software_rasterizer.h",
- "resources/tile_task_worker_pool.cc",
- "resources/tile_task_worker_pool.h",
- "resources/tile_task_runner.cc",
- "resources/tile_task_runner.h",
"resources/release_callback.h",
"resources/resource.cc",
"resources/resource.h",
@@ -440,6 +434,8 @@
"resources/single_release_callback_impl.h",
"resources/skpicture_content_layer_updater.cc",
"resources/skpicture_content_layer_updater.h",
+ "resources/software_rasterizer.cc",
+ "resources/software_rasterizer.h",
"resources/task_graph_runner.cc",
"resources/task_graph_runner.h",
"resources/texture_mailbox.cc",
@@ -456,6 +452,10 @@
"resources/tile_manager.h",
"resources/tile_priority.cc",
"resources/tile_priority.h",
+ "resources/tile_task_runner.cc",
+ "resources/tile_task_runner.h",
+ "resources/tile_task_worker_pool.cc",
+ "resources/tile_task_worker_pool.h",
"resources/tiling_set_eviction_queue.cc",
"resources/tiling_set_eviction_queue.h",
"resources/tiling_set_raster_queue_all.cc",
@@ -527,10 +527,8 @@
"trees/tree_synchronizer.h",
]
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ] # size_t -> int
- }
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
public_deps = [
"//skia",
@@ -562,6 +560,8 @@
"test/animation_test_common.h",
"test/begin_frame_args_test.cc",
"test/begin_frame_args_test.h",
+ "test/failure_output_surface.cc",
+ "test/failure_output_surface.h",
"test/fake_content_layer.cc",
"test/fake_content_layer.h",
"test/fake_content_layer_client.cc",
@@ -614,12 +614,8 @@
"test/fake_tile_manager_client.h",
"test/fake_ui_resource_layer_tree_host_impl.cc",
"test/fake_ui_resource_layer_tree_host_impl.h",
- "test/failure_output_surface.cc",
- "test/failure_output_surface.h",
"test/geometry_test_utils.cc",
"test/geometry_test_utils.h",
- "test/test_in_process_context_provider.cc",
- "test/test_in_process_context_provider.h",
"test/impl_side_painting_settings.h",
"test/layer_test_common.cc",
"test/layer_test_common.h",
@@ -670,6 +666,8 @@
"test/test_gpu_memory_buffer_manager.h",
"test/test_image_factory.cc",
"test/test_image_factory.h",
+ "test/test_in_process_context_provider.cc",
+ "test/test_in_process_context_provider.h",
"test/test_now_source.cc",
"test/test_now_source.h",
"test/test_occlusion_tracker.h",
@@ -685,6 +683,8 @@
"test/tiled_layer_test_common.h",
]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
include_dirs = [
".",
"test",
@@ -744,8 +744,8 @@
"layers/delegated_frame_resource_collection_unittest.cc",
"layers/delegated_renderer_layer_impl_unittest.cc",
"layers/delegated_renderer_layer_unittest.cc",
- "layers/heads_up_display_unittest.cc",
"layers/heads_up_display_layer_impl_unittest.cc",
+ "layers/heads_up_display_unittest.cc",
"layers/io_surface_layer_impl_unittest.cc",
"layers/layer_impl_unittest.cc",
"layers/layer_iterator_unittest.cc",
@@ -759,15 +759,15 @@
"layers/picture_image_layer_unittest.cc",
"layers/picture_layer_impl_unittest.cc",
"layers/picture_layer_unittest.cc",
- "layers/render_surface_unittest.cc",
"layers/render_surface_impl_unittest.cc",
+ "layers/render_surface_unittest.cc",
"layers/scrollbar_layer_unittest.cc",
"layers/solid_color_layer_impl_unittest.cc",
"layers/solid_color_scrollbar_layer_impl_unittest.cc",
- "layers/surface_layer_unittest.cc",
"layers/surface_layer_impl_unittest.cc",
- "layers/texture_layer_unittest.cc",
+ "layers/surface_layer_unittest.cc",
"layers/texture_layer_impl_unittest.cc",
+ "layers/texture_layer_unittest.cc",
"layers/tiled_layer_impl_unittest.cc",
"layers/tiled_layer_unittest.cc",
"layers/ui_resource_layer_impl_unittest.cc",
@@ -792,8 +792,8 @@
"resources/picture_pile_impl_unittest.cc",
"resources/picture_pile_unittest.cc",
"resources/picture_unittest.cc",
+ "resources/platform_color_unittest.cc",
"resources/prioritized_resource_unittest.cc",
- "resources/tile_task_worker_pool_unittest.cc",
"resources/resource_provider_unittest.cc",
"resources/resource_update_controller_unittest.cc",
"resources/scoped_gpu_raster_unittest.cc",
@@ -803,6 +803,7 @@
"resources/texture_uploader_unittest.cc",
"resources/tile_manager_unittest.cc",
"resources/tile_priority_unittest.cc",
+ "resources/tile_task_worker_pool_unittest.cc",
"scheduler/begin_frame_source_unittest.cc",
"scheduler/delay_based_time_source_unittest.cc",
"scheduler/scheduler_state_machine_unittest.cc",
@@ -817,7 +818,6 @@
"trees/layer_tree_host_pixeltest_blending.cc",
"trees/layer_tree_host_pixeltest_filters.cc",
"trees/layer_tree_host_pixeltest_masks.cc",
- "trees/layer_tree_host_pixeltest_on_demand_raster.cc",
"trees/layer_tree_host_pixeltest_readback.cc",
"trees/layer_tree_host_pixeltest_synchronous.cc",
"trees/layer_tree_host_unittest.cc",
@@ -826,8 +826,8 @@
"trees/layer_tree_host_unittest_copyrequest.cc",
"trees/layer_tree_host_unittest_damage.cc",
"trees/layer_tree_host_unittest_delegated.cc",
- "trees/layer_tree_host_unittest_occlusion.cc",
"trees/layer_tree_host_unittest_no_message_loop.cc",
+ "trees/layer_tree_host_unittest_occlusion.cc",
"trees/layer_tree_host_unittest_picture.cc",
"trees/layer_tree_host_unittest_proxy.cc",
"trees/layer_tree_host_unittest_scroll.cc",
@@ -845,10 +845,12 @@
"surfaces/surfaces_pixeltest.cc",
# Setup.
- "test/run_all_unittests.cc",
"test/cc_test_suite.cc",
+ "test/run_all_unittests.cc",
]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
deps = [
":cc",
":test_support",
@@ -876,9 +878,9 @@
"layers/picture_layer_impl_perftest.cc",
"resources/picture_layer_tiling_perftest.cc",
"resources/picture_pile_impl_perftest.cc",
- "resources/tile_task_worker_pool_perftest.cc",
"resources/task_graph_runner_perftest.cc",
"resources/tile_manager_perftest.cc",
+ "resources/tile_task_worker_pool_perftest.cc",
"test/cc_test_suite.cc",
"test/run_all_perftests.cc",
"trees/layer_tree_host_common_perftest.cc",
@@ -886,6 +888,8 @@
"trees/occlusion_tracker_perftest.cc",
]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
deps = [
":cc",
":test_support",
diff --git a/cc/animation/animation.cc b/cc/animation/animation.cc
index 48ebc74..96cb40a 100644
--- a/cc/animation/animation.cc
+++ b/cc/animation/animation.cc
@@ -14,32 +14,28 @@
namespace {
// This should match the RunState enum.
-static const char* const s_runStateNames[] = {
- "WaitingForTargetAvailability",
- "WaitingForDeletion",
- "Starting",
- "Running",
- "Paused",
- "Finished",
- "Aborted"
-};
+static const char* const s_runStateNames[] = {"WAITING_FOR_TARGET_AVAILABILITY",
+ "WAITING_FOR_DELETION",
+ "STARTING",
+ "RUNNING",
+ "PAUSED",
+ "FINISHED",
+ "ABORTED"};
-static_assert(static_cast<int>(cc::Animation::RunStateEnumSize) ==
- arraysize(s_runStateNames),
+static_assert(static_cast<int>(cc::Animation::LAST_RUN_STATE) + 1 ==
+ arraysize(s_runStateNames),
"RunStateEnumSize should equal the number of elements in "
"s_runStateNames");
// This should match the TargetProperty enum.
-static const char* const s_targetPropertyNames[] = {
- "Transform",
- "Opacity",
- "Filter",
- "ScrollOffset",
- "BackgroundColor"
-};
+static const char* const s_targetPropertyNames[] = {"TRANSFORM",
+ "OPACITY",
+ "FILTER",
+ "SCROLL_OFFSET",
+ "BACKGROUND_COLOR"};
-static_assert(static_cast<int>(cc::Animation::TargetPropertyEnumSize) ==
- arraysize(s_targetPropertyNames),
+static_assert(static_cast<int>(cc::Animation::LAST_TARGET_PROPERTY) + 1 ==
+ arraysize(s_targetPropertyNames),
"TargetPropertyEnumSize should equal the number of elements in "
"s_targetPropertyNames");
@@ -65,12 +61,12 @@
id_(animation_id),
group_(group_id),
target_property_(target_property),
- run_state_(WaitingForTargetAvailability),
+ run_state_(WAITING_FOR_TARGET_AVAILABILITY),
iterations_(1),
iteration_start_(0),
- direction_(Normal),
+ direction_(DIRECTION_NORMAL),
playback_rate_(1),
- fill_mode_(FillModeBoth),
+ fill_mode_(FILL_MODE_BOTH),
needs_synchronized_start_time_(false),
received_finished_event_(false),
suspended_(false),
@@ -81,8 +77,8 @@
}
Animation::~Animation() {
- if (run_state_ == Running || run_state_ == Paused)
- SetRunState(Aborted, base::TimeTicks());
+ if (run_state_ == RUNNING || run_state_ == PAUSED)
+ SetRunState(ABORTED, base::TimeTicks());
}
void Animation::SetRunState(RunState run_state,
@@ -97,10 +93,10 @@
s_targetPropertyNames[target_property_],
group_);
- bool is_waiting_to_start = run_state_ == WaitingForTargetAvailability ||
- run_state_ == Starting;
+ bool is_waiting_to_start =
+ run_state_ == WAITING_FOR_TARGET_AVAILABILITY || run_state_ == STARTING;
- if (is_controlling_instance_ && is_waiting_to_start && run_state == Running) {
+ if (is_controlling_instance_ && is_waiting_to_start && run_state == RUNNING) {
TRACE_EVENT_ASYNC_BEGIN1(
"cc", "Animation", this, "Name", TRACE_STR_COPY(name_buffer));
}
@@ -109,9 +105,9 @@
const char* old_run_state_name = s_runStateNames[run_state_];
- if (run_state == Running && run_state_ == Paused)
+ if (run_state == RUNNING && run_state_ == PAUSED)
total_paused_time_ += (monotonic_time - pause_time_);
- else if (run_state == Paused)
+ else if (run_state == PAUSED)
pause_time_ = monotonic_time;
run_state_ = run_state;
@@ -137,13 +133,13 @@
}
void Animation::Suspend(base::TimeTicks monotonic_time) {
- SetRunState(Paused, monotonic_time);
+ SetRunState(PAUSED, monotonic_time);
suspended_ = true;
}
void Animation::Resume(base::TimeTicks monotonic_time) {
suspended_ = false;
- SetRunState(Running, monotonic_time);
+ SetRunState(RUNNING, monotonic_time);
}
bool Animation::IsFinishedAt(base::TimeTicks monotonic_time) const {
@@ -156,7 +152,7 @@
if (playback_rate_ == 0)
return false;
- return run_state_ == Running && iterations_ >= 0 &&
+ return run_state_ == RUNNING && iterations_ >= 0 &&
TimeUtil::Scale(curve_->Duration(),
iterations_ / std::abs(playback_rate_)) <=
(monotonic_time + time_offset_ - start_time_ - total_paused_time_);
@@ -164,7 +160,7 @@
bool Animation::InEffect(base::TimeTicks monotonic_time) const {
return ConvertToActiveTime(monotonic_time) >= base::TimeDelta() ||
- (fill_mode_ == FillModeBoth || fill_mode_ == FillModeBackwards);
+ (fill_mode_ == FILL_MODE_BOTH || fill_mode_ == FILL_MODE_BACKWARDS);
}
base::TimeDelta Animation::ConvertToActiveTime(
@@ -172,7 +168,7 @@
base::TimeTicks trimmed = monotonic_time + time_offset_;
// If we're paused, time is 'stuck' at the pause time.
- if (run_state_ == Paused)
+ if (run_state_ == PAUSED)
trimmed = pause_time_;
// Returned time should always be relative to the start time and should
@@ -181,7 +177,7 @@
// If we're just starting or we're waiting on receiving a start time,
// time is 'stuck' at the initial state.
- if ((run_state_ == Starting && !has_set_start_time()) ||
+ if ((run_state_ == STARTING && !has_set_start_time()) ||
needs_synchronized_start_time())
trimmed = base::TimeTicks() + time_offset_;
@@ -247,9 +243,10 @@
// Check if we are running the animation in reverse direction for the current
// iteration
- bool reverse = (direction_ == Reverse) ||
- (direction_ == Alternate && iteration % 2 == 1) ||
- (direction_ == AlternateReverse && iteration % 2 == 0);
+ bool reverse =
+ (direction_ == DIRECTION_REVERSE) ||
+ (direction_ == DIRECTION_ALTERNATE && iteration % 2 == 1) ||
+ (direction_ == DIRECTION_ALTERNATE_REVERSE && iteration % 2 == 0);
// If we are running the animation in reverse direction, reverse the result
if (reverse)
@@ -280,8 +277,8 @@
void Animation::PushPropertiesTo(Animation* other) const {
// Currently, we only push changes due to pausing and resuming animations on
// the main thread.
- if (run_state_ == Animation::Paused ||
- other->run_state_ == Animation::Paused) {
+ if (run_state_ == Animation::PAUSED ||
+ other->run_state_ == Animation::PAUSED) {
other->run_state_ = run_state_;
other->pause_time_ = pause_time_;
other->total_paused_time_ = total_paused_time_;
diff --git a/cc/animation/animation.h b/cc/animation/animation.h
index 9342f1a..2677fde 100644
--- a/cc/animation/animation.h
+++ b/cc/animation/animation.h
@@ -19,43 +19,48 @@
// loop count, last pause time, and the total time spent paused.
class CC_EXPORT Animation {
public:
- // Animations begin in the 'WaitingForTargetAvailability' state. An Animation
- // waiting for target availibility will run as soon as its target property
- // is free (and all the animations animating with it are also able to run).
- // When this time arrives, the controller will move the animation into the
- // Starting state, and then into the Running state. Running animations may
- // toggle between Running and Paused, and may be stopped by moving into either
- // the Aborted or Finished states. A Finished animation was allowed to run to
- // completion, but an Aborted animation was not.
+ // Animations begin in the 'WAITING_FOR_TARGET_AVAILABILITY' state. An
+ // Animation waiting for target availibility will run as soon as its target
+ // property is free (and all the animations animating with it are also able to
+ // run). When this time arrives, the controller will move the animation into
+ // the STARTING state, and then into the RUNNING state. RUNNING animations may
+ // toggle between RUNNING and PAUSED, and may be stopped by moving into either
+ // the ABORTED or FINISHED states. A FINISHED animation was allowed to run to
+ // completion, but an ABORTED animation was not.
enum RunState {
- WaitingForTargetAvailability = 0,
- WaitingForDeletion,
- Starting,
- Running,
- Paused,
- Finished,
- Aborted,
+ WAITING_FOR_TARGET_AVAILABILITY = 0,
+ WAITING_FOR_DELETION,
+ STARTING,
+ RUNNING,
+ PAUSED,
+ FINISHED,
+ ABORTED,
// This sentinel must be last.
- RunStateEnumSize
+ LAST_RUN_STATE = ABORTED
};
enum TargetProperty {
- Transform = 0,
- Opacity,
- Filter,
- ScrollOffset,
- BackgroundColor,
+ TRANSFORM = 0,
+ OPACITY,
+ FILTER,
+ SCROLL_OFFSET,
+ BACKGROUND_COLOR,
// This sentinel must be last.
- TargetPropertyEnumSize
+ LAST_TARGET_PROPERTY = BACKGROUND_COLOR
};
- enum Direction { Normal, Reverse, Alternate, AlternateReverse };
+ enum Direction {
+ DIRECTION_NORMAL,
+ DIRECTION_REVERSE,
+ DIRECTION_ALTERNATE,
+ DIRECTION_ALTERNATE_REVERSE
+ };
enum FillMode {
- FillModeNone,
- FillModeForwards,
- FillModeBackwards,
- FillModeBoth
+ FILL_MODE_NONE,
+ FILL_MODE_FORWARDS,
+ FILL_MODE_BACKWARDS,
+ FILL_MODE_BOTH
};
static scoped_ptr<Animation> Create(scoped_ptr<AnimationCurve> curve,
@@ -111,9 +116,8 @@
bool IsFinishedAt(base::TimeTicks monotonic_time) const;
bool is_finished() const {
- return run_state_ == Finished ||
- run_state_ == Aborted ||
- run_state_ == WaitingForDeletion;
+ return run_state_ == FINISHED || run_state_ == ABORTED ||
+ run_state_ == WAITING_FOR_DELETION;
}
bool InEffect(base::TimeTicks monotonic_time) const;
@@ -131,7 +135,7 @@
needs_synchronized_start_time_ = needs_synchronized_start_time;
}
- // This is true for animations running on the main thread when the Finished
+ // This is true for animations running on the main thread when the FINISHED
// event sent by the corresponding impl animation has been received.
bool received_finished_event() const {
return received_finished_event_;
@@ -227,10 +231,10 @@
// When pushed from a main-thread controller to a compositor-thread
// controller, an animation will initially only affect pending observers
// (corresponding to layers in the pending tree). Animations that only
- // affect pending observers are able to reach the Starting state and tick
+ // affect pending observers are able to reach the STARTING state and tick
// pending observers, but cannot proceed any further and do not tick active
// observers. After activation, such animations affect both kinds of observers
- // and are able to proceed past the Starting state. When the removal of
+ // and are able to proceed past the STARTING state. When the removal of
// an animation is pushed from a main-thread controller to a
// compositor-thread controller, this initially only makes the animation
// stop affecting pending observers. After activation, such animations no
diff --git a/cc/animation/animation_curve.cc b/cc/animation/animation_curve.cc
index 3acff5d..9e8cae9 100644
--- a/cc/animation/animation_curve.cc
+++ b/cc/animation/animation_curve.cc
@@ -10,48 +10,50 @@
namespace cc {
const ColorAnimationCurve* AnimationCurve::ToColorAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::Color);
+ DCHECK(Type() == AnimationCurve::COLOR);
return static_cast<const ColorAnimationCurve*>(this);
}
-AnimationCurve::CurveType ColorAnimationCurve::Type() const { return Color; }
+AnimationCurve::CurveType ColorAnimationCurve::Type() const {
+ return COLOR;
+}
const FloatAnimationCurve* AnimationCurve::ToFloatAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::Float);
+ DCHECK(Type() == AnimationCurve::FLOAT);
return static_cast<const FloatAnimationCurve*>(this);
}
AnimationCurve::CurveType FloatAnimationCurve::Type() const {
- return Float;
+ return FLOAT;
}
const TransformAnimationCurve* AnimationCurve::ToTransformAnimationCurve()
const {
- DCHECK(Type() == AnimationCurve::Transform);
+ DCHECK(Type() == AnimationCurve::TRANSFORM);
return static_cast<const TransformAnimationCurve*>(this);
}
AnimationCurve::CurveType TransformAnimationCurve::Type() const {
- return Transform;
+ return TRANSFORM;
}
const FilterAnimationCurve* AnimationCurve::ToFilterAnimationCurve() const {
- DCHECK(Type() == AnimationCurve::Filter);
+ DCHECK(Type() == AnimationCurve::FILTER);
return static_cast<const FilterAnimationCurve*>(this);
}
AnimationCurve::CurveType FilterAnimationCurve::Type() const {
- return Filter;
+ return FILTER;
}
const ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve()
const {
- DCHECK(Type() == AnimationCurve::ScrollOffset);
+ DCHECK(Type() == AnimationCurve::SCROLL_OFFSET);
return static_cast<const ScrollOffsetAnimationCurve*>(this);
}
ScrollOffsetAnimationCurve* AnimationCurve::ToScrollOffsetAnimationCurve() {
- DCHECK(Type() == AnimationCurve::ScrollOffset);
+ DCHECK(Type() == AnimationCurve::SCROLL_OFFSET);
return static_cast<ScrollOffsetAnimationCurve*>(this);
}
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h
index 74ce11b..1074203 100644
--- a/cc/animation/animation_curve.h
+++ b/cc/animation/animation_curve.h
@@ -27,7 +27,7 @@
// An animation curve is a function that returns a value given a time.
class CC_EXPORT AnimationCurve {
public:
- enum CurveType { Color, Float, Transform, Filter, ScrollOffset };
+ enum CurveType { COLOR, FLOAT, TRANSFORM, FILTER, SCROLL_OFFSET };
virtual ~AnimationCurve() {}
diff --git a/cc/animation/animation_events.h b/cc/animation/animation_events.h
index e40ca3f..d268162 100644
--- a/cc/animation/animation_events.h
+++ b/cc/animation/animation_events.h
@@ -15,7 +15,7 @@
namespace cc {
struct CC_EXPORT AnimationEvent {
- enum Type { Started, Finished, Aborted, PropertyUpdate };
+ enum Type { STARTED, FINISHED, ABORTED, PROPERTY_UPDATE };
AnimationEvent(Type type,
int layer_id,
diff --git a/cc/animation/animation_unittest.cc b/cc/animation/animation_unittest.cc
index 2522f19..9345c6b 100644
--- a/cc/animation/animation_unittest.cc
+++ b/cc/animation/animation_unittest.cc
@@ -23,9 +23,7 @@
double playback_rate) {
scoped_ptr<Animation> to_return(
Animation::Create(make_scoped_ptr(new FakeFloatAnimationCurve(duration)),
- 0,
- 1,
- Animation::Opacity));
+ 0, 1, Animation::OPACITY));
to_return->set_iterations(iterations);
to_return->set_playback_rate(playback_rate);
return to_return.Pass();
@@ -93,7 +91,7 @@
TEST(AnimationTest, TrimTimeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->set_direction(Animation::Reverse);
+ anim->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_EQ(
1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0)).InSecondsF());
EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -110,7 +108,7 @@
TEST(AnimationTest, TrimTimeAlternateInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -127,7 +125,7 @@
TEST(AnimationTest, TrimTimeAlternateOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -144,7 +142,7 @@
TEST(AnimationTest, TrimTimeAlternateTwoIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -167,7 +165,7 @@
TEST(AnimationTest, TrimTimeAlternateTwoHalfIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2.5));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.25, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -194,7 +192,7 @@
TEST(AnimationTest, TrimTimeAlternateReverseInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->set_direction(Animation::AlternateReverse);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -211,7 +209,7 @@
TEST(AnimationTest, TrimTimeAlternateReverseOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::AlternateReverse);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -228,7 +226,7 @@
TEST(AnimationTest, TrimTimeAlternateReverseTwoIterations) {
scoped_ptr<Animation> anim(CreateAnimation(2));
- anim->set_direction(Animation::AlternateReverse);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -267,7 +265,7 @@
TEST(AnimationTest, TrimTimeStartTimeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_start_time(TicksFromSecondsF(4));
- anim->set_direction(Animation::Reverse);
+ anim->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_EQ(
0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(4.0))
@@ -298,7 +296,7 @@
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(4000));
anim->set_start_time(TicksFromSecondsF(4));
- anim->set_direction(Animation::Reverse);
+ anim->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
@@ -326,7 +324,7 @@
TEST(AnimationTest, TrimTimeNegativeTimeOffsetReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(-4000));
- anim->set_direction(Animation::Reverse);
+ anim->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_EQ(
0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
@@ -340,15 +338,15 @@
TEST(AnimationTest, TrimTimePauseResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_EQ(
0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
.InSecondsF());
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.5));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.5));
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
.InSecondsF());
- anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(1024.0));
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
.InSecondsF());
EXPECT_EQ(1, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.5))
@@ -357,16 +355,16 @@
TEST(AnimationTest, TrimTimePauseResumeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::Reverse);
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
.InSecondsF());
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.25));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.25));
EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
.InSecondsF());
- anim->SetRunState(Animation::Running, TicksFromSecondsF(1024.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(1024.0));
EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.0))
.InSecondsF());
EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(1024.75))
@@ -375,7 +373,7 @@
TEST(AnimationTest, TrimTimeSuspendResume) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_EQ(
0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0)).InSecondsF());
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
@@ -392,8 +390,8 @@
TEST(AnimationTest, TrimTimeSuspendResumeReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_direction(Animation::Reverse);
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->set_direction(Animation::DIRECTION_REVERSE);
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.75, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -410,7 +408,7 @@
TEST(AnimationTest, TrimTimeZeroDuration) {
scoped_ptr<Animation> anim(CreateAnimation(0, 0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
EXPECT_EQ(
@@ -421,7 +419,7 @@
TEST(AnimationTest, TrimTimeStarting) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
- anim->SetRunState(Animation::Starting, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::STARTING, TicksFromSecondsF(0.0));
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
@@ -448,7 +446,7 @@
TEST(AnimationTest, TrimTimeNeedsSynchronizedStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1, 5.0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
anim->set_needs_synchronized_start_time(true);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
@@ -475,7 +473,7 @@
TEST(AnimationTest, IsFinishedAtZeroIterations) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
@@ -483,7 +481,7 @@
TEST(AnimationTest, IsFinishedAtOneIteration) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
@@ -492,7 +490,7 @@
TEST(AnimationTest, IsFinishedAtInfiniteIterations) {
scoped_ptr<Animation> anim(CreateAnimation(-1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.5)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(1.0)));
@@ -502,7 +500,7 @@
TEST(AnimationTest, IsFinishedNegativeTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(-500));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
@@ -516,7 +514,7 @@
TEST(AnimationTest, IsFinishedPositiveTimeOffset) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->set_time_offset(TimeDelta::FromMilliseconds(500));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(-1.0)));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
@@ -526,58 +524,58 @@
TEST(AnimationTest, IsFinishedAtNotRunning) {
scoped_ptr<Animation> anim(CreateAnimation(0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::WaitingForTargetAvailability,
+ anim->SetRunState(Animation::WAITING_FOR_TARGET_AVAILABILITY,
TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
- anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::ABORTED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->IsFinishedAt(TicksFromSecondsF(0.0)));
}
TEST(AnimationTest, IsFinished) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::WaitingForTargetAvailability,
+ anim->SetRunState(Animation::WAITING_FOR_TARGET_AVAILABILITY,
TicksFromSecondsF(0.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
- anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::ABORTED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
}
TEST(AnimationTest, IsFinishedNeedsSynchronizedStartTime) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(2.0));
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Paused, TicksFromSecondsF(2.0));
+ anim->SetRunState(Animation::PAUSED, TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::WaitingForTargetAvailability,
+ anim->SetRunState(Animation::WAITING_FOR_TARGET_AVAILABILITY,
TicksFromSecondsF(2.0));
EXPECT_FALSE(anim->is_finished());
- anim->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
- anim->SetRunState(Animation::Aborted, TicksFromSecondsF(0.0));
+ anim->SetRunState(Animation::ABORTED, TicksFromSecondsF(0.0));
EXPECT_TRUE(anim->is_finished());
}
TEST(AnimationTest, RunStateChangesIgnoredWhileSuspended) {
scoped_ptr<Animation> anim(CreateAnimation(1));
anim->Suspend(TicksFromSecondsF(0));
- EXPECT_EQ(Animation::Paused, anim->run_state());
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(Animation::Paused, anim->run_state());
+ EXPECT_EQ(Animation::PAUSED, anim->run_state());
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(Animation::PAUSED, anim->run_state());
anim->Resume(TicksFromSecondsF(0));
- anim->SetRunState(Animation::Running, TicksFromSecondsF(0.0));
- EXPECT_EQ(Animation::Running, anim->run_state());
+ anim->SetRunState(Animation::RUNNING, TicksFromSecondsF(0.0));
+ EXPECT_EQ(Animation::RUNNING, anim->run_state());
}
TEST(AnimationTest, TrimTimePlaybackNormal) {
@@ -708,7 +706,7 @@
TEST(AnimationTest, TrimTimePlaybackNormalDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, -1));
- anim->set_direction(Animation::Reverse);
+ anim->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
EXPECT_EQ(
@@ -723,7 +721,7 @@
TEST(AnimationTest, TrimTimePlaybackFastDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(1, 4, -2));
- anim->set_direction(Animation::Reverse);
+ anim->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_EQ(0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
EXPECT_EQ(
@@ -742,7 +740,7 @@
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFast) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -767,7 +765,7 @@
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastReverse) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, 2));
- anim->set_direction(Animation::AlternateReverse);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
@@ -794,7 +792,7 @@
TEST(AnimationTest, TrimTimeAlternateTwoIterationsPlaybackFastDoubleReverse) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, -2));
- anim->set_direction(Animation::AlternateReverse);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
EXPECT_EQ(2.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(1.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -820,7 +818,7 @@
TEST(AnimationTest,
TrimTimeAlternateReverseThreeIterationsPlaybackFastAlternateReverse) {
scoped_ptr<Animation> anim(CreateAnimation(3, 2, -2));
- anim->set_direction(Animation::AlternateReverse);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE_REVERSE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.25))
@@ -854,7 +852,7 @@
TEST(AnimationTest,
TrimTimeAlternateReverseTwoIterationsPlaybackNormalAlternate) {
scoped_ptr<Animation> anim(CreateAnimation(2, 2, -1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
EXPECT_EQ(0.5, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.5))
@@ -898,7 +896,7 @@
TEST(AnimationTest, TrimTimeIterationStartAlternate) {
scoped_ptr<Animation> anim(CreateAnimation(2, 1, 1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
anim->set_iteration_start(0.3);
EXPECT_EQ(0.3, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
@@ -918,7 +916,7 @@
TEST(AnimationTest, TrimTimeIterationStartAlternateThreeIterations) {
scoped_ptr<Animation> anim(CreateAnimation(3, 1, 1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
anim->set_iteration_start(1);
EXPECT_EQ(1.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(-1.0))
.InSecondsF());
@@ -943,7 +941,7 @@
TEST(AnimationTest,
TrimTimeIterationStartAlternateThreeIterationsPlaybackReverse) {
scoped_ptr<Animation> anim(CreateAnimation(3, 1, -1));
- anim->set_direction(Animation::Alternate);
+ anim->set_direction(Animation::DIRECTION_ALTERNATE);
anim->set_iteration_start(1);
EXPECT_EQ(0.0, anim->TrimTimeToCurrentIteration(TicksFromSecondsF(0.0))
.InSecondsF());
@@ -959,22 +957,22 @@
TEST(AnimationTest, InEffectFillMode) {
scoped_ptr<Animation> anim(CreateAnimation(1));
- anim->set_fill_mode(Animation::FillModeNone);
+ anim->set_fill_mode(Animation::FILL_MODE_NONE);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeForwards);
+ anim->set_fill_mode(Animation::FILL_MODE_FORWARDS);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBackwards);
+ anim->set_fill_mode(Animation::FILL_MODE_BACKWARDS);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBoth);
+ anim->set_fill_mode(Animation::FILL_MODE_BOTH);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
@@ -982,22 +980,22 @@
TEST(AnimationTest, InEffectFillModePlayback) {
scoped_ptr<Animation> anim(CreateAnimation(1, 1, -1));
- anim->set_fill_mode(Animation::FillModeNone);
+ anim->set_fill_mode(Animation::FILL_MODE_NONE);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeForwards);
+ anim->set_fill_mode(Animation::FILL_MODE_FORWARDS);
EXPECT_FALSE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBackwards);
+ anim->set_fill_mode(Animation::FILL_MODE_BACKWARDS);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
- anim->set_fill_mode(Animation::FillModeBoth);
+ anim->set_fill_mode(Animation::FILL_MODE_BOTH);
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(-1.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(0.0)));
EXPECT_TRUE(anim->InEffect(TicksFromSecondsF(1.0)));
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc
index 1892dd4..c253dae 100644
--- a/cc/animation/layer_animation_controller.cc
+++ b/cc/animation/layer_animation_controller.cc
@@ -45,7 +45,7 @@
base::TimeDelta time_offset) {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->id() == animation_id) {
- animations_[i]->SetRunState(Animation::Paused,
+ animations_[i]->SetRunState(Animation::PAUSED,
time_offset + animations_[i]->start_time());
}
}
@@ -65,13 +65,13 @@
auto animations_to_remove =
animations_.remove_if(HasAnimationId(animation_id));
for (auto it = animations_to_remove; it != animations_.end(); ++it) {
- if ((*it)->target_property() == Animation::ScrollOffset) {
+ if ((*it)->target_property() == Animation::SCROLL_OFFSET) {
scroll_offset_animation_was_interrupted_ = true;
break;
}
}
animations_.erase(animations_to_remove, animations_.end());
- UpdateActivation(NormalActivation);
+ UpdateActivation(NORMAL_ACTIVATION);
}
struct HasAnimationIdAndProperty {
@@ -92,12 +92,12 @@
Animation::TargetProperty target_property) {
auto animations_to_remove = animations_.remove_if(
HasAnimationIdAndProperty(animation_id, target_property));
- if (target_property == Animation::ScrollOffset &&
+ if (target_property == Animation::SCROLL_OFFSET &&
animations_to_remove != animations_.end())
scroll_offset_animation_was_interrupted_ = true;
animations_.erase(animations_to_remove, animations_.end());
- UpdateActivation(NormalActivation);
+ UpdateActivation(NORMAL_ACTIVATION);
}
void LayerAnimationController::AbortAnimations(
@@ -105,7 +105,7 @@
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->target_property() == target_property &&
!animations_[i]->is_finished())
- animations_[i]->SetRunState(Animation::Aborted, last_tick_time_);
+ animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_);
}
}
@@ -125,8 +125,8 @@
RemoveAnimationsCompletedOnMainThread(controller_impl);
PushPropertiesToImplThread(controller_impl);
- controller_impl->UpdateActivation(NormalActivation);
- UpdateActivation(NormalActivation);
+ controller_impl->UpdateActivation(NORMAL_ACTIVATION);
+ UpdateActivation(NORMAL_ACTIVATION);
}
void LayerAnimationController::Animate(base::TimeTicks monotonic_time) {
@@ -157,11 +157,9 @@
base::TimeDelta trimmed =
animation->TrimTimeToCurrentIteration(monotonic_time);
switch (animation->target_property()) {
- case Animation::Opacity: {
- AnimationEvent event(AnimationEvent::PropertyUpdate,
- id_,
- animation->group(),
- Animation::Opacity,
+ case Animation::OPACITY: {
+ AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_,
+ animation->group(), Animation::OPACITY,
monotonic_time);
const FloatAnimationCurve* float_animation_curve =
animation->curve()->ToFloatAnimationCurve();
@@ -171,11 +169,9 @@
break;
}
- case Animation::Transform: {
- AnimationEvent event(AnimationEvent::PropertyUpdate,
- id_,
- animation->group(),
- Animation::Transform,
+ case Animation::TRANSFORM: {
+ AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_,
+ animation->group(), Animation::TRANSFORM,
monotonic_time);
const TransformAnimationCurve* transform_animation_curve =
animation->curve()->ToTransformAnimationCurve();
@@ -185,11 +181,9 @@
break;
}
- case Animation::Filter: {
- AnimationEvent event(AnimationEvent::PropertyUpdate,
- id_,
- animation->group(),
- Animation::Filter,
+ case Animation::FILTER: {
+ AnimationEvent event(AnimationEvent::PROPERTY_UPDATE, id_,
+ animation->group(), Animation::FILTER,
monotonic_time);
const FilterAnimationCurve* filter_animation_curve =
animation->curve()->ToFilterAnimationCurve();
@@ -199,17 +193,16 @@
break;
}
- case Animation::BackgroundColor: { break; }
-
- case Animation::ScrollOffset: {
- // Impl-side changes to scroll offset are already sent back to the
- // main thread (e.g. for user-driven scrolling), so a PropertyUpdate
- // isn't needed.
+ case Animation::BACKGROUND_COLOR: {
break;
}
- case Animation::TargetPropertyEnumSize:
- NOTREACHED();
+ case Animation::SCROLL_OFFSET: {
+ // Impl-side changes to scroll offset are already sent back to the
+ // main thread (e.g. for user-driven scrolling), so a PROPERTY_UPDATE
+ // isn't needed.
+ break;
+ }
}
}
}
@@ -237,7 +230,7 @@
AccumulatePropertyUpdates(last_tick_time_, events);
- UpdateActivation(NormalActivation);
+ UpdateActivation(NORMAL_ACTIVATION);
}
struct AffectsNoObservers {
@@ -258,13 +251,13 @@
AffectsNoObservers()),
animations_.end());
scroll_offset_animation_was_interrupted_ = false;
- UpdateActivation(NormalActivation);
+ UpdateActivation(NORMAL_ACTIVATION);
}
void LayerAnimationController::AddAnimation(scoped_ptr<Animation> animation) {
animations_.push_back(animation.Pass());
needs_to_start_animations_ = true;
- UpdateActivation(NormalActivation);
+ UpdateActivation(NORMAL_ACTIVATION);
}
Animation* LayerAnimationController::GetAnimation(
@@ -315,7 +308,7 @@
if (registrar_)
registrar_->RegisterAnimationController(this);
- UpdateActivation(ForceActivation);
+ UpdateActivation(FORCE_ACTIVATION);
}
void LayerAnimationController::NotifyAnimationStarted(
@@ -375,7 +368,7 @@
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->group() == event.group_id &&
animations_[i]->target_property() == event.target_property) {
- animations_[i]->SetRunState(Animation::Aborted, event.monotonic_time);
+ animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time);
}
}
}
@@ -385,11 +378,11 @@
bool notify_active_observers = true;
bool notify_pending_observers = true;
switch (event.target_property) {
- case Animation::Opacity:
+ case Animation::OPACITY:
NotifyObserversOpacityAnimated(
event.opacity, notify_active_observers, notify_pending_observers);
break;
- case Animation::Transform:
+ case Animation::TRANSFORM:
NotifyObserversTransformAnimated(
event.transform, notify_active_observers, notify_pending_observers);
break;
@@ -423,7 +416,7 @@
bool LayerAnimationController::HasFilterAnimationThatInflatesBounds() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (!animations_[i]->is_finished() &&
- animations_[i]->target_property() == Animation::Filter &&
+ animations_[i]->target_property() == Animation::FILTER &&
animations_[i]
->curve()
->ToFilterAnimationCurve()
@@ -435,7 +428,7 @@
}
bool LayerAnimationController::HasTransformAnimationThatInflatesBounds() const {
- return IsAnimatingProperty(Animation::Transform);
+ return IsAnimatingProperty(Animation::TRANSFORM);
}
bool LayerAnimationController::FilterAnimationBoundsForBox(
@@ -459,7 +452,7 @@
*bounds = gfx::BoxF();
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
const TransformAnimationCurve* transform_animation_curve =
@@ -478,7 +471,7 @@
bool LayerAnimationController::HasAnimationThatAffectsScale() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
const TransformAnimationCurve* transform_animation_curve =
@@ -493,7 +486,7 @@
bool LayerAnimationController::HasOnlyTranslationTransforms() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
const TransformAnimationCurve* transform_animation_curve =
@@ -508,7 +501,7 @@
bool LayerAnimationController::AnimationsPreserveAxisAlignment() const {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
const TransformAnimationCurve* transform_animation_curve =
@@ -524,17 +517,17 @@
*max_scale = 0.f;
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->is_finished() ||
- animations_[i]->target_property() != Animation::Transform)
+ animations_[i]->target_property() != Animation::TRANSFORM)
continue;
bool forward_direction = true;
switch (animations_[i]->direction()) {
- case Animation::Normal:
- case Animation::Alternate:
+ case Animation::DIRECTION_NORMAL:
+ case Animation::DIRECTION_ALTERNATE:
forward_direction = animations_[i]->playback_rate() >= 0.0;
break;
- case Animation::Reverse:
- case Animation::AlternateReverse:
+ case Animation::DIRECTION_REVERSE:
+ case Animation::DIRECTION_ALTERNATE_REVERSE:
forward_direction = animations_[i]->playback_rate() < 0.0;
break;
}
@@ -571,7 +564,7 @@
continue;
// Scroll animations always start at the current scroll offset.
- if (animations_[i]->target_property() == Animation::ScrollOffset) {
+ if (animations_[i]->target_property() == Animation::SCROLL_OFFSET) {
gfx::ScrollOffset current_scroll_offset;
if (controller_impl->value_provider_) {
current_scroll_offset =
@@ -587,7 +580,7 @@
// The new animation should be set to run as soon as possible.
Animation::RunState initial_run_state =
- Animation::WaitingForTargetAvailability;
+ Animation::WAITING_FOR_TARGET_AVAILABILITY;
scoped_ptr<Animation> to_add(
animations_[i]->CloneAndInitialize(initial_run_state));
DCHECK(!to_add->needs_synchronized_start_time());
@@ -600,14 +593,14 @@
Animation* animation,
const LayerAnimationController* main_thread_controller) {
if (animation->is_impl_only()) {
- return (animation->run_state() == Animation::WaitingForDeletion);
+ return (animation->run_state() == Animation::WAITING_FOR_DELETION);
} else {
return !main_thread_controller->GetAnimationById(animation->id());
}
}
static bool AffectsActiveOnlyAndIsWaitingForDeletion(Animation* animation) {
- return animation->run_state() == Animation::WaitingForDeletion &&
+ return animation->run_state() == Animation::WAITING_FOR_DELETION &&
!animation->affects_pending_observers();
}
@@ -615,7 +608,7 @@
LayerAnimationController* controller_impl) const {
// Animations removed on the main thread should no longer affect pending
// observers, and should stop affecting active observers after the next call
- // to ActivateAnimations. If already WaitingForDeletion, they can be removed
+ // to ActivateAnimations. If already WAITING_FOR_DELETION, they can be removed
// immediately.
ScopedPtrVector<Animation>& animations = controller_impl->animations_;
for (size_t i = 0; i < animations.size(); ++i) {
@@ -652,8 +645,8 @@
animations_waiting_for_target.reserve(animations_.size());
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() == Animation::Starting ||
- animations_[i]->run_state() == Animation::Running) {
+ if (animations_[i]->run_state() == Animation::STARTING ||
+ animations_[i]->run_state() == Animation::RUNNING) {
if (animations_[i]->affects_active_observers()) {
blocked_properties_for_active_observers.insert(
animations_[i]->target_property());
@@ -663,7 +656,7 @@
animations_[i]->target_property());
}
} else if (animations_[i]->run_state() ==
- Animation::WaitingForTargetAvailability) {
+ Animation::WAITING_FOR_TARGET_AVAILABILITY) {
animations_waiting_for_target.push_back(i);
}
}
@@ -677,7 +670,7 @@
// for target because it might have changed the run state while handling
// previous animation in this loop (if they belong to same group).
if (animation_waiting_for_target->run_state() ==
- Animation::WaitingForTargetAvailability) {
+ Animation::WAITING_FOR_TARGET_AVAILABILITY) {
TargetProperties enqueued_properties;
bool affects_active_observers =
animation_waiting_for_target->affects_active_observers();
@@ -715,12 +708,12 @@
// If the intersection is null, then we are free to start the animations
// in the group.
if (null_intersection) {
- animation_waiting_for_target->SetRunState(Animation::Starting,
+ animation_waiting_for_target->SetRunState(Animation::STARTING,
monotonic_time);
for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
if (animation_waiting_for_target->group() ==
animations_[j]->group()) {
- animations_[j]->SetRunState(Animation::Starting, monotonic_time);
+ animations_[j]->SetRunState(Animation::STARTING, monotonic_time);
}
}
} else {
@@ -734,18 +727,16 @@
base::TimeTicks monotonic_time,
AnimationEventsVector* events) {
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() == Animation::Starting &&
+ if (animations_[i]->run_state() == Animation::STARTING &&
animations_[i]->affects_active_observers()) {
- animations_[i]->SetRunState(Animation::Running, monotonic_time);
+ animations_[i]->SetRunState(Animation::RUNNING, monotonic_time);
if (!animations_[i]->has_set_start_time() &&
!animations_[i]->needs_synchronized_start_time())
animations_[i]->set_start_time(monotonic_time);
if (events) {
- AnimationEvent started_event(AnimationEvent::Started,
- id_,
- animations_[i]->group(),
- animations_[i]->target_property(),
- monotonic_time);
+ AnimationEvent started_event(
+ AnimationEvent::STARTED, id_, animations_[i]->group(),
+ animations_[i]->target_property(), monotonic_time);
started_event.is_impl_only = animations_[i]->is_impl_only();
if (started_event.is_impl_only)
NotifyAnimationStarted(started_event);
@@ -760,9 +751,9 @@
base::TimeTicks monotonic_time) {
for (size_t i = 0; i < animations_.size(); ++i) {
if (animations_[i]->IsFinishedAt(monotonic_time) &&
- animations_[i]->run_state() != Animation::Aborted &&
- animations_[i]->run_state() != Animation::WaitingForDeletion)
- animations_[i]->SetRunState(Animation::Finished, monotonic_time);
+ animations_[i]->run_state() != Animation::ABORTED &&
+ animations_[i]->run_state() != Animation::WAITING_FOR_DELETION)
+ animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
}
}
@@ -774,21 +765,19 @@
animations_with_same_group_id.reserve(animations_.size());
// Non-aborted animations are marked for deletion after a corresponding
- // AnimationEvent::Finished event is sent or received. This means that if
+ // AnimationEvent::FINISHED event is sent or received. This means that if
// we don't have an events vector, we must ensure that non-aborted animations
// have received a finished event before marking them for deletion.
for (size_t i = 0; i < animations_.size(); i++) {
int group_id = animations_[i]->group();
- if (animations_[i]->run_state() == Animation::Aborted) {
+ if (animations_[i]->run_state() == Animation::ABORTED) {
if (events && !animations_[i]->is_impl_only()) {
- AnimationEvent aborted_event(AnimationEvent::Aborted,
- id_,
- group_id,
+ AnimationEvent aborted_event(AnimationEvent::ABORTED, id_, group_id,
animations_[i]->target_property(),
monotonic_time);
events->push_back(aborted_event);
}
- animations_[i]->SetRunState(Animation::WaitingForDeletion,
+ animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
monotonic_time);
marked_animations_for_deletions = true;
continue;
@@ -797,13 +786,13 @@
bool all_anims_with_same_id_are_finished = false;
// Since deleting an animation on the main thread leads to its deletion
- // on the impl thread, we only mark a Finished main thread animation for
- // deletion once it has received a Finished event from the impl thread.
+ // on the impl thread, we only mark a FINISHED main thread animation for
+ // deletion once it has received a FINISHED event from the impl thread.
bool animation_i_will_send_or_has_received_finish_event =
events || animations_[i]->received_finished_event();
// If an animation is finished, and not already marked for deletion,
// find out if all other animations in the same group are also finished.
- if (animations_[i]->run_state() == Animation::Finished &&
+ if (animations_[i]->run_state() == Animation::FINISHED &&
animation_i_will_send_or_has_received_finish_event) {
// Clear the animations_with_same_group_id if it was added for
// the previous animation's iteration.
@@ -815,16 +804,16 @@
events || animations_[j]->received_finished_event();
if (group_id == animations_[j]->group()) {
if (!animations_[j]->is_finished() ||
- (animations_[j]->run_state() == Animation::Finished &&
+ (animations_[j]->run_state() == Animation::FINISHED &&
!animation_j_will_send_or_has_received_finish_event)) {
all_anims_with_same_id_are_finished = false;
break;
} else if (j >= i &&
- animations_[j]->run_state() != Animation::Aborted) {
+ animations_[j]->run_state() != Animation::ABORTED) {
// Mark down the animations which belong to the same group
// and is not yet aborted. If this current iteration finds that all
// animations with same ID are finished, then the marked
- // animations below will be set to WaitingForDeletion in next
+ // animations below will be set to WAITING_FOR_DELETION in next
// iteration.
animations_with_same_group_id.push_back(j);
}
@@ -839,8 +828,7 @@
size_t animation_index = animations_with_same_group_id[j];
if (events) {
AnimationEvent finished_event(
- AnimationEvent::Finished,
- id_,
+ AnimationEvent::FINISHED, id_,
animations_[animation_index]->group(),
animations_[animation_index]->target_property(),
monotonic_time);
@@ -852,7 +840,7 @@
events->push_back(finished_event);
}
animations_[animation_index]->SetRunState(
- Animation::WaitingForDeletion, monotonic_time);
+ Animation::WAITING_FOR_DELETION, monotonic_time);
}
marked_animations_for_deletions = true;
}
@@ -862,7 +850,7 @@
}
static bool IsWaitingForDeletion(Animation* animation) {
- return animation->run_state() == Animation::WaitingForDeletion;
+ return animation->run_state() == Animation::WAITING_FOR_DELETION;
}
void LayerAnimationController::PurgeAnimationsMarkedForDeletion() {
@@ -875,9 +863,9 @@
void LayerAnimationController::TickAnimations(base::TimeTicks monotonic_time) {
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() == Animation::Starting ||
- animations_[i]->run_state() == Animation::Running ||
- animations_[i]->run_state() == Animation::Paused) {
+ if (animations_[i]->run_state() == Animation::STARTING ||
+ animations_[i]->run_state() == Animation::RUNNING ||
+ animations_[i]->run_state() == Animation::PAUSED) {
if (!animations_[i]->InEffect(monotonic_time))
continue;
@@ -885,7 +873,7 @@
animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
switch (animations_[i]->target_property()) {
- case Animation::Transform: {
+ case Animation::TRANSFORM: {
const TransformAnimationCurve* transform_animation_curve =
animations_[i]->curve()->ToTransformAnimationCurve();
const gfx::Transform transform =
@@ -897,7 +885,7 @@
break;
}
- case Animation::Opacity: {
+ case Animation::OPACITY: {
const FloatAnimationCurve* float_animation_curve =
animations_[i]->curve()->ToFloatAnimationCurve();
const float opacity = std::max(
@@ -909,7 +897,7 @@
break;
}
- case Animation::Filter: {
+ case Animation::FILTER: {
const FilterAnimationCurve* filter_animation_curve =
animations_[i]->curve()->ToFilterAnimationCurve();
const FilterOperations filter =
@@ -921,12 +909,12 @@
break;
}
- case Animation::BackgroundColor: {
+ case Animation::BACKGROUND_COLOR: {
// Not yet implemented.
break;
}
- case Animation::ScrollOffset: {
+ case Animation::SCROLL_OFFSET: {
const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
animations_[i]->curve()->ToScrollOffsetAnimationCurve();
const gfx::ScrollOffset scroll_offset =
@@ -937,22 +925,18 @@
animations_[i]->affects_pending_observers());
break;
}
-
- // Do nothing for sentinel value.
- case Animation::TargetPropertyEnumSize:
- NOTREACHED();
}
}
}
}
void LayerAnimationController::UpdateActivation(UpdateActivationType type) {
- bool force = type == ForceActivation;
+ bool force = type == FORCE_ACTIVATION;
if (registrar_) {
bool was_active = is_active_;
is_active_ = false;
for (size_t i = 0; i < animations_.size(); ++i) {
- if (animations_[i]->run_state() != Animation::WaitingForDeletion) {
+ if (animations_[i]->run_state() != Animation::WAITING_FOR_DELETION) {
is_active_ = true;
break;
}
diff --git a/cc/animation/layer_animation_controller.h b/cc/animation/layer_animation_controller.h
index 48c3bdc..d459515 100644
--- a/cc/animation/layer_animation_controller.h
+++ b/cc/animation/layer_animation_controller.h
@@ -179,10 +179,7 @@
void TickAnimations(base::TimeTicks monotonic_time);
- enum UpdateActivationType {
- NormalActivation,
- ForceActivation
- };
+ enum UpdateActivationType { NORMAL_ACTIVATION, FORCE_ACTIVATION };
void UpdateActivation(UpdateActivationType type);
void NotifyObserversOpacityAnimated(float opacity,
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc
index ba639b3..d8d0b05 100644
--- a/cc/animation/layer_animation_controller_unittest.cc
+++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -49,7 +49,7 @@
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
@@ -63,7 +63,7 @@
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller_impl->GetAnimationById(animation_id)->run_state());
}
@@ -79,7 +79,7 @@
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
int animation_id =
AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
@@ -88,7 +88,7 @@
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller_impl->GetAnimationById(animation_id)->run_state());
AnimationEventsVector events;
@@ -122,13 +122,13 @@
AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
const TimeTicks start_time = TicksFromSecondsF(123);
- controller->GetAnimation(Animation::Opacity)->set_start_time(start_time);
+ controller->GetAnimation(Animation::OPACITY)->set_start_time(start_time);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller_impl->GetAnimationById(animation_id)->run_state());
AnimationEventsVector events;
@@ -202,8 +202,8 @@
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::Finished,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::FINISHED,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_EQ(1u, registrar->active_animation_controllers().size());
events.reset(new AnimationEventsVector);
@@ -211,8 +211,8 @@
TimeDelta::FromMilliseconds(1500));
controller_impl->UpdateState(true, events.get());
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller_impl->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller_impl->GetAnimation(Animation::OPACITY)->run_state());
// The impl thread controller should have de-activated.
EXPECT_EQ(0u, registrar_impl->active_animation_controllers().size());
@@ -221,8 +221,8 @@
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1500));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
// The main thread controller should have de-activated.
EXPECT_EQ(0u, registrar->active_animation_controllers().size());
@@ -247,7 +247,7 @@
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
int animation_id =
AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
@@ -256,7 +256,7 @@
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller_impl->GetAnimationById(animation_id)->run_state());
// Start the animations on each controller.
@@ -265,22 +265,22 @@
controller_impl->UpdateState(true, &events);
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::Running,
+ EXPECT_EQ(Animation::RUNNING,
controller_impl->GetAnimationById(animation_id)->run_state());
- EXPECT_EQ(Animation::Running,
+ EXPECT_EQ(Animation::RUNNING,
controller->GetAnimationById(animation_id)->run_state());
// Pause the main-thread animation.
controller->PauseAnimation(
animation_id,
TimeDelta::FromMilliseconds(1000) + TimeDelta::FromMilliseconds(1000));
- EXPECT_EQ(Animation::Paused,
+ EXPECT_EQ(Animation::PAUSED,
controller->GetAnimationById(animation_id)->run_state());
// The pause run state change should make it to the impl thread controller.
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_EQ(Animation::Paused,
+ EXPECT_EQ(Animation::PAUSED,
controller_impl->GetAnimationById(animation_id)->run_state());
}
@@ -294,7 +294,7 @@
LayerAnimationController::Create(0));
controller->AddValueObserver(&dummy);
- EXPECT_FALSE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_FALSE(controller_impl->GetAnimation(Animation::OPACITY));
int animation_id =
AddOpacityTransitionToController(controller.get(), 1, 0, 1, false);
@@ -304,15 +304,12 @@
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller_impl->GetAnimationById(animation_id)->run_state());
// Notify main thread controller that the animation has started.
- AnimationEvent animation_started_event(AnimationEvent::Started,
- 0,
- group_id,
- Animation::Opacity,
- kInitialTickTime);
+ AnimationEvent animation_started_event(AnimationEvent::STARTED, 0, group_id,
+ Animation::OPACITY, kInitialTickTime);
controller->NotifyAnimationStarted(animation_started_event);
// Force animation to complete on impl thread.
@@ -351,9 +348,9 @@
controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller_impl->UpdateState(true, events.get());
- // There should be a Started event for the animation.
+ // There should be a STARTED event for the animation.
EXPECT_EQ(1u, events->size());
- EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[0].type);
controller->NotifyAnimationStarted((*events)[0]);
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
@@ -369,13 +366,13 @@
EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion());
- // There should be a Finished event for the animation.
+ // There should be a FINISHED event for the animation.
EXPECT_EQ(1u, events->size());
- EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[0].type);
// Neither controller should have deleted the animation yet.
- EXPECT_TRUE(controller->GetAnimation(Animation::Opacity));
- EXPECT_TRUE(controller_impl->GetAnimation(Animation::Opacity));
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ EXPECT_TRUE(controller_impl->GetAnimation(Animation::OPACITY));
controller->NotifyAnimationFinished((*events)[0]);
@@ -399,7 +396,7 @@
const AnimationEventsVector* events) {
const AnimationEvent* event = 0;
for (size_t i = 0; i < events->size(); ++i)
- if ((*events)[i].type == AnimationEvent::PropertyUpdate)
+ if ((*events)[i].type == AnimationEvent::PROPERTY_UPDATE)
event = &(*events)[i];
return event;
@@ -415,8 +412,7 @@
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
EXPECT_FALSE(controller->needs_to_start_animations_for_testing());
controller->AddAnimation(to_add.Pass());
@@ -447,8 +443,7 @@
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_is_impl_only(true);
controller_impl->AddAnimation(to_add.Pass());
@@ -488,7 +483,7 @@
scoped_ptr<KeyframedTransformAnimationCurve> curve(
KeyframedTransformAnimationCurve::Create());
- // Create simple Transform animation.
+ // Create simple TRANSFORM animation.
TransformOperations operations;
curve->AddKeyframe(
TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
@@ -497,7 +492,7 @@
base::TimeDelta::FromSecondsD(1.0), operations, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::Transform));
+ Animation::Create(curve.Pass(), 1, 0, Animation::TRANSFORM));
animation->set_is_impl_only(true);
controller_impl->AddAnimation(animation.Pass());
@@ -549,7 +544,7 @@
end_filters, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::Filter));
+ Animation::Create(curve.Pass(), 1, 0, Animation::FILTER));
controller->AddAnimation(animation.Pass());
controller->Animate(kInitialTickTime);
@@ -587,7 +582,7 @@
scoped_ptr<KeyframedFilterAnimationCurve> curve(
KeyframedFilterAnimationCurve::Create());
- // Create simple Filter animation.
+ // Create simple FILTER animation.
FilterOperations start_filters;
start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f));
curve->AddKeyframe(
@@ -598,7 +593,7 @@
end_filters, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::Filter));
+ Animation::Create(curve.Pass(), 1, 0, Animation::FILTER));
animation->set_is_impl_only(true);
controller_impl->AddAnimation(animation.Pass());
@@ -651,20 +646,20 @@
EaseInOutTimingFunction::Create().Pass()));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
controller->AddAnimation(animation.Pass());
dummy_provider_impl.set_scroll_offset(initial_value);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- TimeDelta duration = controller_impl->GetAnimation(Animation::ScrollOffset)
+ EXPECT_TRUE(controller_impl->GetAnimation(Animation::SCROLL_OFFSET));
+ TimeDelta duration = controller_impl->GetAnimation(Animation::SCROLL_OFFSET)
->curve()
->Duration();
EXPECT_EQ(
duration,
- controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
+ controller->GetAnimation(Animation::SCROLL_OFFSET)->curve()->Duration());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
@@ -730,20 +725,20 @@
EaseInOutTimingFunction::Create().Pass()));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
controller->AddAnimation(animation.Pass());
dummy_provider.set_scroll_offset(initial_value);
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- EXPECT_TRUE(controller_impl->GetAnimation(Animation::ScrollOffset));
- TimeDelta duration = controller_impl->GetAnimation(Animation::ScrollOffset)
+ EXPECT_TRUE(controller_impl->GetAnimation(Animation::SCROLL_OFFSET));
+ TimeDelta duration = controller_impl->GetAnimation(Animation::SCROLL_OFFSET)
->curve()
->Duration();
EXPECT_EQ(
duration,
- controller->GetAnimation(Animation::ScrollOffset)->curve()->Duration());
+ controller->GetAnimation(Animation::SCROLL_OFFSET)->curve()->Duration());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
@@ -803,7 +798,7 @@
double duration_in_seconds = curve->Duration().InSecondsF();
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_is_impl_only(true);
controller_impl->AddAnimation(animation.Pass());
@@ -857,7 +852,7 @@
int animation_id = 1;
scoped_ptr<Animation> animation(Animation::Create(
- curve.Pass(), animation_id, 0, Animation::ScrollOffset));
+ curve.Pass(), animation_id, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
controller->AddAnimation(animation.Pass());
controller->PushAnimationUpdatesTo(controller_impl.get());
@@ -878,8 +873,8 @@
// Now, test the 2-argument version of RemoveAnimation.
curve = ScrollOffsetAnimationCurve::Create(
target_value, EaseInOutTimingFunction::Create().Pass());
- animation =
- Animation::Create(curve.Pass(), animation_id, 0, Animation::ScrollOffset);
+ animation = Animation::Create(curve.Pass(), animation_id, 0,
+ Animation::SCROLL_OFFSET);
animation->set_needs_synchronized_start_time(true);
controller->AddAnimation(animation.Pass());
controller->PushAnimationUpdatesTo(controller_impl.get());
@@ -975,8 +970,7 @@
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_is_impl_only(true);
controller_impl->AddAnimation(to_add.Pass());
@@ -1011,8 +1005,7 @@
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_needs_synchronized_start_time(true);
// We should pause at the first keyframe indefinitely waiting for that
@@ -1033,10 +1026,7 @@
// Send the synchronized start time.
controller->NotifyAnimationStarted(
- AnimationEvent(AnimationEvent::Started,
- 0,
- 1,
- Animation::Opacity,
+ AnimationEvent(AnimationEvent::STARTED, 0, 1, Animation::OPACITY,
kInitialTickTime + TimeDelta::FromMilliseconds(2000)));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(5000));
controller->UpdateState(true, events.get());
@@ -1057,13 +1047,11 @@
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(),
- 2,
- Animation::Opacity));
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f))
+ .Pass(),
+ 2, Animation::OPACITY));
EXPECT_TRUE(controller->needs_to_start_animations_for_testing());
@@ -1099,19 +1087,17 @@
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.f, dummy.opacity());
scoped_ptr<Animation> to_add(CreateAnimation(
- scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(),
- 2,
- Animation::Opacity));
- controller->AbortAnimations(Animation::Opacity);
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f))
+ .Pass(),
+ 2, Animation::OPACITY));
+ controller->AbortAnimations(Animation::OPACITY);
controller->AddAnimation(to_add.Pass());
// Since the previous animation was aborted, the new animation should start
@@ -1137,17 +1123,14 @@
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 1,
+ Animation::TRANSFORM));
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(),
- 2,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 2,
+ Animation::TRANSFORM));
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 2,
- Animation::Opacity));
+ 2, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
@@ -1177,18 +1160,15 @@
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(2)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(2)).Pass(), 1,
+ Animation::TRANSFORM));
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 1.f, 0.5f)).Pass(),
- 2,
- Animation::Opacity));
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f))
+ .Pass(),
+ 2, Animation::OPACITY));
// Animations with id 1 should both start now.
controller->Animate(kInitialTickTime);
@@ -1223,8 +1203,7 @@
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_iterations(3);
controller->AddAnimation(to_add.Pass());
@@ -1270,7 +1249,7 @@
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1, Animation::Opacity));
+ 1, Animation::OPACITY));
to_add->set_iterations(-1);
controller->AddAnimation(to_add.Pass());
@@ -1298,9 +1277,9 @@
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
- EXPECT_TRUE(controller->GetAnimation(Animation::Opacity));
- controller->GetAnimation(Animation::Opacity)
- ->SetRunState(Animation::Aborted,
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ controller->GetAnimation(Animation::OPACITY)
+ ->SetRunState(Animation::ABORTED,
kInitialTickTime + TimeDelta::FromMilliseconds(750));
EXPECT_FALSE(controller->HasActiveAnimation());
EXPECT_EQ(0.75f, dummy.opacity());
@@ -1317,7 +1296,7 @@
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1, Animation::Opacity));
+ 1, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
@@ -1328,9 +1307,9 @@
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
- EXPECT_TRUE(controller->GetAnimation(Animation::Opacity));
- controller->GetAnimation(Animation::Opacity)
- ->SetRunState(Animation::Paused,
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ controller->GetAnimation(Animation::OPACITY)
+ ->SetRunState(Animation::PAUSED,
kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024000));
@@ -1338,9 +1317,9 @@
EXPECT_TRUE(controller->HasActiveAnimation());
EXPECT_EQ(0.5f, dummy.opacity());
- EXPECT_TRUE(controller->GetAnimation(Animation::Opacity));
- controller->GetAnimation(Animation::Opacity)
- ->SetRunState(Animation::Running,
+ EXPECT_TRUE(controller->GetAnimation(Animation::OPACITY));
+ controller->GetAnimation(Animation::OPACITY)
+ ->SetRunState(Animation::RUNNING,
kInitialTickTime + TimeDelta::FromMilliseconds(1024000));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1024250));
controller->UpdateState(true, events.get());
@@ -1364,14 +1343,14 @@
const int animation_id = 2;
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 1, 1,
- Animation::Transform));
+ Animation::TRANSFORM));
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(),
- animation_id, 1, Animation::Opacity));
+ animation_id, 1, Animation::OPACITY));
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.75f))
.Pass(),
- 3, 2, Animation::Opacity));
+ 3, 2, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
@@ -1384,7 +1363,7 @@
EXPECT_TRUE(controller->GetAnimationById(animation_id));
controller->GetAnimationById(animation_id)
- ->SetRunState(Animation::Aborted,
+ ->SetRunState(Animation::ABORTED,
kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
@@ -1410,24 +1389,23 @@
scoped_ptr<Animation> to_add(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(2.0, 0.f, 1.f)).Pass(),
- 0,
- Animation::Opacity));
+ 0, Animation::OPACITY));
to_add->set_needs_synchronized_start_time(true);
controller->AddAnimation(to_add.Pass());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
EXPECT_TRUE(controller->HasActiveAnimation());
- Animation* active_animation = controller->GetAnimation(Animation::Opacity);
+ Animation* active_animation = controller->GetAnimation(Animation::OPACITY);
EXPECT_TRUE(active_animation);
EXPECT_TRUE(active_animation->needs_synchronized_start_time());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
- active_animation = controller_impl->GetAnimation(Animation::Opacity);
+ active_animation = controller_impl->GetAnimation(Animation::OPACITY);
EXPECT_TRUE(active_animation);
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
active_animation->run_state());
}
@@ -1441,17 +1419,15 @@
controller->AddValueObserver(&dummy);
controller->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1)).Pass(), 1,
+ Animation::TRANSFORM));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
controller->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 2,
- Animation::Opacity));
+ 2, Animation::OPACITY));
// Animate but don't UpdateState.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
@@ -1460,7 +1436,7 @@
events.reset(new AnimationEventsVector);
controller->UpdateState(true, events.get());
- // Should have one Started event and one Finished event.
+ // Should have one STARTED event and one FINISHED event.
EXPECT_EQ(2u, events->size());
EXPECT_NE((*events)[0].type, (*events)[1].type);
@@ -1477,7 +1453,7 @@
}
// Tests that an animation controller with only a pending observer gets ticked
-// but doesn't progress animations past the Starting state.
+// but doesn't progress animations past the STARTING state.
TEST(LayerAnimationControllerTest, InactiveObserverGetsTicked) {
scoped_ptr<AnimationEventsVector> events(
make_scoped_ptr(new AnimationEventsVector));
@@ -1487,49 +1463,49 @@
LayerAnimationController::Create(0));
const int id = 1;
- controller->AddAnimation(CreateAnimation(scoped_ptr<AnimationCurve>(
- new FakeFloatTransition(1.0, 0.5f, 1.f)).Pass(),
- id,
- Animation::Opacity));
+ controller->AddAnimation(CreateAnimation(
+ scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.5f, 1.f))
+ .Pass(),
+ id, Animation::OPACITY));
- // Without an observer, the animation shouldn't progress to the Starting
+ // Without an observer, the animation shouldn't progress to the STARTING
// state.
controller->Animate(kInitialTickTime);
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->AddValueObserver(&pending_dummy);
// With only a pending observer, the animation should progress to the
- // Starting state and get ticked at its starting point, but should not
- // progress to Running.
+ // STARTING state and get ticked at its starting point, but should not
+ // progress to RUNNING.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::Starting,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::STARTING,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_EQ(0.5f, pending_dummy.opacity());
- // Even when already in the Starting state, the animation should stay
+ // Even when already in the STARTING state, the animation should stay
// there, and shouldn't be ticked past its starting point.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, events.get());
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::Starting,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::STARTING,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_EQ(0.5f, pending_dummy.opacity());
controller->AddValueObserver(&dummy);
// Now that an active observer has been added, the animation should still
- // initially tick at its starting point, but should now progress to Running.
+ // initially tick at its starting point, but should now progress to RUNNING.
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(3000));
controller->UpdateState(true, events.get());
EXPECT_EQ(1u, events->size());
- EXPECT_EQ(Animation::Running,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::RUNNING,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_EQ(0.5f, pending_dummy.opacity());
EXPECT_EQ(0.5f, dummy.opacity());
@@ -1554,7 +1530,7 @@
base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
+ Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
scoped_ptr<KeyframedTransformAnimationCurve> curve2(
@@ -1567,7 +1543,7 @@
curve2->AddKeyframe(TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 2, 2, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
gfx::BoxF box(1.f, 2.f, -1.f, 3.f, 4.f, 5.f);
@@ -1578,7 +1554,7 @@
bounds.ToString());
controller_impl->GetAnimationById(1)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only the unfinished animation should affect the animated bounds.
EXPECT_TRUE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
@@ -1586,7 +1562,7 @@
bounds.ToString());
controller_impl->GetAnimationById(2)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// There are no longer any running animations.
EXPECT_FALSE(controller_impl->HasTransformAnimationThatInflatesBounds());
@@ -1602,7 +1578,7 @@
operations3.AppendMatrix(transform3);
curve3->AddKeyframe(TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
- animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform);
+ animation = Animation::Create(curve3.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_FALSE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
}
@@ -1619,40 +1595,40 @@
// state.
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), 1, 1,
- Animation::Transform));
+ Animation::TRANSFORM));
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 2, 2, Animation::Opacity));
+ 2, 2, Animation::OPACITY));
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), 3, 3,
- Animation::Transform));
+ Animation::TRANSFORM));
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), 4, 4,
- Animation::Transform));
+ Animation::TRANSFORM));
controller->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 5, 5, Animation::Opacity));
+ 5, 5, Animation::OPACITY));
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
controller->UpdateState(true, nullptr);
- EXPECT_EQ(Animation::Finished, controller->GetAnimationById(1)->run_state());
- EXPECT_EQ(Animation::Finished, controller->GetAnimationById(2)->run_state());
- EXPECT_EQ(Animation::Running, controller->GetAnimationById(3)->run_state());
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(1)->run_state());
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(2)->run_state());
+ EXPECT_EQ(Animation::RUNNING, controller->GetAnimationById(3)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller->GetAnimationById(4)->run_state());
- EXPECT_EQ(Animation::Running, controller->GetAnimationById(5)->run_state());
+ EXPECT_EQ(Animation::RUNNING, controller->GetAnimationById(5)->run_state());
- controller->AbortAnimations(Animation::Transform);
+ controller->AbortAnimations(Animation::TRANSFORM);
- // Only un-finished Transform animations should have been aborted.
- EXPECT_EQ(Animation::Finished, controller->GetAnimationById(1)->run_state());
- EXPECT_EQ(Animation::Finished, controller->GetAnimationById(2)->run_state());
- EXPECT_EQ(Animation::Aborted, controller->GetAnimationById(3)->run_state());
- EXPECT_EQ(Animation::Aborted, controller->GetAnimationById(4)->run_state());
- EXPECT_EQ(Animation::Running, controller->GetAnimationById(5)->run_state());
+ // Only un-finished TRANSFORM animations should have been aborted.
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(1)->run_state());
+ EXPECT_EQ(Animation::FINISHED, controller->GetAnimationById(2)->run_state());
+ EXPECT_EQ(Animation::ABORTED, controller->GetAnimationById(3)->run_state());
+ EXPECT_EQ(Animation::ABORTED, controller->GetAnimationById(4)->run_state());
+ EXPECT_EQ(Animation::RUNNING, controller->GetAnimationById(5)->run_state());
}
// An animation aborted on the main thread should get deleted on both threads.
@@ -1673,17 +1649,17 @@
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- controller->AbortAnimations(Animation::Opacity);
- EXPECT_EQ(Animation::Aborted,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ controller->AbortAnimations(Animation::OPACITY);
+ EXPECT_EQ(Animation::ABORTED,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_FALSE(dummy.animation_waiting_for_deletion());
EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
EXPECT_TRUE(dummy.animation_waiting_for_deletion());
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
@@ -1709,9 +1685,9 @@
controller_impl->ActivateAnimations();
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- controller_impl->AbortAnimations(Animation::Opacity);
- EXPECT_EQ(Animation::Aborted,
- controller_impl->GetAnimation(Animation::Opacity)->run_state());
+ controller_impl->AbortAnimations(Animation::OPACITY);
+ EXPECT_EQ(Animation::ABORTED,
+ controller_impl->GetAnimation(Animation::OPACITY)->run_state());
EXPECT_FALSE(dummy.animation_waiting_for_deletion());
EXPECT_FALSE(dummy_impl.animation_waiting_for_deletion());
@@ -1720,19 +1696,19 @@
controller_impl->UpdateState(true, &events);
EXPECT_TRUE(dummy_impl.animation_waiting_for_deletion());
EXPECT_EQ(1u, events.size());
- EXPECT_EQ(AnimationEvent::Aborted, events[0].type);
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller_impl->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(AnimationEvent::ABORTED, events[0].type);
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller_impl->GetAnimation(Animation::OPACITY)->run_state());
controller->NotifyAnimationAborted(events[0]);
- EXPECT_EQ(Animation::Aborted,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::ABORTED,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
controller->UpdateState(true, nullptr);
EXPECT_TRUE(dummy.animation_waiting_for_deletion());
- EXPECT_EQ(Animation::WaitingForDeletion,
- controller->GetAnimation(Animation::Opacity)->run_state());
+ EXPECT_EQ(Animation::WAITING_FOR_DELETION,
+ controller->GetAnimation(Animation::OPACITY)->run_state());
controller->PushAnimationUpdatesTo(controller_impl.get());
controller_impl->ActivateAnimations();
@@ -1740,7 +1716,7 @@
EXPECT_FALSE(controller_impl->GetAnimationById(animation_id));
}
-// Ensure that we only generate Finished events for animations in a group
+// Ensure that we only generate FINISHED events for animations in a group
// once all animations in that group are finished.
TEST(LayerAnimationControllerTest, FinishedEventsForGroup) {
scoped_ptr<AnimationEventsVector> events(
@@ -1755,18 +1731,18 @@
// Add two animations with the same group id but different durations.
controller_impl->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeTransformTransition(2.0)).Pass(), 1,
- group_id, Animation::Transform));
+ group_id, Animation::TRANSFORM));
controller_impl->AddAnimation(Animation::Create(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 2, group_id, Animation::Opacity));
+ 2, group_id, Animation::OPACITY));
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
// Both animations should have started.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
- EXPECT_EQ(AnimationEvent::Started, (*events)[1].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[1].type);
events.reset(new AnimationEventsVector);
controller_impl->Animate(kInitialTickTime +
@@ -1774,25 +1750,25 @@
controller_impl->UpdateState(true, events.get());
// The opacity animation should be finished, but should not have generated
- // a Finished event yet.
+ // a FINISHED event yet.
EXPECT_EQ(0u, events->size());
- EXPECT_EQ(Animation::Finished,
+ EXPECT_EQ(Animation::FINISHED,
controller_impl->GetAnimationById(2)->run_state());
- EXPECT_EQ(Animation::Running,
+ EXPECT_EQ(Animation::RUNNING,
controller_impl->GetAnimationById(1)->run_state());
controller_impl->Animate(kInitialTickTime +
TimeDelta::FromMilliseconds(2000));
controller_impl->UpdateState(true, events.get());
- // Both animations should have generated Finished events.
+ // Both animations should have generated FINISHED events.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type);
- EXPECT_EQ(AnimationEvent::Finished, (*events)[1].type);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[1].type);
}
// Ensure that when a group has a mix of aborted and finished animations,
-// we generate a Finished event for the finished animation and an Aborted
+// we generate a FINISHED event for the finished animation and an ABORTED
// event for the aborted animation.
TEST(LayerAnimationControllerTest, FinishedAndAbortedEventsForGroup) {
scoped_ptr<AnimationEventsVector> events(
@@ -1804,36 +1780,34 @@
// Add two animations with the same group id.
controller_impl->AddAnimation(CreateAnimation(
- scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(),
- 1,
- Animation::Transform));
+ scoped_ptr<AnimationCurve>(new FakeTransformTransition(1.0)).Pass(), 1,
+ Animation::TRANSFORM));
controller_impl->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
// Both animations should have started.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Started, (*events)[0].type);
- EXPECT_EQ(AnimationEvent::Started, (*events)[1].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[0].type);
+ EXPECT_EQ(AnimationEvent::STARTED, (*events)[1].type);
- controller_impl->AbortAnimations(Animation::Opacity);
+ controller_impl->AbortAnimations(Animation::OPACITY);
events.reset(new AnimationEventsVector);
controller_impl->Animate(kInitialTickTime +
TimeDelta::FromMilliseconds(1000));
controller_impl->UpdateState(true, events.get());
- // We should have exactly 2 events: a Finished event for the tranform
- // animation, and an Aborted event for the opacity animation.
+ // We should have exactly 2 events: a FINISHED event for the tranform
+ // animation, and an ABORTED event for the opacity animation.
EXPECT_EQ(2u, events->size());
- EXPECT_EQ(AnimationEvent::Finished, (*events)[0].type);
- EXPECT_EQ(Animation::Transform, (*events)[0].target_property);
- EXPECT_EQ(AnimationEvent::Aborted, (*events)[1].type);
- EXPECT_EQ(Animation::Opacity, (*events)[1].target_property);
+ EXPECT_EQ(AnimationEvent::FINISHED, (*events)[0].type);
+ EXPECT_EQ(Animation::TRANSFORM, (*events)[0].target_property);
+ EXPECT_EQ(AnimationEvent::ABORTED, (*events)[1].type);
+ EXPECT_EQ(Animation::OPACITY, (*events)[1].target_property);
}
TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) {
@@ -1844,8 +1818,7 @@
controller_impl->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
// Opacity animations don't affect scale.
EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale());
@@ -1861,7 +1834,7 @@
base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 2, 2, Animation::Transform));
+ Animation::Create(curve1.Pass(), 2, 2, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
// Translations don't affect scale.
@@ -1877,13 +1850,13 @@
curve2->AddKeyframe(TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 3, 3, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_TRUE(controller_impl->HasAnimationThatAffectsScale());
controller_impl->GetAnimationById(3)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only unfinished animations should be considered by
// HasAnimationThatAffectsScale.
@@ -1898,8 +1871,7 @@
controller_impl->AddAnimation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
// Opacity animations aren't non-translation transforms.
EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms());
@@ -1915,7 +1887,7 @@
base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 2, 2, Animation::Transform));
+ Animation::Create(curve1.Pass(), 2, 2, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
// The only transform animation we've added is a translation.
@@ -1931,14 +1903,14 @@
curve2->AddKeyframe(TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 3, 3, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
// A scale animation is not a translation.
EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms());
controller_impl->GetAnimationById(3)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only unfinished animations should be considered by
// HasOnlyTranslationTransforms.
@@ -1964,7 +1936,7 @@
base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
scoped_ptr<Animation> animation(
- Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
+ Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM));
controller_impl->AddAnimation(animation.Pass());
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
@@ -1980,7 +1952,7 @@
curve2->AddKeyframe(TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
- animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform);
+ animation = Animation::Create(curve2.Pass(), 2, 2, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
@@ -1996,15 +1968,15 @@
curve3->AddKeyframe(TransformKeyframe::Create(
base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
- animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform);
+ animation = Animation::Create(curve3.Pass(), 3, 3, Animation::TRANSFORM);
controller_impl->AddAnimation(animation.Pass());
EXPECT_FALSE(controller_impl->MaximumTargetScale(&max_scale));
controller_impl->GetAnimationById(3)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
controller_impl->GetAnimationById(2)
- ->SetRunState(Animation::Finished, TicksFromSecondsF(0.0));
+ ->SetRunState(Animation::FINISHED, TicksFromSecondsF(0.0));
// Only unfinished animations should be considered by
// MaximumTargetScale.
@@ -2028,7 +2000,7 @@
base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
scoped_ptr<Animation> animation_owned(
- Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
+ Animation::Create(curve1.Pass(), 1, 1, Animation::TRANSFORM));
Animation* animation = animation_owned.get();
controller_impl->AddAnimation(animation_owned.Pass());
@@ -2036,45 +2008,45 @@
EXPECT_GT(animation->playback_rate(), 0.0);
- // Normal direction with positive playback rate.
- animation->set_direction(Animation::Normal);
+ // NORMAL direction with positive playback rate.
+ animation->set_direction(Animation::DIRECTION_NORMAL);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
- // Alternate direction with positive playback rate.
- animation->set_direction(Animation::Alternate);
+ // ALTERNATE direction with positive playback rate.
+ animation->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
- // Reverse direction with positive playback rate.
- animation->set_direction(Animation::Reverse);
+ // REVERSE direction with positive playback rate.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
- // Alternate reverse direction.
- animation->set_direction(Animation::Reverse);
+ // ALTERNATE reverse direction.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
animation->set_playback_rate(-1.0);
- // Normal direction with negative playback rate.
- animation->set_direction(Animation::Normal);
+ // NORMAL direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_NORMAL);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
- // Alternate direction with negative playback rate.
- animation->set_direction(Animation::Alternate);
+ // ALTERNATE direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_ALTERNATE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(3.f, max_scale);
- // Reverse direction with negative playback rate.
- animation->set_direction(Animation::Reverse);
+ // REVERSE direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
- // Alternate reverse direction with negative playback rate.
- animation->set_direction(Animation::Reverse);
+ // ALTERNATE reverse direction with negative playback rate.
+ animation->set_direction(Animation::DIRECTION_REVERSE);
EXPECT_TRUE(controller_impl->MaximumTargetScale(&max_scale));
EXPECT_EQ(6.f, max_scale);
}
@@ -2103,7 +2075,7 @@
EXPECT_TRUE(controller_impl->needs_to_start_animations_for_testing());
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller_impl->GetAnimationById(animation_id)->run_state());
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
@@ -2114,9 +2086,9 @@
EXPECT_FALSE(controller_impl->needs_to_start_animations_for_testing());
controller_impl->UpdateState(true, events.get());
- // Since the animation hasn't been activated, it should still be Starting
- // rather than Running.
- EXPECT_EQ(Animation::Starting,
+ // Since the animation hasn't been activated, it should still be STARTING
+ // rather than RUNNING.
+ EXPECT_EQ(Animation::STARTING,
controller_impl->GetAnimationById(animation_id)->run_state());
// Since the animation hasn't been activated, only the pending observer
@@ -2135,8 +2107,8 @@
controller_impl->UpdateState(true, events.get());
// Since the animation has been activated, it should have reached the
- // Running state and the active observer should start to get ticked.
- EXPECT_EQ(Animation::Running,
+ // RUNNING state and the active observer should start to get ticked.
+ EXPECT_EQ(Animation::RUNNING,
controller_impl->GetAnimationById(animation_id)->run_state());
EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
EXPECT_EQ(0.5f, dummy_impl.opacity());
@@ -2162,7 +2134,7 @@
controller->PushAnimationUpdatesTo(controller_impl.get());
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id));
- EXPECT_EQ(Animation::WaitingForTargetAvailability,
+ EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
controller_impl->GetAnimationById(animation_id)->run_state());
EXPECT_TRUE(controller_impl->GetAnimationById(animation_id)
->affects_pending_observers());
@@ -2185,8 +2157,8 @@
controller_impl->UpdateState(true, events.get());
// Since the animation has been activated, it should have reached the
- // Running state.
- EXPECT_EQ(Animation::Running,
+ // RUNNING state.
+ EXPECT_EQ(Animation::RUNNING,
controller_impl->GetAnimationById(animation_id)->run_state());
controller_impl->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500));
@@ -2249,7 +2221,7 @@
controller_impl->ActivateAnimations();
controller_impl->Animate(kInitialTickTime);
controller_impl->UpdateState(true, events.get());
- EXPECT_EQ(Animation::Running,
+ EXPECT_EQ(Animation::RUNNING,
controller_impl->GetAnimationById(animation_id)->run_state());
EXPECT_EQ(0.5f, pending_dummy_impl.opacity());
EXPECT_EQ(0.5f, dummy_impl.opacity());
@@ -2261,7 +2233,7 @@
// Delete the animation on the main-thread controller.
controller->RemoveAnimation(
- controller->GetAnimation(Animation::Opacity)->id());
+ controller->GetAnimation(Animation::OPACITY)->id());
controller->PushAnimationUpdatesTo(controller_impl.get());
// The animation should no longer affect pending observers.
@@ -2310,7 +2282,7 @@
// Remove the first animation from the main-thread controller, and add a
// new animation affecting the same property.
controller->RemoveAnimation(
- controller->GetAnimation(Animation::Opacity)->id());
+ controller->GetAnimation(Animation::OPACITY)->id());
int second_animation_id =
AddOpacityTransitionToController(controller.get(), 1, 1.f, 0.5f, true);
controller->PushAnimationUpdatesTo(controller_impl.get());
@@ -2331,10 +2303,10 @@
// The original animation should still be running, and the new animation
// should be starting.
- EXPECT_EQ(Animation::Running,
+ EXPECT_EQ(Animation::RUNNING,
controller_impl->GetAnimationById(first_animation_id)->run_state());
EXPECT_EQ(
- Animation::Starting,
+ Animation::STARTING,
controller_impl->GetAnimationById(second_animation_id)->run_state());
// The active observer should have been ticked by the original animation,
@@ -2359,7 +2331,7 @@
// The new animation should be running, and the active observer should have
// been ticked at the new animation's starting point.
EXPECT_EQ(
- Animation::Running,
+ Animation::RUNNING,
controller_impl->GetAnimationById(second_animation_id)->run_state());
EXPECT_EQ(1.f, pending_dummy_impl.opacity());
EXPECT_EQ(1.f, dummy_impl.opacity());
@@ -2373,15 +2345,14 @@
scoped_ptr<Animation> animation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
+ 1, Animation::OPACITY));
controller->AddAnimation(animation.Pass());
controller->Animate(kInitialTickTime);
- EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity));
+ EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY));
controller->UpdateState(true, nullptr);
EXPECT_TRUE(controller->HasActiveAnimation());
- EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity));
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Filter));
+ EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::FILTER));
EXPECT_EQ(0.f, dummy.opacity());
}
@@ -2393,22 +2364,21 @@
scoped_ptr<Animation> animation(CreateAnimation(
scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(),
- 1,
- Animation::Opacity));
- animation->set_fill_mode(Animation::FillModeNone);
+ 1, Animation::OPACITY));
+ animation->set_fill_mode(Animation::FILL_MODE_NONE);
animation->set_time_offset(TimeDelta::FromMilliseconds(-2000));
controller->AddAnimation(animation.Pass());
controller->Animate(kInitialTickTime);
controller->UpdateState(true, nullptr);
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Opacity));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::OPACITY));
EXPECT_TRUE(controller->HasActiveAnimation());
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Opacity));
- EXPECT_FALSE(controller->IsAnimatingProperty(Animation::Filter));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::OPACITY));
+ EXPECT_FALSE(controller->IsAnimatingProperty(Animation::FILTER));
controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(2000));
controller->UpdateState(true, nullptr);
- EXPECT_TRUE(controller->IsAnimatingProperty(Animation::Opacity));
+ EXPECT_TRUE(controller->IsAnimatingProperty(Animation::OPACITY));
}
} // namespace
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc
index 9567263..87a29c1 100644
--- a/cc/animation/scroll_offset_animation_curve.cc
+++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -90,7 +90,7 @@
}
AnimationCurve::CurveType ScrollOffsetAnimationCurve::Type() const {
- return ScrollOffset;
+ return SCROLL_OFFSET;
}
scoped_ptr<AnimationCurve> ScrollOffsetAnimationCurve::Clone() const {
diff --git a/cc/animation/scroll_offset_animation_curve_unittest.cc b/cc/animation/scroll_offset_animation_curve_unittest.cc
index cb3e914..8aea905 100644
--- a/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -68,7 +68,7 @@
EXPECT_GT(curve->Duration().InSecondsF(), 0);
EXPECT_LT(curve->Duration().InSecondsF(), 0.1);
- EXPECT_EQ(AnimationCurve::ScrollOffset, curve->Type());
+ EXPECT_EQ(AnimationCurve::SCROLL_OFFSET, curve->Type());
EXPECT_EQ(duration, curve->Duration());
EXPECT_VECTOR2DF_EQ(initial_value,
@@ -101,7 +101,7 @@
scoped_ptr<AnimationCurve> clone(curve->Clone().Pass());
- EXPECT_EQ(AnimationCurve::ScrollOffset, clone->Type());
+ EXPECT_EQ(AnimationCurve::SCROLL_OFFSET, clone->Type());
EXPECT_EQ(duration, clone->Duration());
EXPECT_VECTOR2DF_EQ(initial_value,
diff --git a/cc/animation/transform_operation.cc b/cc/animation/transform_operation.cc
index e9ae86d..7421924 100644
--- a/cc/animation/transform_operation.cc
+++ b/cc/animation/transform_operation.cc
@@ -99,14 +99,14 @@
return true;
TransformOperation::Type interpolation_type =
- TransformOperation::TransformOperationIdentity;
+ TransformOperation::TRANSFORM_OPERATION_IDENTITY;
if (IsOperationIdentity(to))
interpolation_type = from->type;
else
interpolation_type = to->type;
switch (interpolation_type) {
- case TransformOperation::TransformOperationTranslate: {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE: {
SkMScalar from_x = IsOperationIdentity(from) ? 0 : from->translate.x;
SkMScalar from_y = IsOperationIdentity(from) ? 0 : from->translate.y;
SkMScalar from_z = IsOperationIdentity(from) ? 0 : from->translate.z;
@@ -118,7 +118,7 @@
BlendSkMScalars(from_z, to_z, progress));
break;
}
- case TransformOperation::TransformOperationRotate: {
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
SkMScalar axis_x = 0;
SkMScalar axis_y = 0;
SkMScalar axis_z = 1;
@@ -140,7 +140,7 @@
}
break;
}
- case TransformOperation::TransformOperationScale: {
+ case TransformOperation::TRANSFORM_OPERATION_SCALE: {
SkMScalar from_x = IsOperationIdentity(from) ? 1 : from->scale.x;
SkMScalar from_y = IsOperationIdentity(from) ? 1 : from->scale.y;
SkMScalar from_z = IsOperationIdentity(from) ? 1 : from->scale.z;
@@ -152,7 +152,7 @@
BlendSkMScalars(from_z, to_z, progress));
break;
}
- case TransformOperation::TransformOperationSkew: {
+ case TransformOperation::TRANSFORM_OPERATION_SKEW: {
SkMScalar from_x = IsOperationIdentity(from) ? 0 : from->skew.x;
SkMScalar from_y = IsOperationIdentity(from) ? 0 : from->skew.y;
SkMScalar to_x = IsOperationIdentity(to) ? 0 : to->skew.x;
@@ -161,7 +161,7 @@
result->SkewY(BlendSkMScalars(from_y, to_y, progress));
break;
}
- case TransformOperation::TransformOperationPerspective: {
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE: {
SkMScalar from_perspective_depth =
IsOperationIdentity(from) ? std::numeric_limits<SkMScalar>::max()
: from->perspective_depth;
@@ -180,7 +180,7 @@
result->ApplyPerspectiveDepth(1.f / blended_perspective_depth);
break;
}
- case TransformOperation::TransformOperationMatrix: {
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX: {
gfx::Transform to_matrix;
if (!IsOperationIdentity(to))
to_matrix = to->matrix;
@@ -192,7 +192,7 @@
return false;
break;
}
- case TransformOperation::TransformOperationIdentity:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
// Do nothing.
break;
}
@@ -375,20 +375,20 @@
}
TransformOperation::Type interpolation_type =
- TransformOperation::TransformOperationIdentity;
+ TransformOperation::TRANSFORM_OPERATION_IDENTITY;
if (is_identity_to)
interpolation_type = from->type;
else
interpolation_type = to->type;
switch (interpolation_type) {
- case TransformOperation::TransformOperationIdentity:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
*bounds = box;
return true;
- case TransformOperation::TransformOperationTranslate:
- case TransformOperation::TransformOperationSkew:
- case TransformOperation::TransformOperationPerspective:
- case TransformOperation::TransformOperationScale: {
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE: {
gfx::Transform from_transform;
gfx::Transform to_transform;
if (!BlendTransformOperations(from, to, min_progress, &from_transform) ||
@@ -404,7 +404,7 @@
return true;
}
- case TransformOperation::TransformOperationRotate: {
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE: {
SkMScalar axis_x = 0;
SkMScalar axis_y = 0;
SkMScalar axis_z = 1;
@@ -429,7 +429,7 @@
}
return true;
}
- case TransformOperation::TransformOperationMatrix:
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
return false;
}
NOTREACHED();
diff --git a/cc/animation/transform_operation.h b/cc/animation/transform_operation.h
index 345ff29..3ea5fc2 100644
--- a/cc/animation/transform_operation.h
+++ b/cc/animation/transform_operation.h
@@ -15,18 +15,16 @@
struct TransformOperation {
enum Type {
- TransformOperationTranslate,
- TransformOperationRotate,
- TransformOperationScale,
- TransformOperationSkew,
- TransformOperationPerspective,
- TransformOperationMatrix,
- TransformOperationIdentity
+ TRANSFORM_OPERATION_TRANSLATE,
+ TRANSFORM_OPERATION_ROTATE,
+ TRANSFORM_OPERATION_SCALE,
+ TRANSFORM_OPERATION_SKEW,
+ TRANSFORM_OPERATION_PERSPECTIVE,
+ TRANSFORM_OPERATION_MATRIX,
+ TRANSFORM_OPERATION_IDENTITY
};
- TransformOperation()
- : type(TransformOperationIdentity) {
- }
+ TransformOperation() : type(TRANSFORM_OPERATION_IDENTITY) {}
Type type;
gfx::Transform matrix;
diff --git a/cc/animation/transform_operations.cc b/cc/animation/transform_operations.cc
index d9d58f2..20e8c6a 100644
--- a/cc/animation/transform_operations.cc
+++ b/cc/animation/transform_operations.cc
@@ -85,9 +85,9 @@
bool TransformOperations::AffectsScale() const {
for (size_t i = 0; i < operations_.size(); ++i) {
- if (operations_[i].type == TransformOperation::TransformOperationScale)
+ if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_SCALE)
return true;
- if (operations_[i].type == TransformOperation::TransformOperationMatrix &&
+ if (operations_[i].type == TransformOperation::TRANSFORM_OPERATION_MATRIX &&
!operations_[i].matrix.IsIdentityOrTranslation())
return true;
}
@@ -97,18 +97,18 @@
bool TransformOperations::PreservesAxisAlignment() const {
for (size_t i = 0; i < operations_.size(); ++i) {
switch (operations_[i].type) {
- case TransformOperation::TransformOperationIdentity:
- case TransformOperation::TransformOperationTranslate:
- case TransformOperation::TransformOperationScale:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
continue;
- case TransformOperation::TransformOperationMatrix:
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
if (!operations_[i].matrix.IsIdentity() &&
!operations_[i].matrix.IsScaleOrTranslation())
return false;
continue;
- case TransformOperation::TransformOperationRotate:
- case TransformOperation::TransformOperationSkew:
- case TransformOperation::TransformOperationPerspective:
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
return false;
}
}
@@ -118,17 +118,17 @@
bool TransformOperations::IsTranslation() const {
for (size_t i = 0; i < operations_.size(); ++i) {
switch (operations_[i].type) {
- case TransformOperation::TransformOperationIdentity:
- case TransformOperation::TransformOperationTranslate:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
continue;
- case TransformOperation::TransformOperationMatrix:
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
if (!operations_[i].matrix.IsIdentityOrTranslation())
return false;
continue;
- case TransformOperation::TransformOperationRotate:
- case TransformOperation::TransformOperationScale:
- case TransformOperation::TransformOperationSkew:
- case TransformOperation::TransformOperationPerspective:
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
return false;
}
}
@@ -140,18 +140,18 @@
bool has_scale_component = false;
for (size_t i = 0; i < operations_.size(); ++i) {
switch (operations_[i].type) {
- case TransformOperation::TransformOperationIdentity:
- case TransformOperation::TransformOperationTranslate:
+ case TransformOperation::TRANSFORM_OPERATION_IDENTITY:
+ case TransformOperation::TRANSFORM_OPERATION_TRANSLATE:
continue;
- case TransformOperation::TransformOperationMatrix:
+ case TransformOperation::TRANSFORM_OPERATION_MATRIX:
if (!operations_[i].matrix.IsIdentityOrTranslation())
return false;
continue;
- case TransformOperation::TransformOperationRotate:
- case TransformOperation::TransformOperationSkew:
- case TransformOperation::TransformOperationPerspective:
+ case TransformOperation::TRANSFORM_OPERATION_ROTATE:
+ case TransformOperation::TRANSFORM_OPERATION_SKEW:
+ case TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE:
return false;
- case TransformOperation::TransformOperationScale:
+ case TransformOperation::TRANSFORM_OPERATION_SCALE:
if (has_scale_component)
return false;
has_scale_component = true;
@@ -191,7 +191,7 @@
SkMScalar z) {
TransformOperation to_add;
to_add.matrix.Translate3d(x, y, z);
- to_add.type = TransformOperation::TransformOperationTranslate;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_TRANSLATE;
to_add.translate.x = x;
to_add.translate.y = y;
to_add.translate.z = z;
@@ -205,7 +205,7 @@
SkMScalar degrees) {
TransformOperation to_add;
to_add.matrix.RotateAbout(gfx::Vector3dF(x, y, z), degrees);
- to_add.type = TransformOperation::TransformOperationRotate;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_ROTATE;
to_add.rotate.axis.x = x;
to_add.rotate.axis.y = y;
to_add.rotate.axis.z = z;
@@ -217,7 +217,7 @@
void TransformOperations::AppendScale(SkMScalar x, SkMScalar y, SkMScalar z) {
TransformOperation to_add;
to_add.matrix.Scale3d(x, y, z);
- to_add.type = TransformOperation::TransformOperationScale;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SCALE;
to_add.scale.x = x;
to_add.scale.y = y;
to_add.scale.z = z;
@@ -229,7 +229,7 @@
TransformOperation to_add;
to_add.matrix.SkewX(x);
to_add.matrix.SkewY(y);
- to_add.type = TransformOperation::TransformOperationSkew;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_SKEW;
to_add.skew.x = x;
to_add.skew.y = y;
operations_.push_back(to_add);
@@ -239,7 +239,7 @@
void TransformOperations::AppendPerspective(SkMScalar depth) {
TransformOperation to_add;
to_add.matrix.ApplyPerspectiveDepth(depth);
- to_add.type = TransformOperation::TransformOperationPerspective;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_PERSPECTIVE;
to_add.perspective_depth = depth;
operations_.push_back(to_add);
decomposed_transform_dirty_ = true;
@@ -248,7 +248,7 @@
void TransformOperations::AppendMatrix(const gfx::Transform& matrix) {
TransformOperation to_add;
to_add.matrix = matrix;
- to_add.type = TransformOperation::TransformOperationMatrix;
+ to_add.type = TransformOperation::TRANSFORM_OPERATION_MATRIX;
operations_.push_back(to_add);
decomposed_transform_dirty_ = true;
}
diff --git a/cc/base/latency_info_swap_promise_monitor.cc b/cc/base/latency_info_swap_promise_monitor.cc
index dc28739..de065d1 100644
--- a/cc/base/latency_info_swap_promise_monitor.cc
+++ b/cc/base/latency_info_swap_promise_monitor.cc
@@ -12,12 +12,14 @@
namespace {
-bool AddRenderingScheduledComponent(ui::LatencyInfo* latency_info) {
- if (latency_info->FindLatency(
- ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, nullptr))
+bool AddRenderingScheduledComponent(ui::LatencyInfo* latency_info,
+ bool on_main) {
+ ui::LatencyComponentType type = on_main ?
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT :
+ ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT;
+ if (latency_info->FindLatency(type, 0, nullptr))
return false;
- latency_info->AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT, 0, 0);
+ latency_info->AddLatencyNumber(type, 0, 0);
return true;
}
@@ -48,14 +50,14 @@
LatencyInfoSwapPromiseMonitor::~LatencyInfoSwapPromiseMonitor() {}
void LatencyInfoSwapPromiseMonitor::OnSetNeedsCommitOnMain() {
- if (AddRenderingScheduledComponent(latency_)) {
+ if (AddRenderingScheduledComponent(latency_, true /* on_main */)) {
scoped_ptr<SwapPromise> swap_promise(new LatencyInfoSwapPromise(*latency_));
layer_tree_host_->QueueSwapPromise(swap_promise.Pass());
}
}
void LatencyInfoSwapPromiseMonitor::OnSetNeedsRedrawOnImpl() {
- if (AddRenderingScheduledComponent(latency_)) {
+ if (AddRenderingScheduledComponent(latency_, false /* on_main */)) {
scoped_ptr<SwapPromise> swap_promise(new LatencyInfoSwapPromise(*latency_));
layer_tree_host_impl_->active_tree()->QueueSwapPromise(swap_promise.Pass());
}
diff --git a/cc/blink/cc_blink_tests.gyp b/cc/blink/cc_blink_tests.gyp
index 003d126..2e3fef5 100644
--- a/cc/blink/cc_blink_tests.gyp
+++ b/cc/blink/cc_blink_tests.gyp
@@ -20,10 +20,10 @@
'cc_blink.gyp:cc_blink',
],
'sources': [
+ '../../base/test/run_all_unittests.cc',
'web_animation_unittest.cc',
'web_float_animation_curve_unittest.cc',
'web_layer_impl_fixed_bounds_unittest.cc',
- '../../base/test/run_all_unittests.cc',
],
}
],
diff --git a/cc/blink/web_animation_impl.cc b/cc/blink/web_animation_impl.cc
index 24fa4ec..705c33a 100644
--- a/cc/blink/web_animation_impl.cc
+++ b/cc/blink/web_animation_impl.cc
@@ -119,13 +119,13 @@
blink::WebCompositorAnimation::Direction WebCompositorAnimationImpl::direction()
const {
switch (animation_->direction()) {
- case cc::Animation::Normal:
+ case cc::Animation::DIRECTION_NORMAL:
return DirectionNormal;
- case cc::Animation::Reverse:
+ case cc::Animation::DIRECTION_REVERSE:
return DirectionReverse;
- case cc::Animation::Alternate:
+ case cc::Animation::DIRECTION_ALTERNATE:
return DirectionAlternate;
- case cc::Animation::AlternateReverse:
+ case cc::Animation::DIRECTION_ALTERNATE_REVERSE:
return DirectionAlternateReverse;
default:
NOTREACHED();
@@ -136,16 +136,16 @@
void WebCompositorAnimationImpl::setDirection(Direction direction) {
switch (direction) {
case DirectionNormal:
- animation_->set_direction(cc::Animation::Normal);
+ animation_->set_direction(cc::Animation::DIRECTION_NORMAL);
break;
case DirectionReverse:
- animation_->set_direction(cc::Animation::Reverse);
+ animation_->set_direction(cc::Animation::DIRECTION_REVERSE);
break;
case DirectionAlternate:
- animation_->set_direction(cc::Animation::Alternate);
+ animation_->set_direction(cc::Animation::DIRECTION_ALTERNATE);
break;
case DirectionAlternateReverse:
- animation_->set_direction(cc::Animation::AlternateReverse);
+ animation_->set_direction(cc::Animation::DIRECTION_ALTERNATE_REVERSE);
break;
}
}
@@ -161,13 +161,13 @@
blink::WebCompositorAnimation::FillMode WebCompositorAnimationImpl::fillMode()
const {
switch (animation_->fill_mode()) {
- case cc::Animation::FillModeNone:
+ case cc::Animation::FILL_MODE_NONE:
return FillModeNone;
- case cc::Animation::FillModeForwards:
+ case cc::Animation::FILL_MODE_FORWARDS:
return FillModeForwards;
- case cc::Animation::FillModeBackwards:
+ case cc::Animation::FILL_MODE_BACKWARDS:
return FillModeBackwards;
- case cc::Animation::FillModeBoth:
+ case cc::Animation::FILL_MODE_BOTH:
return FillModeBoth;
default:
NOTREACHED();
@@ -178,16 +178,16 @@
void WebCompositorAnimationImpl::setFillMode(FillMode fill_mode) {
switch (fill_mode) {
case FillModeNone:
- animation_->set_fill_mode(cc::Animation::FillModeNone);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_NONE);
break;
case FillModeForwards:
- animation_->set_fill_mode(cc::Animation::FillModeForwards);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_FORWARDS);
break;
case FillModeBackwards:
- animation_->set_fill_mode(cc::Animation::FillModeBackwards);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_BACKWARDS);
break;
case FillModeBoth:
- animation_->set_fill_mode(cc::Animation::FillModeBoth);
+ animation_->set_fill_mode(cc::Animation::FILL_MODE_BOTH);
break;
}
}
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc
index dc1d430..4941afe 100644
--- a/cc/blink/web_display_item_list_impl.cc
+++ b/cc/blink/web_display_item_list_impl.cc
@@ -35,14 +35,7 @@
void WebDisplayItemListImpl::appendDrawingItem(const SkPicture* picture) {
display_item_list_->AppendItem(cc::DrawingDisplayItem::Create(
- skia::SharePtr(const_cast<SkPicture*>(picture)), gfx::PointF(0, 0)));
-}
-
-void WebDisplayItemListImpl::appendDrawingItem(
- SkPicture* picture,
- const blink::WebFloatPoint& location) {
- display_item_list_->AppendItem(
- cc::DrawingDisplayItem::Create(skia::SharePtr(picture), location));
+ skia::SharePtr(const_cast<SkPicture*>(picture))));
}
void WebDisplayItemListImpl::appendClipItem(
@@ -101,7 +94,6 @@
display_item_list_->AppendItem(cc::EndTransparencyDisplayItem::Create());
}
-#if FILTER_DISPLAY_ITEM_USES_FILTER_OPERATIONS
void WebDisplayItemListImpl::appendFilterItem(
const blink::WebFilterOperations& filters,
const blink::WebFloatRect& bounds) {
@@ -110,22 +102,23 @@
display_item_list_->AppendItem(
cc::FilterDisplayItem::Create(filters_impl.AsFilterOperations(), bounds));
}
-#else
-void WebDisplayItemListImpl::appendFilterItem(
- SkImageFilter* filter,
- const blink::WebFloatRect& bounds) {
- cc::FilterOperations filter_operations;
- filter_operations.Append(
- cc::FilterOperation::CreateReferenceFilter(skia::SharePtr(filter)));
- display_item_list_->AppendItem(
- cc::FilterDisplayItem::Create(filter_operations, bounds));
-}
-#endif
void WebDisplayItemListImpl::appendEndFilterItem() {
display_item_list_->AppendItem(cc::EndFilterDisplayItem::Create());
}
+void WebDisplayItemListImpl::appendScrollItem(
+ const blink::WebSize& scrollOffset,
+ ScrollContainerId) {
+ SkMatrix44 matrix;
+ matrix.setTranslate(-scrollOffset.width, -scrollOffset.height, 0);
+ appendTransformItem(matrix);
+}
+
+void WebDisplayItemListImpl::appendEndScrollItem() {
+ appendEndTransformItem();
+}
+
WebDisplayItemListImpl::~WebDisplayItemListImpl() {
}
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h
index f2ff8c6..8ec7a15 100644
--- a/cc/blink/web_display_item_list_impl.h
+++ b/cc/blink/web_display_item_list_impl.h
@@ -33,8 +33,6 @@
// blink::WebDisplayItemList implementation.
virtual void appendDrawingItem(const SkPicture*);
- virtual void appendDrawingItem(SkPicture*,
- const blink::WebFloatPoint& location);
virtual void appendClipItem(
const blink::WebRect& clip_rect,
const blink::WebVector<SkRRect>& rounded_clip_rects);
@@ -50,14 +48,12 @@
virtual void appendTransparencyItem(float opacity,
blink::WebBlendMode blend_mode);
virtual void appendEndTransparencyItem();
-#if FILTER_DISPLAY_ITEM_USES_FILTER_OPERATIONS
virtual void appendFilterItem(const blink::WebFilterOperations& filters,
const blink::WebFloatRect& bounds);
-#else
- virtual void appendFilterItem(SkImageFilter* filter,
- const blink::WebFloatRect& bounds);
-#endif
virtual void appendEndFilterItem();
+ virtual void appendScrollItem(const blink::WebSize& scrollOffset,
+ ScrollContainerId);
+ virtual void appendEndScrollItem();
private:
scoped_refptr<cc::DisplayItemList> display_item_list_;
diff --git a/cc/blink/web_layer_impl.cc b/cc/blink/web_layer_impl.cc
index 2d5e459..0ef5ae7 100644
--- a/cc/blink/web_layer_impl.cc
+++ b/cc/blink/web_layer_impl.cc
@@ -397,17 +397,17 @@
}
static_assert(static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnNone) ==
- ScrollBlocksOnNone,
+ SCROLL_BLOCKS_ON_NONE,
"ScrollBlocksOn and WebScrollBlocksOn enums must match");
static_assert(static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnStartTouch) ==
- ScrollBlocksOnStartTouch,
+ SCROLL_BLOCKS_ON_START_TOUCH,
"ScrollBlocksOn and WebScrollBlocksOn enums must match");
static_assert(static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnWheelEvent) ==
- ScrollBlocksOnWheelEvent,
+ SCROLL_BLOCKS_ON_WHEEL_EVENT,
"ScrollBlocksOn and WebScrollBlocksOn enums must match");
static_assert(
static_cast<ScrollBlocksOn>(blink::WebScrollBlocksOnScrollEvent) ==
- ScrollBlocksOnScrollEvent,
+ SCROLL_BLOCKS_ON_SCROLL_EVENT,
"ScrollBlocksOn and WebScrollBlocksOn enums must match");
void WebLayerImpl::setScrollBlocksOn(blink::WebScrollBlocksOn blocks) {
diff --git a/cc/cc.gyp b/cc/cc.gyp
index d04b51c..84a0930 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -52,8 +52,8 @@
'animation/layer_animation_value_provider.h',
'animation/scroll_offset_animation_curve.cc',
'animation/scroll_offset_animation_curve.h',
- 'animation/scrollbar_animation_controller.h',
'animation/scrollbar_animation_controller.cc',
+ 'animation/scrollbar_animation_controller.h',
'animation/scrollbar_animation_controller_linear_fade.cc',
'animation/scrollbar_animation_controller_linear_fade.h',
'animation/scrollbar_animation_controller_thinning.cc',
@@ -88,9 +88,9 @@
'base/swap_promise.h',
'base/swap_promise_monitor.cc',
'base/swap_promise_monitor.h',
- 'base/synced_property.h',
'base/switches.cc',
'base/switches.h',
+ 'base/synced_property.h',
'base/tiling_data.cc',
'base/tiling_data.h',
'base/time_util.h',
@@ -120,12 +120,12 @@
'debug/layer_tree_debug_state.h',
'debug/micro_benchmark.cc',
'debug/micro_benchmark.h',
- 'debug/micro_benchmark_impl.cc',
- 'debug/micro_benchmark_impl.h',
'debug/micro_benchmark_controller.cc',
'debug/micro_benchmark_controller.h',
'debug/micro_benchmark_controller_impl.cc',
'debug/micro_benchmark_controller_impl.h',
+ 'debug/micro_benchmark_impl.cc',
+ 'debug/micro_benchmark_impl.h',
'debug/paint_time_counter.cc',
'debug/paint_time_counter.h',
'debug/picture_debug_util.cc',
@@ -151,10 +151,10 @@
'debug/unittest_only_benchmark_impl.h',
'input/input_handler.cc',
'input/input_handler.h',
- 'input/page_scale_animation.cc',
- 'input/page_scale_animation.h',
'input/layer_selection_bound.cc',
'input/layer_selection_bound.h',
+ 'input/page_scale_animation.cc',
+ 'input/page_scale_animation.h',
'input/scroll_elasticity_helper.cc',
'input/scroll_elasticity_helper.h',
'input/selection_bound_type.h',
@@ -273,8 +273,8 @@
'output/copy_output_request.h',
'output/copy_output_result.cc',
'output/copy_output_result.h',
- 'output/delegated_frame_data.h',
'output/delegated_frame_data.cc',
+ 'output/delegated_frame_data.h',
'output/delegating_renderer.cc',
'output/delegating_renderer.h',
'output/direct_renderer.cc',
@@ -285,8 +285,8 @@
'output/filter_operations.h',
'output/geometry_binding.cc',
'output/geometry_binding.h',
- 'output/gl_frame_data.h',
'output/gl_frame_data.cc',
+ 'output/gl_frame_data.h',
'output/gl_renderer.cc',
'output/gl_renderer.h',
'output/gl_renderer_draw_cache.cc',
@@ -334,8 +334,8 @@
'quads/draw_quad.h',
'quads/io_surface_draw_quad.cc',
'quads/io_surface_draw_quad.h',
- 'quads/largest_draw_quad.h',
'quads/largest_draw_quad.cc',
+ 'quads/largest_draw_quad.h',
'quads/list_container.cc',
'quads/list_container.h',
'quads/picture_draw_quad.cc',
@@ -362,10 +362,10 @@
'quads/yuv_video_draw_quad.h',
'resources/bitmap_content_layer_updater.cc',
'resources/bitmap_content_layer_updater.h',
- 'resources/bitmap_tile_task_worker_pool.cc',
- 'resources/bitmap_tile_task_worker_pool.h',
'resources/bitmap_skpicture_content_layer_updater.cc',
'resources/bitmap_skpicture_content_layer_updater.h',
+ 'resources/bitmap_tile_task_worker_pool.cc',
+ 'resources/bitmap_tile_task_worker_pool.h',
'resources/clip_display_item.cc',
'resources/clip_display_item.h',
'resources/clip_path_display_item.cc',
@@ -429,19 +429,13 @@
'resources/raster_source.h',
'resources/raster_source_helper.cc',
'resources/raster_source_helper.h',
+ 'resources/raster_tile_priority_queue.cc',
+ 'resources/raster_tile_priority_queue.h',
'resources/raster_tile_priority_queue_all.cc',
'resources/raster_tile_priority_queue_all.h',
'resources/raster_tile_priority_queue_required.cc',
'resources/raster_tile_priority_queue_required.h',
- 'resources/raster_tile_priority_queue.cc',
- 'resources/raster_tile_priority_queue.h',
'resources/rasterizer.h',
- 'resources/software_rasterizer.cc',
- 'resources/software_rasterizer.h',
- 'resources/tile_task_worker_pool.cc',
- 'resources/tile_task_worker_pool.h',
- 'resources/tile_task_runner.cc',
- 'resources/tile_task_runner.h',
'resources/recording_source.h',
'resources/release_callback.h',
'resources/resource.cc',
@@ -474,6 +468,8 @@
'resources/single_release_callback_impl.h',
'resources/skpicture_content_layer_updater.cc',
'resources/skpicture_content_layer_updater.h',
+ 'resources/software_rasterizer.cc',
+ 'resources/software_rasterizer.h',
'resources/task_graph_runner.cc',
'resources/task_graph_runner.h',
'resources/texture_mailbox.cc',
@@ -490,6 +486,10 @@
'resources/tile_manager.h',
'resources/tile_priority.cc',
'resources/tile_priority.h',
+ 'resources/tile_task_runner.cc',
+ 'resources/tile_task_runner.h',
+ 'resources/tile_task_worker_pool.cc',
+ 'resources/tile_task_worker_pool.h',
'resources/tiling_set_eviction_queue.cc',
'resources/tiling_set_eviction_queue.h',
'resources/tiling_set_raster_queue_all.cc',
@@ -595,14 +595,14 @@
'surfaces/surface.h',
'surfaces/surface_aggregator.cc',
'surfaces/surface_aggregator.h',
+ 'surfaces/surface_display_output_surface.cc',
+ 'surfaces/surface_display_output_surface.h',
'surfaces/surface_factory.cc',
'surfaces/surface_factory.h',
'surfaces/surface_factory_client.h',
'surfaces/surface_id.h',
'surfaces/surface_id_allocator.cc',
'surfaces/surface_id_allocator.h',
- 'surfaces/surface_display_output_surface.cc',
- 'surfaces/surface_display_output_surface.h',
'surfaces/surface_manager.cc',
'surfaces/surface_manager.h',
'surfaces/surface_resource_holder.cc',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 49337bc..4d29a60 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -32,8 +32,8 @@
'layers/delegated_frame_resource_collection_unittest.cc',
'layers/delegated_renderer_layer_impl_unittest.cc',
'layers/delegated_renderer_layer_unittest.cc',
- 'layers/heads_up_display_unittest.cc',
'layers/heads_up_display_layer_impl_unittest.cc',
+ 'layers/heads_up_display_unittest.cc',
'layers/io_surface_layer_impl_unittest.cc',
'layers/layer_impl_unittest.cc',
'layers/layer_iterator_unittest.cc',
@@ -47,15 +47,15 @@
'layers/picture_image_layer_unittest.cc',
'layers/picture_layer_impl_unittest.cc',
'layers/picture_layer_unittest.cc',
- 'layers/render_surface_unittest.cc',
'layers/render_surface_impl_unittest.cc',
+ 'layers/render_surface_unittest.cc',
'layers/scrollbar_layer_unittest.cc',
'layers/solid_color_layer_impl_unittest.cc',
'layers/solid_color_scrollbar_layer_impl_unittest.cc',
- 'layers/surface_layer_unittest.cc',
'layers/surface_layer_impl_unittest.cc',
- 'layers/texture_layer_unittest.cc',
+ 'layers/surface_layer_unittest.cc',
'layers/texture_layer_impl_unittest.cc',
+ 'layers/texture_layer_unittest.cc',
'layers/tiled_layer_impl_unittest.cc',
'layers/tiled_layer_unittest.cc',
'layers/ui_resource_layer_impl_unittest.cc',
@@ -83,8 +83,8 @@
'resources/picture_pile_impl_unittest.cc',
'resources/picture_pile_unittest.cc',
'resources/picture_unittest.cc',
+ 'resources/platform_color_unittest.cc',
'resources/prioritized_resource_unittest.cc',
- 'resources/tile_task_worker_pool_unittest.cc',
'resources/resource_provider_unittest.cc',
'resources/resource_update_controller_unittest.cc',
'resources/scoped_gpu_raster_unittest.cc',
@@ -94,6 +94,7 @@
'resources/texture_uploader_unittest.cc',
'resources/tile_manager_unittest.cc',
'resources/tile_priority_unittest.cc',
+ 'resources/tile_task_worker_pool_unittest.cc',
'resources/video_resource_updater_unittest.cc',
'scheduler/begin_frame_source_unittest.cc',
'scheduler/delay_based_time_source_unittest.cc',
@@ -110,7 +111,6 @@
'trees/layer_tree_host_pixeltest_blending.cc',
'trees/layer_tree_host_pixeltest_filters.cc',
'trees/layer_tree_host_pixeltest_masks.cc',
- 'trees/layer_tree_host_pixeltest_on_demand_raster.cc',
'trees/layer_tree_host_pixeltest_readback.cc',
'trees/layer_tree_host_pixeltest_synchronous.cc',
'trees/layer_tree_host_unittest.cc',
@@ -119,8 +119,8 @@
'trees/layer_tree_host_unittest_copyrequest.cc',
'trees/layer_tree_host_unittest_damage.cc',
'trees/layer_tree_host_unittest_delegated.cc',
- 'trees/layer_tree_host_unittest_occlusion.cc',
'trees/layer_tree_host_unittest_no_message_loop.cc',
+ 'trees/layer_tree_host_unittest_occlusion.cc',
'trees/layer_tree_host_unittest_picture.cc',
'trees/layer_tree_host_unittest_proxy.cc',
'trees/layer_tree_host_unittest_scroll.cc',
@@ -132,6 +132,7 @@
'trees/tree_synchronizer_unittest.cc',
],
'cc_surfaces_unit_tests_source_files': [
+ 'surfaces/display_unittest.cc',
'surfaces/surface_aggregator_test_helpers.cc',
'surfaces/surface_aggregator_test_helpers.h',
'surfaces/surface_aggregator_unittest.cc',
@@ -144,6 +145,8 @@
'test/animation_test_common.h',
'test/begin_frame_args_test.cc',
'test/begin_frame_args_test.h',
+ 'test/failure_output_surface.cc',
+ 'test/failure_output_surface.h',
'test/fake_content_layer.cc',
'test/fake_content_layer.h',
'test/fake_content_layer_client.cc',
@@ -198,12 +201,8 @@
'test/fake_ui_resource_layer_tree_host_impl.h',
'test/fake_video_frame_provider.cc',
'test/fake_video_frame_provider.h',
- 'test/failure_output_surface.cc',
- 'test/failure_output_surface.h',
'test/geometry_test_utils.cc',
'test/geometry_test_utils.h',
- 'test/test_in_process_context_provider.cc',
- 'test/test_in_process_context_provider.h',
'test/impl_side_painting_settings.h',
'test/layer_test_common.cc',
'test/layer_test_common.h',
@@ -254,6 +253,8 @@
'test/test_gpu_memory_buffer_manager.h',
'test/test_image_factory.cc',
'test/test_image_factory.h',
+ 'test/test_in_process_context_provider.cc',
+ 'test/test_in_process_context_provider.h',
'test/test_now_source.cc',
'test/test_now_source.h',
'test/test_occlusion_tracker.h',
@@ -290,8 +291,8 @@
'cc_test_support',
],
'sources': [
- 'test/run_all_unittests.cc',
'test/cc_test_suite.cc',
+ 'test/run_all_unittests.cc',
'<@(cc_unit_tests_source_files)',
'<@(cc_surfaces_unit_tests_source_files)',
],
@@ -349,9 +350,9 @@
'layers/picture_layer_impl_perftest.cc',
'resources/picture_layer_tiling_perftest.cc',
'resources/picture_pile_impl_perftest.cc',
- 'resources/tile_task_worker_pool_perftest.cc',
'resources/task_graph_runner_perftest.cc',
'resources/tile_manager_perftest.cc',
+ 'resources/tile_task_worker_pool_perftest.cc',
'test/cc_test_suite.cc',
'test/run_all_perftests.cc',
'trees/layer_tree_host_common_perftest.cc',
diff --git a/cc/debug/debug_colors.cc b/cc/debug/debug_colors.cc
index daec5cc..38ecf54 100644
--- a/cc/debug/debug_colors.cc
+++ b/cc/debug/debug_colors.cc
@@ -114,9 +114,9 @@
return Scale(2, tree_impl);
}
-// Missing tile borders are red.
+// Missing tile borders are dark grey.
SkColor DebugColors::MissingTileBorderColor() {
- return SkColorSetARGB(100, 255, 0, 0);
+ return SkColorSetARGB(64, 64, 64, 0);
}
int DebugColors::MissingTileBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(1, tree_impl);
@@ -130,11 +130,11 @@
return Scale(1, tree_impl);
}
-// Picture tile borders are dark grey.
-SkColor DebugColors::PictureTileBorderColor() {
- return SkColorSetARGB(64, 64, 64, 0);
+// OOM tile borders are red.
+SkColor DebugColors::OOMTileBorderColor() {
+ return SkColorSetARGB(100, 255, 0, 0);
}
-int DebugColors::PictureTileBorderWidth(const LayerTreeImpl* tree_impl) {
+int DebugColors::OOMTileBorderWidth(const LayerTreeImpl* tree_impl) {
return Scale(1, tree_impl);
}
diff --git a/cc/debug/debug_colors.h b/cc/debug/debug_colors.h
index 52dab85..8e4ec8d 100644
--- a/cc/debug/debug_colors.h
+++ b/cc/debug/debug_colors.h
@@ -56,8 +56,8 @@
static SkColor SolidColorTileBorderColor();
static int SolidColorTileBorderWidth(const LayerTreeImpl* tree_impl);
- static SkColor PictureTileBorderColor();
- static int PictureTileBorderWidth(const LayerTreeImpl* tree_impl);
+ static SkColor OOMTileBorderColor();
+ static int OOMTileBorderWidth(const LayerTreeImpl* tree_impl);
static SkColor DirectPictureBorderColor();
static int DirectPictureBorderWidth(const LayerTreeImpl* tree_impl);
diff --git a/cc/input/input_handler.h b/cc/input/input_handler.h
index d899a85..954f8d7 100644
--- a/cc/input/input_handler.h
+++ b/cc/input/input_handler.h
@@ -66,14 +66,14 @@
// Note these are used in a histogram. Do not reorder or delete existing
// entries.
enum ScrollStatus {
- ScrollOnMainThread = 0,
- ScrollStarted,
- ScrollIgnored,
- ScrollUnknown,
+ SCROLL_ON_MAIN_THREAD = 0,
+ SCROLL_STARTED,
+ SCROLL_IGNORED,
+ SCROLL_UNKNOWN,
// This must be the last entry.
ScrollStatusCount
};
- enum ScrollInputType { Gesture, Wheel, NonBubblingGesture };
+ enum ScrollInputType { GESTURE, WHEEL, NON_BUBBLING_GESTURE };
// Binds a client to this handler to receive notifications. Only one client
// can be bound to an InputHandler. The client must live at least until the
@@ -81,10 +81,10 @@
virtual void BindToClient(InputHandlerClient* client) = 0;
// Selects a layer to be scrolled at a given point in viewport (logical
- // pixel) coordinates. Returns ScrollStarted if the layer at the coordinates
- // can be scrolled, ScrollOnMainThread if the scroll event should instead be
- // delegated to the main thread, or ScrollIgnored if there is nothing to be
- // scrolled at the given coordinates.
+ // pixel) coordinates. Returns SCROLL_STARTED if the layer at the coordinates
+ // can be scrolled, SCROLL_ON_MAIN_THREAD if the scroll event should instead
+ // be delegated to the main thread, or SCROLL_IGNORED if there is nothing to
+ // be scrolled at the given coordinates.
virtual ScrollStatus ScrollBegin(const gfx::Point& viewport_point,
ScrollInputType type) = 0;
@@ -102,7 +102,7 @@
// If the scroll delta hits the root layer, and the layer can no longer move,
// the root overscroll accumulated within this ScrollBegin() scope is reported
// in the return value's |accumulated_overscroll| field.
- // Should only be called if ScrollBegin() returned ScrollStarted.
+ // Should only be called if ScrollBegin() returned SCROLL_STARTED.
virtual InputHandlerScrollResult ScrollBy(
const gfx::Point& viewport_point,
const gfx::Vector2dF& scroll_delta) = 0;
@@ -110,14 +110,14 @@
virtual bool ScrollVerticallyByPage(const gfx::Point& viewport_point,
ScrollDirection direction) = 0;
- // Returns ScrollStarted if a layer was being actively being scrolled,
- // ScrollIgnored if not.
+ // Returns SCROLL_STARTED if a layer was being actively being scrolled,
+ // SCROLL_IGNORED if not.
virtual ScrollStatus FlingScrollBegin() = 0;
virtual void MouseMoveAt(const gfx::Point& mouse_position) = 0;
// Stop scrolling the selected layer. Should only be called if ScrollBegin()
- // returned ScrollStarted.
+ // returned SCROLL_STARTED.
virtual void ScrollEnd() = 0;
virtual void SetRootLayerScrollOffsetDelegate(
diff --git a/cc/input/scroll_elasticity_helper.cc b/cc/input/scroll_elasticity_helper.cc
index 1e9fe7d..1c496d9 100644
--- a/cc/input/scroll_elasticity_helper.cc
+++ b/cc/input/scroll_elasticity_helper.cc
@@ -15,6 +15,7 @@
explicit ScrollElasticityHelperImpl(LayerTreeHostImpl* layer_tree_host_impl);
~ScrollElasticityHelperImpl() override;
+ bool IsUserScrollable() const override;
gfx::Vector2dF StretchAmount() const override;
void SetStretchAmount(const gfx::Vector2dF& stretch_amount) override;
gfx::ScrollOffset ScrollOffset() const override;
@@ -34,6 +35,14 @@
ScrollElasticityHelperImpl::~ScrollElasticityHelperImpl() {
}
+bool ScrollElasticityHelperImpl::IsUserScrollable() const {
+ LayerImpl* layer = layer_tree_host_impl_->OuterViewportScrollLayer();
+ if (!layer)
+ return false;
+ return layer->user_scrollable_horizontal() ||
+ layer->user_scrollable_vertical();
+}
+
gfx::Vector2dF ScrollElasticityHelperImpl::StretchAmount() const {
return layer_tree_host_impl_->active_tree()->elastic_overscroll()->Current(
true);
diff --git a/cc/input/scroll_elasticity_helper.h b/cc/input/scroll_elasticity_helper.h
index bf444ee..a2bdbfe 100644
--- a/cc/input/scroll_elasticity_helper.h
+++ b/cc/input/scroll_elasticity_helper.h
@@ -52,6 +52,8 @@
virtual ~ScrollElasticityHelper() {}
+ virtual bool IsUserScrollable() const = 0;
+
// The amount that the view is stretched past the normal allowable bounds.
virtual gfx::Vector2dF StretchAmount() const = 0;
virtual void SetStretchAmount(const gfx::Vector2dF& stretch_amount) = 0;
diff --git a/cc/layers/content_layer.cc b/cc/layers/content_layer.cc
index 6af92ec..d1ff842 100644
--- a/cc/layers/content_layer.cc
+++ b/cc/layers/content_layer.cc
@@ -114,10 +114,6 @@
updater_->SetOpaque(opaque);
}
-bool ContentLayer::SupportsLCDText() const {
- return true;
-}
-
skia::RefPtr<SkPicture> ContentLayer::GetPicture() const {
if (!DrawsContent())
return skia::RefPtr<SkPicture>();
diff --git a/cc/layers/content_layer.h b/cc/layers/content_layer.h
index 22dd8fd..5d6ac15 100644
--- a/cc/layers/content_layer.h
+++ b/cc/layers/content_layer.h
@@ -46,8 +46,6 @@
void SetContentsOpaque(bool contents_opaque) override;
- bool SupportsLCDText() const override;
-
skia::RefPtr<SkPicture> GetPicture() const override;
void OnOutputSurfaceCreated() override;
diff --git a/cc/layers/heads_up_display_layer_impl.cc b/cc/layers/heads_up_display_layer_impl.cc
index 97fddae..19217c9 100644
--- a/cc/layers/heads_up_display_layer_impl.cc
+++ b/cc/layers/heads_up_display_layer_impl.cc
@@ -97,7 +97,7 @@
scoped_ptr<ScopedResource> resource =
ScopedResource::Create(resource_provider);
resource->Allocate(internal_content_bounds_,
- ResourceProvider::TextureHintImmutable, RGBA_8888);
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
resources_.push_back(resource.Pass());
}
@@ -210,13 +210,10 @@
size_t row_bytes = 0;
const void* pixels = hud_surface_->getCanvas()->peekPixels(&info, &row_bytes);
DCHECK(pixels);
- gfx::Rect content_rect(internal_content_bounds_);
DCHECK(info.colorType() == kN32_SkColorType);
- resource_provider->SetPixels(resources_.back()->id(),
- static_cast<const uint8_t*>(pixels),
- content_rect,
- content_rect,
- gfx::Vector2d());
+ resource_provider->CopyToResource(resources_.back()->id(),
+ static_cast<const uint8_t*>(pixels),
+ internal_content_bounds_);
}
void HeadsUpDisplayLayerImpl::ReleaseResources() {
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc
index 19b505b..ca0e3b8 100644
--- a/cc/layers/layer.cc
+++ b/cc/layers/layer.cc
@@ -71,7 +71,7 @@
force_render_surface_(false),
transform_is_invertible_(true),
has_render_surface_(false),
- scroll_blocks_on_(ScrollBlocksOnNone),
+ scroll_blocks_on_(SCROLL_BLOCKS_ON_NONE),
background_color_(0),
opacity_(1.f),
blend_mode_(SkXfermode::kSrcOver_Mode),
@@ -471,7 +471,7 @@
}
bool Layer::FilterIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Filter);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::FILTER);
}
void Layer::SetBackgroundFilters(const FilterOperations& filters) {
@@ -491,7 +491,7 @@
}
bool Layer::OpacityIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Opacity);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::OPACITY);
}
bool Layer::OpacityCanAnimateOnImplThread() const {
@@ -601,7 +601,7 @@
}
bool Layer::TransformIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Transform);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::TRANSFORM);
}
void Layer::SetScrollParent(Layer* parent) {
@@ -909,7 +909,7 @@
draw_checkerboard_for_missing_tiles_);
layer->SetDrawsContent(DrawsContent());
layer->SetHideLayerAndSubtree(hide_layer_and_subtree_);
- layer->SetHasRenderSurface(has_render_surface_);
+ layer->SetHasRenderSurface(has_render_surface_ || layer->HasCopyRequest());
if (!layer->FilterIsAnimatingOnImplOnly() && !FilterIsAnimating())
layer->SetFilters(filters_);
DCHECK(!(FilterIsAnimating() && layer->FilterIsAnimatingOnImplOnly()));
@@ -1181,7 +1181,7 @@
if (!layer_animation_controller_->animation_registrar())
return false;
- if (animation->target_property() == Animation::ScrollOffset &&
+ if (animation->target_property() == Animation::SCROLL_OFFSET &&
!layer_animation_controller_->animation_registrar()
->supports_scroll_animations())
return false;
@@ -1240,10 +1240,6 @@
return layer_tree_host_->rendering_stats_instrumentation();
}
-bool Layer::SupportsLCDText() const {
- return false;
-}
-
void Layer::RemoveFromScrollTree() {
if (scroll_children_.get()) {
std::set<Layer*> copy = *scroll_children_;
diff --git a/cc/layers/layer.h b/cc/layers/layer.h
index 873f360..8eb7c3d 100644
--- a/cc/layers/layer.h
+++ b/cc/layers/layer.h
@@ -242,7 +242,6 @@
bool screen_space_opacity_is_animating() const {
return draw_properties_.screen_space_opacity_is_animating;
}
- bool can_use_lcd_text() const { return draw_properties_.can_use_lcd_text; }
bool is_clipped() const { return draw_properties_.is_clipped; }
gfx::Rect clip_rect() const { return draw_properties_.clip_rect; }
gfx::Rect drawable_content_rect() const {
@@ -457,8 +456,6 @@
float raster_scale() const { return raster_scale_; }
bool raster_scale_is_unknown() const { return raster_scale_ == 0.f; }
- virtual bool SupportsLCDText() const;
-
void SetNeedsPushProperties();
bool needs_push_properties() const { return needs_push_properties_; }
bool descendant_needs_push_properties() const {
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 6e11644..63fd4dc 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -54,7 +54,7 @@
should_scroll_on_main_thread_(false),
have_wheel_event_handlers_(false),
have_scroll_event_handlers_(false),
- scroll_blocks_on_(ScrollBlocksOnNone),
+ scroll_blocks_on_(SCROLL_BLOCKS_ON_NONE),
user_scrollable_horizontal_(true),
user_scrollable_vertical_(true),
stacking_order_changed_(false),
@@ -425,12 +425,12 @@
ScrollBlocksOn effective_block_mode) const {
if (should_scroll_on_main_thread()) {
TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread");
- return InputHandler::ScrollOnMainThread;
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
}
if (!screen_space_transform().IsInvertible()) {
TRACE_EVENT0("cc", "LayerImpl::TryScroll: Ignored NonInvertibleTransform");
- return InputHandler::ScrollIgnored;
+ return InputHandler::SCROLL_IGNORED;
}
if (!non_fast_scrollable_region().IsEmpty()) {
@@ -440,7 +440,7 @@
if (!screen_space_transform().GetInverse(&inverse_screen_space_transform)) {
// TODO(shawnsingh): We shouldn't be applying a projection if screen space
// transform is uninvertible here. Perhaps we should be returning
- // ScrollOnMainThread in this case?
+ // SCROLL_ON_MAIN_THREAD in this case?
}
gfx::PointF hit_test_point_in_content_space =
@@ -456,25 +456,25 @@
gfx::ToRoundedPoint(hit_test_point_in_layer_space))) {
TRACE_EVENT0("cc",
"LayerImpl::tryScroll: Failed NonFastScrollableRegion");
- return InputHandler::ScrollOnMainThread;
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
}
}
if (have_scroll_event_handlers() &&
- effective_block_mode & ScrollBlocksOnScrollEvent) {
+ effective_block_mode & SCROLL_BLOCKS_ON_SCROLL_EVENT) {
TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed ScrollEventHandlers");
- return InputHandler::ScrollOnMainThread;
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
}
- if (type == InputHandler::Wheel && have_wheel_event_handlers() &&
- effective_block_mode & ScrollBlocksOnWheelEvent) {
+ if (type == InputHandler::WHEEL && have_wheel_event_handlers() &&
+ effective_block_mode & SCROLL_BLOCKS_ON_WHEEL_EVENT) {
TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed WheelEventHandlers");
- return InputHandler::ScrollOnMainThread;
+ return InputHandler::SCROLL_ON_MAIN_THREAD;
}
if (!scrollable()) {
TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable");
- return InputHandler::ScrollIgnored;
+ return InputHandler::SCROLL_IGNORED;
}
gfx::ScrollOffset max_scroll_offset = MaxScrollOffset();
@@ -482,10 +482,10 @@
TRACE_EVENT0("cc",
"LayerImpl::tryScroll: Ignored. Technically scrollable,"
" but has no affordance in either direction.");
- return InputHandler::ScrollIgnored;
+ return InputHandler::SCROLL_IGNORED;
}
- return InputHandler::ScrollStarted;
+ return InputHandler::SCROLL_STARTED;
}
gfx::Rect LayerImpl::LayerRectToContentRect(
@@ -517,7 +517,7 @@
draw_checkerboard_for_missing_tiles_);
layer->SetDrawsContent(DrawsContent());
layer->SetHideLayerAndSubtree(hide_layer_and_subtree_);
- layer->SetHasRenderSurface(!!render_surface());
+ layer->SetHasRenderSurface(!!render_surface() || layer->HasCopyRequest());
layer->SetFilters(filters());
layer->SetBackgroundFilters(background_filters());
layer->SetMasksToBounds(masks_to_bounds_);
@@ -672,7 +672,7 @@
result->SetBoolean("DrawsContent", draws_content_);
result->SetBoolean("Is3dSorted", Is3dSorted());
- result->SetDouble("Opacity", opacity());
+ result->SetDouble("OPACITY", opacity());
result->SetBoolean("ContentsOpaque", contents_opaque_);
if (scrollable())
@@ -689,11 +689,11 @@
if (scroll_blocks_on_) {
list = new base::ListValue;
- if (scroll_blocks_on_ & ScrollBlocksOnStartTouch)
+ if (scroll_blocks_on_ & SCROLL_BLOCKS_ON_START_TOUCH)
list->AppendString("StartTouch");
- if (scroll_blocks_on_ & ScrollBlocksOnWheelEvent)
+ if (scroll_blocks_on_ & SCROLL_BLOCKS_ON_WHEEL_EVENT)
list->AppendString("WheelEvent");
- if (scroll_blocks_on_ & ScrollBlocksOnScrollEvent)
+ if (scroll_blocks_on_ & SCROLL_BLOCKS_ON_SCROLL_EVENT)
list->AppendString("ScrollEvent");
result->Set("ScrollBlocksOn", list);
}
@@ -946,12 +946,12 @@
}
bool LayerImpl::FilterIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Filter);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::FILTER);
}
bool LayerImpl::FilterIsAnimatingOnImplOnly() const {
Animation* filter_animation =
- layer_animation_controller_->GetAnimation(Animation::Filter);
+ layer_animation_controller_->GetAnimation(Animation::FILTER);
return filter_animation && filter_animation->is_impl_only();
}
@@ -989,12 +989,12 @@
}
bool LayerImpl::OpacityIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Opacity);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::OPACITY);
}
bool LayerImpl::OpacityIsAnimatingOnImplOnly() const {
Animation* opacity_animation =
- layer_animation_controller_->GetAnimation(Animation::Opacity);
+ layer_animation_controller_->GetAnimation(Animation::OPACITY);
return opacity_animation && opacity_animation->is_impl_only();
}
@@ -1066,12 +1066,12 @@
}
bool LayerImpl::TransformIsAnimating() const {
- return layer_animation_controller_->IsAnimatingProperty(Animation::Transform);
+ return layer_animation_controller_->IsAnimatingProperty(Animation::TRANSFORM);
}
bool LayerImpl::TransformIsAnimatingOnImplOnly() const {
Animation* transform_animation =
- layer_animation_controller_->GetAnimation(Animation::Transform);
+ layer_animation_controller_->GetAnimation(Animation::TRANSFORM);
return transform_animation && transform_animation->is_impl_only();
}
@@ -1332,7 +1332,7 @@
void LayerImpl::DidBecomeActive() {
if (layer_tree_impl_->settings().scrollbar_animator ==
- LayerTreeSettings::NoAnimator) {
+ LayerTreeSettings::NO_ANIMATOR) {
return;
}
@@ -1573,7 +1573,7 @@
base::TimeTicks monotonic_time,
Animation::TargetProperty target_property,
int group) {
- if (target_property == Animation::ScrollOffset)
+ if (target_property == Animation::SCROLL_OFFSET)
layer_tree_impl_->InputScrollAnimationFinished();
}
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 97fd205..5de0d9a 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -667,7 +667,7 @@
bool have_wheel_event_handlers_ : 1;
bool have_scroll_event_handlers_ : 1;
- static_assert(ScrollBlocksOnMax < (1 << 3), "ScrollBlocksOn too big");
+ static_assert(SCROLL_BLOCKS_ON_MAX < (1 << 3), "ScrollBlocksOn too big");
ScrollBlocksOn scroll_blocks_on_ : 3;
bool user_scrollable_horizontal_ : 1;
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 460726f..8a61510 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -738,8 +738,9 @@
1.0,
0,
100);
- impl_layer->layer_animation_controller()->GetAnimation(Animation::Transform)->
- set_is_impl_only(true);
+ impl_layer->layer_animation_controller()
+ ->GetAnimation(Animation::TRANSFORM)
+ ->set_is_impl_only(true);
transform.Rotate(45.0);
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetTransform(transform));
@@ -779,8 +780,9 @@
0.3f,
0.7f,
false);
- impl_layer->layer_animation_controller()->GetAnimation(Animation::Opacity)->
- set_is_impl_only(true);
+ impl_layer->layer_animation_controller()
+ ->GetAnimation(Animation::OPACITY)
+ ->set_is_impl_only(true);
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetOpacity(0.75f));
EXPECT_FALSE(impl_layer->LayerPropertyChanged());
@@ -815,8 +817,9 @@
impl_layer->ResetAllChangeTrackingForSubtree();
AddAnimatedFilterToController(
impl_layer->layer_animation_controller(), 1.0, 1.f, 2.f);
- impl_layer->layer_animation_controller()->GetAnimation(Animation::Filter)->
- set_is_impl_only(true);
+ impl_layer->layer_animation_controller()
+ ->GetAnimation(Animation::FILTER)
+ ->set_is_impl_only(true);
filters.Append(FilterOperation::CreateSepiaFilter(0.5f));
EXPECT_SET_NEEDS_COMMIT(1, test_layer->SetFilters(filters));
@@ -1148,7 +1151,7 @@
curve->AddKeyframe(
FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 0.7f, nullptr));
scoped_ptr<Animation> animation =
- Animation::Create(curve.Pass(), 0, 0, Animation::Opacity);
+ Animation::Create(curve.Pass(), 0, 0, Animation::OPACITY);
return layer->AddAnimation(animation.Pass());
}
diff --git a/cc/layers/picture_image_layer.cc b/cc/layers/picture_image_layer.cc
index 9f35d6e..6886612 100644
--- a/cc/layers/picture_image_layer.cc
+++ b/cc/layers/picture_image_layer.cc
@@ -73,8 +73,7 @@
PaintContents(canvas, clip, painting_control);
skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
- display_item_list->AppendItem(
- DrawingDisplayItem::Create(picture, gfx::Point()));
+ display_item_list->AppendItem(DrawingDisplayItem::Create(picture));
return display_item_list;
}
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index d40f555..3d2d38e 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -52,9 +52,6 @@
case PENDING_TREE:
tree = host_impl_.pending_tree();
break;
- case NUM_TREES:
- NOTREACHED();
- break;
}
TestablePictureImageLayerImpl* layer =
new TestablePictureImageLayerImpl(tree, id);
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 0ca2ae7..e7918e2 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -23,7 +23,6 @@
: client_(client),
instrumentation_object_tracker_(id()),
update_source_frame_number_(-1),
- can_use_lcd_text_for_update_(true),
is_mask_(false),
nearest_neighbor_(false) {
}
@@ -69,8 +68,10 @@
layer_impl->SetNearestNeighbor(nearest_neighbor_);
+ // Preserve lcd text settings from the current raster source.
+ bool can_use_lcd_text = layer_impl->RasterSourceUsesLCDText();
scoped_refptr<RasterSource> raster_source =
- recording_source_->CreateRasterSource();
+ recording_source_->CreateRasterSource(can_use_lcd_text);
layer_impl->UpdateRasterSource(raster_source, &recording_invalidation_,
nullptr);
DCHECK(recording_invalidation_.IsEmpty());
@@ -107,14 +108,12 @@
update_source_frame_number_ = layer_tree_host()->source_frame_number();
bool updated = Layer::Update(queue, occlusion);
- bool can_use_lcd_text_changed = UpdateCanUseLCDText();
-
gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
visible_content_rect(), 1.f / contents_scale_x());
gfx::Size layer_size = paint_properties().bounds;
if (last_updated_visible_content_rect_ == visible_content_rect() &&
- recording_source_->GetSize() == layer_size && !can_use_lcd_text_changed &&
+ recording_source_->GetSize() == layer_size &&
pending_invalidation_.IsEmpty()) {
// Only early out if the visible content rect of this layer hasn't changed.
return updated;
@@ -147,9 +146,8 @@
// for them.
DCHECK(client_);
updated |= recording_source_->UpdateAndExpandInvalidation(
- client_, &recording_invalidation_, can_use_lcd_text_for_update_,
- layer_size, visible_layer_rect, update_source_frame_number_,
- RecordingSource::RECORD_NORMALLY);
+ client_, &recording_invalidation_, layer_size, visible_layer_rect,
+ update_source_frame_number_, RecordingSource::RECORD_NORMALLY);
last_updated_visible_content_rect_ = visible_content_rect();
if (updated) {
@@ -167,20 +165,6 @@
is_mask_ = is_mask;
}
-bool PictureLayer::SupportsLCDText() const {
- return true;
-}
-
-bool PictureLayer::UpdateCanUseLCDText() {
- if (!can_use_lcd_text_for_update_)
- return false; // Don't allow the LCD text state to change once disabled.
- if (can_use_lcd_text_for_update_ == can_use_lcd_text())
- return false;
-
- can_use_lcd_text_for_update_ = can_use_lcd_text();
- return true;
-}
-
skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
// We could either flatten the RecordingSource into a single SkPicture,
// or paint a fresh one depending on what we intend to do with the
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index 648d1c9..767de27 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -33,7 +33,6 @@
bool Update(ResourceUpdateQueue* queue,
const OcclusionTracker<Layer>* occlusion) override;
void SetIsMask(bool is_mask) override;
- bool SupportsLCDText() const override;
skia::RefPtr<SkPicture> GetPicture() const override;
bool IsSuitableForGpuRasterization() const override;
@@ -56,8 +55,6 @@
bool is_mask() const { return is_mask_; }
private:
- bool UpdateCanUseLCDText();
-
ContentLayerClient* client_;
scoped_ptr<RecordingSource> recording_source_;
devtools_instrumentation::
@@ -69,7 +66,6 @@
gfx::Rect last_updated_visible_content_rect_;
int update_source_frame_number_;
- bool can_use_lcd_text_for_update_;
bool is_mask_;
bool nearest_neighbor_;
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index f62a866..e819afd 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -225,9 +225,9 @@
if (mode == TileDrawInfo::SOLID_COLOR_MODE) {
color = DebugColors::SolidColorTileBorderColor();
width = DebugColors::SolidColorTileBorderWidth(layer_tree_impl());
- } else if (mode == TileDrawInfo::PICTURE_PILE_MODE) {
- color = DebugColors::PictureTileBorderColor();
- width = DebugColors::PictureTileBorderWidth(layer_tree_impl());
+ } else if (mode == TileDrawInfo::OOM_MODE) {
+ color = DebugColors::OOMTileBorderColor();
+ width = DebugColors::OOMTileBorderWidth(layer_tree_impl());
} else if (iter.resolution() == HIGH_RESOLUTION) {
color = DebugColors::HighResTileBorderColor();
width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
@@ -313,30 +313,6 @@
has_draw_quad = true;
break;
}
- case TileDrawInfo::PICTURE_PILE_MODE: {
- if (!layer_tree_impl()
- ->GetRendererCapabilities()
- .allow_rasterize_on_demand) {
- ++on_demand_missing_tile_count;
- break;
- }
-
- gfx::RectF texture_rect = iter.texture_rect();
-
- ResourceProvider* resource_provider =
- layer_tree_impl()->resource_provider();
- ResourceFormat format =
- resource_provider->memory_efficient_texture_format();
- PictureDrawQuad* quad =
- render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- quad->SetNew(shared_quad_state, geometry_rect, opaque_rect,
- visible_geometry_rect, texture_rect,
- iter->desired_texture_size(), nearest_neighbor_, format,
- iter->content_rect(), iter->contents_scale(),
- raster_source_);
- has_draw_quad = true;
- break;
- }
case TileDrawInfo::SOLID_COLOR_MODE: {
SolidColorDrawQuad* quad =
render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
@@ -345,6 +321,8 @@
has_draw_quad = true;
break;
}
+ case TileDrawInfo::OOM_MODE:
+ break; // Checkerboard.
}
}
@@ -565,6 +543,36 @@
MaximumContentsScale());
}
+void PictureLayerImpl::UpdateCanUseLCDTextAfterCommit() {
+ // This function is only allowed to be called after commit, due to it not
+ // being smart about sharing tiles and because otherwise it would cause
+ // flashes by switching out tiles in place that may be currently on screen.
+ DCHECK(layer_tree_impl()->IsSyncTree());
+
+ // Don't allow the LCD text state to change once disabled.
+ if (!RasterSourceUsesLCDText())
+ return;
+ if (can_use_lcd_text() == RasterSourceUsesLCDText())
+ return;
+
+ // Raster sources are considered const, so in order to update the state
+ // a new one must be created and all tiles recreated.
+ scoped_refptr<RasterSource> new_raster_source =
+ raster_source_->CreateCloneWithoutLCDText();
+ // Synthetically invalidate everything.
+ gfx::Rect bounds_rect(bounds());
+ Region invalidation(bounds_rect);
+ UpdateRasterSource(new_raster_source, &invalidation, nullptr);
+ SetUpdateRect(bounds_rect);
+
+ DCHECK(!RasterSourceUsesLCDText());
+}
+
+bool PictureLayerImpl::RasterSourceUsesLCDText() const {
+ return raster_source_ ? raster_source_->CanUseLCDText()
+ : layer_tree_impl()->settings().can_use_lcd_text;
+}
+
void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
if (layer_tree_impl()->IsActiveTree()) {
gfx::RectF layer_damage_rect =
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index f32e56f..9500e22 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -79,6 +79,8 @@
Region* new_invalidation,
const PictureLayerTilingSet* pending_set);
bool UpdateTiles(bool resourceless_software_draw);
+ void UpdateCanUseLCDTextAfterCommit();
+ bool RasterSourceUsesLCDText() const;
// Mask-related functions.
void GetContentsResourceId(ResourceProvider::ResourceId* resource_id,
diff --git a/cc/layers/picture_layer_impl_perftest.cc b/cc/layers/picture_layer_impl_perftest.cc
index 62f4129..ea73cb2 100644
--- a/cc/layers/picture_layer_impl_perftest.cc
+++ b/cc/layers/picture_layer_impl_perftest.cc
@@ -72,7 +72,8 @@
int num_tiles,
const gfx::Size& viewport_size) {
host_impl_.SetViewportSize(viewport_size);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
timer_.Reset();
do {
@@ -96,7 +97,8 @@
host_impl_.SetViewportSize(viewport.size());
pending_layer_->PushScrollOffsetFromMainThread(
gfx::ScrollOffset(viewport.x(), viewport.y()));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
timer_.Reset();
do {
@@ -114,7 +116,8 @@
int num_tiles,
const gfx::Size& viewport_size) {
host_impl_.SetViewportSize(viewport_size);
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
SMOOTHNESS_TAKES_PRIORITY,
@@ -145,7 +148,8 @@
host_impl_.SetViewportSize(viewport.size());
pending_layer_->PushScrollOffsetFromMainThread(
gfx::ScrollOffset(viewport.x(), viewport.y()));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
TreePriority priorities[] = {SAME_PRIORITY_FOR_BOTH_TREES,
SMOOTHNESS_TAKES_PRIORITY,
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index f00b2e4..26f3be5 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -128,7 +128,8 @@
active_layer_ = static_cast<FakePictureLayerImpl*>(
host_impl_.active_tree()->LayerById(id_));
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
}
void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
@@ -223,7 +224,8 @@
host_impl_.pending_tree()->LayerById(id_));
// Add tilings/tiles for the layer.
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
}
void SetupDrawPropertiesAndUpdateTiles(FakePictureLayerImpl* layer,
@@ -431,7 +433,8 @@
viewport_rect_for_tile_priority,
transform_for_tile_priority,
resourceless_software_draw);
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
gfx::Rect viewport_rect_for_tile_priority_in_view_space =
viewport_rect_for_tile_priority;
@@ -465,7 +468,7 @@
viewport_rect_for_tile_priority,
transform_for_tile_priority,
resourceless_software_draw);
- host_impl_.active_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
gfx::Transform screen_to_view(gfx::Transform::kSkipInitialization);
bool success = transform_for_tile_priority.GetInverse(&screen_to_view);
@@ -603,7 +606,8 @@
host_impl_.SetExternalDrawConstraints(
transform, viewport, viewport, viewport_rect_for_tile_priority,
transform_for_tile_priority, resourceless_software_draw);
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
EXPECT_EQ(viewport_rect_for_tile_priority,
active_layer_->viewport_rect_for_tile_priority_in_content_space());
@@ -621,7 +625,7 @@
// should remain to be the previously cached value.
EXPECT_EQ(viewport_rect_for_tile_priority,
active_layer_->viewport_rect_for_tile_priority_in_content_space());
- host_impl_.active_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
// Now the UpdateDrawProperties is called. The viewport rect for tile
// priority should be the latest value.
@@ -1312,7 +1316,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
FakePictureLayerImpl* pending_mask =
static_cast<FakePictureLayerImpl*>(pending_layer_->mask_layer());
@@ -1362,7 +1367,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
// The mask tiling gets scaled down.
EXPECT_LT(pending_mask->HighResTiling()->contents_scale(), 1.f);
@@ -1418,7 +1423,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
EXPECT_EQ(0u, pending_mask->num_tilings());
}
@@ -1450,7 +1455,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
FakePictureLayerImpl* pending_mask =
static_cast<FakePictureLayerImpl*>(pending_layer_->mask_layer());
@@ -1771,7 +1777,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
// Set visible content rect that is different from
// external_viewport_for_tile_priority.
@@ -1811,7 +1818,7 @@
// Activate and draw active layer.
host_impl_.ActivateSyncTree();
- host_impl_.active_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
active_layer_->draw_properties().visible_content_rect = visible_content_rect;
scoped_ptr<RenderPass> render_pass = RenderPass::Create();
@@ -2415,7 +2422,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.f));
ActivateTree();
@@ -2596,8 +2604,8 @@
// However, this is also a regression test for PictureLayerImpl in that
// not having this update will cause a crash.
TEST_F(DeferredInitPictureLayerImplTest, PreventUpdateTilesDuringLostContext) {
- host_impl_.pending_tree()->UpdateDrawProperties();
- host_impl_.active_tree()->UpdateDrawProperties();
+ host_impl_.pending_tree()->UpdateDrawProperties(true);
+ host_impl_.active_tree()->UpdateDrawProperties(false);
EXPECT_FALSE(host_impl_.pending_tree()->needs_update_draw_properties());
EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
@@ -2609,7 +2617,7 @@
// These will crash PictureLayerImpl if this is not true.
ASSERT_TRUE(host_impl_.pending_tree()->needs_update_draw_properties());
ASSERT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
- host_impl_.active_tree()->UpdateDrawProperties();
+ host_impl_.active_tree()->UpdateDrawProperties(false);
}
TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
@@ -3855,7 +3863,8 @@
SetupPendingTree(pending_pile);
pending_layer_->SetBounds(layer_bounds);
ActivateTree();
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
std::vector<Tile*> tiles =
active_layer_->HighResTiling()->AllTilesForTesting();
host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
@@ -3905,7 +3914,7 @@
WhichTree tree,
size_t expected_occluded_tile_count) {
WhichTree twin_tree = tree == ACTIVE_TREE ? PENDING_TREE : ACTIVE_TREE;
- for (int priority_count = 0; priority_count < NUM_TREE_PRIORITIES;
+ for (int priority_count = 0; priority_count <= LAST_TREE_PRIORITY;
++priority_count) {
TreePriority tree_priority = static_cast<TreePriority>(priority_count);
size_t occluded_tile_count = 0u;
@@ -4006,9 +4015,6 @@
// eviction queue.
EXPECT_EQ(ACTIVE_TREE, tree);
break;
- case NUM_TREE_PRIORITIES:
- NOTREACHED();
- break;
}
}
queue->Pop();
@@ -4068,7 +4074,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
unoccluded_tile_count = 0;
queue.reset(new TilingSetRasterQueueAll(
@@ -4092,7 +4099,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
unoccluded_tile_count = 0;
queue.reset(new TilingSetRasterQueueAll(
@@ -4166,7 +4173,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
@@ -4206,7 +4214,7 @@
time_ticks += base::TimeDelta::FromMilliseconds(200);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
@@ -4280,7 +4288,8 @@
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
// UpdateDrawProperties with the occluding layer.
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
EXPECT_EQ(5u, pending_layer_->num_tilings());
@@ -4479,7 +4488,8 @@
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
// UpdateDrawProperties with the occluding layer.
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
// The expected number of occluded tiles on each of the 2 tilings for each of
// the 3 tree priorities.
@@ -4670,11 +4680,11 @@
Region invalidation(layer_rect);
recording_source->UpdateAndExpandInvalidation(
- &client, &invalidation, false, layer_bounds, layer_rect, frame_number++,
+ &client, &invalidation, layer_bounds, layer_rect, frame_number++,
RecordingSource::RECORD_NORMALLY);
scoped_refptr<RasterSource> pending_raster_source =
- recording_source->CreateRasterSource();
+ recording_source->CreateRasterSource(true);
SetupPendingTreeWithFixedTileSize(pending_raster_source, tile_size, Region());
ActivateTree();
@@ -4733,15 +4743,16 @@
Region invalidation1(layer_rect);
recording_source->UpdateAndExpandInvalidation(
- &client, &invalidation1, false, layer_bounds, layer_rect, frame_number++,
+ &client, &invalidation1, layer_bounds, layer_rect, frame_number++,
RecordingSource::RECORD_NORMALLY);
scoped_refptr<RasterSource> raster_source1 =
- recording_source->CreateRasterSource();
+ recording_source->CreateRasterSource(true);
SetupPendingTree(raster_source1);
ActivateTree();
- host_impl_.active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.active_tree()->UpdateDrawProperties(update_lcd_text);
// We've started with a solid layer that contains some tilings.
ASSERT_TRUE(active_layer_->tilings());
@@ -4751,11 +4762,11 @@
Region invalidation2(layer_rect);
recording_source->UpdateAndExpandInvalidation(
- &client, &invalidation2, false, layer_bounds, layer_rect, frame_number++,
+ &client, &invalidation2, layer_bounds, layer_rect, frame_number++,
RecordingSource::RECORD_NORMALLY);
scoped_refptr<RasterSource> raster_source2 =
- recording_source->CreateRasterSource();
+ recording_source->CreateRasterSource(true);
SetupPendingTree(raster_source2);
ActivateTree();
diff --git a/cc/layers/scroll_blocks_on.h b/cc/layers/scroll_blocks_on.h
index 2447298..f41e7fd 100644
--- a/cc/layers/scroll_blocks_on.h
+++ b/cc/layers/scroll_blocks_on.h
@@ -6,12 +6,13 @@
#define CC_LAYERS_SCROLL_BLOCKS_ON_H_
enum ScrollBlocksOn {
- ScrollBlocksOnNone = 0x0,
- ScrollBlocksOnStartTouch = 0x1,
- ScrollBlocksOnWheelEvent = 0x2,
- ScrollBlocksOnScrollEvent = 0x4,
- ScrollBlocksOnMax = ScrollBlocksOnStartTouch | ScrollBlocksOnWheelEvent |
- ScrollBlocksOnScrollEvent
+ SCROLL_BLOCKS_ON_NONE = 0x0,
+ SCROLL_BLOCKS_ON_START_TOUCH = 0x1,
+ SCROLL_BLOCKS_ON_WHEEL_EVENT = 0x2,
+ SCROLL_BLOCKS_ON_SCROLL_EVENT = 0x4,
+ SCROLL_BLOCKS_ON_MAX = SCROLL_BLOCKS_ON_START_TOUCH |
+ SCROLL_BLOCKS_ON_WHEEL_EVENT |
+ SCROLL_BLOCKS_ON_SCROLL_EVENT
};
inline ScrollBlocksOn operator|(ScrollBlocksOn a, ScrollBlocksOn b) {
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index c70b93a..36c37e9 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -173,9 +173,10 @@
// When the scrollbar is not an overlay scrollbar, the scroll should be
// responded to on the main thread as the compositor does not yet implement
// scrollbar scrolling.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- scrollbar_layer_impl->TryScroll(
- gfx::Point(0, 0), InputHandler::Gesture, ScrollBlocksOnNone));
+ EXPECT_EQ(
+ InputHandler::SCROLL_ON_MAIN_THREAD,
+ scrollbar_layer_impl->TryScroll(gfx::Point(0, 0), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
// Create and attach an overlay scrollbar.
scrollbar.reset(new FakeScrollbar(false, false, true));
@@ -187,9 +188,10 @@
// The user shouldn't be able to drag an overlay scrollbar and the scroll
// may be handled in the compositor.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- scrollbar_layer_impl->TryScroll(
- gfx::Point(0, 0), InputHandler::Gesture, ScrollBlocksOnNone));
+ EXPECT_EQ(
+ InputHandler::SCROLL_IGNORED,
+ scrollbar_layer_impl->TryScroll(gfx::Point(0, 0), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
}
TEST_F(ScrollbarLayerTest, ScrollOffsetSynchronization) {
diff --git a/cc/layers/texture_layer_impl.cc b/cc/layers/texture_layer_impl.cc
index d9ddee7..4f4b12e 100644
--- a/cc/layers/texture_layer_impl.cc
+++ b/cc/layers/texture_layer_impl.cc
@@ -105,7 +105,7 @@
if (!texture_copy_->id()) {
texture_copy_->Allocate(texture_mailbox_.shared_memory_size(),
- ResourceProvider::TextureHintImmutable,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
}
diff --git a/cc/layers/video_layer_impl.cc b/cc/layers/video_layer_impl.cc
index 559e0ac..228f2cc 100644
--- a/cc/layers/video_layer_impl.cc
+++ b/cc/layers/video_layer_impl.cc
@@ -222,10 +222,13 @@
DCHECK_GE(frame_resources_.size(), 3u);
if (frame_resources_.size() < 3u)
break;
- YUVVideoDrawQuad::ColorSpace color_space =
- frame_->format() == media::VideoFrame::YV12J
- ? YUVVideoDrawQuad::REC_601_JPEG
- : YUVVideoDrawQuad::REC_601;
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601;
+ if (frame_->format() == media::VideoFrame::YV12J) {
+ color_space = YUVVideoDrawQuad::JPEG;
+ } else if (frame_->format() == media::VideoFrame::YV12HD) {
+ color_space = YUVVideoDrawQuad::REC_709;
+ }
+
gfx::RectF tex_coord_rect(
tex_x_offset, tex_y_offset, tex_width_scale, tex_height_scale);
YUVVideoDrawQuad* yuv_video_quad =
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 9fbd4a5..5867fce 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -409,7 +409,7 @@
enlarge_pass_texture_amount_.y());
if (!texture->id())
texture->Allocate(
- size, ResourceProvider::TextureHintImmutableFramebuffer, RGBA_8888);
+ size, ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER, RGBA_8888);
DCHECK(texture->id());
return BindFramebufferToTexture(frame, texture, render_pass->output_rect);
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
index 2612f10..5c560dc 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -84,54 +84,54 @@
SamplerType SamplerTypeFromTextureTarget(GLenum target) {
switch (target) {
case GL_TEXTURE_2D:
- return SamplerType2D;
+ return SAMPLER_TYPE_2D;
case GL_TEXTURE_RECTANGLE_ARB:
- return SamplerType2DRect;
+ return SAMPLER_TYPE_2D_RECT;
case GL_TEXTURE_EXTERNAL_OES:
- return SamplerTypeExternalOES;
+ return SAMPLER_TYPE_EXTERNAL_OES;
default:
NOTREACHED();
- return SamplerType2D;
+ return SAMPLER_TYPE_2D;
}
}
BlendMode BlendModeFromSkXfermode(SkXfermode::Mode mode) {
switch (mode) {
case SkXfermode::kSrcOver_Mode:
- return BlendModeNormal;
+ return BLEND_MODE_NORMAL;
case SkXfermode::kScreen_Mode:
- return BlendModeScreen;
+ return BLEND_MODE_SCREEN;
case SkXfermode::kOverlay_Mode:
- return BlendModeOverlay;
+ return BLEND_MODE_OVERLAY;
case SkXfermode::kDarken_Mode:
- return BlendModeDarken;
+ return BLEND_MODE_DARKEN;
case SkXfermode::kLighten_Mode:
- return BlendModeLighten;
+ return BLEND_MODE_LIGHTEN;
case SkXfermode::kColorDodge_Mode:
- return BlendModeColorDodge;
+ return BLEND_MODE_COLOR_DODGE;
case SkXfermode::kColorBurn_Mode:
- return BlendModeColorBurn;
+ return BLEND_MODE_COLOR_BURN;
case SkXfermode::kHardLight_Mode:
- return BlendModeHardLight;
+ return BLEND_MODE_HARD_LIGHT;
case SkXfermode::kSoftLight_Mode:
- return BlendModeSoftLight;
+ return BLEND_MODE_SOFT_LIGHT;
case SkXfermode::kDifference_Mode:
- return BlendModeDifference;
+ return BLEND_MODE_DIFFERENCE;
case SkXfermode::kExclusion_Mode:
- return BlendModeExclusion;
+ return BLEND_MODE_EXCLUSION;
case SkXfermode::kMultiply_Mode:
- return BlendModeMultiply;
+ return BLEND_MODE_MULTIPLY;
case SkXfermode::kHue_Mode:
- return BlendModeHue;
+ return BLEND_MODE_HUE;
case SkXfermode::kSaturation_Mode:
- return BlendModeSaturation;
+ return BLEND_MODE_SATURATION;
case SkXfermode::kColor_Mode:
- return BlendModeColor;
+ return BLEND_MODE_COLOR;
case SkXfermode::kLuminosity_Mode:
- return BlendModeLuminosity;
+ return BLEND_MODE_LUMINOSITY;
default:
NOTREACHED();
- return BlendModeNone;
+ return BLEND_MODE_NONE;
}
}
@@ -513,7 +513,8 @@
DrawIOSurfaceQuad(frame, IOSurfaceDrawQuad::MaterialCast(quad));
break;
case DrawQuad::PICTURE_CONTENT:
- DrawPictureQuad(frame, PictureDrawQuad::MaterialCast(quad));
+ // PictureDrawQuad should only be used for resourceless software draws.
+ NOTREACHED();
break;
case DrawQuad::RENDER_PASS:
DrawRenderPassQuad(frame, RenderPassDrawQuad::MaterialCast(quad));
@@ -845,7 +846,7 @@
ScopedResource::Create(resource_provider_);
// CopyTexImage2D fails when called on a texture having immutable storage.
device_background_texture->Allocate(
- bounding_rect.size(), ResourceProvider::TextureHintDefault, RGBA_8888);
+ bounding_rect.size(), ResourceProvider::TEXTURE_HINT_DEFAULT, RGBA_8888);
{
ResourceProvider::ScopedWriteLockGL lock(resource_provider_,
device_background_texture->id());
@@ -980,7 +981,7 @@
scoped_ptr<ResourceProvider::ScopedSamplerGL> mask_resource_lock;
unsigned mask_texture_id = 0;
- SamplerType mask_sampler = SamplerTypeNA;
+ SamplerType mask_sampler = SAMPLER_TYPE_NA;
if (quad->mask_resource_id) {
mask_resource_lock.reset(new ResourceProvider::ScopedSamplerGL(
resource_provider_, quad->mask_resource_id, GL_TEXTURE1, GL_LINEAR));
@@ -1031,7 +1032,7 @@
DCHECK_EQ(background_texture || background_image, use_shaders_for_blending);
BlendMode shader_blend_mode = use_shaders_for_blending
? BlendModeFromSkXfermode(blend_mode)
- : BlendModeNone;
+ : BLEND_MODE_NONE;
if (use_aa && mask_texture_id && !use_color_matrix) {
const RenderPassMaskProgramAA* program = GetRenderPassMaskProgramAA(
@@ -1218,7 +1219,7 @@
GLC(gl_, gl_->Uniform1i(shader_mask_sampler_location, 1));
gfx::RectF mask_uv_rect = quad->MaskUVRect();
- if (mask_sampler != SamplerType2D) {
+ if (mask_sampler != SAMPLER_TYPE_2D) {
mask_uv_rect.Scale(quad->mask_texture_size.width(),
quad->mask_texture_size.height());
}
@@ -1637,7 +1638,7 @@
float fragment_tex_scale_y = clamp_tex_rect.height();
// Map to normalized texture coordinates.
- if (sampler != SamplerType2DRect) {
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
gfx::Size texture_size = quad->texture_size;
DCHECK(!texture_size.IsEmpty());
fragment_tex_translate_x /= texture_size.width();
@@ -1727,7 +1728,7 @@
float vertex_tex_scale_y = tex_coord_rect.height();
// Map to normalized texture coordinates.
- if (sampler != SamplerType2DRect) {
+ if (sampler != SAMPLER_TYPE_2D_RECT) {
gfx::Size texture_size = quad->texture_size;
DCHECK(!texture_size.IsEmpty());
vertex_tex_translate_x /= texture_size.width();
@@ -1899,9 +1900,12 @@
float yuv_to_rgb_rec601[9] = {
1.164f, 1.164f, 1.164f, 0.0f, -.391f, 2.018f, 1.596f, -.813f, 0.0f,
};
- float yuv_to_rgb_rec601_jpeg[9] = {
+ float yuv_to_rgb_jpeg[9] = {
1.f, 1.f, 1.f, 0.0f, -.34414f, 1.772f, 1.402f, -.71414f, 0.0f,
};
+ float yuv_to_rgb_rec709[9] = {
+ 1.164f, 1.164f, 1.164f, 0.0f, -0.213f, 2.112f, 1.793f, -0.533f, 0.0f,
+ };
// These values map to 16, 128, and 128 respectively, and are computed
// as a fraction over 256 (e.g. 16 / 256 = 0.0625).
@@ -1909,12 +1913,12 @@
// Y - 16 : Gives 16 values of head and footroom for overshooting
// U - 128 : Turns unsigned U into signed U [-128,127]
// V - 128 : Turns unsigned V into signed V [-128,127]
- float yuv_adjust_rec601[3] = {
+ float yuv_adjust_constrained[3] = {
-0.0625f, -0.5f, -0.5f,
};
// Same as above, but without the head and footroom.
- float yuv_adjust_rec601_jpeg[3] = {
+ float yuv_adjust_full[3] = {
0.0f, -0.5f, -0.5f,
};
@@ -1924,11 +1928,15 @@
switch (quad->color_space) {
case YUVVideoDrawQuad::REC_601:
yuv_to_rgb = yuv_to_rgb_rec601;
- yuv_adjust = yuv_adjust_rec601;
+ yuv_adjust = yuv_adjust_constrained;
break;
- case YUVVideoDrawQuad::REC_601_JPEG:
- yuv_to_rgb = yuv_to_rgb_rec601_jpeg;
- yuv_adjust = yuv_adjust_rec601_jpeg;
+ case YUVVideoDrawQuad::REC_709:
+ yuv_to_rgb = yuv_to_rgb_rec709;
+ yuv_adjust = yuv_adjust_constrained;
+ break;
+ case YUVVideoDrawQuad::JPEG:
+ yuv_to_rgb = yuv_to_rgb_jpeg;
+ yuv_adjust = yuv_adjust_full;
break;
}
@@ -1977,54 +1985,6 @@
program->vertex_shader().matrix_location());
}
-void GLRenderer::DrawPictureQuad(const DrawingFrame* frame,
- const PictureDrawQuad* quad) {
- if (on_demand_tile_raster_bitmap_.width() != quad->texture_size.width() ||
- on_demand_tile_raster_bitmap_.height() != quad->texture_size.height()) {
- on_demand_tile_raster_bitmap_.allocN32Pixels(quad->texture_size.width(),
- quad->texture_size.height());
-
- if (on_demand_tile_raster_resource_id_)
- resource_provider_->DeleteResource(on_demand_tile_raster_resource_id_);
-
- on_demand_tile_raster_resource_id_ = resource_provider_->CreateGLTexture(
- quad->texture_size,
- GL_TEXTURE_2D,
- GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- quad->texture_format);
- }
-
- SkCanvas canvas(on_demand_tile_raster_bitmap_);
- quad->raster_source->PlaybackToCanvas(&canvas, quad->content_rect,
- quad->contents_scale);
-
- uint8_t* bitmap_pixels = NULL;
- SkBitmap on_demand_tile_raster_bitmap_dest;
- SkColorType colorType = ResourceFormatToSkColorType(quad->texture_format);
- if (on_demand_tile_raster_bitmap_.colorType() != colorType) {
- on_demand_tile_raster_bitmap_.copyTo(&on_demand_tile_raster_bitmap_dest,
- colorType);
- // TODO(kaanb): The GL pipeline assumes a 4-byte alignment for the
- // bitmap data. This check will be removed once crbug.com/293728 is fixed.
- CHECK_EQ(0u, on_demand_tile_raster_bitmap_dest.rowBytes() % 4);
- bitmap_pixels = reinterpret_cast<uint8_t*>(
- on_demand_tile_raster_bitmap_dest.getPixels());
- } else {
- bitmap_pixels =
- reinterpret_cast<uint8_t*>(on_demand_tile_raster_bitmap_.getPixels());
- }
-
- resource_provider_->SetPixels(on_demand_tile_raster_resource_id_,
- bitmap_pixels,
- gfx::Rect(quad->texture_size),
- gfx::Rect(quad->texture_size),
- gfx::Vector2d());
-
- DrawContentQuad(frame, quad, on_demand_tile_raster_resource_id_);
-}
-
struct TextureProgramBinding {
template <class Program>
void Set(Program* program) {
@@ -2775,8 +2735,8 @@
if (!tile_checkerboard_program_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::checkerboardProgram::initalize");
tile_checkerboard_program_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA,
+ SAMPLER_TYPE_NA);
}
return &tile_checkerboard_program_;
}
@@ -2785,8 +2745,7 @@
if (!debug_border_program_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::debugBorderProgram::initialize");
debug_border_program_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA);
}
return &debug_border_program_;
}
@@ -2795,8 +2754,7 @@
if (!solid_color_program_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::solidColorProgram::initialize");
solid_color_program_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA);
}
return &solid_color_program_;
}
@@ -2805,8 +2763,7 @@
if (!solid_color_program_aa_.initialized()) {
TRACE_EVENT0("cc", "GLRenderer::solidColorProgramAA::initialize");
solid_color_program_aa_.Initialize(output_surface_->context_provider(),
- TexCoordPrecisionNA,
- SamplerTypeNA);
+ TEX_COORD_PRECISION_NA, SAMPLER_TYPE_NA);
}
return &solid_color_program_aa_;
}
@@ -2815,16 +2772,14 @@
TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
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,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
@@ -2833,17 +2788,15 @@
TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
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,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
@@ -2853,11 +2806,11 @@
SamplerType sampler,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskProgram* program =
&render_pass_mask_program_[precision][sampler][blend_mode];
if (!program->initialized()) {
@@ -2873,11 +2826,11 @@
SamplerType sampler,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskProgramAA* program =
&render_pass_mask_program_aa_[precision][sampler][blend_mode];
if (!program->initialized()) {
@@ -2892,17 +2845,15 @@
GLRenderer::GetRenderPassColorMatrixProgram(TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassColorMatrixProgram* program =
&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,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
@@ -2911,18 +2862,16 @@
GLRenderer::GetRenderPassColorMatrixProgramAA(TexCoordPrecision precision,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassColorMatrixProgramAA* program =
&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,
- blend_mode);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D, blend_mode);
}
return program;
}
@@ -2932,11 +2881,11 @@
SamplerType sampler,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskColorMatrixProgram* program =
&render_pass_mask_color_matrix_program_[precision][sampler][blend_mode];
if (!program->initialized()) {
@@ -2953,11 +2902,11 @@
SamplerType sampler,
BlendMode blend_mode) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
DCHECK_GE(blend_mode, 0);
- DCHECK_LT(blend_mode, NumBlendModes);
+ DCHECK_LE(blend_mode, LAST_BLEND_MODE);
RenderPassMaskColorMatrixProgramAA* program =
&render_pass_mask_color_matrix_program_aa_[precision][sampler]
[blend_mode];
@@ -2974,9 +2923,9 @@
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgram* program = &tile_program_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgram::initialize");
@@ -2990,9 +2939,9 @@
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramOpaque* program = &tile_program_opaque_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramOpaque::initialize");
@@ -3006,9 +2955,9 @@
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramAA* program = &tile_program_aa_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramAA::initialize");
@@ -3022,9 +2971,9 @@
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramSwizzle* program = &tile_program_swizzle_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzle::initialize");
@@ -3038,9 +2987,9 @@
GLRenderer::GetTileProgramSwizzleOpaque(TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramSwizzleOpaque* program =
&tile_program_swizzle_opaque_[precision][sampler];
if (!program->initialized()) {
@@ -3055,9 +3004,9 @@
TexCoordPrecision precision,
SamplerType sampler) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
DCHECK_GE(sampler, 0);
- DCHECK_LT(sampler, NumSamplerTypes);
+ DCHECK_LE(sampler, LAST_SAMPLER_TYPE);
TileProgramSwizzleAA* program = &tile_program_swizzle_aa_[precision][sampler];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::tileProgramSwizzleAA::initialize");
@@ -3070,12 +3019,12 @@
const GLRenderer::TextureProgram* GLRenderer::GetTextureProgram(
TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
TextureProgram* program = &texture_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D);
}
return program;
}
@@ -3083,14 +3032,14 @@
const GLRenderer::NonPremultipliedTextureProgram*
GLRenderer::GetNonPremultipliedTextureProgram(TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
NonPremultipliedTextureProgram* program =
&nonpremultiplied_texture_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::NonPremultipliedTextureProgram::Initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D);
}
return program;
}
@@ -3098,12 +3047,12 @@
const GLRenderer::TextureBackgroundProgram*
GLRenderer::GetTextureBackgroundProgram(TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
TextureBackgroundProgram* program = &texture_background_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::textureProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D);
}
return program;
}
@@ -3112,14 +3061,14 @@
GLRenderer::GetNonPremultipliedTextureBackgroundProgram(
TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
NonPremultipliedTextureBackgroundProgram* program =
&nonpremultiplied_texture_background_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc",
"GLRenderer::NonPremultipliedTextureProgram::Initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D);
}
return program;
}
@@ -3127,12 +3076,12 @@
const GLRenderer::TextureProgram* GLRenderer::GetTextureIOSurfaceProgram(
TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
TextureProgram* program = &texture_io_surface_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::textureIOSurfaceProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2DRect);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D_RECT);
}
return program;
}
@@ -3140,12 +3089,12 @@
const GLRenderer::VideoYUVProgram* GLRenderer::GetVideoYUVProgram(
TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
VideoYUVProgram* program = &video_yuv_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::videoYUVProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D);
}
return program;
}
@@ -3153,12 +3102,12 @@
const GLRenderer::VideoYUVAProgram* GLRenderer::GetVideoYUVAProgram(
TexCoordPrecision precision) {
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
VideoYUVAProgram* program = &video_yuva_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::videoYUVAProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerType2D);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_2D);
}
return program;
}
@@ -3168,13 +3117,13 @@
if (!Capabilities().using_egl_image)
return NULL;
DCHECK_GE(precision, 0);
- DCHECK_LT(precision, NumTexCoordPrecisions);
+ DCHECK_LE(precision, LAST_TEX_COORD_PRECISION);
VideoStreamTextureProgram* program =
&video_stream_texture_program_[precision];
if (!program->initialized()) {
TRACE_EVENT0("cc", "GLRenderer::streamTextureProgram::initialize");
- program->Initialize(
- output_surface_->context_provider(), precision, SamplerTypeExternalOES);
+ program->Initialize(output_surface_->context_provider(), precision,
+ SAMPLER_TYPE_EXTERNAL_OES);
}
return program;
}
@@ -3182,8 +3131,8 @@
void GLRenderer::CleanupSharedObjects() {
shared_geometry_ = nullptr;
- for (int i = 0; i < NumTexCoordPrecisions; ++i) {
- for (int j = 0; j < NumSamplerTypes; ++j) {
+ for (int i = 0; i <= LAST_TEX_COORD_PRECISION; ++i) {
+ for (int j = 0; j <= LAST_SAMPLER_TYPE; ++j) {
tile_program_[i][j].Cleanup(gl_);
tile_program_opaque_[i][j].Cleanup(gl_);
tile_program_swizzle_[i][j].Cleanup(gl_);
@@ -3191,14 +3140,14 @@
tile_program_aa_[i][j].Cleanup(gl_);
tile_program_swizzle_aa_[i][j].Cleanup(gl_);
- for (int k = 0; k < NumBlendModes; k++) {
+ for (int k = 0; k <= LAST_BLEND_MODE; k++) {
render_pass_mask_program_[i][j][k].Cleanup(gl_);
render_pass_mask_program_aa_[i][j][k].Cleanup(gl_);
render_pass_mask_color_matrix_program_aa_[i][j][k].Cleanup(gl_);
render_pass_mask_color_matrix_program_[i][j][k].Cleanup(gl_);
}
}
- for (int j = 0; j < NumBlendModes; j++) {
+ for (int j = 0; j <= LAST_BLEND_MODE; j++) {
render_pass_program_[i][j].Cleanup(gl_);
render_pass_program_aa_[i][j].Cleanup(gl_);
render_pass_color_matrix_program_[i][j].Cleanup(gl_);
diff --git a/cc/output/gl_renderer.h b/cc/output/gl_renderer.h
index 22e7706..25c7096 100644
--- a/cc/output/gl_renderer.h
+++ b/cc/output/gl_renderer.h
@@ -376,47 +376,62 @@
const SolidColorProgram* GetSolidColorProgram();
const SolidColorProgramAA* GetSolidColorProgramAA();
- TileProgram tile_program_[NumTexCoordPrecisions][NumSamplerTypes];
+ TileProgram
+ tile_program_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
TileProgramOpaque
- tile_program_opaque_[NumTexCoordPrecisions][NumSamplerTypes];
- TileProgramAA tile_program_aa_[NumTexCoordPrecisions][NumSamplerTypes];
- TileProgramSwizzle
- tile_program_swizzle_[NumTexCoordPrecisions][NumSamplerTypes];
+ tile_program_opaque_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
+ TileProgramAA
+ tile_program_aa_[LAST_TEX_COORD_PRECISION + 1][LAST_SAMPLER_TYPE + 1];
+ TileProgramSwizzle tile_program_swizzle_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
TileProgramSwizzleOpaque
- tile_program_swizzle_opaque_[NumTexCoordPrecisions][NumSamplerTypes];
- TileProgramSwizzleAA
- tile_program_swizzle_aa_[NumTexCoordPrecisions][NumSamplerTypes];
+ tile_program_swizzle_opaque_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
+ TileProgramSwizzleAA tile_program_swizzle_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1];
TileCheckerboardProgram tile_checkerboard_program_;
- TextureProgram texture_program_[NumTexCoordPrecisions];
+ TextureProgram texture_program_[LAST_TEX_COORD_PRECISION + 1];
NonPremultipliedTextureProgram
- nonpremultiplied_texture_program_[NumTexCoordPrecisions];
- TextureBackgroundProgram texture_background_program_[NumTexCoordPrecisions];
+ nonpremultiplied_texture_program_[LAST_TEX_COORD_PRECISION + 1];
+ TextureBackgroundProgram
+ texture_background_program_[LAST_TEX_COORD_PRECISION + 1];
NonPremultipliedTextureBackgroundProgram
- nonpremultiplied_texture_background_program_[NumTexCoordPrecisions];
- TextureProgram texture_io_surface_program_[NumTexCoordPrecisions];
+ nonpremultiplied_texture_background_program_[LAST_TEX_COORD_PRECISION +
+ 1];
+ TextureProgram texture_io_surface_program_[LAST_TEX_COORD_PRECISION + 1];
- RenderPassProgram render_pass_program_[NumTexCoordPrecisions][NumBlendModes];
- RenderPassProgramAA
- render_pass_program_aa_[NumTexCoordPrecisions][NumBlendModes];
- RenderPassMaskProgram render_pass_mask_program_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
- RenderPassMaskProgramAA render_pass_mask_program_aa_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
+ RenderPassProgram
+ render_pass_program_[LAST_TEX_COORD_PRECISION + 1][LAST_BLEND_MODE + 1];
+ RenderPassProgramAA render_pass_program_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_BLEND_MODE + 1];
+ RenderPassMaskProgram
+ render_pass_mask_program_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1][LAST_BLEND_MODE + 1];
+ RenderPassMaskProgramAA
+ render_pass_mask_program_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE + 1][LAST_BLEND_MODE +
+ 1];
RenderPassColorMatrixProgram
- render_pass_color_matrix_program_[NumTexCoordPrecisions][NumBlendModes];
- RenderPassColorMatrixProgramAA render_pass_color_matrix_program_aa_
- [NumTexCoordPrecisions][NumBlendModes];
- RenderPassMaskColorMatrixProgram render_pass_mask_color_matrix_program_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
- RenderPassMaskColorMatrixProgramAA render_pass_mask_color_matrix_program_aa_
- [NumTexCoordPrecisions][NumSamplerTypes][NumBlendModes];
+ render_pass_color_matrix_program_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_BLEND_MODE + 1];
+ RenderPassColorMatrixProgramAA
+ render_pass_color_matrix_program_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_BLEND_MODE + 1];
+ RenderPassMaskColorMatrixProgram
+ render_pass_mask_color_matrix_program_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE +
+ 1][LAST_BLEND_MODE + 1];
+ RenderPassMaskColorMatrixProgramAA
+ render_pass_mask_color_matrix_program_aa_[LAST_TEX_COORD_PRECISION +
+ 1][LAST_SAMPLER_TYPE +
+ 1][LAST_BLEND_MODE + 1];
- VideoYUVProgram video_yuv_program_[NumTexCoordPrecisions];
- VideoYUVAProgram video_yuva_program_[NumTexCoordPrecisions];
+ VideoYUVProgram video_yuv_program_[LAST_TEX_COORD_PRECISION + 1];
+ VideoYUVAProgram video_yuva_program_[LAST_TEX_COORD_PRECISION + 1];
VideoStreamTextureProgram
- video_stream_texture_program_[NumTexCoordPrecisions];
+ video_stream_texture_program_[LAST_TEX_COORD_PRECISION + 1];
DebugBorderProgram debug_border_program_;
SolidColorProgram solid_color_program_;
diff --git a/cc/output/gl_renderer_unittest.cc b/cc/output/gl_renderer_unittest.cc
index c5c1e4d..fc70900 100644
--- a/cc/output/gl_renderer_unittest.cc
+++ b/cc/output/gl_renderer_unittest.cc
@@ -57,41 +57,39 @@
static inline SkXfermode::Mode BlendModeToSkXfermode(BlendMode blend_mode) {
switch (blend_mode) {
- case BlendModeNone:
- case BlendModeNormal:
+ case BLEND_MODE_NONE:
+ case BLEND_MODE_NORMAL:
return SkXfermode::kSrcOver_Mode;
- case BlendModeScreen:
+ case BLEND_MODE_SCREEN:
return SkXfermode::kScreen_Mode;
- case BlendModeOverlay:
+ case BLEND_MODE_OVERLAY:
return SkXfermode::kOverlay_Mode;
- case BlendModeDarken:
+ case BLEND_MODE_DARKEN:
return SkXfermode::kDarken_Mode;
- case BlendModeLighten:
+ case BLEND_MODE_LIGHTEN:
return SkXfermode::kLighten_Mode;
- case BlendModeColorDodge:
+ case BLEND_MODE_COLOR_DODGE:
return SkXfermode::kColorDodge_Mode;
- case BlendModeColorBurn:
+ case BLEND_MODE_COLOR_BURN:
return SkXfermode::kColorBurn_Mode;
- case BlendModeHardLight:
+ case BLEND_MODE_HARD_LIGHT:
return SkXfermode::kHardLight_Mode;
- case BlendModeSoftLight:
+ case BLEND_MODE_SOFT_LIGHT:
return SkXfermode::kSoftLight_Mode;
- case BlendModeDifference:
+ case BLEND_MODE_DIFFERENCE:
return SkXfermode::kDifference_Mode;
- case BlendModeExclusion:
+ case BLEND_MODE_EXCLUSION:
return SkXfermode::kExclusion_Mode;
- case BlendModeMultiply:
+ case BLEND_MODE_MULTIPLY:
return SkXfermode::kMultiply_Mode;
- case BlendModeHue:
+ case BLEND_MODE_HUE:
return SkXfermode::kHue_Mode;
- case BlendModeSaturation:
+ case BLEND_MODE_SATURATION:
return SkXfermode::kSaturation_Mode;
- case BlendModeColor:
+ case BLEND_MODE_COLOR:
return SkXfermode::kColor_Mode;
- case BlendModeLuminosity:
+ case BLEND_MODE_LUMINOSITY:
return SkXfermode::kLuminosity_Mode;
- case NumBlendModes:
- NOTREACHED();
}
return SkXfermode::kSrcOver_Mode;
}
@@ -105,13 +103,13 @@
EXPECT_PROGRAM_VALID(renderer()->GetDebugBorderProgram());
EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgram());
EXPECT_PROGRAM_VALID(renderer()->GetSolidColorProgramAA());
- TestShadersWithTexCoordPrecision(TexCoordPrecisionMedium);
- TestShadersWithTexCoordPrecision(TexCoordPrecisionHigh);
+ TestShadersWithTexCoordPrecision(TEX_COORD_PRECISION_MEDIUM);
+ TestShadersWithTexCoordPrecision(TEX_COORD_PRECISION_HIGH);
ASSERT_FALSE(renderer()->IsContextLost());
}
void TestShadersWithTexCoordPrecision(TexCoordPrecision precision) {
- for (int i = 0; i < NumBlendModes; ++i) {
+ for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
BlendMode blend_mode = static_cast<BlendMode>(i);
EXPECT_PROGRAM_VALID(
renderer()->GetRenderPassProgram(precision, blend_mode));
@@ -132,11 +130,11 @@
EXPECT_PROGRAM_VALID(renderer()->GetVideoStreamTextureProgram(precision));
else
EXPECT_FALSE(renderer()->GetVideoStreamTextureProgram(precision));
- TestShadersWithSamplerType(precision, SamplerType2D);
- TestShadersWithSamplerType(precision, SamplerType2DRect);
+ TestShadersWithSamplerType(precision, SAMPLER_TYPE_2D);
+ TestShadersWithSamplerType(precision, SAMPLER_TYPE_2D_RECT);
// This is unlikely to be ever true in tests due to usage of osmesa.
if (renderer()->Capabilities().using_egl_image)
- TestShadersWithSamplerType(precision, SamplerTypeExternalOES);
+ TestShadersWithSamplerType(precision, SAMPLER_TYPE_EXTERNAL_OES);
}
void TestShadersWithSamplerType(TexCoordPrecision precision,
@@ -149,7 +147,7 @@
renderer()->GetTileProgramSwizzleOpaque(precision, sampler));
EXPECT_PROGRAM_VALID(
renderer()->GetTileProgramSwizzleAA(precision, sampler));
- for (int i = 0; i < NumBlendModes; ++i) {
+ for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
BlendMode blend_mode = static_cast<BlendMode>(i);
EXPECT_PROGRAM_VALID(
renderer()->GetRenderPassMaskProgram(precision, sampler, blend_mode));
@@ -1437,9 +1435,8 @@
TestRenderPass* root_pass;
ResourceProvider::ResourceId mask = resource_provider_->CreateResource(
- gfx::Size(20, 12),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(20, 12), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider_->best_texture_format());
resource_provider_->AllocateForTesting(mask);
@@ -1469,10 +1466,10 @@
gfx::Transform transform_causing_aa;
transform_causing_aa.Rotate(20.0);
- for (int i = 0; i < NumBlendModes; ++i) {
+ for (int i = 0; i <= LAST_BLEND_MODE; ++i) {
BlendMode blend_mode = static_cast<BlendMode>(i);
SkXfermode::Mode xfer_mode = BlendModeToSkXfermode(blend_mode);
- settings_.force_blending_with_shaders = (blend_mode != BlendModeNone);
+ settings_.force_blending_with_shaders = (blend_mode != BLEND_MODE_NONE);
// RenderPassProgram
render_passes_in_draw_order_.clear();
child_pass = AddRenderPass(&render_passes_in_draw_order_,
@@ -1499,7 +1496,7 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassProgram(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassColorMatrixProgram
render_passes_in_draw_order_.clear();
@@ -1524,7 +1521,7 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassColorMatrixProgram(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassMaskProgram
render_passes_in_draw_order_.clear();
@@ -1553,8 +1550,8 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskProgram(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskProgram(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
// RenderPassMaskColorMatrixProgram
render_passes_in_draw_order_.clear();
@@ -1579,8 +1576,8 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskColorMatrixProgram(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskColorMatrixProgram(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
// RenderPassProgramAA
render_passes_in_draw_order_.clear();
@@ -1609,7 +1606,7 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassProgramAA(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassColorMatrixProgramAA
render_passes_in_draw_order_.clear();
@@ -1634,7 +1631,7 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassColorMatrixProgramAA(TexCoordPrecisionMedium, blend_mode);
+ TestRenderPassColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM, blend_mode);
// RenderPassMaskProgramAA
render_passes_in_draw_order_.clear();
@@ -1663,8 +1660,8 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskProgramAA(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskProgramAA(TEX_COORD_PRECISION_MEDIUM, SAMPLER_TYPE_2D,
+ blend_mode);
// RenderPassMaskColorMatrixProgramAA
render_passes_in_draw_order_.clear();
@@ -1689,8 +1686,8 @@
viewport_rect,
viewport_rect,
false);
- TestRenderPassMaskColorMatrixProgramAA(
- TexCoordPrecisionMedium, SamplerType2D, blend_mode);
+ TestRenderPassMaskColorMatrixProgramAA(TEX_COORD_PRECISION_MEDIUM,
+ SAMPLER_TYPE_2D, blend_mode);
}
}
@@ -1742,7 +1739,7 @@
// If use_aa incorrectly ignores clipping, it will use the
// RenderPassProgramAA shader instead of the RenderPassProgram.
- TestRenderPassProgram(TexCoordPrecisionMedium, BlendModeNone);
+ TestRenderPassProgram(TEX_COORD_PRECISION_MEDIUM, BLEND_MODE_NONE);
}
TEST_F(GLRendererShaderTest, DrawSolidColorShader) {
diff --git a/cc/output/program_binding.h b/cc/output/program_binding.h
index a10d0ab..9c3244c 100644
--- a/cc/output/program_binding.h
+++ b/cc/output/program_binding.h
@@ -59,7 +59,7 @@
void Initialize(ContextProvider* context_provider,
TexCoordPrecision precision,
SamplerType sampler,
- BlendMode blend_mode = BlendModeNone) {
+ BlendMode blend_mode = BLEND_MODE_NONE) {
DCHECK(context_provider);
DCHECK(!initialized_);
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index d7d1211..9e9175e 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -123,19 +123,14 @@
SkColorGetR(texel_color),
SkColorGetG(texel_color),
SkColorGetB(texel_color));
- std::vector<uint32_t> pixels(rect.size().GetArea(), pixel_color);
+ size_t num_pixels = static_cast<size_t>(rect.width()) * rect.height();
+ std::vector<uint32_t> pixels(num_pixels, pixel_color);
- ResourceProvider::ResourceId resource =
- resource_provider->CreateResource(rect.size(),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
- resource_provider->SetPixels(
- resource,
- reinterpret_cast<uint8_t*>(&pixels.front()),
- rect,
- rect,
- gfx::Vector2d());
+ ResourceProvider::ResourceId resource = resource_provider->CreateResource(
+ rect.size(), GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
+ resource_provider->CopyToResource(
+ resource, reinterpret_cast<uint8_t*>(&pixels.front()), rect.size());
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
@@ -162,6 +157,13 @@
TYPED_TEST_CASE(RendererPixelTest, RendererTypes);
template <typename RendererType>
+class SoftwareRendererPixelTest : public RendererPixelTest<RendererType> {};
+
+typedef ::testing::Types<SoftwareRenderer, SoftwareRendererWithExpandedViewport>
+ SoftwareRendererTypes;
+TYPED_TEST_CASE(SoftwareRendererPixelTest, SoftwareRendererTypes);
+
+template <typename RendererType>
class FuzzyForSoftwareOnlyPixelComparator : public PixelComparator {
public:
explicit FuzzyForSoftwareOnlyPixelComparator(bool discard_alpha)
@@ -872,18 +874,13 @@
ResourceProvider::ResourceId mask_resource_id =
this->resource_provider_->CreateResource(
- mask_rect.size(),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ mask_rect.size(), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
{
SkAutoLockPixels lock(bitmap);
- this->resource_provider_->SetPixels(
- mask_resource_id,
- reinterpret_cast<uint8_t*>(bitmap.getPixels()),
- mask_rect,
- mask_rect,
- gfx::Vector2d());
+ this->resource_provider_->CopyToResource(
+ mask_resource_id, reinterpret_cast<uint8_t*>(bitmap.getPixels()),
+ mask_rect.size());
}
// This RenderPassDrawQuad does not include the full |viewport_rect| which is
@@ -1379,7 +1376,7 @@
FuzzyPixelOffByOneComparator(true)));
}
-TYPED_TEST(RendererPixelTest, PictureDrawQuadIdentityScale) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadIdentityScale) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
// TODO(enne): the renderer should figure this out on its own.
@@ -1459,7 +1456,7 @@
}
// Not WithSkiaGPUBackend since that path currently requires tiles for opacity.
-TYPED_TEST(RendererPixelTest, PictureDrawQuadOpacity) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadOpacity) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
ResourceFormat texture_format = RGBA_8888;
@@ -1536,7 +1533,7 @@
// If we disable image filtering, then a 2x2 bitmap should appear as four
// huge sharp squares.
-TYPED_TEST(RendererPixelTest, PictureDrawQuadDisableImageFiltering) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadDisableImageFiltering) {
// We only care about this in software mode since bilinear filtering is
// cheap in hardware.
if (!IsSoftwareRenderer<TypeParam>())
@@ -1593,7 +1590,7 @@
}
// This disables filtering by setting |nearest_neighbor| on the PictureDrawQuad.
-TYPED_TEST(RendererPixelTest, PictureDrawQuadNearestNeighbor) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNearestNeighbor) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
ResourceFormat texture_format = RGBA_8888;
@@ -1662,19 +1659,13 @@
gfx::Size tile_size(2, 2);
ResourceProvider::ResourceId resource =
this->resource_provider_->CreateResource(
- tile_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888);
{
SkAutoLockPixels lock(bitmap);
- this->resource_provider_->SetPixels(
- resource,
- static_cast<uint8_t*>(bitmap.getPixels()),
- gfx::Rect(tile_size),
- gfx::Rect(tile_size),
- gfx::Vector2d());
+ this->resource_provider_->CopyToResource(
+ resource, static_cast<uint8_t*>(bitmap.getPixels()), tile_size);
}
RenderPassId id(1, 1);
@@ -1700,7 +1691,7 @@
ExactPixelComparator(true)));
}
-TYPED_TEST(RendererPixelTest, PictureDrawQuadNonIdentityScale) {
+TYPED_TEST(SoftwareRendererPixelTest, PictureDrawQuadNonIdentityScale) {
gfx::Size pile_tile_size(1000, 1000);
gfx::Rect viewport(this->device_viewport_size_);
// TODO(enne): the renderer should figure this out on its own.
@@ -2001,45 +1992,6 @@
&capture_rect));
}
-TEST_F(GLRendererPixelTest, PictureDrawQuadTexture4444) {
- gfx::Size pile_tile_size(1000, 1000);
- gfx::Rect viewport(this->device_viewport_size_);
- ResourceFormat texture_format = RGBA_4444;
- bool nearest_neighbor = false;
-
- RenderPassId id(1, 1);
- gfx::Transform transform_to_root;
- scoped_ptr<RenderPass> pass =
- CreateTestRenderPass(id, viewport, transform_to_root);
-
- // One viewport-filling blue quad
- scoped_ptr<FakePicturePile> blue_recording =
- FakePicturePile::CreateFilledPile(pile_tile_size, viewport.size());
- SkPaint blue_paint;
- blue_paint.setColor(SK_ColorBLUE);
- blue_recording->add_draw_rect_with_paint(viewport, blue_paint);
- blue_recording->RerecordPile();
- scoped_refptr<FakePicturePileImpl> blue_pile =
- FakePicturePileImpl::CreateFromPile(blue_recording.get(), nullptr);
-
- gfx::Transform blue_content_to_target_transform;
- SharedQuadState* blue_shared_state = CreateTestSharedQuadState(
- blue_content_to_target_transform, viewport, pass.get());
-
- PictureDrawQuad* blue_quad = pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
- blue_quad->SetNew(blue_shared_state, viewport, gfx::Rect(), viewport,
- gfx::RectF(0.f, 0.f, 1.f, 1.f), viewport.size(),
- nearest_neighbor, texture_format, viewport, 1.f,
- blue_pile.get());
-
- RenderPassList pass_list;
- pass_list.push_back(pass.Pass());
-
- EXPECT_TRUE(this->RunPixelTest(&pass_list,
- base::FilePath(FILE_PATH_LITERAL("blue.png")),
- ExactPixelComparator(true)));
-}
-
TYPED_TEST(RendererPixelTest, WrapModeRepeat) {
gfx::Rect rect(this->device_viewport_size_);
@@ -2049,7 +2001,7 @@
SharedQuadState* shared_state =
CreateTestSharedQuadState(gfx::Transform(), rect, pass.get());
- gfx::Rect texture_rect(4, 4);
+ gfx::Size texture_size(4, 4);
SkPMColor colors[4] = {
SkPreMultiplyColor(SkColorSetARGB(255, 0, 255, 0)),
SkPreMultiplyColor(SkColorSetARGB(255, 0, 128, 0)),
@@ -2064,33 +2016,23 @@
};
ResourceProvider::ResourceId resource =
this->resource_provider_->CreateResource(
- texture_rect.size(),
- GL_REPEAT,
- ResourceProvider::TextureHintImmutable,
+ texture_size, GL_REPEAT, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888);
- this->resource_provider_->SetPixels(
- resource,
- reinterpret_cast<uint8_t*>(pixels),
- texture_rect,
- texture_rect,
- gfx::Vector2d());
+ this->resource_provider_->CopyToResource(
+ resource, reinterpret_cast<uint8_t*>(pixels), texture_size);
float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
TextureDrawQuad* texture_quad =
pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
texture_quad->SetNew(
- shared_state,
- gfx::Rect(this->device_viewport_size_),
- gfx::Rect(),
- gfx::Rect(this->device_viewport_size_),
- resource,
+ shared_state, gfx::Rect(this->device_viewport_size_), gfx::Rect(),
+ gfx::Rect(this->device_viewport_size_), resource,
true, // premultiplied_alpha
gfx::PointF(0.0f, 0.0f), // uv_top_left
gfx::PointF( // uv_bottom_right
- this->device_viewport_size_.width() / texture_rect.width(),
- this->device_viewport_size_.height() / texture_rect.height()),
- SK_ColorWHITE,
- vertex_opacity,
+ this->device_viewport_size_.width() / texture_size.width(),
+ this->device_viewport_size_.height() / texture_size.height()),
+ SK_ColorWHITE, vertex_opacity,
false, // flipped
false); // nearest_neighbor
diff --git a/cc/output/shader.cc b/cc/output/shader.cc
index 0a33e53..1891546 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -52,7 +52,7 @@
TexCoordPrecision requested_precision,
std::string shader_string) {
switch (requested_precision) {
- case TexCoordPrecisionHigh:
+ case TEX_COORD_PRECISION_HIGH:
DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
return "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
" #define TexCoordPrecision highp\n"
@@ -60,10 +60,10 @@
" #define TexCoordPrecision mediump\n"
"#endif\n" +
shader_string;
- case TexCoordPrecisionMedium:
+ case TEX_COORD_PRECISION_MEDIUM:
DCHECK_NE(shader_string.find("TexCoordPrecision"), std::string::npos);
return "#define TexCoordPrecision mediump\n" + shader_string;
- case TexCoordPrecisionNA:
+ case TEX_COORD_PRECISION_NA:
DCHECK_EQ(shader_string.find("TexCoordPrecision"), std::string::npos);
DCHECK_EQ(shader_string.find("texture2D"), std::string::npos);
DCHECK_EQ(shader_string.find("texture2DRect"), std::string::npos);
@@ -104,34 +104,34 @@
int highp_threshold = std::max(*highp_threshold_cache, highp_threshold_min);
if (x > highp_threshold || y > highp_threshold)
- return TexCoordPrecisionHigh;
- return TexCoordPrecisionMedium;
+ return TEX_COORD_PRECISION_HIGH;
+ return TEX_COORD_PRECISION_MEDIUM;
}
static std::string SetFragmentSamplerType(SamplerType requested_type,
std::string shader_string) {
switch (requested_type) {
- case SamplerType2D:
+ case SAMPLER_TYPE_2D:
DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
return "#define SamplerType sampler2D\n"
"#define TextureLookup texture2D\n" +
shader_string;
- case SamplerType2DRect:
+ case SAMPLER_TYPE_2D_RECT:
DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
return "#extension GL_ARB_texture_rectangle : require\n"
"#define SamplerType sampler2DRect\n"
"#define TextureLookup texture2DRect\n" +
shader_string;
- case SamplerTypeExternalOES:
+ case SAMPLER_TYPE_EXTERNAL_OES:
DCHECK_NE(shader_string.find("SamplerType"), std::string::npos);
DCHECK_NE(shader_string.find("TextureLookup"), std::string::npos);
return "#extension GL_OES_EGL_image_external : require\n"
"#define SamplerType samplerExternalOES\n"
"#define TextureLookup texture2D\n" +
shader_string;
- case SamplerTypeNA:
+ case SAMPLER_TYPE_NA:
DCHECK_EQ(shader_string.find("SamplerType"), std::string::npos);
DCHECK_EQ(shader_string.find("TextureLookup"), std::string::npos);
return shader_string;
@@ -734,7 +734,7 @@
FragmentTexBlendMode::FragmentTexBlendMode()
: backdrop_location_(-1),
backdrop_rect_location_(-1),
- blend_mode_(BlendModeNone) {
+ blend_mode_(BLEND_MODE_NONE) {
}
std::string FragmentTexBlendMode::SetBlendModeFunctions(
@@ -908,20 +908,20 @@
});
switch (blend_mode_) {
- case BlendModeOverlay:
- case BlendModeHardLight:
+ case BLEND_MODE_OVERLAY:
+ case BLEND_MODE_HARD_LIGHT:
return kFunctionHardLight;
- case BlendModeColorDodge:
+ case BLEND_MODE_COLOR_DODGE:
return kFunctionColorDodgeComponent;
- case BlendModeColorBurn:
+ case BLEND_MODE_COLOR_BURN:
return kFunctionColorBurnComponent;
- case BlendModeSoftLight:
+ case BLEND_MODE_SOFT_LIGHT:
return kFunctionSoftLightComponentPosDstAlpha;
- case BlendModeHue:
- case BlendModeSaturation:
+ case BLEND_MODE_HUE:
+ case BLEND_MODE_SATURATION:
return kFunctionLum + kFunctionSat;
- case BlendModeColor:
- case BlendModeLuminosity:
+ case BLEND_MODE_COLOR:
+ case BLEND_MODE_LUMINOSITY:
return kFunctionLum;
default:
return std::string();
@@ -939,29 +939,29 @@
std::string FragmentTexBlendMode::GetBlendFunctionBodyForRGB() const {
switch (blend_mode_) {
- case BlendModeNormal:
+ case BLEND_MODE_NORMAL:
return "result.rgb = src.rgb + dst.rgb * (1.0 - src.a);";
- case BlendModeScreen:
+ case BLEND_MODE_SCREEN:
return "result.rgb = src.rgb + (1.0 - src.rgb) * dst.rgb;";
- case BlendModeLighten:
+ case BLEND_MODE_LIGHTEN:
return "result.rgb = max((1.0 - src.a) * dst.rgb + src.rgb,"
" (1.0 - dst.a) * src.rgb + dst.rgb);";
- case BlendModeOverlay:
+ case BLEND_MODE_OVERLAY:
return "result.rgb = hardLight(dst, src);";
- case BlendModeDarken:
+ case BLEND_MODE_DARKEN:
return "result.rgb = min((1.0 - src.a) * dst.rgb + src.rgb,"
" (1.0 - dst.a) * src.rgb + dst.rgb);";
- case BlendModeColorDodge:
+ case BLEND_MODE_COLOR_DODGE:
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:
+ case BLEND_MODE_COLOR_BURN:
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:
+ case BLEND_MODE_HARD_LIGHT:
return "result.rgb = hardLight(src, dst);";
- case BlendModeSoftLight:
+ case BLEND_MODE_SOFT_LIGHT:
return "if (0.0 == dst.a) {"
" result.rgb = src.rgb;"
"} else {"
@@ -969,15 +969,15 @@
" result.g = getSoftLightComponent(src.g, src.a, dst.g, dst.a);"
" result.b = getSoftLightComponent(src.b, src.a, dst.b, dst.a);"
"}";
- case BlendModeDifference:
+ case BLEND_MODE_DIFFERENCE:
return "result.rgb = src.rgb + dst.rgb -"
" 2.0 * min(src.rgb * dst.a, dst.rgb * src.a);";
- case BlendModeExclusion:
+ case BLEND_MODE_EXCLUSION:
return "result.rgb = dst.rgb + src.rgb - 2.0 * dst.rgb * src.rgb;";
- case BlendModeMultiply:
+ case BLEND_MODE_MULTIPLY:
return "result.rgb = (1.0 - src.a) * dst.rgb +"
" (1.0 - dst.a) * src.rgb + src.rgb * dst.rgb;";
- case BlendModeHue:
+ case BLEND_MODE_HUE:
return "vec4 dstSrcAlpha = dst * src.a;"
"result.rgb ="
" set_luminance(set_saturation(src.rgb * dst.a,"
@@ -985,27 +985,26 @@
" dstSrcAlpha.a,"
" dstSrcAlpha.rgb);"
"result.rgb += (1.0 - src.a) * dst.rgb + (1.0 - dst.a) * src.rgb;";
- case BlendModeSaturation:
+ case BLEND_MODE_SATURATION:
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:
+ case BLEND_MODE_COLOR:
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:
+ case BLEND_MODE_LUMINOSITY:
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;";
- case BlendModeNone:
- case NumBlendModes:
+ case BLEND_MODE_NONE:
NOTREACHED();
}
return "result = vec4(1.0, 0.0, 0.0, 1.0);";
diff --git a/cc/output/shader.h b/cc/output/shader.h
index 3c8102e..93407d4 100644
--- a/cc/output/shader.h
+++ b/cc/output/shader.h
@@ -24,39 +24,39 @@
namespace cc {
enum TexCoordPrecision {
- TexCoordPrecisionNA = 0,
- TexCoordPrecisionMedium = 1,
- TexCoordPrecisionHigh = 2,
- NumTexCoordPrecisions = 3
+ TEX_COORD_PRECISION_NA = 0,
+ TEX_COORD_PRECISION_MEDIUM = 1,
+ TEX_COORD_PRECISION_HIGH = 2,
+ LAST_TEX_COORD_PRECISION = 2
};
enum SamplerType {
- SamplerTypeNA = 0,
- SamplerType2D = 1,
- SamplerType2DRect = 2,
- SamplerTypeExternalOES = 3,
- NumSamplerTypes = 4
+ SAMPLER_TYPE_NA = 0,
+ SAMPLER_TYPE_2D = 1,
+ SAMPLER_TYPE_2D_RECT = 2,
+ SAMPLER_TYPE_EXTERNAL_OES = 3,
+ LAST_SAMPLER_TYPE = 3
};
enum BlendMode {
- BlendModeNone,
- BlendModeNormal,
- BlendModeScreen,
- BlendModeOverlay,
- BlendModeDarken,
- BlendModeLighten,
- BlendModeColorDodge,
- BlendModeColorBurn,
- BlendModeHardLight,
- BlendModeSoftLight,
- BlendModeDifference,
- BlendModeExclusion,
- BlendModeMultiply,
- BlendModeHue,
- BlendModeSaturation,
- BlendModeColor,
- BlendModeLuminosity,
- NumBlendModes
+ BLEND_MODE_NONE,
+ BLEND_MODE_NORMAL,
+ BLEND_MODE_SCREEN,
+ BLEND_MODE_OVERLAY,
+ BLEND_MODE_DARKEN,
+ BLEND_MODE_LIGHTEN,
+ BLEND_MODE_COLOR_DODGE,
+ BLEND_MODE_COLOR_BURN,
+ BLEND_MODE_HARD_LIGHT,
+ BLEND_MODE_SOFT_LIGHT,
+ BLEND_MODE_DIFFERENCE,
+ BLEND_MODE_EXCLUSION,
+ BLEND_MODE_MULTIPLY,
+ BLEND_MODE_HUE,
+ BLEND_MODE_SATURATION,
+ BLEND_MODE_COLOR,
+ BLEND_MODE_LUMINOSITY,
+ LAST_BLEND_MODE = BLEND_MODE_LUMINOSITY
};
// Note: The highp_threshold_cache must be provided by the caller to make
@@ -329,7 +329,7 @@
BlendMode blend_mode() const { return blend_mode_; }
void set_blend_mode(BlendMode blend_mode) { blend_mode_ = blend_mode; }
- bool has_blend_mode() const { return blend_mode_ != BlendModeNone; }
+ bool has_blend_mode() const { return blend_mode_ != BLEND_MODE_NONE; }
protected:
FragmentTexBlendMode();
diff --git a/cc/output/shader_unittest.cc b/cc/output/shader_unittest.cc
index 4fd696f..675e47f 100644
--- a/cc/output/shader_unittest.cc
+++ b/cc/output/shader_unittest.cc
@@ -27,24 +27,32 @@
gfx::Size bigSize(2560, 2560);
threshold_min = 0;
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, closePoint));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, smallSize));
- EXPECT_EQ(TexCoordPrecisionHigh, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, farPoint));
- EXPECT_EQ(TexCoordPrecisionHigh, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, bigSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ closePoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ smallSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ farPoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_HIGH,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ bigSize));
threshold_min = 3000;
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, closePoint));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, smallSize));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, farPoint));
- EXPECT_EQ(TexCoordPrecisionMedium, TexCoordPrecisionRequired(
- &stub_gl, &threshold_cache, threshold_min, bigSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ closePoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ smallSize));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ farPoint));
+ EXPECT_EQ(TEX_COORD_PRECISION_MEDIUM,
+ TexCoordPrecisionRequired(&stub_gl, &threshold_cache, threshold_min,
+ bigSize));
}
} // namespace cc
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 488ca09..5360d59 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -223,11 +223,11 @@
bool SoftwareRenderer::IsSoftwareResource(
ResourceProvider::ResourceId resource_id) const {
switch (resource_provider_->GetResourceType(resource_id)) {
- case ResourceProvider::GLTexture:
+ case ResourceProvider::RESOURCE_TYPE_GL_TEXTURE:
return false;
- case ResourceProvider::Bitmap:
+ case ResourceProvider::RESOURCE_TYPE_BITMAP:
return true;
- case ResourceProvider::InvalidType:
+ case ResourceProvider::RESOURCE_TYPE_INVALID:
break;
}
diff --git a/cc/output/software_renderer_unittest.cc b/cc/output/software_renderer_unittest.cc
index fa25200..3b2c4bc 100644
--- a/cc/output/software_renderer_unittest.cc
+++ b/cc/output/software_renderer_unittest.cc
@@ -155,16 +155,12 @@
ResourceProvider::ResourceId resource_yellow =
resource_provider()->CreateResource(
- outer_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ outer_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
ResourceProvider::ResourceId resource_cyan =
resource_provider()->CreateResource(
- inner_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ inner_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
SkBitmap yellow_tile;
yellow_tile.allocN32Pixels(outer_size.width(), outer_size.height());
@@ -174,17 +170,11 @@
cyan_tile.allocN32Pixels(inner_size.width(), inner_size.height());
cyan_tile.eraseColor(SK_ColorCYAN);
- resource_provider()->SetPixels(
- resource_yellow,
- static_cast<uint8_t*>(yellow_tile.getPixels()),
- gfx::Rect(outer_size),
- gfx::Rect(outer_size),
- gfx::Vector2d());
- resource_provider()->SetPixels(resource_cyan,
- static_cast<uint8_t*>(cyan_tile.getPixels()),
- gfx::Rect(inner_size),
- gfx::Rect(inner_size),
- gfx::Vector2d());
+ resource_provider()->CopyToResource(
+ resource_yellow, static_cast<uint8_t*>(yellow_tile.getPixels()),
+ outer_size);
+ resource_provider()->CopyToResource(
+ resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), inner_size);
gfx::Rect root_rect = outer_rect;
@@ -252,9 +242,7 @@
ResourceProvider::ResourceId resource_cyan =
resource_provider()->CreateResource(
- tile_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ tile_size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888);
SkBitmap cyan_tile; // The lowest five rows are yellow.
@@ -265,11 +253,8 @@
0, visible_rect.bottom() - 1, tile_rect.width(), tile_rect.bottom()),
SK_ColorYELLOW);
- resource_provider()->SetPixels(resource_cyan,
- static_cast<uint8_t*>(cyan_tile.getPixels()),
- gfx::Rect(tile_size),
- gfx::Rect(tile_size),
- gfx::Vector2d());
+ resource_provider()->CopyToResource(
+ resource_cyan, static_cast<uint8_t*>(cyan_tile.getPixels()), tile_size);
gfx::Rect root_rect(tile_size);
diff --git a/cc/quads/draw_polygon.cc b/cc/quads/draw_polygon.cc
index 71dbf36..026be2c 100644
--- a/cc/quads/draw_polygon.cc
+++ b/cc/quads/draw_polygon.cc
@@ -93,7 +93,7 @@
// Checks whether or not shape a lies on the front or back side of b, or
// whether they should be considered coplanar. If on the back side, we
-// say ABeforeB because it should be drawn in that order.
+// say A_BEFORE_B because it should be drawn in that order.
// Assumes that layers are split and there are no intersecting planes.
BspCompareResult DrawPolygon::SideCompare(const DrawPolygon& a,
const DrawPolygon& b) {
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index 6b51398..b7c1bdf 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -643,7 +643,7 @@
ResourceProvider::ResourceId u_plane_resource_id = 532;
ResourceProvider::ResourceId v_plane_resource_id = 4;
ResourceProvider::ResourceId a_plane_resource_id = 63;
- YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601_JPEG;
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::JPEG;
CREATE_SHARED_STATE();
CREATE_QUAD_9_NEW(YUVVideoDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
@@ -899,7 +899,7 @@
ResourceProvider::ResourceId u_plane_resource_id = 532;
ResourceProvider::ResourceId v_plane_resource_id = 4;
ResourceProvider::ResourceId a_plane_resource_id = 63;
- YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::REC_601_JPEG;
+ YUVVideoDrawQuad::ColorSpace color_space = YUVVideoDrawQuad::JPEG;
CREATE_SHARED_STATE();
CREATE_QUAD_9_NEW(YUVVideoDrawQuad, opaque_rect, visible_rect, tex_coord_rect,
diff --git a/cc/quads/yuv_video_draw_quad.h b/cc/quads/yuv_video_draw_quad.h
index d57d56f..15bce98 100644
--- a/cc/quads/yuv_video_draw_quad.h
+++ b/cc/quads/yuv_video_draw_quad.h
@@ -15,9 +15,10 @@
class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
public:
enum ColorSpace {
- REC_601, // SDTV standard with restricted "studio swing" color range.
- REC_601_JPEG, // Full color range [0, 255] variant of the above.
- COLOR_SPACE_LAST = REC_601_JPEG
+ REC_601, // SDTV standard with restricted "studio swing" color range.
+ REC_709, // HDTV standard with restricted "studio swing" color range.
+ JPEG, // Full color range [0, 255] JPEG color space.
+ COLOR_SPACE_LAST = JPEG
};
~YUVVideoDrawQuad() override;
diff --git a/cc/resources/display_item_list_unittest.cc b/cc/resources/display_item_list_unittest.cc
index ddf2cb7..c9b9558 100644
--- a/cc/resources/display_item_list_unittest.cc
+++ b/cc/resources/display_item_list_unittest.cc
@@ -37,13 +37,15 @@
unsigned char pixels[4 * 100 * 100] = {0};
scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+ gfx::PointF offset(8.f, 9.f);
+ gfx::RectF recording_rect(offset, layer_rect.size());
canvas = skia::SharePtr(
- recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ recorder.beginRecording(gfx::RectFToSkRect(recording_rect)));
+ canvas->translate(offset.x(), offset.y());
canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
picture = skia::AdoptRef(recorder.endRecording());
- gfx::PointF offset(8.f, 9.f);
- list->AppendItem(DrawingDisplayItem::Create(picture, offset));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
DrawDisplayList(pixels, layer_rect, list);
SkBitmap expected_bitmap;
@@ -75,22 +77,26 @@
unsigned char pixels[4 * 100 * 100] = {0};
scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+ gfx::PointF first_offset(8.f, 9.f);
+ gfx::RectF first_recording_rect(first_offset, layer_rect.size());
canvas = skia::SharePtr(
- recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect)));
+ canvas->translate(first_offset.x(), first_offset.y());
canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
picture = skia::AdoptRef(recorder.endRecording());
- gfx::PointF first_offset(8.f, 9.f);
- list->AppendItem(DrawingDisplayItem::Create(picture, first_offset));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
gfx::Rect clip_rect(60, 60, 10, 10);
list->AppendItem(ClipDisplayItem::Create(clip_rect, std::vector<SkRRect>()));
+ gfx::PointF second_offset(2.f, 3.f);
+ gfx::RectF second_recording_rect(second_offset, layer_rect.size());
canvas = skia::SharePtr(
- recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect)));
+ canvas->translate(second_offset.x(), second_offset.y());
canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
picture = skia::AdoptRef(recorder.endRecording());
- gfx::PointF second_offset(2.f, 3.f);
- list->AppendItem(DrawingDisplayItem::Create(picture, second_offset));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
list->AppendItem(EndClipDisplayItem::Create());
@@ -126,23 +132,27 @@
unsigned char pixels[4 * 100 * 100] = {0};
scoped_refptr<DisplayItemList> list = DisplayItemList::Create();
+ gfx::PointF first_offset(8.f, 9.f);
+ gfx::RectF first_recording_rect(first_offset, layer_rect.size());
canvas = skia::SharePtr(
- recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ recorder.beginRecording(gfx::RectFToSkRect(first_recording_rect)));
+ canvas->translate(first_offset.x(), first_offset.y());
canvas->drawRectCoords(0.f, 0.f, 60.f, 60.f, red_paint);
picture = skia::AdoptRef(recorder.endRecording());
- gfx::PointF first_offset(8.f, 9.f);
- list->AppendItem(DrawingDisplayItem::Create(picture, first_offset));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
gfx::Transform transform;
transform.Rotate(45.0);
list->AppendItem(TransformDisplayItem::Create(transform));
+ gfx::PointF second_offset(2.f, 3.f);
+ gfx::RectF second_recording_rect(second_offset, layer_rect.size());
canvas = skia::SharePtr(
- recorder.beginRecording(layer_rect.width(), layer_rect.height()));
+ recorder.beginRecording(gfx::RectFToSkRect(second_recording_rect)));
+ canvas->translate(second_offset.x(), second_offset.y());
canvas->drawRectCoords(50.f, 50.f, 75.f, 75.f, blue_paint);
picture = skia::AdoptRef(recorder.endRecording());
- gfx::PointF second_offset(2.f, 3.f);
- list->AppendItem(DrawingDisplayItem::Create(picture, second_offset));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
list->AppendItem(EndTransformDisplayItem::Create());
diff --git a/cc/resources/display_list_raster_source.cc b/cc/resources/display_list_raster_source.cc
index 4479a16..ab0292e 100644
--- a/cc/resources/display_list_raster_source.cc
+++ b/cc/resources/display_list_raster_source.cc
@@ -26,14 +26,12 @@
namespace cc {
-scoped_refptr<DisplayListRasterSource> DisplayListRasterSource::Create() {
- return make_scoped_refptr(new DisplayListRasterSource);
-}
-
scoped_refptr<DisplayListRasterSource>
DisplayListRasterSource::CreateFromDisplayListRecordingSource(
- const DisplayListRecordingSource* other) {
- return make_scoped_refptr(new DisplayListRasterSource(other));
+ const DisplayListRecordingSource* other,
+ bool can_use_lcd_text) {
+ return make_scoped_refptr(
+ new DisplayListRasterSource(other, can_use_lcd_text));
}
DisplayListRasterSource::DisplayListRasterSource()
@@ -48,11 +46,12 @@
}
DisplayListRasterSource::DisplayListRasterSource(
- const DisplayListRecordingSource* other)
+ const DisplayListRecordingSource* other,
+ bool can_use_lcd_text)
: display_list_(other->display_list_),
background_color_(other->background_color_),
requires_clear_(other->requires_clear_),
- can_use_lcd_text_(other->can_use_lcd_text_),
+ can_use_lcd_text_(can_use_lcd_text),
is_solid_color_(other->is_solid_color_),
solid_color_(other->solid_color_),
recorded_viewport_(other->recorded_viewport_),
@@ -63,6 +62,24 @@
should_attempt_to_use_distance_field_text_(false) {
}
+DisplayListRasterSource::DisplayListRasterSource(
+ const DisplayListRasterSource* other,
+ bool can_use_lcd_text)
+ : display_list_(other->display_list_),
+ background_color_(other->background_color_),
+ requires_clear_(other->requires_clear_),
+ can_use_lcd_text_(can_use_lcd_text),
+ is_solid_color_(other->is_solid_color_),
+ solid_color_(other->solid_color_),
+ recorded_viewport_(other->recorded_viewport_),
+ size_(other->size_),
+ clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
+ slow_down_raster_scale_factor_for_debug_(
+ other->slow_down_raster_scale_factor_for_debug_),
+ should_attempt_to_use_distance_field_text_(
+ other->should_attempt_to_use_distance_field_text_) {
+}
+
DisplayListRasterSource::~DisplayListRasterSource() {
}
@@ -197,4 +214,11 @@
return can_use_lcd_text_;
}
+scoped_refptr<RasterSource> DisplayListRasterSource::CreateCloneWithoutLCDText()
+ const {
+ bool can_use_lcd_text = false;
+ return scoped_refptr<RasterSource>(
+ new DisplayListRasterSource(this, can_use_lcd_text));
+}
+
} // namespace cc
diff --git a/cc/resources/display_list_raster_source.h b/cc/resources/display_list_raster_source.h
index f095231..44177fb 100644
--- a/cc/resources/display_list_raster_source.h
+++ b/cc/resources/display_list_raster_source.h
@@ -21,9 +21,9 @@
class CC_EXPORT DisplayListRasterSource : public RasterSource {
public:
- static scoped_refptr<DisplayListRasterSource> Create();
static scoped_refptr<DisplayListRasterSource>
- CreateFromDisplayListRecordingSource(const DisplayListRecordingSource* other);
+ CreateFromDisplayListRecordingSource(const DisplayListRecordingSource* other,
+ bool can_use_lcd_text);
// RasterSource overrides.
void PlaybackToCanvas(SkCanvas* canvas,
@@ -52,10 +52,14 @@
skia::RefPtr<SkPicture> GetFlattenedPicture() override;
size_t GetPictureMemoryUsage() const override;
bool CanUseLCDText() const override;
+ scoped_refptr<RasterSource> CreateCloneWithoutLCDText() const override;
protected:
DisplayListRasterSource();
- explicit DisplayListRasterSource(const DisplayListRecordingSource* other);
+ DisplayListRasterSource(const DisplayListRecordingSource* other,
+ bool can_use_lcd_text);
+ DisplayListRasterSource(const DisplayListRasterSource* other,
+ bool can_use_lcd_text);
~DisplayListRasterSource() override;
// These members are const as this raster source may be in use on another
diff --git a/cc/resources/display_list_recording_source.cc b/cc/resources/display_list_recording_source.cc
index 01a3bce..517f49f 100644
--- a/cc/resources/display_list_recording_source.cc
+++ b/cc/resources/display_list_recording_source.cc
@@ -28,7 +28,6 @@
DisplayListRecordingSource::DisplayListRecordingSource()
: slow_down_raster_scale_factor_for_debug_(0),
- can_use_lcd_text_(true),
requires_clear_(false),
is_solid_color_(false),
solid_color_(SK_ColorTRANSPARENT),
@@ -43,7 +42,6 @@
bool DisplayListRecordingSource::UpdateAndExpandInvalidation(
ContentLayerClient* painter,
Region* invalidation,
- bool can_use_lcd_text,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
@@ -55,12 +53,6 @@
updated = true;
}
- if (can_use_lcd_text_ != can_use_lcd_text) {
- can_use_lcd_text_ = can_use_lcd_text;
- invalidation->Union(gfx::Rect(GetSize()));
- updated = true;
- }
-
gfx::Rect old_recorded_viewport = recorded_viewport_;
recorded_viewport_ = visible_layer_rect;
recorded_viewport_.Inset(-pixel_record_distance_, -pixel_record_distance_);
@@ -152,10 +144,11 @@
return is_suitable_for_gpu_rasterization_;
}
-scoped_refptr<RasterSource> DisplayListRecordingSource::CreateRasterSource()
- const {
+scoped_refptr<RasterSource> DisplayListRecordingSource::CreateRasterSource(
+ bool can_use_lcd_text) const {
return scoped_refptr<RasterSource>(
- DisplayListRasterSource::CreateFromDisplayListRecordingSource(this));
+ DisplayListRasterSource::CreateFromDisplayListRecordingSource(
+ this, can_use_lcd_text));
}
gfx::Size DisplayListRecordingSource::GetTileGridSizeForTesting() const {
diff --git a/cc/resources/display_list_recording_source.h b/cc/resources/display_list_recording_source.h
index 21a24fb..1e713e1 100644
--- a/cc/resources/display_list_recording_source.h
+++ b/cc/resources/display_list_recording_source.h
@@ -20,12 +20,12 @@
// RecordingSource overrides.
bool UpdateAndExpandInvalidation(ContentLayerClient* painter,
Region* invalidation,
- bool can_use_lcd_text,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
RecordingMode recording_mode) override;
- scoped_refptr<RasterSource> CreateRasterSource() const override;
+ scoped_refptr<RasterSource> CreateRasterSource(
+ bool can_use_lcd_text) const override;
gfx::Size GetSize() const final;
void SetEmptyBounds() override;
void SetSlowdownRasterScaleFactor(int factor) override;
@@ -41,7 +41,6 @@
gfx::Rect recorded_viewport_;
gfx::Size size_;
int slow_down_raster_scale_factor_for_debug_;
- bool can_use_lcd_text_;
bool requires_clear_;
bool is_solid_color_;
SkColor solid_color_;
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc
index 1ef149f..6dffad9 100644
--- a/cc/resources/drawing_display_item.cc
+++ b/cc/resources/drawing_display_item.cc
@@ -18,9 +18,8 @@
namespace cc {
-DrawingDisplayItem::DrawingDisplayItem(skia::RefPtr<SkPicture> picture,
- gfx::PointF location)
- : picture_(picture), location_(location) {
+DrawingDisplayItem::DrawingDisplayItem(skia::RefPtr<SkPicture> picture)
+ : picture_(picture) {
}
DrawingDisplayItem::~DrawingDisplayItem() {
@@ -29,7 +28,6 @@
void DrawingDisplayItem::Raster(SkCanvas* canvas,
SkDrawPictureCallback* callback) const {
canvas->save();
- canvas->translate(location_.x(), location_.y());
if (callback)
picture_->playback(canvas, callback);
else
@@ -39,7 +37,6 @@
void DrawingDisplayItem::RasterForTracing(SkCanvas* canvas) const {
canvas->save();
- canvas->translate(location_.x(), location_.y());
// The picture debugger in about:tracing doesn't drill down into |drawPicture|
// operations. Calling |playback()| rather than |drawPicture()| causes the
// skia operations in |picture_| to appear individually in the picture
@@ -54,7 +51,7 @@
}
int DrawingDisplayItem::ApproximateOpCount() const {
- return picture_->approximateOpCount() + sizeof(gfx::PointF);
+ return picture_->approximateOpCount();
}
size_t DrawingDisplayItem::PictureMemoryUsage() const {
@@ -66,9 +63,11 @@
base::trace_event::TracedValue* array) const {
array->BeginDictionary();
array->SetString("name", "DrawingDisplayItem");
- array->SetString("location",
- base::StringPrintf("[%f,%f]", picture_->cullRect().x(),
- picture_->cullRect().y()));
+ array->SetString(
+ "cullRect",
+ base::StringPrintf("[%f,%f,%f,%f]", picture_->cullRect().x(),
+ picture_->cullRect().y(), picture_->cullRect().width(),
+ picture_->cullRect().height()));
std::string b64_picture;
PictureDebugUtil::SerializeAsBase64(picture_.get(), &b64_picture);
array->SetString("skp64", b64_picture);
diff --git a/cc/resources/drawing_display_item.h b/cc/resources/drawing_display_item.h
index 1f63ed3..b45a039 100644
--- a/cc/resources/drawing_display_item.h
+++ b/cc/resources/drawing_display_item.h
@@ -21,9 +21,9 @@
public:
~DrawingDisplayItem() override;
- static scoped_ptr<DrawingDisplayItem> Create(skia::RefPtr<SkPicture> picture,
- gfx::PointF location) {
- return make_scoped_ptr(new DrawingDisplayItem(picture, location));
+ static scoped_ptr<DrawingDisplayItem> Create(
+ skia::RefPtr<SkPicture> picture) {
+ return make_scoped_ptr(new DrawingDisplayItem(picture));
}
void Raster(SkCanvas* canvas, SkDrawPictureCallback* callback) const override;
@@ -35,11 +35,10 @@
void AsValueInto(base::trace_event::TracedValue* array) const override;
protected:
- DrawingDisplayItem(skia::RefPtr<SkPicture> picture, gfx::PointF location);
+ explicit DrawingDisplayItem(skia::RefPtr<SkPicture> picture);
private:
skia::RefPtr<SkPicture> picture_;
- gfx::PointF location_;
};
} // namespace cc
diff --git a/cc/resources/gpu_rasterizer.cc b/cc/resources/gpu_rasterizer.cc
index e0097f8..6e318ed 100644
--- a/cc/resources/gpu_rasterizer.cc
+++ b/cc/resources/gpu_rasterizer.cc
@@ -123,7 +123,7 @@
SkMultiPictureDraw multi_picture_draw;
multi_picture_draw.add(write_lock->sk_surface()->getCanvas(),
picture.get());
- multi_picture_draw.draw(false);
+ multi_picture_draw.draw(msaa_sample_count_ > 0);
write_lock->ReleaseSkSurface();
}
}
diff --git a/cc/resources/one_copy_tile_task_worker_pool.cc b/cc/resources/one_copy_tile_task_worker_pool.cc
index cee568a..e6a367a 100644
--- a/cc/resources/one_copy_tile_task_worker_pool.cc
+++ b/cc/resources/one_copy_tile_task_worker_pool.cc
@@ -167,6 +167,13 @@
void OneCopyTileTaskWorkerPool::ScheduleTasks(TileTaskQueue* queue) {
TRACE_EVENT0("cc", "OneCopyTileTaskWorkerPool::ScheduleTasks");
+#if DCHECK_IS_ON()
+ {
+ base::AutoLock lock(lock_);
+ DCHECK(!shutdown_);
+ }
+#endif
+
if (tasks_pending_.none())
TRACE_EVENT_ASYNC_BEGIN0("cc", "ScheduledTasks", this);
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index 7e94e18..2b15aea 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -166,7 +166,6 @@
const gfx::Size& tile_grid_size)
: min_contents_scale_(0),
slow_down_raster_scale_factor_for_debug_(0),
- can_use_lcd_text_(true),
has_any_recordings_(false),
clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
requires_clear_(true),
@@ -186,22 +185,17 @@
bool PicturePile::UpdateAndExpandInvalidation(
ContentLayerClient* painter,
Region* invalidation,
- bool can_use_lcd_text,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
RecordingSource::RecordingMode recording_mode) {
- bool can_use_lcd_text_changed = can_use_lcd_text_ != can_use_lcd_text;
- can_use_lcd_text_ = can_use_lcd_text;
-
gfx::Rect interest_rect = visible_layer_rect;
interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_);
recorded_viewport_ = interest_rect;
recorded_viewport_.Intersect(gfx::Rect(layer_size));
- bool updated =
- ApplyInvalidationAndResize(interest_rect, invalidation, layer_size,
- frame_number, can_use_lcd_text_changed);
+ bool updated = ApplyInvalidationAndResize(interest_rect, invalidation,
+ layer_size, frame_number);
std::vector<gfx::Rect> invalid_tiles;
GetInvalidTileRects(interest_rect, invalidation, visible_layer_rect,
frame_number, &invalid_tiles);
@@ -223,8 +217,7 @@
bool PicturePile::ApplyInvalidationAndResize(const gfx::Rect& interest_rect,
Region* invalidation,
const gfx::Size& layer_size,
- int frame_number,
- bool can_use_lcd_text_changed) {
+ int frame_number) {
bool updated = false;
Region synthetic_invalidation;
@@ -233,14 +226,6 @@
tiling_.SetTilingSize(layer_size);
updated = true;
}
- if (can_use_lcd_text_changed) {
- // When LCD text is enabled/disabled, we must drop any raster tiles for
- // the pile, so they can be recreated in a manner consistent with the new
- // setting. We do this with |synthetic_invalidation| since we don't need to
- // do a new recording, just invalidate rastered content.
- synthetic_invalidation.Union(gfx::Rect(GetSize()));
- updated = true;
- }
gfx::Rect interest_rect_over_tiles =
tiling_.ExpandRectToTileBounds(interest_rect);
@@ -593,9 +578,10 @@
}
}
-scoped_refptr<RasterSource> PicturePile::CreateRasterSource() const {
+scoped_refptr<RasterSource> PicturePile::CreateRasterSource(
+ bool can_use_lcd_text) const {
return scoped_refptr<RasterSource>(
- PicturePileImpl::CreateFromPicturePile(this));
+ PicturePileImpl::CreateFromPicturePile(this, can_use_lcd_text));
}
gfx::Size PicturePile::GetSize() const {
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index 2a9a3ce..bab06c8 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -25,12 +25,12 @@
// RecordingSource overrides.
bool UpdateAndExpandInvalidation(ContentLayerClient* painter,
Region* invalidation,
- bool can_use_lcd_text,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
RecordingMode recording_mode) override;
- scoped_refptr<RasterSource> CreateRasterSource() const override;
+ scoped_refptr<RasterSource> CreateRasterSource(
+ bool can_use_lcd_text) const override;
gfx::Size GetSize() const final;
void SetEmptyBounds() override;
void SetSlowdownRasterScaleFactor(int factor) override;
@@ -95,7 +95,6 @@
float min_contents_scale_;
gfx::Size tile_grid_size_;
int slow_down_raster_scale_factor_for_debug_;
- bool can_use_lcd_text_;
// A hint about whether there are any recordings. This may be a false
// positive.
bool has_any_recordings_;
@@ -120,8 +119,7 @@
bool ApplyInvalidationAndResize(const gfx::Rect& interest_rect,
Region* invalidation,
const gfx::Size& layer_size,
- int frame_number,
- bool can_use_lcd_text_changed);
+ int frame_number);
void DetermineIfSolidColor();
void SetBufferPixels(int buffer_pixels);
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index d629888..a9bad90 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -19,14 +19,15 @@
namespace cc {
scoped_refptr<PicturePileImpl> PicturePileImpl::CreateFromPicturePile(
- const PicturePile* other) {
- return make_scoped_refptr(new PicturePileImpl(other));
+ const PicturePile* other,
+ bool can_use_lcd_text) {
+ return make_scoped_refptr(new PicturePileImpl(other, can_use_lcd_text));
}
PicturePileImpl::PicturePileImpl()
: background_color_(SK_ColorTRANSPARENT),
requires_clear_(true),
- can_use_lcd_text_(false),
+ can_use_lcd_text_(true),
is_solid_color_(false),
solid_color_(SK_ColorTRANSPARENT),
has_any_recordings_(false),
@@ -36,12 +37,13 @@
should_attempt_to_use_distance_field_text_(false) {
}
-PicturePileImpl::PicturePileImpl(const PicturePile* other)
+PicturePileImpl::PicturePileImpl(const PicturePile* other,
+ bool can_use_lcd_text)
: picture_map_(other->picture_map_),
tiling_(other->tiling_),
background_color_(other->background_color_),
requires_clear_(other->requires_clear_),
- can_use_lcd_text_(other->can_use_lcd_text_),
+ can_use_lcd_text_(can_use_lcd_text),
is_solid_color_(other->is_solid_color_),
solid_color_(other->solid_color_),
recorded_viewport_(other->recorded_viewport_),
@@ -53,6 +55,25 @@
should_attempt_to_use_distance_field_text_(false) {
}
+PicturePileImpl::PicturePileImpl(const PicturePileImpl* other,
+ bool can_use_lcd_text)
+ : picture_map_(other->picture_map_),
+ tiling_(other->tiling_),
+ background_color_(other->background_color_),
+ requires_clear_(other->requires_clear_),
+ can_use_lcd_text_(can_use_lcd_text),
+ is_solid_color_(other->is_solid_color_),
+ solid_color_(other->solid_color_),
+ recorded_viewport_(other->recorded_viewport_),
+ has_any_recordings_(other->has_any_recordings_),
+ clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
+ min_contents_scale_(other->min_contents_scale_),
+ slow_down_raster_scale_factor_for_debug_(
+ other->slow_down_raster_scale_factor_for_debug_),
+ should_attempt_to_use_distance_field_text_(
+ other->should_attempt_to_use_distance_field_text_) {
+}
+
PicturePileImpl::~PicturePileImpl() {
}
@@ -383,6 +404,13 @@
return can_use_lcd_text_;
}
+scoped_refptr<RasterSource> PicturePileImpl::CreateCloneWithoutLCDText() const {
+ DCHECK(CanUseLCDText());
+ bool can_use_lcd_text = false;
+ return scoped_refptr<RasterSource>(
+ new PicturePileImpl(this, can_use_lcd_text));
+}
+
PicturePileImpl::PixelRefIterator::PixelRefIterator(
const gfx::Rect& content_rect,
float contents_scale,
diff --git a/cc/resources/picture_pile_impl.h b/cc/resources/picture_pile_impl.h
index 1f94cec..c35dd0f 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -30,7 +30,8 @@
class CC_EXPORT PicturePileImpl : public RasterSource {
public:
static scoped_refptr<PicturePileImpl> CreateFromPicturePile(
- const PicturePile* other);
+ const PicturePile* other,
+ bool can_use_lcd_text);
// RasterSource overrides. See RasterSource header for full description.
// When slow-down-raster-scale-factor is set to a value greater than 1, the
@@ -58,6 +59,7 @@
SkColor GetSolidColor() const override;
bool HasRecordings() const override;
bool CanUseLCDText() const override;
+ scoped_refptr<RasterSource> CreateCloneWithoutLCDText() const override;
// Tracing functionality.
void DidBeginTracing() override;
@@ -99,7 +101,8 @@
using PictureInfo = PicturePile::PictureInfo;
PicturePileImpl();
- explicit PicturePileImpl(const PicturePile* other);
+ explicit PicturePileImpl(const PicturePile* other, bool can_use_lcd_text);
+ explicit PicturePileImpl(const PicturePileImpl* other, bool can_use_lcd_text);
~PicturePileImpl() override;
int buffer_pixels() const { return tiling_.border_texels(); }
diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc
index b834979..91ad7ce 100644
--- a/cc/resources/picture_pile_unittest.cc
+++ b/cc/resources/picture_pile_unittest.cc
@@ -42,9 +42,9 @@
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect) {
frame_number_++;
- return pile_.UpdateAndExpandInvalidation(
- &client_, invalidation, false, layer_size, visible_layer_rect,
- frame_number_, RecordingSource::RECORD_NORMALLY);
+ return pile_.UpdateAndExpandInvalidation(&client_, invalidation, layer_size,
+ visible_layer_rect, frame_number_,
+ RecordingSource::RECORD_NORMALLY);
}
bool UpdateWholePile() {
diff --git a/cc/resources/platform_color_unittest.cc b/cc/resources/platform_color_unittest.cc
new file mode 100644
index 0000000..83b2a1e
--- /dev/null
+++ b/cc/resources/platform_color_unittest.cc
@@ -0,0 +1,42 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/resources/platform_color.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+// Verify SameComponentOrder on this platform.
+TEST(PlatformColorTest, SameComponentOrder) {
+ bool rgba = !!SK_B32_SHIFT;
+
+ for (size_t i = 0; i <= RESOURCE_FORMAT_MAX; ++i) {
+ ResourceFormat format = static_cast<ResourceFormat>(i);
+ switch (format) {
+ case RGBA_8888:
+ EXPECT_EQ(rgba, PlatformColor::SameComponentOrder(format));
+ break;
+ case RGBA_4444:
+ // RGBA_4444 indicates the number of bytes per pixel but the format
+ // doesn't actually imply RGBA ordering. It uses the native ordering.
+ EXPECT_EQ(true, PlatformColor::SameComponentOrder(format));
+ break;
+ case BGRA_8888:
+ EXPECT_NE(rgba, PlatformColor::SameComponentOrder(format));
+ break;
+ case ALPHA_8:
+ case LUMINANCE_8:
+ case RGB_565:
+ case ETC1:
+ case RED_8:
+ EXPECT_FALSE(PlatformColor::SameComponentOrder(format));
+ break;
+ }
+ }
+}
+
+} // namespace
+} // namespace cc
diff --git a/cc/resources/prioritized_resource_manager.cc b/cc/resources/prioritized_resource_manager.cc
index 48177e3..236377b 100644
--- a/cc/resources/prioritized_resource_manager.cc
+++ b/cc/resources/prioritized_resource_manager.cc
@@ -451,11 +451,8 @@
DCHECK(resource_provider);
ResourceProvider::ResourceId resource_id =
resource_provider->CreateManagedResource(
- size,
- GL_TEXTURE_2D,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- format);
+ size, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
PrioritizedResource::Backing* backing = new PrioritizedResource::Backing(
resource_id, resource_provider, size, format);
memory_use_bytes_ += backing->bytes();
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index 929e49d..171d2a5 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -99,6 +99,8 @@
// Return true if LCD anti-aliasing may be used when rastering text.
virtual bool CanUseLCDText() const = 0;
+ virtual scoped_refptr<RasterSource> CreateCloneWithoutLCDText() const = 0;
+
protected:
friend class base::RefCountedThreadSafe<RasterSource>;
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
index 8915361..fdd8eb4 100644
--- a/cc/resources/recording_source.h
+++ b/cc/resources/recording_source.h
@@ -34,13 +34,13 @@
// Return true iff the pile was modified.
virtual bool UpdateAndExpandInvalidation(ContentLayerClient* painter,
Region* invalidation,
- bool can_use_lcd_text,
const gfx::Size& layer_size,
const gfx::Rect& visible_layer_rect,
int frame_number,
RecordingMode recording_mode) = 0;
- virtual scoped_refptr<RasterSource> CreateRasterSource() const = 0;
+ virtual scoped_refptr<RasterSource> CreateRasterSource(
+ bool can_use_lcd_text) const = 0;
virtual gfx::Size GetSize() const = 0;
virtual void SetEmptyBounds() = 0;
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 42ef4b3..115238f 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -266,7 +266,7 @@
allow_overlay(false),
read_lock_fence(NULL),
size(),
- origin(Internal),
+ origin(INTERNAL),
target(0),
original_filter(0),
filter(0),
@@ -274,8 +274,8 @@
bound_image_id(0),
texture_pool(0),
wrap_mode(0),
- hint(TextureHintImmutable),
- type(InvalidType),
+ hint(TEXTURE_HINT_IMMUTABLE),
+ type(RESOURCE_TYPE_INVALID),
format(RGBA_8888),
shared_bitmap(NULL),
gpu_memory_buffer(NULL) {
@@ -322,12 +322,12 @@
texture_pool(texture_pool),
wrap_mode(wrap_mode),
hint(hint),
- type(GLTexture),
+ type(RESOURCE_TYPE_GL_TEXTURE),
format(format),
shared_bitmap(NULL),
gpu_memory_buffer(NULL) {
DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
- DCHECK_EQ(origin == Internal, !!texture_pool);
+ DCHECK_EQ(origin == INTERNAL, !!texture_pool);
}
ResourceProvider::Resource::Resource(uint8_t* pixels,
@@ -365,13 +365,13 @@
bound_image_id(0),
texture_pool(0),
wrap_mode(wrap_mode),
- hint(TextureHintImmutable),
- type(Bitmap),
+ hint(TEXTURE_HINT_IMMUTABLE),
+ type(RESOURCE_TYPE_BITMAP),
format(RGBA_8888),
shared_bitmap(bitmap),
gpu_memory_buffer(NULL) {
DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT);
- DCHECK(origin == Delegated || pixels);
+ DCHECK(origin == DELEGATED || pixels);
if (bitmap)
shared_bitmap_id = bitmap->id();
}
@@ -410,8 +410,8 @@
bound_image_id(0),
texture_pool(0),
wrap_mode(wrap_mode),
- hint(TextureHintImmutable),
- type(Bitmap),
+ hint(TEXTURE_HINT_IMMUTABLE),
+ type(RESOURCE_TYPE_BITMAP),
format(RGBA_8888),
shared_bitmap_id(bitmap_id),
shared_bitmap(NULL),
@@ -445,15 +445,15 @@
else
resource_provider->InitializeSoftware();
- DCHECK_NE(InvalidType, resource_provider->default_resource_type());
+ DCHECK_NE(RESOURCE_TYPE_INVALID, resource_provider->default_resource_type());
return resource_provider.Pass();
}
ResourceProvider::~ResourceProvider() {
while (!children_.empty())
- DestroyChildInternal(children_.begin(), ForShutdown);
+ DestroyChildInternal(children_.begin(), FOR_SHUTDOWN);
while (!resources_.empty())
- DeleteResourceInternal(resources_.begin(), ForShutdown);
+ DeleteResourceInternal(resources_.begin(), FOR_SHUTDOWN);
CleanUpGLIfNeeded();
}
@@ -481,17 +481,17 @@
ResourceFormat format) {
DCHECK(!size.IsEmpty());
switch (default_resource_type_) {
- case GLTexture:
+ case RESOURCE_TYPE_GL_TEXTURE:
return CreateGLTexture(size,
GL_TEXTURE_2D,
GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
wrap_mode,
hint,
format);
- case Bitmap:
+ case RESOURCE_TYPE_BITMAP:
DCHECK_EQ(RGBA_8888, format);
return CreateBitmap(size, wrap_mode);
- case InvalidType:
+ case RESOURCE_TYPE_INVALID:
break;
}
@@ -507,17 +507,17 @@
ResourceFormat format) {
DCHECK(!size.IsEmpty());
switch (default_resource_type_) {
- case GLTexture:
+ case RESOURCE_TYPE_GL_TEXTURE:
return CreateGLTexture(size,
target,
GL_TEXTURE_POOL_MANAGED_CHROMIUM,
wrap_mode,
hint,
format);
- case Bitmap:
+ case RESOURCE_TYPE_BITMAP:
DCHECK_EQ(RGBA_8888, format);
return CreateBitmap(size, wrap_mode);
- case InvalidType:
+ case RESOURCE_TYPE_INVALID:
break;
}
@@ -537,15 +537,8 @@
DCHECK(thread_checker_.CalledOnValidThread());
ResourceId id = next_id_++;
- Resource resource(0,
- size,
- Resource::Internal,
- target,
- GL_LINEAR,
- texture_pool,
- wrap_mode,
- hint,
- format);
+ Resource resource(0, size, Resource::INTERNAL, target, GL_LINEAR,
+ texture_pool, wrap_mode, hint, format);
resource.allocated = false;
resources_[id] = resource;
return id;
@@ -561,8 +554,8 @@
DCHECK(pixels);
ResourceId id = next_id_++;
- Resource resource(
- pixels, bitmap.release(), size, Resource::Internal, GL_LINEAR, wrap_mode);
+ Resource resource(pixels, bitmap.release(), size, Resource::INTERNAL,
+ GL_LINEAR, wrap_mode);
resource.allocated = true;
resources_[id] = resource;
return id;
@@ -574,15 +567,10 @@
DCHECK(thread_checker_.CalledOnValidThread());
ResourceId id = next_id_++;
- Resource resource(0,
- gfx::Size(),
- Resource::Internal,
- GL_TEXTURE_RECTANGLE_ARB,
- GL_LINEAR,
- GL_TEXTURE_POOL_UNMANAGED_CHROMIUM,
- GL_CLAMP_TO_EDGE,
- TextureHintImmutable,
- RGBA_8888);
+ Resource resource(0, gfx::Size(), Resource::INTERNAL,
+ GL_TEXTURE_RECTANGLE_ARB, GL_LINEAR,
+ GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, GL_CLAMP_TO_EDGE,
+ TEXTURE_HINT_IMMUTABLE, RGBA_8888);
LazyCreate(&resource);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
@@ -603,22 +591,16 @@
DCHECK(mailbox.IsValid());
Resource& resource = resources_[id];
if (mailbox.IsTexture()) {
- resource = Resource(0,
- gfx::Size(),
- Resource::External,
- mailbox.target(),
- mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR,
- 0,
- GL_CLAMP_TO_EDGE,
- TextureHintImmutable,
- RGBA_8888);
+ resource = Resource(0, gfx::Size(), Resource::EXTERNAL, mailbox.target(),
+ mailbox.nearest_neighbor() ? GL_NEAREST : GL_LINEAR, 0,
+ GL_CLAMP_TO_EDGE, TEXTURE_HINT_IMMUTABLE, RGBA_8888);
} else {
DCHECK(mailbox.IsSharedMemory());
SharedBitmap* shared_bitmap = mailbox.shared_bitmap();
uint8_t* pixels = shared_bitmap->pixels();
DCHECK(pixels);
resource = Resource(pixels, shared_bitmap, mailbox.shared_memory_size(),
- Resource::External, GL_LINEAR, GL_CLAMP_TO_EDGE);
+ Resource::EXTERNAL, GL_LINEAR, GL_CLAMP_TO_EDGE);
}
resource.allocated = true;
resource.mailbox = mailbox;
@@ -642,7 +624,7 @@
resource->marked_for_deletion = true;
return;
} else {
- DeleteResourceInternal(it, Normal);
+ DeleteResourceInternal(it, NORMAL);
}
}
@@ -652,38 +634,38 @@
Resource* resource = &it->second;
bool lost_resource = resource->lost;
- DCHECK(resource->exported_count == 0 || style != Normal);
- if (style == ForShutdown && resource->exported_count > 0)
+ DCHECK(resource->exported_count == 0 || style != NORMAL);
+ if (style == FOR_SHUTDOWN && resource->exported_count > 0)
lost_resource = true;
if (resource->image_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id));
}
if (resource->gl_upload_query_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id));
}
if (resource->gl_read_lock_query_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_read_lock_query_id));
}
if (resource->gl_pixel_buffer_id) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id));
}
- if (resource->origin == Resource::External) {
+ if (resource->origin == Resource::EXTERNAL) {
DCHECK(resource->mailbox.IsValid());
GLuint sync_point = resource->mailbox.sync_point();
- if (resource->type == GLTexture) {
+ if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
DCHECK(resource->mailbox.IsTexture());
lost_resource |= lost_output_surface_;
GLES2Interface* gl = ContextGL();
@@ -709,18 +691,18 @@
resource->gl_id = 0;
}
if (resource->shared_bitmap) {
- DCHECK(resource->origin != Resource::External);
- DCHECK_EQ(Bitmap, resource->type);
+ DCHECK(resource->origin != Resource::EXTERNAL);
+ DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
delete resource->shared_bitmap;
resource->pixels = NULL;
}
if (resource->pixels) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
delete[] resource->pixels;
resource->pixels = NULL;
}
if (resource->gpu_memory_buffer) {
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
delete resource->gpu_memory_buffer;
resource->gpu_memory_buffer = NULL;
}
@@ -740,12 +722,12 @@
Resource* resource = GetResource(id);
DCHECK(!resource->locked_for_write);
DCHECK(!resource->lock_for_read_count);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(ReadLockFenceHasPassed(resource));
LazyAllocate(resource);
- if (resource->type == GLTexture) {
+ if (resource->type == RESOURCE_TYPE_GL_TEXTURE) {
DCHECK(resource->gl_id);
DCHECK(!resource->pending_set_pixels);
DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
@@ -760,7 +742,7 @@
resource->format,
resource->size);
} else {
- DCHECK_EQ(Bitmap, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
DCHECK(resource->allocated);
DCHECK_EQ(RGBA_8888, resource->format);
DCHECK(source_rect.x() >= image_rect.x());
@@ -780,6 +762,54 @@
}
}
+void ResourceProvider::CopyToResource(ResourceId id,
+ const uint8_t* image,
+ const gfx::Size& image_size) {
+ Resource* resource = GetResource(id);
+ DCHECK(!resource->locked_for_write);
+ DCHECK(!resource->lock_for_read_count);
+ DCHECK(resource->origin == Resource::INTERNAL);
+ DCHECK_EQ(resource->exported_count, 0);
+ DCHECK(ReadLockFenceHasPassed(resource));
+ LazyAllocate(resource);
+
+ DCHECK_EQ(image_size.width(), resource->size.width());
+ DCHECK_EQ(image_size.height(), resource->size.height());
+
+ if (resource->type == RESOURCE_TYPE_BITMAP) {
+ DCHECK_EQ(RESOURCE_TYPE_BITMAP, resource->type);
+ DCHECK(resource->allocated);
+ DCHECK_EQ(RGBA_8888, resource->format);
+ SkImageInfo source_info =
+ SkImageInfo::MakeN32Premul(image_size.width(), image_size.height());
+ size_t image_stride = image_size.width() * 4;
+
+ ScopedWriteLockSoftware lock(this, id);
+ SkCanvas dest(lock.sk_bitmap());
+ dest.writePixels(source_info, image, image_stride, 0, 0);
+ } else {
+ DCHECK(resource->gl_id);
+ DCHECK(!resource->pending_set_pixels);
+ DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D));
+ GLES2Interface* gl = ContextGL();
+ DCHECK(gl);
+ DCHECK(texture_uploader_.get());
+ gl->BindTexture(GL_TEXTURE_2D, resource->gl_id);
+
+ if (resource->format == ETC1) {
+ size_t num_bytes = static_cast<size_t>(image_size.width()) *
+ image_size.height() * BitsPerPixel(ETC1) / 8;
+ gl->CompressedTexImage2D(GL_TEXTURE_2D, 0, GLInternalFormat(ETC1),
+ image_size.width(), image_size.height(), 0,
+ num_bytes, image);
+ } else {
+ gl->TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_size.width(),
+ image_size.height(), GLDataFormat(resource->format),
+ GLDataType(resource->format), image);
+ }
+ }
+}
+
size_t ResourceProvider::NumBlockingUploads() {
if (!texture_uploader_)
return 0;
@@ -858,8 +888,8 @@
LazyCreate(resource);
- if (resource->type == GLTexture && !resource->gl_id) {
- DCHECK(resource->origin != Resource::Internal);
+ if (resource->type == RESOURCE_TYPE_GL_TEXTURE && !resource->gl_id) {
+ DCHECK(resource->origin != Resource::INTERNAL);
DCHECK(resource->mailbox.IsTexture());
// Mailbox sync_points must be processed by a call to
@@ -908,12 +938,12 @@
if (resource->marked_for_deletion && !resource->lock_for_read_count) {
if (!resource->child_id) {
// The resource belongs to this ResourceProvider, so it can be destroyed.
- DeleteResourceInternal(it, Normal);
+ DeleteResourceInternal(it, NORMAL);
} else {
ChildMap::iterator child_it = children_.find(resource->child_id);
ResourceIdArray unused;
unused.push_back(id);
- DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
}
}
}
@@ -929,14 +959,14 @@
bool ResourceProvider::CanLockForWrite(ResourceId id) {
Resource* resource = GetResource(id);
return !resource->locked_for_write && !resource->lock_for_read_count &&
- !resource->exported_count && resource->origin == Resource::Internal &&
+ !resource->exported_count && resource->origin == Resource::INTERNAL &&
!resource->lost && ReadLockFenceHasPassed(resource);
}
void ResourceProvider::UnlockForWrite(ResourceProvider::Resource* resource) {
DCHECK(resource->locked_for_write);
DCHECK_EQ(resource->exported_count, 0);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
resource->locked_for_write = false;
}
@@ -1034,7 +1064,7 @@
gpu_memory_buffer_(nullptr),
size_(resource_->size),
format_(resource_->format) {
- DCHECK_EQ(GLTexture, resource_->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource_->type);
std::swap(gpu_memory_buffer_, resource_->gpu_memory_buffer);
}
@@ -1187,7 +1217,7 @@
highp_threshold_min_(highp_threshold_min),
next_id_(1),
next_child_(1),
- default_resource_type_(InvalidType),
+ default_resource_type_(RESOURCE_TYPE_INVALID),
use_texture_storage_ext_(false),
use_texture_format_bgra_(false),
use_texture_usage_hint_(false),
@@ -1204,11 +1234,11 @@
void ResourceProvider::InitializeSoftware() {
DCHECK(thread_checker_.CalledOnValidThread());
- DCHECK_NE(Bitmap, default_resource_type_);
+ DCHECK_NE(RESOURCE_TYPE_BITMAP, default_resource_type_);
CleanUpGLIfNeeded();
- default_resource_type_ = Bitmap;
+ default_resource_type_ = RESOURCE_TYPE_BITMAP;
// Pick an arbitrary limit here similar to what hardware might.
max_texture_size_ = 16 * 1024;
best_texture_format_ = RGBA_8888;
@@ -1217,11 +1247,11 @@
void ResourceProvider::InitializeGL() {
DCHECK(thread_checker_.CalledOnValidThread());
DCHECK(!texture_uploader_);
- DCHECK_NE(GLTexture, default_resource_type_);
+ DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, default_resource_type_);
DCHECK(!texture_id_allocator_);
DCHECK(!buffer_id_allocator_);
- default_resource_type_ = GLTexture;
+ default_resource_type_ = RESOURCE_TYPE_GL_TEXTURE;
const ContextProvider::Capabilities& caps =
output_surface_->context_provider()->ContextCapabilities();
@@ -1250,7 +1280,7 @@
void ResourceProvider::CleanUpGLIfNeeded() {
GLES2Interface* gl = ContextGL();
- if (default_resource_type_ != GLTexture) {
+ if (default_resource_type_ != RESOURCE_TYPE_GL_TEXTURE) {
// We are not in GL mode, but double check before returning.
DCHECK(!gl);
DCHECK(!texture_uploader_);
@@ -1263,7 +1293,7 @@
for (ResourceMap::const_iterator itr = resources_.begin();
itr != resources_.end();
++itr) {
- DCHECK_NE(GLTexture, itr->second.type);
+ DCHECK_NE(RESOURCE_TYPE_GL_TEXTURE, itr->second.type);
}
#endif // DCHECK_IS_ON()
@@ -1287,7 +1317,7 @@
void ResourceProvider::DestroyChild(int child_id) {
ChildMap::iterator it = children_.find(child_id);
DCHECK(it != children_.end());
- DestroyChildInternal(it, Normal);
+ DestroyChildInternal(it, NORMAL);
}
void ResourceProvider::DestroyChildInternal(ChildMap::iterator it,
@@ -1295,7 +1325,7 @@
DCHECK(thread_checker_.CalledOnValidThread());
Child& child = it->second;
- DCHECK(style == ForShutdown || !child.marked_for_deletion);
+ DCHECK(style == FOR_SHUTDOWN || !child.marked_for_deletion);
ResourceIdArray resources_for_child;
@@ -1379,21 +1409,14 @@
ResourceId local_id = next_id_++;
Resource& resource = resources_[local_id];
if (it->is_software) {
- resource = Resource(it->mailbox_holder.mailbox,
- it->size,
- Resource::Delegated,
- GL_LINEAR,
- it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
+ resource =
+ Resource(it->mailbox_holder.mailbox, it->size, Resource::DELEGATED,
+ GL_LINEAR, it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE);
} else {
- resource = Resource(0,
- it->size,
- Resource::Delegated,
- it->mailbox_holder.texture_target,
- it->filter,
- 0,
+ resource = Resource(0, it->size, Resource::DELEGATED,
+ it->mailbox_holder.texture_target, it->filter, 0,
it->is_repeated ? GL_REPEAT : GL_CLAMP_TO_EDGE,
- TextureHintImmutable,
- it->format);
+ TEXTURE_HINT_IMMUTABLE, it->format);
resource.mailbox = TextureMailbox(it->mailbox_holder.mailbox,
it->mailbox_holder.texture_target,
it->mailbox_holder.sync_point);
@@ -1438,7 +1461,7 @@
if (!resource_is_in_use)
unused.push_back(local_id);
}
- DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused);
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL, unused);
}
// static
@@ -1505,7 +1528,7 @@
if (returned.sync_point) {
DCHECK(!resource->has_shared_bitmap_id);
- if (resource->origin == Resource::Internal) {
+ if (resource->origin == Resource::INTERNAL) {
DCHECK(resource->gl_id);
GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point));
} else {
@@ -1519,18 +1542,18 @@
if (!resource->child_id) {
// The resource belongs to this ResourceProvider, so it can be destroyed.
- DeleteResourceInternal(map_iterator, Normal);
+ DeleteResourceInternal(map_iterator, NORMAL);
continue;
}
- DCHECK(resource->origin == Resource::Delegated);
+ DCHECK(resource->origin == Resource::DELEGATED);
// Delete the resource and return it to the child it came from one.
if (resource->child_id != child_id) {
if (child_id) {
DCHECK_NE(resources_for_child.size(), 0u);
DCHECK(child_it != children_.end());
- DeleteAndReturnUnusedResourcesToChild(
- child_it, Normal, resources_for_child);
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
+ resources_for_child);
resources_for_child.clear();
}
@@ -1544,8 +1567,8 @@
if (child_id) {
DCHECK_NE(resources_for_child.size(), 0u);
DCHECK(child_it != children_.end());
- DeleteAndReturnUnusedResourcesToChild(
- child_it, Normal, resources_for_child);
+ DeleteAndReturnUnusedResourcesToChild(child_it, NORMAL,
+ resources_for_child);
}
}
@@ -1555,7 +1578,7 @@
Resource* source = GetResource(id);
DCHECK(!source->locked_for_write);
DCHECK(!source->lock_for_read_count);
- DCHECK(source->origin != Resource::External || source->mailbox.IsValid());
+ DCHECK(source->origin != Resource::EXTERNAL || source->mailbox.IsValid());
DCHECK(source->allocated);
resource->id = id;
resource->format = source->format;
@@ -1565,13 +1588,13 @@
resource->is_repeated = (source->wrap_mode == GL_REPEAT);
resource->allow_overlay = source->allow_overlay;
- if (source->type == Bitmap) {
+ if (source->type == RESOURCE_TYPE_BITMAP) {
resource->mailbox_holder.mailbox = source->shared_bitmap_id;
resource->is_software = true;
} else if (!source->mailbox.IsValid()) {
LazyCreate(source);
DCHECK(source->gl_id);
- DCHECK(source->origin == Resource::Internal);
+ DCHECK(source->origin == Resource::INTERNAL);
GLC(gl,
gl->BindTexture(resource->mailbox_holder.texture_target,
source->gl_id));
@@ -1590,7 +1613,7 @@
DCHECK(source->mailbox.IsTexture());
if (source->image_id && source->dirty_image) {
DCHECK(source->gl_id);
- DCHECK(source->origin == Resource::Internal);
+ DCHECK(source->origin == Resource::INTERNAL);
GLC(gl,
gl->BindTexture(resource->mailbox_holder.texture_target,
source->gl_id));
@@ -1635,9 +1658,10 @@
DCHECK(child_info->child_to_parent_map.count(child_id));
bool is_lost =
- resource.lost || (resource.type == GLTexture && lost_output_surface_);
+ resource.lost ||
+ (resource.type == RESOURCE_TYPE_GL_TEXTURE && lost_output_surface_);
if (resource.exported_count > 0 || resource.lock_for_read_count > 0) {
- if (style != ForShutdown) {
+ if (style != FOR_SHUTDOWN) {
// Defer this until we receive the resource back from the parent or
// the read lock is released.
resource.marked_for_deletion = true;
@@ -1666,7 +1690,7 @@
ReturnedResource returned;
returned.id = child_id;
returned.sync_point = resource.mailbox.sync_point();
- if (!returned.sync_point && resource.type == GLTexture)
+ if (!returned.sync_point && resource.type == RESOURCE_TYPE_GL_TEXTURE)
need_sync_point = true;
returned.count = resource.imported_count;
returned.lost = is_lost;
@@ -1702,12 +1726,12 @@
"ResourceProvider::AcquirePixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
DCHECK_NE(ETC1, resource->format);
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
if (!resource->gl_pixel_buffer_id)
@@ -1728,7 +1752,7 @@
"ResourceProvider::ReleasePixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
@@ -1744,7 +1768,7 @@
resource->locked_for_write = false;
}
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
if (!resource->gl_pixel_buffer_id)
return;
GLES2Interface* gl = ContextGL();
@@ -1761,12 +1785,12 @@
"ResourceProvider::MapPixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
*stride = 0;
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
DCHECK(resource->gl_pixel_buffer_id);
@@ -1785,11 +1809,11 @@
"ResourceProvider::UnmapPixelBuffer");
Resource* resource = GetResource(id);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(!resource->image_id);
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
DCHECK(resource->gl_pixel_buffer_id);
@@ -1833,7 +1857,7 @@
DCHECK(!resource->pending_set_pixels);
LazyCreate(resource);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK(resource->gl_id || resource->allocated);
DCHECK(ReadLockFenceHasPassed(resource));
DCHECK(!resource->image_id);
@@ -1842,7 +1866,7 @@
resource->allocated = true;
LockForWrite(id);
- DCHECK_EQ(GLTexture, resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, resource->type);
DCHECK(resource->gl_id);
GLES2Interface* gl = ContextGL();
DCHECK(gl);
@@ -1944,14 +1968,15 @@
}
void ResourceProvider::LazyCreate(Resource* resource) {
- if (resource->type != GLTexture || resource->origin != Resource::Internal)
+ if (resource->type != RESOURCE_TYPE_GL_TEXTURE ||
+ resource->origin != Resource::INTERNAL)
return;
if (resource->gl_id)
return;
DCHECK(resource->texture_pool);
- DCHECK(resource->origin == Resource::Internal);
+ DCHECK(resource->origin == Resource::INTERNAL);
DCHECK(!resource->mailbox.IsValid());
resource->gl_id = texture_id_allocator_->NextId();
@@ -1975,7 +2000,7 @@
GLC(gl,
gl->TexParameteri(
resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool));
- if (use_texture_usage_hint_ && (resource->hint & TextureHintFramebuffer)) {
+ if (use_texture_usage_hint_ && (resource->hint & TEXTURE_HINT_FRAMEBUFFER)) {
GLC(gl,
gl->TexParameteri(resource->target,
GL_TEXTURE_USAGE_ANGLE,
@@ -2002,7 +2027,7 @@
GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id));
if (use_texture_storage_ext_ &&
IsFormatSupportedForStorage(format, use_texture_format_bgra_) &&
- (resource->hint & TextureHintImmutable)) {
+ (resource->hint & TEXTURE_HINT_IMMUTABLE)) {
GLenum storage_format = TextureToStorageFormat(format);
GLC(gl,
gl->TexStorage2DEXT(
@@ -2042,18 +2067,18 @@
Resource* source_resource = GetResource(source_id);
DCHECK(!source_resource->lock_for_read_count);
- DCHECK(source_resource->origin == Resource::Internal);
+ DCHECK(source_resource->origin == Resource::INTERNAL);
DCHECK_EQ(source_resource->exported_count, 0);
- DCHECK_EQ(GLTexture, source_resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, source_resource->type);
DCHECK(source_resource->allocated);
LazyCreate(source_resource);
Resource* dest_resource = GetResource(dest_id);
DCHECK(!dest_resource->locked_for_write);
DCHECK(!dest_resource->lock_for_read_count);
- DCHECK(dest_resource->origin == Resource::Internal);
+ DCHECK(dest_resource->origin == Resource::INTERNAL);
DCHECK_EQ(dest_resource->exported_count, 0);
- DCHECK_EQ(GLTexture, dest_resource->type);
+ DCHECK_EQ(RESOURCE_TYPE_GL_TEXTURE, dest_resource->type);
LazyAllocate(dest_resource);
DCHECK_EQ(source_resource->type, dest_resource->type);
@@ -2114,7 +2139,7 @@
Resource* resource = GetResource(id);
DCHECK_EQ(resource->exported_count, 0);
DCHECK(resource->allocated);
- if (resource->type != GLTexture || resource->gl_id)
+ if (resource->type != RESOURCE_TYPE_GL_TEXTURE || resource->gl_id)
return;
if (!resource->mailbox.sync_point())
return;
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 167ef20..95e1294 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -67,16 +67,16 @@
typedef std::set<ResourceId> ResourceIdSet;
typedef base::hash_map<ResourceId, ResourceId> ResourceIdMap;
enum TextureHint {
- TextureHintDefault = 0x0,
- TextureHintImmutable = 0x1,
- TextureHintFramebuffer = 0x2,
- TextureHintImmutableFramebuffer =
- TextureHintImmutable | TextureHintFramebuffer
+ TEXTURE_HINT_DEFAULT = 0x0,
+ TEXTURE_HINT_IMMUTABLE = 0x1,
+ TEXTURE_HINT_FRAMEBUFFER = 0x2,
+ TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER =
+ TEXTURE_HINT_IMMUTABLE | TEXTURE_HINT_FRAMEBUFFER
};
enum ResourceType {
- InvalidType = 0,
- GLTexture = 1,
- Bitmap,
+ RESOURCE_TYPE_INVALID = 0,
+ RESOURCE_TYPE_GL_TEXTURE = 1,
+ RESOURCE_TYPE_BITMAP,
};
static scoped_ptr<ResourceProvider> Create(
@@ -150,11 +150,15 @@
// Update pixels from image, copying source_rect (in image) to dest_offset (in
// the resource).
+ // NOTE: DEPRECATED. Use CopyToResource() instead.
void SetPixels(ResourceId id,
const uint8_t* image,
const gfx::Rect& image_rect,
const gfx::Rect& source_rect,
const gfx::Vector2d& dest_offset);
+ void CopyToResource(ResourceId id,
+ const uint8_t* image,
+ const gfx::Size& image_size);
// Check upload status.
size_t NumBlockingUploads();
@@ -434,7 +438,7 @@
private:
struct Resource {
- enum Origin { Internal, External, Delegated };
+ enum Origin { INTERNAL, EXTERNAL, DELEGATED };
Resource();
~Resource();
@@ -547,8 +551,8 @@
ResourceId id,
TransferableResource* resource);
enum DeleteStyle {
- Normal,
- ForShutdown,
+ NORMAL,
+ FOR_SHUTDOWN,
};
void DeleteResourceInternal(ResourceMap::iterator it, DeleteStyle style);
void DeleteAndReturnUnusedResourcesToChild(ChildMap::iterator child_it,
diff --git a/cc/resources/resource_provider_unittest.cc b/cc/resources/resource_provider_unittest.cc
index 2bba801..fdd7fc0 100644
--- a/cc/resources/resource_provider_unittest.cc
+++ b/cc/resources/resource_provider_unittest.cc
@@ -354,14 +354,14 @@
uint8_t* pixels) {
resource_provider->WaitSyncPointIfNeeded(id);
switch (resource_provider->default_resource_type()) {
- case ResourceProvider::GLTexture: {
+ case ResourceProvider::RESOURCE_TYPE_GL_TEXTURE: {
ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id);
ASSERT_NE(0U, lock_gl.texture_id());
context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id());
context->GetPixels(size, format, pixels);
break;
}
- case ResourceProvider::Bitmap: {
+ case ResourceProvider::RESOURCE_TYPE_BITMAP: {
ResourceProvider::ScopedReadLockSoftware lock_software(resource_provider,
id);
memcpy(pixels,
@@ -369,7 +369,7 @@
lock_software.sk_bitmap()->getSize());
break;
}
- case ResourceProvider::InvalidType:
+ case ResourceProvider::RESOURCE_TYPE_INVALID:
NOTREACHED();
break;
}
@@ -384,7 +384,7 @@
child_context_(NULL),
main_thread_task_runner_(BlockingTaskRunner::Create(NULL)) {
switch (GetParam()) {
- case ResourceProvider::GLTexture: {
+ case ResourceProvider::RESOURCE_TYPE_GL_TEXTURE: {
scoped_ptr<ResourceProviderContext> context3d(
ResourceProviderContext::Create(shared_data_.get()));
context3d_ = context3d.get();
@@ -401,13 +401,13 @@
FakeOutputSurface::Create3d(child_context_owned.Pass());
break;
}
- case ResourceProvider::Bitmap:
+ case ResourceProvider::RESOURCE_TYPE_BITMAP:
output_surface_ = FakeOutputSurface::CreateSoftware(
make_scoped_ptr(new SoftwareOutputDevice));
child_output_surface_ = FakeOutputSurface::CreateSoftware(
make_scoped_ptr(new SoftwareOutputDevice));
break;
- case ResourceProvider::InvalidType:
+ case ResourceProvider::RESOURCE_TYPE_INVALID:
NOTREACHED();
break;
}
@@ -458,7 +458,7 @@
bool* lost_resource,
bool* release_called,
uint32* sync_point) {
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
unsigned texture = child_context_->createTexture();
gpu::Mailbox gpu_mailbox;
child_context_->bindTexture(GL_TEXTURE_2D, texture);
@@ -516,15 +516,14 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_EQ(1, static_cast<int>(resource_provider->num_resources()));
- if (expected_default_type == ResourceProvider::GLTexture)
+ if (expected_default_type == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_EQ(0u, context->NumTextures());
uint8_t data[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
- if (expected_default_type == ResourceProvider::GLTexture)
+ resource_provider->CopyToResource(id, data, size);
+ if (expected_default_type == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_EQ(1u, context->NumTextures());
uint8_t result[4] = { 0 };
@@ -533,7 +532,7 @@
resource_provider->DeleteResource(id);
EXPECT_EQ(0, static_cast<int>(resource_provider->num_resources()));
- if (expected_default_type == ResourceProvider::GLTexture)
+ if (expected_default_type == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_EQ(0u, context->NumTextures());
}
@@ -548,7 +547,7 @@
ASSERT_EQ(16U, pixel_size);
ResourceProvider::ResourceId id = resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t image[16] = { 0 };
gfx::Rect image_rect(size);
@@ -608,8 +607,40 @@
resource_provider_->DeleteResource(id);
}
+TEST_P(ResourceProviderTest, SimpleUpload) {
+ gfx::Size size(2, 2);
+ ResourceFormat format = RGBA_8888;
+ size_t pixel_size = TextureSizeBytes(size, format);
+ ASSERT_EQ(16U, pixel_size);
+
+ ResourceProvider::ResourceId id = resource_provider_->CreateResource(
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
+
+ uint8_t image[16] = {0};
+ resource_provider_->CopyToResource(id, image, size);
+ {
+ uint8_t result[16] = {0};
+ uint8_t expected[16] = {0};
+ GetResourcePixels(resource_provider_.get(), context(), id, size, format,
+ result);
+ EXPECT_EQ(0, memcmp(expected, result, pixel_size));
+ }
+
+ for (uint8_t i = 0; i < pixel_size; ++i)
+ image[i] = i;
+ resource_provider_->CopyToResource(id, image, size);
+ {
+ uint8_t result[16] = {0};
+ uint8_t expected[16] = {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
+ GetResourcePixels(resource_provider_.get(), context(), id, size, format,
+ result);
+ EXPECT_EQ(0, memcmp(expected, result, pixel_size));
+ }
+}
+
TEST_P(ResourceProviderTest, TransferGLResources) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
@@ -617,18 +648,17 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = { 5, 5, 5, 5 };
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
{
ResourceProvider::ScopedWriteLockGpuMemoryBuffer lock(
child_resource_provider_.get(), id3);
@@ -855,16 +885,15 @@
}
TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
gfx::Size size(1, 1);
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = {1, 2, 3, 4};
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -908,7 +937,7 @@
TEST_P(ResourceProviderTest, AllowOverlayTransfersToParent) {
// Overlays only supported on the GL path.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
uint32 sync_point = 0;
@@ -958,7 +987,7 @@
}
TEST_P(ResourceProviderTest, TransferSoftwareResources) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
gfx::Size size(1, 1);
@@ -967,15 +996,14 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = { 5, 5, 5, 5 };
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
scoped_ptr<SharedBitmap> shared_bitmap(CreateAndFillSharedBitmap(
shared_bitmap_manager_.get(), gfx::Size(1, 1), 0));
@@ -1143,7 +1171,7 @@
}
TEST_P(ResourceProviderTest, TransferGLToSoftware) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
scoped_ptr<ResourceProviderContext> child_context_owned(
@@ -1169,10 +1197,9 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider->CopyToResource(id1, data1, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1207,7 +1234,7 @@
}
TEST_P(ResourceProviderTest, TransferInvalidSoftware) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
gfx::Size size(1, 1);
@@ -1216,10 +1243,9 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1264,15 +1290,14 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = {5, 5, 5, 5};
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1286,7 +1311,7 @@
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
@@ -1316,7 +1341,7 @@
resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
@@ -1342,7 +1367,7 @@
EXPECT_EQ(0u, resource_provider_->num_resources());
ASSERT_EQ(2u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, returned_to_child[0].sync_point);
EXPECT_NE(0u, returned_to_child[1].sync_point);
}
@@ -1358,15 +1383,14 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data1[4] = {1, 2, 3, 4};
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id1, data1, size);
ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data2[4] = {5, 5, 5, 5};
- child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id2, data2, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1380,7 +1404,7 @@
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
@@ -1410,7 +1434,7 @@
resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
ASSERT_EQ(2u, list.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
}
@@ -1445,7 +1469,7 @@
EXPECT_EQ(1u, resource_provider_->num_resources());
ASSERT_EQ(1u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, returned_to_child[0].sync_point);
}
EXPECT_FALSE(returned_to_child[0].lost);
@@ -1455,7 +1479,7 @@
// lost at this point, and returned.
resource_provider_ = nullptr;
ASSERT_EQ(1u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_NE(0u, returned_to_child[0].sync_point);
}
EXPECT_TRUE(returned_to_child[0].lost);
@@ -1469,10 +1493,9 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id, data, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1485,7 +1508,7 @@
child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
&list);
ASSERT_EQ(1u, list.size());
- if (GetParam() == ResourceProvider::GLTexture)
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
resource_provider_->ReceiveFromChild(child_id, list);
@@ -1505,7 +1528,7 @@
resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
ASSERT_EQ(1u, returned_to_child.size());
- if (GetParam() == ResourceProvider::GLTexture)
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
EXPECT_NE(0u, returned_to_child[0].sync_point);
child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
}
@@ -1519,10 +1542,9 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
uint8_t data[4] = {1, 2, 3, 4};
- gfx::Rect rect(size);
- child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
+ child_resource_provider_->CopyToResource(id, data, size);
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1672,7 +1694,8 @@
ASSERT_EQ(4U, pixel_size);
ResourceProvider::ResourceId id = child_resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
// The new texture is created with GL_LINEAR.
EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id))
@@ -1695,10 +1718,9 @@
Mock::VerifyAndClearExpectations(child_context);
uint8_t data[4] = { 1, 2, 3, 4 };
- gfx::Rect rect(size);
EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id));
- child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
+ child_resource_provider->CopyToResource(id, data, size);
Mock::VerifyAndClearExpectations(child_context);
// The texture is set to |child_filter| in the child.
@@ -1798,20 +1820,20 @@
};
TEST_P(ResourceProviderTest, TextureFilters_ChildNearestParentLinear) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureFilters::RunTest(GL_NEAREST, GL_LINEAR);
}
TEST_P(ResourceProviderTest, TextureFilters_ChildLinearParentNearest) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureFilters::RunTest(GL_LINEAR, GL_NEAREST);
}
TEST_P(ResourceProviderTest, TransferMailboxResources) {
// Other mailbox transfers tested elsewhere.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
unsigned texture = context()->createTexture();
context()->bindTexture(GL_TEXTURE_2D, texture);
@@ -1943,13 +1965,12 @@
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId resource =
child_resource_provider_->CreateResource(
- size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
format);
child_resource_provider_->AllocateForTesting(resource);
// Expect a GL resource to be lost.
- bool should_lose_resource = GetParam() == ResourceProvider::GLTexture;
+ bool should_lose_resource =
+ GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE;
ReturnedResourceArray returned_to_child;
int child_id =
@@ -1999,9 +2020,7 @@
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId resource =
child_resource_provider_->CreateResource(
- size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
format);
child_resource_provider_->AllocateForTesting(resource);
@@ -2112,7 +2131,7 @@
ASSERT_EQ(1u, returned_to_child.size());
// Losing an output surface only loses hardware resources.
EXPECT_EQ(returned_to_child[0].lost,
- GetParam() == ResourceProvider::GLTexture);
+ GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE);
child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
returned_to_child.clear();
}
@@ -2120,7 +2139,8 @@
// Delete the resource in the child. Expect the resource to be lost if it's
// a GL texture.
child_resource_provider_->DeleteResource(resource);
- EXPECT_EQ(lost_resource, GetParam() == ResourceProvider::GLTexture);
+ EXPECT_EQ(lost_resource,
+ GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE);
}
TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
@@ -2204,7 +2224,7 @@
child_resource_provider_ = nullptr;
- if (GetParam() == ResourceProvider::GLTexture) {
+ if (GetParam() == ResourceProvider::RESOURCE_TYPE_GL_TEXTURE) {
EXPECT_LE(sync_point, release_sync_point);
}
EXPECT_TRUE(release_called);
@@ -2238,7 +2258,7 @@
TEST_P(ResourceProviderTest, LostContext) {
// TextureMailbox callbacks only exist for GL textures for now.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
unsigned texture = context()->createTexture();
context()->bindTexture(GL_TEXTURE_2D, texture);
@@ -2274,7 +2294,7 @@
TEST_P(ResourceProviderTest, ScopedSampler) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2300,7 +2320,7 @@
int texture_id = 1;
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
// Check that the texture gets created with the right sampler settings.
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id))
@@ -2361,7 +2381,7 @@
TEST_P(ResourceProviderTest, ManagedResource) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2388,11 +2408,8 @@
// Check that the texture gets created with the right sampler settings.
ResourceProvider::ResourceId id = resource_provider->CreateManagedResource(
- size,
- GL_TEXTURE_2D,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- format);
+ size, GL_TEXTURE_2D, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
EXPECT_CALL(*context,
texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
@@ -2416,7 +2433,7 @@
TEST_P(ResourceProviderTest, TextureWrapMode) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2445,12 +2462,8 @@
GLint wrap_mode = texture_id == 1 ? GL_CLAMP_TO_EDGE : GL_REPEAT;
// Check that the texture gets created with the right sampler settings.
ResourceProvider::ResourceId id = resource_provider->CreateGLTexture(
- size,
- GL_TEXTURE_2D,
- texture_pool,
- wrap_mode,
- ResourceProvider::TextureHintImmutable,
- format);
+ size, GL_TEXTURE_2D, texture_pool, wrap_mode,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
EXPECT_CALL(*context,
texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
@@ -2473,7 +2486,7 @@
TEST_P(ResourceProviderTest, TextureHint) {
// Sampling is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2501,10 +2514,10 @@
GLenum texture_pool = GL_TEXTURE_POOL_UNMANAGED_CHROMIUM;
const ResourceProvider::TextureHint hints[4] = {
- ResourceProvider::TextureHintDefault,
- ResourceProvider::TextureHintImmutable,
- ResourceProvider::TextureHintFramebuffer,
- ResourceProvider::TextureHintImmutableFramebuffer,
+ ResourceProvider::TEXTURE_HINT_DEFAULT,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ ResourceProvider::TEXTURE_HINT_FRAMEBUFFER,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
};
for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) {
// Check that the texture gets created with the right sampler settings.
@@ -2530,9 +2543,9 @@
texParameteri(GL_TEXTURE_2D,
GL_TEXTURE_POOL_CHROMIUM,
GL_TEXTURE_POOL_UNMANAGED_CHROMIUM));
- // Check only TextureHintFramebuffer set GL_TEXTURE_USAGE_ANGLE.
+ // Check only TEXTURE_HINT_FRAMEBUFFER set GL_TEXTURE_USAGE_ANGLE.
bool is_framebuffer_hint =
- hints[texture_id - 1] & ResourceProvider::TextureHintFramebuffer;
+ hints[texture_id - 1] & ResourceProvider::TEXTURE_HINT_FRAMEBUFFER;
EXPECT_CALL(*context,
texParameteri(GL_TEXTURE_2D,
GL_TEXTURE_USAGE_ANGLE,
@@ -2546,7 +2559,7 @@
}
TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) {
- if (GetParam() != ResourceProvider::Bitmap)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_BITMAP)
return;
gfx::Size size(64, 64);
@@ -2700,7 +2713,7 @@
TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_LinearToLinear) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureMailboxGLFilters::RunTest(
@@ -2713,7 +2726,7 @@
TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_NearestToNearest) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureMailboxGLFilters::RunTest(
@@ -2726,7 +2739,7 @@
TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_NearestToLinear) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureMailboxGLFilters::RunTest(
@@ -2739,7 +2752,7 @@
TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D_LinearToNearest) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
ResourceProviderTestTextureMailboxGLFilters::RunTest(
@@ -2752,7 +2765,7 @@
TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2827,7 +2840,7 @@
TEST_P(ResourceProviderTest,
TextureMailbox_WaitSyncPointIfNeeded_WithSyncPoint) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -2886,7 +2899,7 @@
TEST_P(ResourceProviderTest, TextureMailbox_WaitSyncPointIfNeeded_NoSyncPoint) {
// Mailboxing is only supported for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<TextureStateTrackingContext> context_owned(
@@ -3013,7 +3026,7 @@
TEST_P(ResourceProviderTest, TextureAllocation) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3035,7 +3048,6 @@
gfx::Size size(2, 2);
gfx::Vector2d offset(0, 0);
- gfx::Rect rect(0, 0, 2, 2);
ResourceFormat format = RGBA_8888;
ResourceProvider::ResourceId id = 0;
uint8_t pixels[16] = { 0 };
@@ -3043,7 +3055,7 @@
// Lazy allocation. Don't allocate when creating the resource.
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1);
@@ -3056,13 +3068,13 @@
// Do allocate when we set the pixels.
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1);
EXPECT_CALL(*context, texSubImage2D(_, _, _, _, 2, 2, _, _, _)).Times(1);
- resource_provider->SetPixels(id, pixels, rect, rect, offset);
+ resource_provider->CopyToResource(id, pixels, size);
EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
resource_provider->DeleteResource(id);
@@ -3071,7 +3083,7 @@
// Same for async version.
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
resource_provider->AcquirePixelBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
@@ -3091,7 +3103,7 @@
TEST_P(ResourceProviderTest, TextureAllocationHint) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3117,10 +3129,10 @@
const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888};
const ResourceProvider::TextureHint hints[4] = {
- ResourceProvider::TextureHintDefault,
- ResourceProvider::TextureHintImmutable,
- ResourceProvider::TextureHintFramebuffer,
- ResourceProvider::TextureHintImmutableFramebuffer,
+ ResourceProvider::TEXTURE_HINT_DEFAULT,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ ResourceProvider::TEXTURE_HINT_FRAMEBUFFER,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
};
for (size_t i = 0; i < arraysize(formats); ++i) {
for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) {
@@ -3131,7 +3143,7 @@
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
bool is_immutable_hint =
- hints[texture_id - 1] & ResourceProvider::TextureHintImmutable;
+ hints[texture_id - 1] & ResourceProvider::TEXTURE_HINT_IMMUTABLE;
bool support_immutable_texture =
is_immutable_hint && formats[i] == RGBA_8888;
EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2))
@@ -3150,7 +3162,7 @@
TEST_P(ResourceProviderTest, TextureAllocationHint_BGRA) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3177,10 +3189,10 @@
const ResourceFormat formats[2] = {RGBA_8888, BGRA_8888};
const ResourceProvider::TextureHint hints[4] = {
- ResourceProvider::TextureHintDefault,
- ResourceProvider::TextureHintImmutable,
- ResourceProvider::TextureHintFramebuffer,
- ResourceProvider::TextureHintImmutableFramebuffer,
+ ResourceProvider::TEXTURE_HINT_DEFAULT,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ ResourceProvider::TEXTURE_HINT_FRAMEBUFFER,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE_FRAMEBUFFER,
};
for (size_t i = 0; i < arraysize(formats); ++i) {
for (GLuint texture_id = 1; texture_id <= arraysize(hints); ++texture_id) {
@@ -3191,7 +3203,7 @@
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
bool is_immutable_hint =
- hints[texture_id - 1] & ResourceProvider::TextureHintImmutable;
+ hints[texture_id - 1] & ResourceProvider::TEXTURE_HINT_IMMUTABLE;
EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2))
.Times(is_immutable_hint ? 1 : 0);
EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _))
@@ -3207,7 +3219,7 @@
}
TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3233,7 +3245,7 @@
1));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
resource_provider->AcquirePixelBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
@@ -3254,7 +3266,7 @@
TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3280,7 +3292,7 @@
1));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
resource_provider->AcquirePixelBuffer(id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
@@ -3329,7 +3341,7 @@
EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
GL_INNOCENT_CONTEXT_RESET_ARB);
@@ -3343,7 +3355,7 @@
TEST_P(ResourceProviderTest, Image_GLTexture) {
// Only for GL textures.
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3372,7 +3384,7 @@
1));
id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA))
.WillOnce(Return(kImageId))
@@ -3427,7 +3439,7 @@
}
TEST_P(ResourceProviderTest, CopyResource_GLTexture) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
new StrictMock<AllocationTrackingContext3D>);
@@ -3459,7 +3471,7 @@
1));
source_id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, createImageCHROMIUM(_, kWidth, kHeight, GL_RGBA))
.WillOnce(Return(kImageId))
@@ -3472,7 +3484,7 @@
Mock::VerifyAndClearExpectations(context);
dest_id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
EXPECT_CALL(*context, NextTextureId())
.WillOnce(Return(kDestTextureId))
@@ -3521,7 +3533,8 @@
output_surface->InitializeAndSetContext3d(context_provider, nullptr);
resource_provider->InitializeGL();
- CheckCreateResource(ResourceProvider::GLTexture, resource_provider, context);
+ CheckCreateResource(ResourceProvider::RESOURCE_TYPE_GL_TEXTURE,
+ resource_provider, context);
}
TEST(ResourceProviderTest, BasicInitializeGLSoftware) {
@@ -3544,7 +3557,8 @@
false,
1));
- CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
+ CheckCreateResource(ResourceProvider::RESOURCE_TYPE_BITMAP,
+ resource_provider.get(), NULL);
InitializeGLAndCheck(shared_data.get(),
resource_provider.get(),
@@ -3552,7 +3566,8 @@
resource_provider->InitializeSoftware();
output_surface->ReleaseGL();
- CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
+ CheckCreateResource(ResourceProvider::RESOURCE_TYPE_BITMAP,
+ resource_provider.get(), NULL);
InitializeGLAndCheck(shared_data.get(),
resource_provider.get(),
@@ -3560,7 +3575,7 @@
}
TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) {
- if (GetParam() != ResourceProvider::GLTexture)
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
@@ -3585,7 +3600,7 @@
int texture_id = 123;
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, ETC1);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, ETC1);
EXPECT_NE(0u, id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
@@ -3595,8 +3610,8 @@
resource_provider->DeleteResource(id);
}
-TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) {
- if (GetParam() != ResourceProvider::GLTexture)
+TEST_P(ResourceProviderTest, CompressedTextureETC1Upload) {
+ if (GetParam() != ResourceProvider::RESOURCE_TYPE_GL_TEXTURE)
return;
scoped_ptr<AllocationTrackingContext3D> context_owned(
@@ -3622,15 +3637,14 @@
uint8_t pixels[8];
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, ETC1);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE, ETC1);
EXPECT_NE(0u, id);
EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
EXPECT_CALL(*context,
compressedTexImage2D(
_, 0, _, size.width(), size.height(), _, _, _)).Times(1);
- resource_provider->SetPixels(
- id, pixels, gfx::Rect(size), gfx::Rect(size), gfx::Vector2d(0, 0));
+ resource_provider->CopyToResource(id, pixels, size);
EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
resource_provider->DeleteResource(id);
@@ -3639,7 +3653,8 @@
INSTANTIATE_TEST_CASE_P(
ResourceProviderTests,
ResourceProviderTest,
- ::testing::Values(ResourceProvider::GLTexture, ResourceProvider::Bitmap));
+ ::testing::Values(ResourceProvider::RESOURCE_TYPE_GL_TEXTURE,
+ ResourceProvider::RESOURCE_TYPE_BITMAP));
class TextureIdAllocationTrackingContext : public TestWebGraphicsContext3D {
public:
@@ -3681,7 +3696,8 @@
kTextureAllocationChunkSize));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
resource_provider->AllocateForTesting(id);
Mock::VerifyAndClearExpectations(context);
@@ -3701,7 +3717,8 @@
kTextureAllocationChunkSize));
ResourceProvider::ResourceId id = resource_provider->CreateResource(
- size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureHintImmutable, format);
+ size, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
resource_provider->AllocateForTesting(id);
Mock::VerifyAndClearExpectations(context);
diff --git a/cc/resources/scoped_resource.cc b/cc/resources/scoped_resource.cc
index 3b13559..e701182 100644
--- a/cc/resources/scoped_resource.cc
+++ b/cc/resources/scoped_resource.cc
@@ -38,10 +38,7 @@
set_dimensions(size, format);
set_id(resource_provider_->CreateManagedResource(
- size,
- target,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ size, target, GL_CLAMP_TO_EDGE, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
format));
#if DCHECK_IS_ON()
diff --git a/cc/resources/scoped_resource_unittest.cc b/cc/resources/scoped_resource_unittest.cc
index a141218..b95d814 100644
--- a/cc/resources/scoped_resource_unittest.cc
+++ b/cc/resources/scoped_resource_unittest.cc
@@ -57,8 +57,8 @@
1));
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
- texture->Allocate(
- gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888);
+ texture->Allocate(gfx::Size(30, 30), ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
// The texture has an allocated byte-size now.
size_t expected_bytes = 30 * 30 * 4;
@@ -89,8 +89,8 @@
ScopedResource::Create(resource_provider.get());
EXPECT_EQ(0u, resource_provider->num_resources());
- texture->Allocate(
- gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888);
+ texture->Allocate(gfx::Size(30, 30),
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
EXPECT_LT(0u, texture->id());
EXPECT_EQ(1u, resource_provider->num_resources());
}
@@ -100,8 +100,8 @@
scoped_ptr<ScopedResource> texture =
ScopedResource::Create(resource_provider.get());
EXPECT_EQ(0u, resource_provider->num_resources());
- texture->Allocate(
- gfx::Size(30, 30), ResourceProvider::TextureHintImmutable, RGBA_8888);
+ texture->Allocate(gfx::Size(30, 30),
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
EXPECT_LT(0u, texture->id());
EXPECT_EQ(1u, resource_provider->num_resources());
texture->Free();
diff --git a/cc/resources/texture_uploader.cc b/cc/resources/texture_uploader.cc
index 3d0f681..601fa8f 100644
--- a/cc/resources/texture_uploader.cc
+++ b/cc/resources/texture_uploader.cc
@@ -146,14 +146,7 @@
if (is_full_upload)
BeginQuery();
- if (format == ETC1) {
- // ETC1 does not support subimage uploads.
- DCHECK(is_full_upload);
- UploadWithTexImageETC1(image, size);
- } else {
- UploadWithMapTexSubImage(
- image, image_rect, source_rect, dest_offset, format);
- }
+ UploadWithMapTexSubImage(image, image_rect, source_rect, dest_offset, format);
if (is_full_upload)
EndQuery();
@@ -291,22 +284,6 @@
gl_->UnmapTexSubImage2DCHROMIUM(pixel_dest);
}
-void TextureUploader::UploadWithTexImageETC1(const uint8* image,
- const gfx::Size& size) {
- TRACE_EVENT0("cc", "TextureUploader::UploadWithTexImageETC1");
- DCHECK_EQ(0, size.width() % 4);
- DCHECK_EQ(0, size.height() % 4);
-
- gl_->CompressedTexImage2D(GL_TEXTURE_2D,
- 0,
- GLInternalFormat(ETC1),
- size.width(),
- size.height(),
- 0,
- Resource::MemorySizeBytes(size, ETC1),
- image);
-}
-
void TextureUploader::ProcessQueries() {
while (!pending_queries_.empty()) {
if (pending_queries_.front()->IsPending())
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index 39d48a8..1576047 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -39,7 +39,7 @@
id_(s_next_id_++),
scheduled_priority_(0) {
set_raster_source(raster_source);
- for (int i = 0; i < NUM_TREES; i++)
+ for (int i = 0; i <= LAST_TREE; i++)
is_occluded_[i] = false;
}
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index 698f43d..c3ca623 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -88,7 +88,7 @@
bool HasResource() const { return draw_info_.has_resource(); }
bool NeedsRaster() const {
- return draw_info_.mode() == TileDrawInfo::PICTURE_PILE_MODE ||
+ return draw_info_.mode() == TileDrawInfo::OOM_MODE ||
!draw_info_.IsReadyToDraw();
}
@@ -150,9 +150,9 @@
gfx::Size desired_texture_size_;
gfx::Rect content_rect_;
float contents_scale_;
- bool is_occluded_[NUM_TREES];
+ bool is_occluded_[LAST_TREE + 1];
- TilePriority priority_[NUM_TREES];
+ TilePriority priority_[LAST_TREE + 1];
TileDrawInfo draw_info_;
int layer_id_;
diff --git a/cc/resources/tile_draw_info.cc b/cc/resources/tile_draw_info.cc
index 7761d72..e75ea59 100644
--- a/cc/resources/tile_draw_info.cc
+++ b/cc/resources/tile_draw_info.cc
@@ -21,7 +21,7 @@
case RESOURCE_MODE:
return !!resource_;
case SOLID_COLOR_MODE:
- case PICTURE_PILE_MODE:
+ case OOM_MODE:
return true;
}
NOTREACHED();
diff --git a/cc/resources/tile_draw_info.h b/cc/resources/tile_draw_info.h
index 54ca946..0c6bbf6 100644
--- a/cc/resources/tile_draw_info.h
+++ b/cc/resources/tile_draw_info.h
@@ -17,7 +17,7 @@
// This class holds all the state relevant to drawing a tile.
class CC_EXPORT TileDrawInfo {
public:
- enum Mode { RESOURCE_MODE, SOLID_COLOR_MODE, PICTURE_PILE_MODE };
+ enum Mode { RESOURCE_MODE, SOLID_COLOR_MODE, OOM_MODE };
TileDrawInfo();
~TileDrawInfo();
@@ -49,7 +49,7 @@
}
bool requires_resource() const {
- return mode_ == RESOURCE_MODE || mode_ == PICTURE_PILE_MODE;
+ return mode_ == RESOURCE_MODE || mode_ == OOM_MODE;
}
inline bool has_resource() const { return !!resource_; }
@@ -72,7 +72,7 @@
solid_color_ = color;
}
- void set_rasterize_on_demand() { mode_ = PICTURE_PILE_MODE; }
+ void set_oom() { mode_ = OOM_MODE; }
Mode mode_;
SkColor solid_color_;
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 94b6332..00ae3da 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -439,11 +439,11 @@
global_state_.tree_priority,
RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
- // Use on-demand raster for any tiles that have not been been assigned
- // memory. This ensures that we draw even when OOM.
+ // Change to OOM mode for any tiles that have not been been assigned memory.
+ // This ensures that we draw even when OOM.
for (; !required_for_draw_queue->IsEmpty(); required_for_draw_queue->Pop()) {
Tile* tile = required_for_draw_queue->Top();
- tile->draw_info().set_rasterize_on_demand();
+ tile->draw_info().set_oom();
client_->NotifyTileStateChanged(tile);
}
@@ -604,8 +604,8 @@
TileDrawInfo& draw_info = tile->draw_info();
tile->scheduled_priority_ = schedule_priority++;
- DCHECK(draw_info.mode() == TileDrawInfo::PICTURE_PILE_MODE ||
- !draw_info.IsReadyToDraw());
+ DCHECK_IMPLIES(draw_info.mode() != TileDrawInfo::OOM_MODE,
+ !draw_info.IsReadyToDraw());
// If the tile already has a raster_task, then the memory used by it is
// already accounted for in memory_usage. Otherwise, we'll have to acquire
@@ -973,31 +973,30 @@
// Likewise if we don't allow any tiles (as is the case when we're
// invisible), if we have tiles that aren't ready, then we shouldn't
// activate as activation can cause checkerboards.
- bool allow_rasterize_on_demand =
- global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
- global_state_.memory_limit_policy != ALLOW_NOTHING;
+ bool wait_for_all_required_tiles =
+ global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
+ global_state_.memory_limit_policy == ALLOW_NOTHING;
- // Use on-demand raster for any required-for-activation tiles that have
- // not been been assigned memory after reaching a steady memory state. This
- // ensures that we activate even when OOM. Note that we can't reuse the queue
- // we used for AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call
- // could have evicted some tiles that would not be picked up by the old raster
- // queue.
+ // Mark any required-for-activation tiles that have not been been assigned
+ // memory after reaching a steady memory state as OOM. This ensures that we
+ // activate even when OOM. Note that we can't reuse the queue we used for
+ // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
+ // evicted some tiles that would not be picked up by the old raster queue.
scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
client_->BuildRasterQueue(
global_state_.tree_priority,
RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
- // If we have tiles to mark as rasterize on demand, but we don't allow
- // rasterize on demand, then skip activation and return early.
- if (!required_for_activation_queue->IsEmpty() && !allow_rasterize_on_demand)
+ // If we have tiles left to raster for activation, and we don't allow
+ // activating without them, then skip activation and return early.
+ if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles)
return;
- // Mark required tiles as rasterize on demand.
+ // Mark required tiles as OOM so that we can activate without them.
for (; !required_for_activation_queue->IsEmpty();
required_for_activation_queue->Pop()) {
Tile* tile = required_for_activation_queue->Top();
- tile->draw_info().set_rasterize_on_demand();
+ tile->draw_info().set_oom();
client_->NotifyTileStateChanged(tile);
}
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 7c316ac..87d1837 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -355,7 +355,8 @@
++next_id;
}
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
for (FakePictureLayerImpl* layer : layers)
layer->CreateAllTiles();
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index 4f441b3..19ccf24 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -127,7 +127,8 @@
host_impl_.pending_tree()->LayerById(id_));
// Add tilings/tiles for the layer.
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
}
TileManager* tile_manager() { return host_impl_.tile_manager(); }
@@ -541,7 +542,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
host_impl_.SetRequiresHighResToDraw();
scoped_ptr<RasterTilePriorityQueue> queue(host_impl_.BuildRasterQueue(
@@ -771,7 +773,8 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
ActivateTree();
SetupPendingTree(pending_pile);
@@ -909,14 +912,15 @@
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
pending_child_layer->SetOpacity(0.0);
time_ticks += base::TimeDelta::FromMilliseconds(1);
host_impl_.SetCurrentBeginFrameArgs(
CreateBeginFrameArgsForTesting(BEGINFRAME_FROM_HERE, time_ticks));
- host_impl_.pending_tree()->UpdateDrawProperties();
+ host_impl_.pending_tree()->UpdateDrawProperties(update_lcd_text);
// Renew all of the tile priorities.
gfx::Rect viewport(layer_bounds);
diff --git a/cc/resources/tile_priority.h b/cc/resources/tile_priority.h
index 5067aa6..5247b3c 100644
--- a/cc/resources/tile_priority.h
+++ b/cc/resources/tile_priority.h
@@ -24,7 +24,7 @@
// e.g. in Tile::priority_.
ACTIVE_TREE = 0,
PENDING_TREE = 1,
- NUM_TREES = 2
+ LAST_TREE = 1
// Be sure to update WhichTreeAsValue when adding new fields.
};
scoped_ptr<base::Value> WhichTreeAsValue(WhichTree tree);
@@ -118,7 +118,7 @@
SAME_PRIORITY_FOR_BOTH_TREES,
SMOOTHNESS_TAKES_PRIORITY,
NEW_CONTENT_TAKES_PRIORITY,
- NUM_TREE_PRIORITIES
+ LAST_TREE_PRIORITY = NEW_CONTENT_TAKES_PRIORITY
// Be sure to update TreePriorityAsValue when adding new fields.
};
std::string TreePriorityToString(TreePriority prio);
diff --git a/cc/resources/tile_task_worker_pool_perftest.cc b/cc/resources/tile_task_worker_pool_perftest.cc
index 450bcbe..71da7b1 100644
--- a/cc/resources/tile_task_worker_pool_perftest.cc
+++ b/cc/resources/tile_task_worker_pool_perftest.cc
@@ -206,7 +206,7 @@
for (unsigned i = 0; i < num_raster_tasks; ++i) {
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(size, ResourceProvider::TextureHintImmutable,
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888);
ImageDecodeTask::Vector dependencies = image_decode_tasks;
@@ -270,6 +270,8 @@
break;
case TILE_TASK_WORKER_POOL_TYPE_GPU:
Create3dOutputSurfaceAndResourceProvider();
+ rasterizer_ = GpuRasterizer::Create(
+ context_provider_.get(), resource_provider_.get(), false, false, 0);
tile_task_worker_pool_ = GpuTileTaskWorkerPool::Create(
task_runner_.get(), task_graph_runner_.get(),
static_cast<GpuRasterizer*>(rasterizer_.get()));
diff --git a/cc/resources/tile_task_worker_pool_unittest.cc b/cc/resources/tile_task_worker_pool_unittest.cc
index 1e84674..d7cb155 100644
--- a/cc/resources/tile_task_worker_pool_unittest.cc
+++ b/cc/resources/tile_task_worker_pool_unittest.cc
@@ -240,7 +240,8 @@
void AppendTask(unsigned id, const gfx::Size& size) {
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
const Resource* const_resource = resource.get();
ImageDecodeTask::Vector empty;
@@ -258,7 +259,8 @@
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
const Resource* const_resource = resource.get();
ImageDecodeTask::Vector empty;
@@ -387,7 +389,8 @@
// Verify a resource of this size is larger than the transfer buffer.
scoped_ptr<ScopedResource> resource(
ScopedResource::Create(resource_provider_.get()));
- resource->Allocate(size, ResourceProvider::TextureHintImmutable, RGBA_8888);
+ resource->Allocate(size, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ RGBA_8888);
EXPECT_GE(resource->bytes(), kMaxTransferBufferUsageBytes);
}
diff --git a/cc/resources/tiling_set_eviction_queue.cc b/cc/resources/tiling_set_eviction_queue.cc
index f13c915..1f0e213 100644
--- a/cc/resources/tiling_set_eviction_queue.cc
+++ b/cc/resources/tiling_set_eviction_queue.cc
@@ -330,9 +330,6 @@
return false;
case SAME_PRIORITY_FOR_BOTH_TREES:
break;
- case NUM_TREE_PRIORITIES:
- NOTREACHED();
- break;
}
// The priority for tile priority of a shared tile will be a combined
diff --git a/cc/resources/ui_resource_request.h b/cc/resources/ui_resource_request.h
index 6d89761..b89e567 100644
--- a/cc/resources/ui_resource_request.h
+++ b/cc/resources/ui_resource_request.h
@@ -16,9 +16,9 @@
class CC_EXPORT UIResourceRequest {
public:
enum UIResourceRequestType {
- UIResourceCreate,
- UIResourceDelete,
- UIResourceInvalidRequest
+ UI_RESOURCE_CREATE,
+ UI_RESOURCE_DELETE,
+ UI_RESOURCE_INVALID_REQUEST
};
UIResourceRequest(UIResourceRequestType type, UIResourceId id);
diff --git a/cc/resources/video_resource_updater.cc b/cc/resources/video_resource_updater.cc
index 0e772eb..1b089df 100644
--- a/cc/resources/video_resource_updater.cc
+++ b/cc/resources/video_resource_updater.cc
@@ -8,6 +8,7 @@
#include "base/bind.h"
#include "base/trace_event/trace_event.h"
+#include "cc/base/util.h"
#include "cc/output/gl_renderer.h"
#include "cc/resources/resource_provider.h"
#include "gpu/GLES2/gl2extchromium.h"
@@ -95,9 +96,9 @@
// TODO(danakj): Abstract out hw/sw resource create/delete from
// ResourceProvider and stop using ResourceProvider in this class.
const ResourceProvider::ResourceId resource_id =
- resource_provider_->CreateResource(plane_size, GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- format);
+ resource_provider_->CreateResource(
+ plane_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, format);
if (resource_id == 0)
return all_resources_.end();
@@ -317,14 +318,41 @@
if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) {
// We need to transfer data from |video_frame| to the plane resource.
- const uint8_t* input_plane_pixels = video_frame->data(i);
+ // TODO(reveman): Can use GpuMemoryBuffers here to improve performance.
- gfx::Rect image_rect(0, 0, video_frame->stride(i),
- plane_resource.resource_size.height());
- gfx::Rect source_rect(plane_resource.resource_size);
- resource_provider_->SetPixels(plane_resource.resource_id,
- input_plane_pixels, image_rect, source_rect,
- gfx::Vector2d());
+ // The |resource_size_pixels| is the size of the resource we want to
+ // upload to.
+ gfx::Size resource_size_pixels = plane_resource.resource_size;
+ // The |video_stride_pixels| is the width of the video frame we are
+ // uploading (including non-frame data to fill in the stride).
+ size_t video_stride_pixels = video_frame->stride(i);
+
+ size_t bytes_per_pixel = BitsPerPixel(plane_resource.resource_format) / 8;
+ // Use 4-byte row alignment (OpenGL default) for upload performance.
+ // Assuming that GL_UNPACK_ALIGNMENT has not changed from default.
+ size_t upload_image_stride =
+ RoundUp<size_t>(bytes_per_pixel * resource_size_pixels.width(), 4u);
+
+ const uint8_t* pixels;
+ if (upload_image_stride == video_stride_pixels * bytes_per_pixel) {
+ pixels = video_frame->data(i);
+ } else {
+ // Avoid malloc for each frame/plane if possible.
+ size_t needed_size =
+ upload_image_stride * resource_size_pixels.height();
+ if (upload_pixels_.size() < needed_size)
+ upload_pixels_.resize(needed_size);
+ for (int row = 0; row < resource_size_pixels.height(); ++row) {
+ uint8_t* dst = &upload_pixels_[upload_image_stride * row];
+ const uint8_t* src = video_frame->data(i) +
+ bytes_per_pixel * video_stride_pixels * row;
+ memcpy(dst, src, resource_size_pixels.width() * bytes_per_pixel);
+ }
+ pixels = &upload_pixels_[0];
+ }
+
+ resource_provider_->CopyToResource(plane_resource.resource_id, pixels,
+ resource_size_pixels);
SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resource);
}
diff --git a/cc/resources/video_resource_updater.h b/cc/resources/video_resource_updater.h
index 622fe68..1bccf79 100644
--- a/cc/resources/video_resource_updater.h
+++ b/cc/resources/video_resource_updater.h
@@ -131,6 +131,7 @@
ContextProvider* context_provider_;
ResourceProvider* resource_provider_;
scoped_ptr<media::SkCanvasVideoRenderer> video_renderer_;
+ std::vector<uint8_t> upload_pixels_;
// Recycle resources so that we can reduce the number of allocations and
// data transfers.
diff --git a/cc/resources/video_resource_updater_unittest.cc b/cc/resources/video_resource_updater_unittest.cc
index 5433bcf..2098357 100644
--- a/cc/resources/video_resource_updater_unittest.cc
+++ b/cc/resources/video_resource_updater_unittest.cc
@@ -38,6 +38,21 @@
int upload_count_;
};
+class SharedBitmapManagerAllocationCounter : public TestSharedBitmapManager {
+ public:
+ scoped_ptr<SharedBitmap> AllocateSharedBitmap(
+ const gfx::Size& size) override {
+ ++allocation_count_;
+ return TestSharedBitmapManager::AllocateSharedBitmap(size);
+ }
+
+ int AllocationCount() { return allocation_count_; }
+ void ResetAllocationCount() { allocation_count_ = 0; }
+
+ private:
+ int allocation_count_;
+};
+
class VideoResourceUpdaterTest : public testing::Test {
protected:
VideoResourceUpdaterTest() {
@@ -49,7 +64,12 @@
output_surface3d_ =
FakeOutputSurface::Create3d(context3d.Pass());
CHECK(output_surface3d_->BindToClient(&client_));
- shared_bitmap_manager_.reset(new TestSharedBitmapManager());
+
+ output_surface_software_ = FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
+ CHECK(output_surface_software_->BindToClient(&client_));
+
+ shared_bitmap_manager_.reset(new SharedBitmapManagerAllocationCounter());
resource_provider3d_ =
ResourceProvider::Create(output_surface3d_.get(),
shared_bitmap_manager_.get(),
@@ -58,6 +78,10 @@
0,
false,
1);
+
+ resource_provider_software_ = ResourceProvider::Create(
+ output_surface_software_.get(), shared_bitmap_manager_.get(), NULL,
+ NULL, 0, false, 1);
}
scoped_refptr<media::VideoFrame> CreateTestYUVVideoFrame() {
@@ -85,8 +109,10 @@
WebGraphicsContext3DUploadCounter* context3d_;
FakeOutputSurfaceClient client_;
scoped_ptr<FakeOutputSurface> output_surface3d_;
- scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
+ scoped_ptr<FakeOutputSurface> output_surface_software_;
+ scoped_ptr<SharedBitmapManagerAllocationCounter> shared_bitmap_manager_;
scoped_ptr<ResourceProvider> resource_provider3d_;
+ scoped_ptr<ResourceProvider> resource_provider_software_;
};
TEST_F(VideoResourceUpdaterTest, SoftwareFrame) {
@@ -112,6 +138,7 @@
EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
EXPECT_EQ(size_t(3), resources.mailboxes.size());
EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(0), resources.software_resources.size());
// Expect exactly three texture uploads, one for each plane.
EXPECT_EQ(3, context3d_->UploadCount());
@@ -143,6 +170,7 @@
EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE, resources.type);
EXPECT_EQ(size_t(3), resources.mailboxes.size());
EXPECT_EQ(size_t(3), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(0), resources.software_resources.size());
// Expect exactly three texture uploads, one for each plane.
EXPECT_EQ(3, context3d_->UploadCount());
@@ -156,5 +184,72 @@
EXPECT_EQ(0, context3d_->UploadCount());
}
+TEST_F(VideoResourceUpdaterTest, SoftwareFrameSoftwareCompositor) {
+ VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
+ scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
+
+ VideoFrameExternalResources resources =
+ updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+}
+
+TEST_F(VideoResourceUpdaterTest, ReuseResourceSoftwareCompositor) {
+ VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
+ scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
+ video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
+
+ // Allocate the resources for a software video frame.
+ shared_bitmap_manager_->ResetAllocationCount();
+ VideoFrameExternalResources resources =
+ updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // Expect exactly one allocated shared bitmap.
+ EXPECT_EQ(1, shared_bitmap_manager_->AllocationCount());
+
+ // Simulate the ResourceProvider releasing the resource back to the video
+ // updater.
+ resources.software_release_callback.Run(0, false, nullptr);
+
+ // Allocate resources for the same frame.
+ shared_bitmap_manager_->ResetAllocationCount();
+ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // The data should be reused so expect no new allocations.
+ EXPECT_EQ(0, shared_bitmap_manager_->AllocationCount());
+}
+
+TEST_F(VideoResourceUpdaterTest, ReuseResourceNoDeleteSoftwareCompositor) {
+ VideoResourceUpdater updater(nullptr, resource_provider_software_.get());
+ scoped_refptr<media::VideoFrame> video_frame = CreateTestYUVVideoFrame();
+ video_frame->set_timestamp(base::TimeDelta::FromSeconds(1234));
+
+ // Allocate the resources for a software video frame.
+ shared_bitmap_manager_->ResetAllocationCount();
+ VideoFrameExternalResources resources =
+ updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // Expect exactly one allocated shared bitmap.
+ EXPECT_EQ(1, shared_bitmap_manager_->AllocationCount());
+
+ // Allocate resources for the same frame.
+ shared_bitmap_manager_->ResetAllocationCount();
+ resources = updater.CreateExternalResourcesFromVideoFrame(video_frame);
+ EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE, resources.type);
+ EXPECT_EQ(size_t(0), resources.mailboxes.size());
+ EXPECT_EQ(size_t(0), resources.release_callbacks.size());
+ EXPECT_EQ(size_t(1), resources.software_resources.size());
+ // The data should be reused so expect no new allocations.
+ EXPECT_EQ(0, shared_bitmap_manager_->AllocationCount());
+}
+
} // namespace
} // namespace cc
diff --git a/cc/scheduler/scheduler.cc b/cc/scheduler/scheduler.cc
index ed8c0a2..904a057 100644
--- a/cc/scheduler/scheduler.cc
+++ b/cc/scheduler/scheduler.cc
@@ -335,6 +335,9 @@
if (state_machine_.ShouldSetNeedsBeginFrames(
frame_source_->NeedsBeginFrames())) {
frame_source_->SetNeedsBeginFrames(state_machine_.BeginFrameNeeded());
+ if (!frame_source_->NeedsBeginFrames()) {
+ client_->SendBeginMainFrameNotExpectedSoon();
+ }
}
if (state_machine_.begin_impl_frame_state() ==
diff --git a/cc/scheduler/scheduler.h b/cc/scheduler/scheduler.h
index 82f305a..370ac25 100644
--- a/cc/scheduler/scheduler.h
+++ b/cc/scheduler/scheduler.h
@@ -49,6 +49,7 @@
virtual base::TimeDelta CommitToActivateDurationEstimate() = 0;
virtual void DidBeginImplFrameDeadline() = 0;
virtual void SendBeginFramesToChildren(const BeginFrameArgs& args) = 0;
+ virtual void SendBeginMainFrameNotExpectedSoon() = 0;
protected:
virtual ~SchedulerClient() {}
diff --git a/cc/scheduler/scheduler_unittest.cc b/cc/scheduler/scheduler_unittest.cc
index ac52271..50cc846 100644
--- a/cc/scheduler/scheduler_unittest.cc
+++ b/cc/scheduler/scheduler_unittest.cc
@@ -161,6 +161,10 @@
begin_frame_is_sent_to_children_ = true;
}
+ void SendBeginMainFrameNotExpectedSoon() override {
+ PushAction("SendBeginMainFrameNotExpectedSoon");
+ }
+
base::Callback<bool(void)> ImplFrameDeadlinePending(bool state) {
return base::Bind(&FakeSchedulerClient::ImplFrameDeadlinePendingCallback,
base::Unretained(this),
@@ -517,7 +521,8 @@
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client_);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
client_->Reset();
}
@@ -1001,7 +1006,8 @@
EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
client->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
EXPECT_FALSE(scheduler_->BeginImplFrameDeadlinePending());
EXPECT_EQ(0, client->num_draws());
@@ -1376,7 +1382,8 @@
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client_);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
client_->Reset();
}
@@ -1627,7 +1634,7 @@
// Make sure SetNeedsBeginFrame isn't called on the client
// when the BeginFrame is no longer needed.
task_runner().RunPendingTasks(); // Run posted deadline.
- EXPECT_NO_ACTION(client_);
+ EXPECT_SINGLE_ACTION("SendBeginMainFrameNotExpectedSoon", client_);
client_->Reset();
}
@@ -1783,7 +1790,8 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
// Do nothing when impl frame is in deadine pending state.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client_);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
client_->Reset();
scheduler_->NotifyBeginMainFrameStarted();
@@ -1814,7 +1822,8 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
// Do nothing when impl frame is in deadine pending state.
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client_);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
client_->Reset();
// Run posted deadline.
@@ -1881,10 +1890,12 @@
scheduler_->DidLoseOutputSurface();
if (impl_side_painting) {
// Sync tree should be forced to activate.
- EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 0, 2);
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 2);
+ EXPECT_ACTION("ScheduledActionActivateSyncTree", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
} else {
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client_);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
}
client_->Reset();
@@ -1916,7 +1927,8 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client_);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
client_->Reset();
task_runner().RunPendingTasks(); // Run posted deadline.
@@ -1967,8 +1979,9 @@
client_->Reset();
EXPECT_FALSE(scheduler_->IsBeginRetroFrameArgsEmpty());
scheduler_->DidLoseOutputSurface();
- EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 2);
- EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 2);
+ EXPECT_ACTION("ScheduledActionBeginOutputSurfaceCreation", client_, 0, 3);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 1, 3);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 2, 3);
EXPECT_TRUE(scheduler_->IsBeginRetroFrameArgsEmpty());
// Posted BeginRetroFrame is aborted.
@@ -2028,7 +2041,8 @@
client_->Reset();
EXPECT_FALSE(scheduler_->IsBeginRetroFrameArgsEmpty());
scheduler_->DidLoseOutputSurface();
- EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(false)", client_);
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
EXPECT_TRUE(scheduler_->IsBeginRetroFrameArgsEmpty());
// BeginImplFrame deadline should abort drawing.
@@ -2069,7 +2083,7 @@
client_->Reset();
scheduler_->DidLoseOutputSurface();
- EXPECT_NO_ACTION(client_);
+ EXPECT_SINGLE_ACTION("SendBeginMainFrameNotExpectedSoon", client_);
EXPECT_FALSE(scheduler_->frame_source().NeedsBeginFrames());
client_->Reset();
@@ -2347,5 +2361,40 @@
EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 0, 1);
}
+// Tests to ensure that we send a BeginMainFrameNotExpectedSoon when expected.
+TEST_F(SchedulerTest, SendBeginMainFrameNotExpectedSoon) {
+ scheduler_settings_.use_external_begin_frame_source = true;
+ SetUpScheduler(true);
+
+ // SetNeedsCommit should begin the frame on the next BeginImplFrame.
+ scheduler_->SetNeedsCommit();
+ EXPECT_SINGLE_ACTION("SetNeedsBeginFrames(true)", client_);
+ client_->Reset();
+
+ // Trigger a frame draw.
+ EXPECT_SCOPED(AdvanceFrame());
+ scheduler_->NotifyBeginMainFrameStarted();
+ scheduler_->NotifyReadyToCommit();
+ task_runner().RunPendingTasks();
+ EXPECT_ACTION("WillBeginImplFrame", client_, 0, 5);
+ EXPECT_ACTION("ScheduledActionSendBeginMainFrame", client_, 1, 5);
+ EXPECT_ACTION("ScheduledActionCommit", client_, 2, 5);
+ EXPECT_ACTION("ScheduledActionAnimate", client_, 3, 5);
+ EXPECT_ACTION("ScheduledActionDrawAndSwapIfPossible", client_, 4, 5);
+ client_->Reset();
+
+ // The following BeginImplFrame deadline should SetNeedsBeginFrame(false)
+ // and send a SendBeginMainFrameNotExpectedSoon.
+ EXPECT_SCOPED(AdvanceFrame());
+ EXPECT_SINGLE_ACTION("WillBeginImplFrame", client_);
+ EXPECT_TRUE(scheduler_->BeginImplFrameDeadlinePending());
+ client_->Reset();
+
+ task_runner().RunPendingTasks(); // Run posted deadline.
+ EXPECT_ACTION("SetNeedsBeginFrames(false)", client_, 0, 2);
+ EXPECT_ACTION("SendBeginMainFrameNotExpectedSoon", client_, 1, 2);
+ client_->Reset();
+}
+
} // namespace
} // namespace cc
diff --git a/cc/surfaces/display.cc b/cc/surfaces/display.cc
index ab1f0af..7ec4672 100644
--- a/cc/surfaces/display.cc
+++ b/cc/surfaces/display.cc
@@ -134,25 +134,46 @@
}
DelegatedFrameData* frame_data = frame->delegated_frame_data.get();
- gfx::Size surface_size =
- frame_data->render_pass_list.back()->output_rect.size();
+ frame->metadata.latency_info.insert(frame->metadata.latency_info.end(),
+ stored_latency_info_.begin(),
+ stored_latency_info_.end());
+ stored_latency_info_.clear();
+ bool have_copy_requests = false;
+ for (const auto* pass : frame_data->render_pass_list) {
+ have_copy_requests |= !pass->copy_requests.empty();
+ }
- gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
- gfx::Rect device_clip_rect = device_viewport_rect;
- bool disable_picture_quad_image_filtering = false;
+ gfx::Size surface_size;
+ bool have_damage = false;
+ if (!frame_data->render_pass_list.empty()) {
+ surface_size = frame_data->render_pass_list.back()->output_rect.size();
+ have_damage =
+ !frame_data->render_pass_list.back()->damage_rect.size().IsEmpty();
+ }
+ bool avoid_swap = surface_size != current_surface_size_;
+ bool should_draw = !frame->metadata.latency_info.empty() ||
+ have_copy_requests || (have_damage && !avoid_swap);
- renderer_->DecideRenderPassAllocationsForFrame(frame_data->render_pass_list);
- renderer_->DrawFrame(&frame_data->render_pass_list,
- device_scale_factor_,
- device_viewport_rect,
- device_clip_rect,
- disable_picture_quad_image_filtering);
+ if (should_draw) {
+ gfx::Rect device_viewport_rect = gfx::Rect(current_surface_size_);
+ gfx::Rect device_clip_rect = device_viewport_rect;
+ bool disable_picture_quad_image_filtering = false;
- if (surface_size != current_surface_size_) {
+ renderer_->DecideRenderPassAllocationsForFrame(
+ frame_data->render_pass_list);
+ renderer_->DrawFrame(&frame_data->render_pass_list, device_scale_factor_,
+ device_viewport_rect, device_clip_rect,
+ disable_picture_quad_image_filtering);
+ }
+
+ if (should_draw && !avoid_swap) {
+ renderer_->SwapBuffers(frame->metadata);
+ } else {
+ stored_latency_info_.insert(stored_latency_info_.end(),
+ frame->metadata.latency_info.begin(),
+ frame->metadata.latency_info.end());
DidSwapBuffers();
DidSwapBuffersComplete();
- } else {
- renderer_->SwapBuffers(frame->metadata);
}
return true;
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index 99e66fb..ed96d07 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -5,6 +5,8 @@
#ifndef CC_SURFACES_DISPLAY_H_
#define CC_SURFACES_DISPLAY_H_
+#include <vector>
+
#include "base/memory/scoped_ptr.h"
#include "cc/output/output_surface_client.h"
#include "cc/output/renderer.h"
@@ -101,6 +103,7 @@
scoped_ptr<DirectRenderer> renderer_;
scoped_ptr<BlockingTaskRunner> blocking_main_thread_task_runner_;
scoped_ptr<TextureMailboxDeleter> texture_mailbox_deleter_;
+ std::vector<ui::LatencyInfo> stored_latency_info_;
DISALLOW_COPY_AND_ASSIGN(Display);
};
diff --git a/cc/surfaces/display_unittest.cc b/cc/surfaces/display_unittest.cc
new file mode 100644
index 0000000..7b01244
--- /dev/null
+++ b/cc/surfaces/display_unittest.cc
@@ -0,0 +1,239 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/output/compositor_frame.h"
+#include "cc/output/copy_output_result.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/render_pass.h"
+#include "cc/resources/shared_bitmap_manager.h"
+#include "cc/surfaces/display.h"
+#include "cc/surfaces/display_client.h"
+#include "cc/surfaces/surface.h"
+#include "cc/surfaces/surface_factory.h"
+#include "cc/surfaces/surface_factory_client.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "cc/surfaces/surface_manager.h"
+#include "cc/test/fake_output_surface.h"
+#include "cc/test/test_shared_bitmap_manager.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cc {
+namespace {
+
+class EmptySurfaceFactoryClient : public SurfaceFactoryClient {
+ public:
+ void ReturnResources(const ReturnedResourceArray& resources) override {}
+};
+
+class DisplayTest : public testing::Test {
+ public:
+ DisplayTest() : factory_(&manager_, &empty_client_) {}
+
+ void SetUp() override {
+ output_surface_ = FakeOutputSurface::CreateSoftware(
+ make_scoped_ptr(new SoftwareOutputDevice));
+ shared_bitmap_manager_.reset(new TestSharedBitmapManager);
+ output_surface_ptr_ = output_surface_.get();
+ }
+
+ protected:
+ void SubmitFrame(RenderPassList* pass_list, SurfaceId surface_id) {
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ pass_list->swap(frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+
+ factory_.SubmitFrame(surface_id, frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ }
+
+ SurfaceManager manager_;
+ EmptySurfaceFactoryClient empty_client_;
+ SurfaceFactory factory_;
+ scoped_ptr<FakeOutputSurface> output_surface_;
+ FakeOutputSurface* output_surface_ptr_;
+ scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
+};
+
+class TestDisplayClient : public DisplayClient {
+ public:
+ TestDisplayClient() : damaged(false), swapped(false) {}
+ ~TestDisplayClient() override {}
+
+ void DisplayDamaged() override { damaged = true; }
+ void DidSwapBuffers() override { swapped = true; }
+ void DidSwapBuffersComplete() override {}
+ void CommitVSyncParameters(base::TimeTicks timebase,
+ base::TimeDelta interval) override {}
+ void OutputSurfaceLost() override {}
+ void SetMemoryPolicy(const ManagedMemoryPolicy& policy) override {}
+
+ bool damaged;
+ bool swapped;
+};
+
+void CopyCallback(bool* called, scoped_ptr<CopyOutputResult> result) {
+ *called = true;
+}
+
+// Check that frame is damaged and swapped only under correct conditions.
+TEST_F(DisplayTest, DisplayDamaged) {
+ TestDisplayClient client;
+ RendererSettings settings;
+ settings.partial_swap_enabled = true;
+ Display display(&client, &manager_, shared_bitmap_manager_.get(), nullptr,
+ settings);
+
+ display.Initialize(output_surface_.Pass());
+
+ SurfaceId surface_id(7u);
+ EXPECT_FALSE(client.damaged);
+ display.SetSurfaceId(surface_id, 1.f);
+ EXPECT_TRUE(client.damaged);
+
+ client.damaged = false;
+ display.Resize(gfx::Size(100, 100));
+ EXPECT_TRUE(client.damaged);
+
+ factory_.Create(surface_id);
+
+ // First draw from surface should have full damage.
+ RenderPassList pass_list;
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 1, 1);
+ pass->id = RenderPassId(1, 1);
+ pass_list.push_back(pass.Pass());
+
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ EXPECT_FALSE(client.swapped);
+ EXPECT_EQ(0u, output_surface_ptr_->num_sent_frames());
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(1u, output_surface_ptr_->num_sent_frames());
+ SoftwareFrameData* software_data =
+ output_surface_ptr_->last_sent_frame().software_frame_data.get();
+ ASSERT_NE(nullptr, software_data);
+ EXPECT_EQ(gfx::Size(100, 100).ToString(), software_data->size.ToString());
+ EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
+ software_data->damage_rect.ToString());
+
+ {
+ // Only damaged portion should be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 1, 1);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+ software_data =
+ output_surface_ptr_->last_sent_frame().software_frame_data.get();
+ ASSERT_NE(nullptr, software_data);
+ EXPECT_EQ(gfx::Size(100, 100).ToString(), software_data->size.ToString());
+ EXPECT_EQ(gfx::Rect(10, 10, 1, 1).ToString(),
+ software_data->damage_rect.ToString());
+ }
+
+ {
+ // Pass has no damage so shouldn't be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+ }
+
+ {
+ // Pass is wrong size so shouldn't be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 99, 99);
+ pass->damage_rect = gfx::Rect(10, 10, 10, 10);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(2u, output_surface_ptr_->num_sent_frames());
+ }
+
+ {
+ // Pass has copy output request so should be swapped.
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ bool copy_called = false;
+ pass->copy_requests.push_back(CopyOutputRequest::CreateRequest(
+ base::Bind(&CopyCallback, ©_called)));
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ SubmitFrame(&pass_list, surface_id);
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(3u, output_surface_ptr_->num_sent_frames());
+ EXPECT_TRUE(copy_called);
+ }
+
+ // Pass has latency info so should be swapped.
+ {
+ pass = RenderPass::Create();
+ pass->output_rect = gfx::Rect(0, 0, 100, 100);
+ pass->damage_rect = gfx::Rect(10, 10, 0, 0);
+ pass->id = RenderPassId(1, 1);
+
+ pass_list.push_back(pass.Pass());
+ client.damaged = false;
+ scoped_ptr<DelegatedFrameData> frame_data(new DelegatedFrameData);
+ pass_list.swap(frame_data->render_pass_list);
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = frame_data.Pass();
+ frame->metadata.latency_info.push_back(ui::LatencyInfo());
+
+ factory_.SubmitFrame(surface_id, frame.Pass(),
+ SurfaceFactory::DrawCallback());
+ EXPECT_TRUE(client.damaged);
+
+ client.swapped = false;
+ display.Draw();
+ EXPECT_TRUE(client.swapped);
+ EXPECT_EQ(4u, output_surface_ptr_->num_sent_frames());
+ }
+
+ factory_.Destroy(surface_id);
+}
+
+} // namespace
+} // namespace cc
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc
index f6179cc..d04c5d3 100644
--- a/cc/test/animation_test_common.cc
+++ b/cc/test/animation_test_common.cc
@@ -44,10 +44,8 @@
int id = AnimationIdProvider::NextAnimationId();
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(),
- id,
- AnimationIdProvider::NextGroupId(),
- Animation::Opacity));
+ Animation::Create(curve.Pass(), id, AnimationIdProvider::NextGroupId(),
+ Animation::OPACITY));
animation->set_needs_synchronized_start_time(true);
target->AddAnimation(animation.Pass());
@@ -73,10 +71,8 @@
int id = AnimationIdProvider::NextAnimationId();
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(),
- id,
- AnimationIdProvider::NextGroupId(),
- Animation::Transform));
+ Animation::Create(curve.Pass(), id, AnimationIdProvider::NextGroupId(),
+ Animation::TRANSFORM));
animation->set_needs_synchronized_start_time(true);
target->AddAnimation(animation.Pass());
@@ -122,7 +118,7 @@
int id = AnimationIdProvider::NextAnimationId();
scoped_ptr<Animation> animation(Animation::Create(
- curve.Pass(), id, AnimationIdProvider::NextGroupId(), Animation::Filter));
+ curve.Pass(), id, AnimationIdProvider::NextGroupId(), Animation::FILTER));
animation->set_needs_synchronized_start_time(true);
target->AddAnimation(animation.Pass());
diff --git a/cc/test/data/blue.png b/cc/test/data/blue.png
deleted file mode 100644
index 48a2680..0000000
--- a/cc/test/data/blue.png
+++ /dev/null
Binary files differ
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc
index 23b73f5..ab958e9 100644
--- a/cc/test/fake_content_layer_client.cc
+++ b/cc/test/fake_content_layer_client.cc
@@ -69,13 +69,12 @@
it != draw_rects_.end(); ++it) {
const gfx::RectF& draw_rect = it->first;
const SkPaint& paint = it->second;
- canvas = skia::SharePtr(
- recorder.beginRecording(draw_rect.width(), draw_rect.height()));
+ canvas =
+ skia::SharePtr(recorder.beginRecording(gfx::RectFToSkRect(draw_rect)));
canvas->drawRectCoords(0.f, 0.f, draw_rect.width(), draw_rect.height(),
paint);
picture = skia::AdoptRef(recorder.endRecording());
- list->AppendItem(DrawingDisplayItem::Create(
- picture, gfx::PointF(draw_rect.x(), draw_rect.y())));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
}
for (BitmapVector::const_iterator it = draw_bitmaps_.begin();
@@ -84,8 +83,7 @@
recorder.beginRecording(it->bitmap.width(), it->bitmap.height()));
canvas->drawBitmap(it->bitmap, 0.f, 0.f, &it->paint);
picture = skia::AdoptRef(recorder.endRecording());
- list->AppendItem(DrawingDisplayItem::Create(
- picture, gfx::PointF(it->point.x(), it->point.y())));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
}
if (fill_with_nonsolid_color_) {
@@ -94,11 +92,11 @@
while (!draw_rect.IsEmpty()) {
SkPaint paint;
paint.setColor(red ? SK_ColorRED : SK_ColorBLUE);
- canvas =
- skia::SharePtr(recorder.beginRecording(clip.width(), clip.height()));
+ canvas = skia::SharePtr(
+ recorder.beginRecording(gfx::RectFToSkRect(draw_rect)));
canvas->drawRect(gfx::RectFToSkRect(draw_rect), paint);
picture = skia::AdoptRef(recorder.endRecording());
- list->AppendItem(DrawingDisplayItem::Create(picture, gfx::PointF()));
+ list->AppendItem(DrawingDisplayItem::Create(picture));
draw_rect.Inset(1, 1);
}
}
diff --git a/cc/test/fake_layer_tree_host_client.h b/cc/test/fake_layer_tree_host_client.h
index f5f3504..b5093ad 100644
--- a/cc/test/fake_layer_tree_host_client.h
+++ b/cc/test/fake_layer_tree_host_client.h
@@ -33,6 +33,7 @@
void WillBeginMainFrame() override {}
void DidBeginMainFrame() override {}
void BeginMainFrame(const BeginFrameArgs& args) override {}
+ void BeginMainFrameNotExpectedSoon() override {}
void Layout() override {}
void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
const gfx::Vector2dF& outer_delta,
diff --git a/cc/test/fake_layer_tree_host_impl.cc b/cc/test/fake_layer_tree_host_impl.cc
index bfac501..ccfb203 100644
--- a/cc/test/fake_layer_tree_host_impl.cc
+++ b/cc/test/fake_layer_tree_host_impl.cc
@@ -86,7 +86,8 @@
void FakeLayerTreeHostImpl::UpdateNumChildrenAndDrawProperties(
LayerTreeImpl* layerTree) {
RecursiveUpdateNumChildren(layerTree->root_layer());
- layerTree->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ layerTree->UpdateDrawProperties(update_lcd_text);
}
} // namespace cc
diff --git a/cc/test/fake_picture_pile.cc b/cc/test/fake_picture_pile.cc
index cc0a7ba..4db6c58 100644
--- a/cc/test/fake_picture_pile.cc
+++ b/cc/test/fake_picture_pile.cc
@@ -49,7 +49,8 @@
return CreatePile(tile_size, layer_bounds, is_filled);
}
-scoped_refptr<RasterSource> FakePicturePile::CreateRasterSource() const {
+scoped_refptr<RasterSource> FakePicturePile::CreateRasterSource(
+ bool can_use_lcd_text) const {
return FakePicturePileImpl::CreateFromPile(this, playback_allowed_event_);
}
diff --git a/cc/test/fake_picture_pile.h b/cc/test/fake_picture_pile.h
index 054eaa2..48b8914 100644
--- a/cc/test/fake_picture_pile.h
+++ b/cc/test/fake_picture_pile.h
@@ -34,7 +34,8 @@
const gfx::Size& layer_bounds);
// PicturePile overrides.
- scoped_refptr<RasterSource> CreateRasterSource() const override;
+ scoped_refptr<RasterSource> CreateRasterSource(
+ bool can_use_lcd_text) const override;
using PicturePile::buffer_pixels;
using PicturePile::CanRasterSlowTileCheck;
diff --git a/cc/test/fake_picture_pile_impl.cc b/cc/test/fake_picture_pile_impl.cc
index 8353d27..ab255cc 100644
--- a/cc/test/fake_picture_pile_impl.cc
+++ b/cc/test/fake_picture_pile_impl.cc
@@ -21,7 +21,7 @@
FakePicturePileImpl::FakePicturePileImpl(
const PicturePile* other,
base::WaitableEvent* playback_allowed_event)
- : PicturePileImpl(other),
+ : PicturePileImpl(other, true),
playback_allowed_event_(playback_allowed_event),
tile_grid_size_(other->GetTileGridSizeForTesting()) {
}
diff --git a/cc/test/layer_tree_json_parser.cc b/cc/test/layer_tree_json_parser.cc
index efe70a0..b0b81f7 100644
--- a/cc/test/layer_tree_json_parser.cc
+++ b/cc/test/layer_tree_json_parser.cc
@@ -156,11 +156,11 @@
for (size_t i = 0; i < list->GetSize(); i++) {
success &= list->GetString(i, &str);
if (str == "StartTouch")
- blocks |= ScrollBlocksOnStartTouch;
+ blocks |= SCROLL_BLOCKS_ON_START_TOUCH;
else if (str == "WheelEvent")
- blocks |= ScrollBlocksOnWheelEvent;
+ blocks |= SCROLL_BLOCKS_ON_WHEEL_EVENT;
else if (str == "ScrollEvent")
- blocks |= ScrollBlocksOnScrollEvent;
+ blocks |= SCROLL_BLOCKS_ON_SCROLL_EVENT;
else
success = false;
}
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index f7ab9c2..dbb9ba5 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -63,10 +63,8 @@
return output_surface.Pass();
}
-void LayerTreePixelTest::CommitCompleteOnThread(LayerTreeHostImpl* impl) {
- LayerTreeImpl* commit_tree =
- impl->pending_tree() ? impl->pending_tree() : impl->active_tree();
- if (commit_tree->source_frame_number() != 0)
+void LayerTreePixelTest::WillActivateTreeOnThread(LayerTreeHostImpl* impl) {
+ if (impl->sync_tree()->source_frame_number() != 0)
return;
DirectRenderer* renderer = static_cast<DirectRenderer*>(impl->renderer());
diff --git a/cc/test/layer_tree_pixel_test.h b/cc/test/layer_tree_pixel_test.h
index 8d02280..da030d1 100644
--- a/cc/test/layer_tree_pixel_test.h
+++ b/cc/test/layer_tree_pixel_test.h
@@ -41,7 +41,7 @@
~LayerTreePixelTest() override;
scoped_ptr<OutputSurface> CreateOutputSurface() override;
- void CommitCompleteOnThread(LayerTreeHostImpl* impl) override;
+ void WillActivateTreeOnThread(LayerTreeHostImpl* impl) override;
virtual scoped_ptr<CopyOutputRequest> CreateCopyOutputRequest();
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index ce69079..129a27d 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -441,6 +441,7 @@
void DidAbortSwapBuffers() override {}
void ScheduleComposite() override { test_hooks_->ScheduleComposite(); }
void DidCompletePageScaleAnimation() override {}
+ void BeginMainFrameNotExpectedSoon() override {}
private:
explicit LayerTreeHostClientForTesting(TestHooks* test_hooks)
diff --git a/cc/test/render_pass_test_common.cc b/cc/test/render_pass_test_common.cc
index 7c91f0d..0e3fe22 100644
--- a/cc/test/render_pass_test_common.cc
+++ b/cc/test/render_pass_test_common.cc
@@ -35,46 +35,39 @@
const float vertex_opacity[] = {1.0f, 1.0f, 1.0f, 1.0f};
ResourceProvider::ResourceId resource1 = resource_provider->CreateResource(
- gfx::Size(45, 5),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(45, 5), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(resource1);
ResourceProvider::ResourceId resource2 = resource_provider->CreateResource(
- gfx::Size(346, 61),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(346, 61), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(resource2);
ResourceProvider::ResourceId resource3 = resource_provider->CreateResource(
- gfx::Size(12, 134),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(12, 134), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(resource3);
ResourceProvider::ResourceId resource4 = resource_provider->CreateResource(
- gfx::Size(56, 12),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(56, 12), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(resource4);
gfx::Size resource5_size(73, 26);
ResourceProvider::ResourceId resource5 = resource_provider->CreateResource(
- resource5_size,
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ resource5_size, GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(resource5);
ResourceProvider::ResourceId resource6 = resource_provider->CreateResource(
- gfx::Size(64, 92),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(64, 92), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(resource6);
ResourceProvider::ResourceId resource7 = resource_provider->CreateResource(
- gfx::Size(9, 14),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(9, 14), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(resource7);
@@ -243,9 +236,8 @@
ResourceProvider::ResourceId plane_resources[4];
for (int i = 0; i < 4; ++i) {
plane_resources[i] = resource_provider->CreateResource(
- gfx::Size(20, 12),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ gfx::Size(20, 12), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
resource_provider->best_texture_format());
resource_provider->AllocateForTesting(plane_resources[i]);
}
diff --git a/cc/test/test_web_graphics_context_3d.cc b/cc/test/test_web_graphics_context_3d.cc
index 8aa392d..28b16c8 100644
--- a/cc/test/test_web_graphics_context_3d.cc
+++ b/cc/test/test_web_graphics_context_3d.cc
@@ -64,7 +64,7 @@
height_(0),
scale_factor_(-1.f),
test_support_(NULL),
- last_update_type_(NoUpdate),
+ last_update_type_(NO_UPDATE),
next_insert_sync_point_(1),
last_waited_sync_point_(0),
unpack_alignment_(4),
diff --git a/cc/test/test_web_graphics_context_3d.h b/cc/test/test_web_graphics_context_3d.h
index 31182f8..c2dee45 100644
--- a/cc/test/test_web_graphics_context_3d.h
+++ b/cc/test/test_web_graphics_context_3d.h
@@ -373,11 +373,7 @@
void clear_reshape_called() { reshape_called_ = false; }
float scale_factor() const { return scale_factor_; }
- enum UpdateType {
- NoUpdate = 0,
- PrepareTexture,
- PostSubBuffer
- };
+ enum UpdateType { NO_UPDATE = 0, PREPARE_TEXTURE, POST_SUB_BUFFER };
gfx::Rect update_rect() const { return update_rect_; }
diff --git a/cc/trees/layer_sorter.cc b/cc/trees/layer_sorter.cc
index e171fe0..bde4920 100644
--- a/cc/trees/layer_sorter.cc
+++ b/cc/trees/layer_sorter.cc
@@ -90,7 +90,7 @@
// Early out if the projected bounds don't overlap.
if (!a->projected_bounds.Intersects(b->projected_bounds))
- return None;
+ return NONE;
gfx::PointF aPoints[4] = { a->projected_quad.p1(),
a->projected_quad.p2(),
@@ -123,7 +123,7 @@
overlap_points.push_back(r);
if (overlap_points.empty())
- return None;
+ return NONE;
// Check the corresponding layer depth value for all overlap points to
// determine which layer is in front.
@@ -157,7 +157,7 @@
// If we can't tell which should come first, we use document order.
if (!accurate)
- return ABeforeB;
+ return A_BEFORE_B;
float max_diff =
std::abs(max_positive) > std::abs(max_negative) ?
@@ -176,9 +176,9 @@
// Maintain relative order if the layers have the same depth at all
// intersection points.
if (max_diff <= 0.f)
- return ABeforeB;
+ return A_BEFORE_B;
- return BBeforeA;
+ return B_BEFORE_A;
}
LayerShape::LayerShape() {}
@@ -320,10 +320,10 @@
&weight);
GraphNode* start_node = NULL;
GraphNode* end_node = NULL;
- if (overlap_result == ABeforeB) {
+ if (overlap_result == A_BEFORE_B) {
start_node = &node_a;
end_node = &node_b;
- } else if (overlap_result == BBeforeA) {
+ } else if (overlap_result == B_BEFORE_A) {
start_node = &node_b;
end_node = &node_a;
}
diff --git a/cc/trees/layer_sorter.h b/cc/trees/layer_sorter.h
index b783ded..4cfa8fe 100644
--- a/cc/trees/layer_sorter.h
+++ b/cc/trees/layer_sorter.h
@@ -68,11 +68,7 @@
void Sort(LayerImplList::iterator first, LayerImplList::iterator last);
- enum ABCompareResult {
- ABeforeB,
- BBeforeA,
- None
- };
+ enum ABCompareResult { A_BEFORE_B, B_BEFORE_A, NONE };
static ABCompareResult CheckOverlap(LayerShape* a,
LayerShape* b,
diff --git a/cc/trees/layer_sorter_unittest.cc b/cc/trees/layer_sorter_unittest.cc
index ba7765b..74d3cf5 100644
--- a/cc/trees/layer_sorter_unittest.cc
+++ b/cc/trees/layer_sorter_unittest.cc
@@ -37,12 +37,12 @@
overlap_result =
LayerSorter::CheckOverlap(&front, &back, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::BBeforeA, overlap_result);
+ EXPECT_EQ(LayerSorter::B_BEFORE_A, overlap_result);
EXPECT_EQ(1.f, weight);
overlap_result =
LayerSorter::CheckOverlap(&back, &front, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
+ EXPECT_EQ(LayerSorter::A_BEFORE_B, overlap_result);
EXPECT_EQ(1.f, weight);
// One layer translated off to the right. No overlap should be detected.
@@ -51,7 +51,7 @@
LayerShape back_right(2.f, 2.f, right_translate);
overlap_result =
LayerSorter::CheckOverlap(&front, &back_right, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::None, overlap_result);
+ EXPECT_EQ(LayerSorter::NONE, overlap_result);
// When comparing a layer with itself, z difference is always 0.
overlap_result =
@@ -80,7 +80,7 @@
overlap_result =
LayerSorter::CheckOverlap(&front_face, &left_face, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::BBeforeA, overlap_result);
+ EXPECT_EQ(LayerSorter::B_BEFORE_A, overlap_result);
}
TEST(LayerSorterTest, IntersectingLayerOverlap) {
@@ -107,7 +107,7 @@
&rotated_face,
z_threshold,
&weight);
- EXPECT_NE(LayerSorter::None, overlap_result);
+ EXPECT_NE(LayerSorter::NONE, overlap_result);
EXPECT_EQ(0.f, weight);
}
@@ -145,13 +145,13 @@
overlap_result =
LayerSorter::CheckOverlap(&layer_a, &layer_c, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
+ EXPECT_EQ(LayerSorter::A_BEFORE_B, overlap_result);
overlap_result =
LayerSorter::CheckOverlap(&layer_c, &layer_b, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
+ EXPECT_EQ(LayerSorter::A_BEFORE_B, overlap_result);
overlap_result =
LayerSorter::CheckOverlap(&layer_a, &layer_b, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::None, overlap_result);
+ EXPECT_EQ(LayerSorter::NONE, overlap_result);
}
TEST(LayerSorterTest, LayersUnderPathologicalPerspectiveTransform) {
@@ -192,7 +192,7 @@
overlap_result =
LayerSorter::CheckOverlap(&layer_a, &layer_b, z_threshold, &weight);
- EXPECT_EQ(LayerSorter::ABeforeB, overlap_result);
+ EXPECT_EQ(LayerSorter::A_BEFORE_B, overlap_result);
}
TEST(LayerSorterTest, VerifyExistingOrderingPreservedWhenNoZDiff) {
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index f478078..49e374d 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -133,7 +133,6 @@
partial_texture_update_requests_(0),
did_complete_scale_animation_(false),
in_paint_layer_contents_(false),
- total_frames_used_for_lcd_text_metrics_(0),
id_(s_layer_tree_host_sequence_number.GetNext() + 1),
next_commit_forces_redraw_(false),
shared_bitmap_manager_(shared_bitmap_manager),
@@ -233,6 +232,10 @@
client_->DidBeginMainFrame();
}
+void LayerTreeHost::BeginMainFrameNotExpectedSoon() {
+ client_->BeginMainFrameNotExpectedSoon();
+}
+
void LayerTreeHost::BeginMainFrame(const BeginFrameArgs& args) {
inside_begin_main_frame_ = true;
client_->BeginMainFrame(args);
@@ -559,19 +562,19 @@
animation_controllers.find(event_layer_id);
if (iter != animation_controllers.end()) {
switch ((*events)[event_index].type) {
- case AnimationEvent::Started:
+ case AnimationEvent::STARTED:
(*iter).second->NotifyAnimationStarted((*events)[event_index]);
break;
- case AnimationEvent::Finished:
+ case AnimationEvent::FINISHED:
(*iter).second->NotifyAnimationFinished((*events)[event_index]);
break;
- case AnimationEvent::Aborted:
+ case AnimationEvent::ABORTED:
(*iter).second->NotifyAnimationAborted((*events)[event_index]);
break;
- case AnimationEvent::PropertyUpdate:
+ case AnimationEvent::PROPERTY_UPDATE:
(*iter).second->NotifyAnimationPropertyUpdate((*events)[event_index]);
break;
}
@@ -809,18 +812,6 @@
gpu_rasterization_histogram_recorded_ = true;
}
-void LayerTreeHost::CalculateLCDTextMetricsCallback(Layer* layer) {
- if (!layer->SupportsLCDText())
- return;
-
- lcd_text_metrics_.total_num_cc_layers++;
- if (layer->draw_properties().can_use_lcd_text) {
- lcd_text_metrics_.total_num_cc_layers_can_use_lcd_text++;
- if (layer->contents_opaque())
- lcd_text_metrics_.total_num_cc_layers_will_use_lcd_text++;
- }
-}
-
bool LayerTreeHost::UsingSharedMemoryResources() {
return GetRendererCapabilities().using_shared_memory_resources;
}
@@ -861,29 +852,6 @@
settings_.verify_property_trees, &update_list,
render_surface_layer_list_id);
LayerTreeHostCommon::CalculateDrawProperties(&inputs);
-
- if (total_frames_used_for_lcd_text_metrics_ <=
- kTotalFramesToUseForLCDTextMetrics) {
- LayerTreeHostCommon::CallFunctionForSubtree(
- root_layer,
- base::Bind(&LayerTreeHost::CalculateLCDTextMetricsCallback,
- base::Unretained(this)));
- total_frames_used_for_lcd_text_metrics_++;
- }
-
- if (total_frames_used_for_lcd_text_metrics_ ==
- kTotalFramesToUseForLCDTextMetrics) {
- total_frames_used_for_lcd_text_metrics_++;
-
- UMA_HISTOGRAM_PERCENTAGE(
- "Renderer4.LCDText.PercentageOfCandidateLayers",
- lcd_text_metrics_.total_num_cc_layers_can_use_lcd_text * 100.0 /
- lcd_text_metrics_.total_num_cc_layers);
- UMA_HISTOGRAM_PERCENTAGE(
- "Renderer4.LCDText.PercentageOfAALayers",
- lcd_text_metrics_.total_num_cc_layers_will_use_lcd_text * 100.0 /
- lcd_text_metrics_.total_num_cc_layers_can_use_lcd_text);
- }
}
// Reset partial texture update requests.
@@ -1251,8 +1219,7 @@
ui_resource_client_map_.end());
bool resource_lost = false;
- UIResourceRequest request(UIResourceRequest::UIResourceCreate,
- next_id,
+ UIResourceRequest request(UIResourceRequest::UI_RESOURCE_CREATE, next_id,
client->GetBitmap(next_id, resource_lost));
ui_resource_request_queue_.push_back(request);
@@ -1270,7 +1237,7 @@
if (iter == ui_resource_client_map_.end())
return;
- UIResourceRequest request(UIResourceRequest::UIResourceDelete, uid);
+ UIResourceRequest request(UIResourceRequest::UI_RESOURCE_DELETE, uid);
ui_resource_request_queue_.push_back(request);
ui_resource_client_map_.erase(iter);
}
@@ -1282,8 +1249,7 @@
UIResourceId uid = iter->first;
const UIResourceClientData& data = iter->second;
bool resource_lost = true;
- UIResourceRequest request(UIResourceRequest::UIResourceCreate,
- uid,
+ UIResourceRequest request(UIResourceRequest::UI_RESOURCE_CREATE, uid,
data.client->GetBitmap(uid, resource_lost));
ui_resource_request_queue_.push_back(request);
}
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index b17b5a4..d41e73d 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -113,6 +113,7 @@
void WillBeginMainFrame();
void DidBeginMainFrame();
void BeginMainFrame(const BeginFrameArgs& args);
+ void BeginMainFrameNotExpectedSoon();
void AnimateLayers(base::TimeTicks monotonic_frame_begin_time);
void DidStopFlinging();
void Layout();
@@ -447,20 +448,6 @@
bool in_paint_layer_contents_;
- static const int kTotalFramesToUseForLCDTextMetrics = 50;
- int total_frames_used_for_lcd_text_metrics_;
-
- struct LCDTextMetrics {
- LCDTextMetrics()
- : total_num_cc_layers(0),
- total_num_cc_layers_can_use_lcd_text(0),
- total_num_cc_layers_will_use_lcd_text(0) {}
-
- int64 total_num_cc_layers;
- int64 total_num_cc_layers_can_use_lcd_text;
- int64 total_num_cc_layers_will_use_lcd_text;
- };
- LCDTextMetrics lcd_text_metrics_;
int id_;
bool next_commit_forces_redraw_;
diff --git a/cc/trees/layer_tree_host_client.h b/cc/trees/layer_tree_host_client.h
index 574325b..6b30532 100644
--- a/cc/trees/layer_tree_host_client.h
+++ b/cc/trees/layer_tree_host_client.h
@@ -26,6 +26,7 @@
// Marks finishing compositing-related tasks on the main thread. In threaded
// mode, this corresponds to DidCommit().
virtual void BeginMainFrame(const BeginFrameArgs& args) = 0;
+ virtual void BeginMainFrameNotExpectedSoon() = 0;
virtual void DidBeginMainFrame() = 0;
virtual void Layout() = 0;
virtual void ApplyViewportDeltas(
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 70c5037..7a3b5ad 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -161,8 +161,8 @@
}
enum TranslateRectDirection {
- TranslateRectDirectionToAncestor,
- TranslateRectDirectionToDescendant
+ TRANSLATE_RECT_DIRECTION_TO_ANCESTOR,
+ TRANSLATE_RECT_DIRECTION_TO_DESCENDANT
};
template <typename LayerType>
@@ -172,7 +172,7 @@
TranslateRectDirection direction) {
gfx::Vector2dF translation = ComputeChangeOfBasisTranslation<LayerType>(
ancestor_layer, descendant_layer);
- if (direction == TranslateRectDirectionToDescendant)
+ if (direction == TRANSLATE_RECT_DIRECTION_TO_DESCENDANT)
translation.Scale(-1.f);
return gfx::ToEnclosingRect(
gfx::RectF(rect.origin() + translation, rect.size()));
@@ -211,20 +211,16 @@
// clip rects will want to be in its target space, not ours.
if (clip_parent == layer->clip_parent()) {
*clip_rect_in_parent_target_space = TranslateRectToTargetSpace<LayerType>(
- *clip_parent,
- *layer->parent(),
- *clip_rect_in_parent_target_space,
- TranslateRectDirectionToDescendant);
+ *clip_parent, *layer->parent(), *clip_rect_in_parent_target_space,
+ TRANSLATE_RECT_DIRECTION_TO_DESCENDANT);
} else {
// If we're being clipped by our scroll parent, we must translate through
// our common ancestor. This happens to be our parent, so it is sufficent to
// translate from our clip parent's space to the space of its ancestor (our
// parent).
- *clip_rect_in_parent_target_space =
- TranslateRectToTargetSpace<LayerType>(*layer->parent(),
- *clip_parent,
- *clip_rect_in_parent_target_space,
- TranslateRectDirectionToAncestor);
+ *clip_rect_in_parent_target_space = TranslateRectToTargetSpace<LayerType>(
+ *layer->parent(), *clip_parent, *clip_rect_in_parent_target_space,
+ TRANSLATE_RECT_DIRECTION_TO_ANCESTOR);
}
}
@@ -286,10 +282,8 @@
// so we'll need to transform it before it is applied.
if (layer->clip_parent()) {
clip_rect = TranslateRectToTargetSpace<LayerType>(
- *layer->clip_parent(),
- *layer,
- clip_rect,
- TranslateRectDirectionToDescendant);
+ *layer->clip_parent(), *layer, clip_rect,
+ TRANSLATE_RECT_DIRECTION_TO_DESCENDANT);
}
target_rect.Intersect(clip_rect);
}
@@ -1203,12 +1197,30 @@
}
};
+static bool ValidateRenderSurface(LayerImpl* layer) {
+ // This test verifies that there are no cases where a LayerImpl needs
+ // a render surface, but doesn't have one.
+ if (layer->render_surface())
+ return true;
+
+ return layer->filters().IsEmpty() && layer->background_filters().IsEmpty() &&
+ !layer->mask_layer() && !layer->replica_layer() &&
+ !IsRootLayer(layer) && !layer->is_root_for_isolated_group() &&
+ !layer->HasCopyRequest();
+}
+
+static bool ValidateRenderSurface(Layer* layer) {
+ return true;
+}
+
// Recursively walks the layer tree to compute any information that is needed
// before doing the main recursion.
template <typename LayerType>
static void PreCalculateMetaInformation(
LayerType* layer,
PreCalculateMetaInformationRecursiveData* recursive_data) {
+ DCHECK(ValidateRenderSurface(layer));
+
layer->draw_properties().sorted_for_recursion = false;
layer->draw_properties().has_child_with_a_scroll_parent = false;
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index de5f44a..30cc15a 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -5677,56 +5677,60 @@
class LCDTextTest
: public LayerTreeHostCommonTestBase,
public testing::TestWithParam<LCDTextTestParam> {
+ public:
+ LCDTextTest()
+ : host_impl_(&proxy_, &shared_bitmap_manager_),
+ root_(nullptr),
+ child_(nullptr),
+ grand_child_(nullptr) {}
+
protected:
void SetUp() override {
can_use_lcd_text_ = std::tr1::get<0>(GetParam());
layers_always_allowed_lcd_text_ = std::tr1::get<1>(GetParam());
- root_ = Layer::Create();
- child_ = Layer::Create();
- grand_child_ = Layer::Create();
- child_->AddChild(grand_child_.get());
- root_->AddChild(child_.get());
+ scoped_ptr<LayerImpl> root_ptr =
+ LayerImpl::Create(host_impl_.active_tree(), 1);
+ scoped_ptr<LayerImpl> child_ptr =
+ LayerImpl::Create(host_impl_.active_tree(), 2);
+ scoped_ptr<LayerImpl> grand_child_ptr =
+ LayerImpl::Create(host_impl_.active_tree(), 3);
+
+ // Stash raw pointers to look at later.
+ root_ = root_ptr.get();
+ child_ = child_ptr.get();
+ grand_child_ = grand_child_ptr.get();
+
+ child_->AddChild(grand_child_ptr.Pass());
+ root_->AddChild(child_ptr.Pass());
+ host_impl_.active_tree()->SetRootLayer(root_ptr.Pass());
root_->SetContentsOpaque(true);
child_->SetContentsOpaque(true);
grand_child_->SetContentsOpaque(true);
gfx::Transform identity_matrix;
- SetLayerPropertiesForTesting(root_.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 1),
- true,
+ SetLayerPropertiesForTesting(root_, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 1), true, false,
+ true);
+ SetLayerPropertiesForTesting(child_, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 1), true, false,
+ std::tr1::get<2>(GetParam()));
+ SetLayerPropertiesForTesting(grand_child_, identity_matrix, gfx::Point3F(),
+ gfx::PointF(), gfx::Size(1, 1), true, false,
false);
- SetLayerPropertiesForTesting(child_.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 1),
- true,
- false);
- SetLayerPropertiesForTesting(grand_child_.get(),
- identity_matrix,
- gfx::Point3F(),
- gfx::PointF(),
- gfx::Size(1, 1),
- true,
- false);
-
- child_->SetForceRenderSurface(std::tr1::get<2>(GetParam()));
-
- host_ = CreateFakeLayerTreeHost();
- host_->SetRootLayer(root_);
}
bool can_use_lcd_text_;
bool layers_always_allowed_lcd_text_;
- scoped_ptr<FakeLayerTreeHost> host_;
- scoped_refptr<Layer> root_;
- scoped_refptr<Layer> child_;
- scoped_refptr<Layer> grand_child_;
+
+ FakeImplProxy proxy_;
+ TestSharedBitmapManager shared_bitmap_manager_;
+ FakeLayerTreeHostImpl host_impl_;
+
+ LayerImpl* root_;
+ LayerImpl* child_;
+ LayerImpl* grand_child_;
};
TEST_P(LCDTextTest, CanUseLCDText) {
@@ -5735,7 +5739,7 @@
// Case 1: Identity transform.
gfx::Transform identity_matrix;
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
@@ -5745,7 +5749,7 @@
gfx::Transform integral_translation;
integral_translation.Translate(1.0, 2.0);
child_->SetTransform(integral_translation);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
@@ -5755,7 +5759,7 @@
gfx::Transform non_integral_translation;
non_integral_translation.Translate(1.5, 2.5);
child_->SetTransform(non_integral_translation);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
@@ -5765,7 +5769,7 @@
gfx::Transform rotation;
rotation.Rotate(10.0);
child_->SetTransform(rotation);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
@@ -5775,7 +5779,7 @@
gfx::Transform scale;
scale.Scale(2.0, 2.0);
child_->SetTransform(scale);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
@@ -5785,7 +5789,7 @@
gfx::Transform skew;
skew.SkewX(10.0);
child_->SetTransform(skew);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
@@ -5794,7 +5798,7 @@
// Case 7: Translucent.
child_->SetTransform(identity_matrix);
child_->SetOpacity(0.5f);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
@@ -5803,7 +5807,7 @@
// Case 8: Sanity check: restore transform and opacity.
child_->SetTransform(identity_matrix);
child_->SetOpacity(1.f);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
@@ -5811,7 +5815,7 @@
// Case 9: Non-opaque content.
child_->SetContentsOpaque(false);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_not_lcd_text, child_->can_use_lcd_text());
@@ -5819,7 +5823,7 @@
// Case 10: Sanity check: restore content opaqueness.
child_->SetContentsOpaque(true);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
@@ -5830,7 +5834,7 @@
bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_;
// Sanity check: Make sure can_use_lcd_text_ is set on each node.
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
@@ -5841,7 +5845,7 @@
AddOpacityTransitionToController(
child_->layer_animation_controller(), 10.0, 0.9f, 0.1f, false);
- ExecuteCalculateDrawProperties(root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_,
+ ExecuteCalculateDrawProperties(root_, 1.f, 1.f, NULL, can_use_lcd_text_,
layers_always_allowed_lcd_text_);
// Text AA should not be adjusted while animation is active.
// Make sure LCD text AA setting remains unchanged.
@@ -7971,11 +7975,11 @@
0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
grand_parent->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
parent_raw->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
child_raw->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
TransformOperations perspective;
perspective.AppendPerspective(10.f);
@@ -7995,7 +7999,7 @@
0.f, grand_child_raw->draw_properties().maximum_animation_contents_scale);
child_raw->layer_animation_controller()->AbortAnimations(
- Animation::Transform);
+ Animation::TRANSFORM);
gfx::Transform scale_matrix;
scale_matrix.Scale(1.f, 2.f);
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 3cb2858..eef1cc3 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -307,8 +307,11 @@
if (settings_.impl_side_painting) {
// Impl-side painting needs an update immediately post-commit to have the
// opportunity to create tilings. Other paths can call UpdateDrawProperties
- // more lazily when needed prior to drawing.
- sync_tree()->UpdateDrawProperties();
+ // more lazily when needed prior to drawing. Because invalidations may
+ // be coming from the main thread, it's safe to do an update for lcd text
+ // at this point and see if lcd text needs to be disabled on any layers.
+ bool update_lcd_text = true;
+ sync_tree()->UpdateDrawProperties(update_lcd_text);
// Start working on newly created tiles immediately if needed.
if (tile_manager_ && tile_priorities_dirty_)
PrepareTiles();
@@ -473,7 +476,7 @@
}
static ScrollBlocksOn EffectiveScrollBlocksOn(LayerImpl* layer) {
- ScrollBlocksOn blocks = ScrollBlocksOnNone;
+ ScrollBlocksOn blocks = SCROLL_BLOCKS_ON_NONE;
for (; layer; layer = NextScrollLayer(layer)) {
blocks |= layer->scroll_blocks_on();
}
@@ -492,7 +495,7 @@
LayerImpl* layer_impl =
active_tree_->FindLayerThatIsHitByPoint(device_viewport_point);
ScrollBlocksOn blocking = EffectiveScrollBlocksOn(layer_impl);
- if (!(blocking & ScrollBlocksOnStartTouch))
+ if (!(blocking & SCROLL_BLOCKS_ON_START_TOUCH))
return false;
// Now determine if there are actually any handlers at that point.
@@ -1046,7 +1049,8 @@
UMA_HISTOGRAM_CUSTOM_COUNTS(
"Compositing.NumActiveLayers", active_tree_->NumLayers(), 1, 400, 20);
- bool ok = active_tree_->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ bool ok = active_tree_->UpdateDrawProperties(update_lcd_text);
DCHECK(ok) << "UpdateDrawProperties failed during draw";
// This will cause NotifyTileStateChanged() to be called for any visible tiles
@@ -1619,12 +1623,19 @@
}
CompositorFrameMetadata metadata = MakeCompositorFrameMetadata();
active_tree()->FinishSwapPromises(&metadata);
- for (size_t i = 0; i < metadata.latency_info.size(); i++) {
+ for (auto& latency : metadata.latency_info) {
TRACE_EVENT_FLOW_STEP0(
"input,benchmark",
"LatencyInfo.Flow",
- TRACE_ID_DONT_MANGLE(metadata.latency_info[i].trace_id),
+ TRACE_ID_DONT_MANGLE(latency.trace_id),
"SwapBuffers");
+ // Only add the latency component once for renderer swap, not the browser
+ // swap.
+ if (!latency.FindLatency(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
+ 0, nullptr)) {
+ latency.AddLatencyNumber(ui::INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
+ 0, 0);
+ }
}
renderer_->SwapBuffers(metadata);
return true;
@@ -2295,7 +2306,7 @@
// thread.
ScrollStatus status =
layer_impl->TryScroll(device_viewport_point, type, block_mode);
- if (status == ScrollOnMainThread) {
+ if (status == SCROLL_ON_MAIN_THREAD) {
*scroll_on_main_thread = true;
return NULL;
}
@@ -2307,7 +2318,7 @@
status =
scroll_layer_impl->TryScroll(device_viewport_point, type, block_mode);
// If any layer wants to divert the scroll event to the main thread, abort.
- if (status == ScrollOnMainThread) {
+ if (status == SCROLL_ON_MAIN_THREAD) {
*scroll_on_main_thread = true;
return NULL;
}
@@ -2316,7 +2327,7 @@
scroll_layer_impl->have_scroll_event_handlers())
*optional_has_ancestor_scroll_handler = true;
- if (status == ScrollStarted && !potentially_scrolling_layer_impl)
+ if (status == SCROLL_STARTED && !potentially_scrolling_layer_impl)
potentially_scrolling_layer_impl = scroll_layer_impl;
}
@@ -2363,7 +2374,7 @@
active_tree_->FindFirstScrollingLayerThatIsHitByPoint(
device_viewport_point);
if (scroll_layer_impl && !HasScrollAncestor(layer_impl, scroll_layer_impl))
- return ScrollUnknown;
+ return SCROLL_UNKNOWN;
}
bool scroll_on_main_thread = false;
@@ -2376,18 +2387,18 @@
if (scroll_on_main_thread) {
UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", true);
- return ScrollOnMainThread;
+ return SCROLL_ON_MAIN_THREAD;
}
if (scrolling_layer_impl) {
active_tree_->SetCurrentlyScrollingLayer(scrolling_layer_impl);
- should_bubble_scrolls_ = (type != NonBubblingGesture);
- wheel_scrolling_ = (type == Wheel);
+ should_bubble_scrolls_ = (type != NON_BUBBLING_GESTURE);
+ wheel_scrolling_ = (type == WHEEL);
client_->RenewTreePriority();
UMA_HISTOGRAM_BOOLEAN("TryScroll.SlowScroll", false);
- return ScrollStarted;
+ return SCROLL_STARTED;
}
- return ScrollIgnored;
+ return SCROLL_IGNORED;
}
InputHandler::ScrollStatus LayerTreeHostImpl::ScrollAnimated(
@@ -2396,9 +2407,9 @@
if (LayerImpl* layer_impl = CurrentlyScrollingLayer()) {
Animation* animation =
layer_impl->layer_animation_controller()->GetAnimation(
- Animation::ScrollOffset);
+ Animation::SCROLL_OFFSET);
if (!animation)
- return ScrollIgnored;
+ return SCROLL_IGNORED;
ScrollOffsetAnimationCurve* curve =
animation->curve()->ToScrollOffsetAnimationCurve();
@@ -2413,13 +2424,13 @@
CurrentBeginFrameArgs().frame_time).InSecondsF(),
new_target);
- return ScrollStarted;
+ return SCROLL_STARTED;
}
// ScrollAnimated is only used for wheel scrolls. We use the same bubbling
// behavior as ScrollBy to determine which layer to animate, but we do not
// do the Android-specific things in ScrollBy like showing top controls.
- InputHandler::ScrollStatus scroll_status = ScrollBegin(viewport_point, Wheel);
- if (scroll_status == ScrollStarted) {
+ InputHandler::ScrollStatus scroll_status = ScrollBegin(viewport_point, WHEEL);
+ if (scroll_status == SCROLL_STARTED) {
gfx::Vector2dF pending_delta = scroll_delta;
for (LayerImpl* layer_impl = CurrentlyScrollingLayer(); layer_impl;
layer_impl = layer_impl->parent()) {
@@ -2450,17 +2461,15 @@
EaseInOutTimingFunction::Create());
curve->SetInitialValue(current_offset);
- scoped_ptr<Animation> animation =
- Animation::Create(curve.Pass(),
- AnimationIdProvider::NextAnimationId(),
- AnimationIdProvider::NextGroupId(),
- Animation::ScrollOffset);
+ scoped_ptr<Animation> animation = Animation::Create(
+ curve.Pass(), AnimationIdProvider::NextAnimationId(),
+ AnimationIdProvider::NextGroupId(), Animation::SCROLL_OFFSET);
animation->set_is_impl_only(true);
layer_impl->layer_animation_controller()->AddAnimation(animation.Pass());
SetNeedsAnimate();
- return ScrollStarted;
+ return SCROLL_STARTED;
}
}
ScrollEnd();
@@ -2811,13 +2820,13 @@
InputHandler::ScrollStatus LayerTreeHostImpl::FlingScrollBegin() {
if (!active_tree_->CurrentlyScrollingLayer())
- return ScrollIgnored;
+ return SCROLL_IGNORED;
if (settings_.ignore_root_layer_flings &&
(active_tree_->CurrentlyScrollingLayer() == InnerViewportScrollLayer() ||
active_tree_->CurrentlyScrollingLayer() == OuterViewportScrollLayer())) {
ClearCurrentlyScrollingLayer();
- return ScrollIgnored;
+ return SCROLL_IGNORED;
}
if (!wheel_scrolling_) {
@@ -2827,7 +2836,7 @@
should_bubble_scrolls_ = false;
}
- return ScrollStarted;
+ return SCROLL_STARTED;
}
float LayerTreeHostImpl::DeviceSpaceDistanceToLayer(
@@ -2871,12 +2880,9 @@
}
bool scroll_on_main_thread = false;
- LayerImpl* scroll_layer_impl =
- FindScrollLayerForDeviceViewportPoint(device_viewport_point,
- InputHandler::Gesture,
- layer_impl,
- &scroll_on_main_thread,
- NULL);
+ LayerImpl* scroll_layer_impl = FindScrollLayerForDeviceViewportPoint(
+ device_viewport_point, InputHandler::GESTURE, layer_impl,
+ &scroll_on_main_thread, NULL);
if (scroll_on_main_thread || !scroll_layer_impl)
return;
@@ -3373,11 +3379,9 @@
format = ETC1;
break;
}
- id =
- resource_provider_->CreateResource(bitmap.GetSize(),
- wrap_mode,
- ResourceProvider::TextureHintImmutable,
- format);
+ id = resource_provider_->CreateResource(
+ bitmap.GetSize(), wrap_mode, ResourceProvider::TEXTURE_HINT_IMMUTABLE,
+ format);
UIResourceData data;
data.resource_id = id;
@@ -3387,11 +3391,8 @@
ui_resource_map_[uid] = data;
AutoLockUIResourceBitmap bitmap_lock(bitmap);
- resource_provider_->SetPixels(id,
- bitmap_lock.GetPixels(),
- gfx::Rect(bitmap.GetSize()),
- gfx::Rect(bitmap.GetSize()),
- gfx::Vector2d(0, 0));
+ resource_provider_->CopyToResource(id, bitmap_lock.GetPixels(),
+ bitmap.GetSize());
MarkUIResourceNotEvicted(uid);
}
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
index 6dd0d5a..60f4b44 100644
--- a/cc/trees/layer_tree_host_impl.h
+++ b/cc/trees/layer_tree_host_impl.h
@@ -328,6 +328,8 @@
const LayerTreeImpl* recycle_tree() const { return recycle_tree_.get(); }
// Returns the tree LTH synchronizes with.
LayerTreeImpl* sync_tree() {
+ // TODO(enne): This is bogus. It should return based on the value of
+ // Proxy::CommitToActiveTree and not whether the pending tree exists.
return pending_tree_ ? pending_tree_.get() : active_tree_.get();
}
virtual void CreatePendingTree();
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 07fb048..38b2d66 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -497,16 +497,16 @@
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(0, 10),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
EXPECT_TRUE(did_request_redraw_);
EXPECT_TRUE(did_request_commit_);
}
@@ -516,8 +516,8 @@
host_impl_->SetViewportSize(gfx::Size(50, 50));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_FALSE(host_impl_->IsActivelyScrolling());
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_TRUE(host_impl_->IsActivelyScrolling());
@@ -527,8 +527,8 @@
TEST_F(LayerTreeHostImplTest, ScrollWithoutRootLayer) {
// We should not crash when trying to scroll an empty layer tree.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollWithoutRenderer) {
@@ -544,8 +544,8 @@
// We should not crash when trying to scroll after the renderer initialization
// fails.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ReplaceTreeWhileScrolling) {
@@ -554,8 +554,8 @@
DrawFrame();
// We should not crash if the tree is replaced while we are scrolling.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->active_tree()->DetachLayerTree();
scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
@@ -578,25 +578,26 @@
// With registered event handlers, wheel scrolls don't necessarily
// have to go to the main thread.
root->SetHaveWheelEventHandlers(true);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollEnd();
// But typically the scroll-blocks-on mode will require them to.
- root->SetScrollBlocksOn(ScrollBlocksOnWheelEvent | ScrollBlocksOnStartTouch);
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT |
+ SCROLL_BLOCKS_ON_START_TOUCH);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
// But gesture scrolls can still be handled.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollEnd();
// And if the handlers go away, wheel scrolls can again be processed
// on impl (despite the scroll-blocks-on mode).
root->SetHaveWheelEventHandlers(false);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollEnd();
}
@@ -621,20 +622,21 @@
// Touch handler regions determine whether touch events block scroll.
root->SetTouchEventHandlerRegion(gfx::Rect(0, 0, 100, 100));
EXPECT_FALSE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 10)));
- root->SetScrollBlocksOn(ScrollBlocksOnStartTouch | ScrollBlocksOnWheelEvent);
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_START_TOUCH |
+ SCROLL_BLOCKS_ON_WHEEL_EVENT);
EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 10)));
// But they don't influence the actual handling of the scroll gestures.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollEnd();
// It's the union of scroll-blocks-on mode bits across all layers in the
// scroll paret chain that matters.
EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 30)));
- root->SetScrollBlocksOn(ScrollBlocksOnNone);
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_NONE);
EXPECT_FALSE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 30)));
- child->SetScrollBlocksOn(ScrollBlocksOnStartTouch);
+ child->SetScrollBlocksOn(SCROLL_BLOCKS_ON_START_TOUCH);
EXPECT_TRUE(host_impl_->DoTouchEventsBlockScrollAt(gfx::Point(10, 30)));
}
@@ -647,30 +649,31 @@
// With registered scroll handlers, scrolls don't generally have to go
// to the main thread.
root->SetHaveScrollEventHandlers(true);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollEnd();
// Even the default scroll blocks on mode doesn't require this.
- root->SetScrollBlocksOn(ScrollBlocksOnWheelEvent | ScrollBlocksOnStartTouch);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT |
+ SCROLL_BLOCKS_ON_START_TOUCH);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollEnd();
// But the page can opt in to blocking on scroll event handlers.
- root->SetScrollBlocksOn(ScrollBlocksOnScrollEvent);
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
- // Gesture and Wheel scrolls behave identically in this regard.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // GESTURE and WHEEL scrolls behave identically in this regard.
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
// And if the handlers go away, scrolls can again be processed on impl
// (despite the scroll-blocks-on mode).
root->SetHaveScrollEventHandlers(false);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollEnd();
}
@@ -713,36 +716,36 @@
}
// Scroll-blocks-on on a layer affects scrolls that hit that layer.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE));
host_impl_->ScrollEnd();
- child1->SetScrollBlocksOn(ScrollBlocksOnScrollEvent);
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::Gesture));
+ child1->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE));
// But not those that hit only other layers.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
host_impl_->ScrollEnd();
// It's the union of bits set across the scroll ancestor chain that matters.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
host_impl_->ScrollEnd();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::WHEEL));
host_impl_->ScrollEnd();
- root->SetScrollBlocksOn(ScrollBlocksOnWheelEvent);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::Gesture));
+ root->SetScrollBlocksOn(SCROLL_BLOCKS_ON_WHEEL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
host_impl_->ScrollEnd();
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::Wheel));
- child2->SetScrollBlocksOn(ScrollBlocksOnScrollEvent);
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::Wheel));
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::WHEEL));
+ child2->SetScrollBlocksOn(SCROLL_BLOCKS_ON_SCROLL_EVENT);
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::WHEEL));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 25), InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchscreen) {
@@ -751,16 +754,14 @@
DrawFrame();
// Ignore the fling since no layer is being scrolled
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
// Start scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Now the fling should go ahead since we've started scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
}
TEST_F(LayerTreeHostImplTest, FlingOnlyWhenScrollingTouchpad) {
@@ -769,16 +770,14 @@
DrawFrame();
// Ignore the fling since no layer is being scrolled
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
// Start scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
// Now the fling should go ahead since we've started scrolling a layer
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
}
TEST_F(LayerTreeHostImplTest, NoFlingWhenScrollingOnMain) {
@@ -790,12 +789,11 @@
root->SetShouldScrollOnMainThread(true);
// Start scrolling a layer
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// The fling should be ignored since there's no layer being scrolled impl-side
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED, host_impl_->FlingScrollBegin());
}
TEST_F(LayerTreeHostImplTest, ShouldScrollOnMainThread) {
@@ -806,10 +804,10 @@
root->SetShouldScrollOnMainThread(true);
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionBasic) {
@@ -823,38 +821,34 @@
DrawFrame();
// All scroll types inside the non-fast scrollable region should fail.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(25, 25),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(25, 25), InputHandler::WHEEL));
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
- InputHandler::Wheel));
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(25, 25),
- InputHandler::Gesture));
+ InputHandler::WHEEL));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(25, 25), InputHandler::GESTURE));
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
// All scroll types outside this region should succeed.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(75, 75),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(75, 75), InputHandler::WHEEL));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(25, 25),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(75, 75), InputHandler::GESTURE));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(75, 75),
- InputHandler::Gesture));
+ InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, NonFastScrollableRegionWithOffset) {
@@ -870,18 +864,16 @@
// This point would fall into the non-fast scrollable region except that we've
// moved the layer down by 25 pixels.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(40, 10),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(40, 10), InputHandler::WHEEL));
EXPECT_TRUE(host_impl_->IsCurrentlyScrollingLayerAt(gfx::Point(40, 10),
- InputHandler::Wheel));
+ InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 1));
host_impl_->ScrollEnd();
// This point is still inside the non-fast region.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(10, 10),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollHandlerNotPresent) {
@@ -891,7 +883,7 @@
DrawFrame();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
@@ -904,7 +896,7 @@
DrawFrame();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
EXPECT_TRUE(host_impl_->scroll_affects_scroll_handler());
host_impl_->ScrollEnd();
EXPECT_FALSE(host_impl_->scroll_affects_scroll_handler());
@@ -916,8 +908,8 @@
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Trying to scroll to the left/top will not succeed.
EXPECT_FALSE(
@@ -962,9 +954,8 @@
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
// Trying to scroll without a vertical scrollbar will fail.
EXPECT_FALSE(host_impl_->ScrollVerticallyByPage(
@@ -1006,8 +997,8 @@
DrawFrame();
gfx::Point scroll_position(10, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(scroll_position, InputHandler::WHEEL));
EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(), overflow->CurrentScrollOffset());
@@ -1019,8 +1010,8 @@
overflow->set_user_scrollable_horizontal(false);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(scroll_position, InputHandler::WHEEL));
EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 10), overflow->CurrentScrollOffset());
@@ -1031,8 +1022,8 @@
overflow->set_user_scrollable_vertical(false);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(scroll_position, InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(scroll_position, InputHandler::WHEEL));
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 0), scroll_layer->CurrentScrollOffset());
EXPECT_VECTOR_EQ(gfx::Vector2dF(10, 20), overflow->CurrentScrollOffset());
@@ -1063,7 +1054,7 @@
float page_scale_delta = 2.f;
- host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
host_impl_->PinchGestureEnd();
@@ -1090,16 +1081,15 @@
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
host_impl_->PinchGestureEnd();
host_impl_->ScrollEnd();
gfx::Vector2d scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -1117,8 +1107,8 @@
new LatencyInfoSwapPromise(latency_info));
SetupScrollAndContentsLayers(gfx::Size(100, 100));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->QueueSwapPromiseForMainThreadScrollUpdate(swap_promise.Pass());
host_impl_->ScrollEnd();
@@ -1146,7 +1136,7 @@
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
- host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
host_impl_->PinchGestureEnd();
@@ -1167,7 +1157,7 @@
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 10.f;
- host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(50, 50), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(50, 50));
host_impl_->PinchGestureEnd();
@@ -1187,7 +1177,7 @@
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(50, 50));
float page_scale_delta = 0.1f;
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -1209,7 +1199,7 @@
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(20, 20));
float page_scale_delta = 1.f;
- host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(20, 20));
@@ -1231,7 +1221,7 @@
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(20, 20));
float page_scale_delta = 1.f;
- host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(10, 10), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point(10, 10));
host_impl_->ScrollBy(gfx::Point(10, 10), gfx::Vector2d(-10, -10));
@@ -1252,7 +1242,7 @@
scroll_layer->PullDeltaForMainThread();
scroll_layer->PushScrollOffsetFromMainThread(gfx::ScrollOffset(0, 0));
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(2.f, gfx::Point(0, 0));
host_impl_->PinchGestureUpdate(1.f, gfx::Point(0, 0));
@@ -1618,7 +1608,7 @@
TEST_F(LayerTreeHostImplTest, ScrollbarLinearFadeScheduling) {
LayerTreeSettings settings;
- settings.scrollbar_animator = LayerTreeSettings::LinearFade;
+ settings.scrollbar_animator = LayerTreeSettings::LINEAR_FADE;
settings.scrollbar_fade_delay_ms = 20;
settings.scrollbar_fade_duration_ms = 20;
@@ -1630,14 +1620,14 @@
EXPECT_FALSE(did_request_redraw_);
// If no scroll happened during a scroll gesture, it should have no effect.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
host_impl_->ScrollEnd();
EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
EXPECT_FALSE(did_request_redraw_);
EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
// After a scroll, a fade animation should be scheduled about 20ms from now.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 5));
host_impl_->ScrollEnd();
did_request_redraw_ = false;
@@ -1668,7 +1658,7 @@
requested_scrollbar_animation_delay_ = base::TimeDelta();
// Unnecessarily Fade animation of solid color scrollbar is not triggered.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
host_impl_->ScrollEnd();
EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
@@ -1676,7 +1666,7 @@
TEST_F(LayerTreeHostImplTest, ScrollbarFadePinchZoomScrollbars) {
LayerTreeSettings settings;
- settings.scrollbar_animator = LayerTreeSettings::LinearFade;
+ settings.scrollbar_animator = LayerTreeSettings::LINEAR_FADE;
settings.scrollbar_fade_delay_ms = 20;
settings.scrollbar_fade_duration_ms = 20;
settings.use_pinch_zoom_scrollbars = true;
@@ -1691,14 +1681,14 @@
EXPECT_FALSE(did_request_animate_);
// If no scroll happened during a scroll gesture, it should have no effect.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
host_impl_->ScrollEnd();
EXPECT_EQ(base::TimeDelta(), requested_scrollbar_animation_delay_);
EXPECT_FALSE(did_request_animate_);
EXPECT_TRUE(scrollbar_fade_start_.Equals(base::Closure()));
// After a scroll, no fade animation should be scheduled.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
host_impl_->ScrollEnd();
did_request_redraw_ = false;
@@ -1715,7 +1705,7 @@
host_impl_->SetPageScaleOnActiveTree(1.1f);
// After a scroll, a fade animation should be scheduled about 20ms from now.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL);
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(5, 0));
host_impl_->ScrollEnd();
did_request_redraw_ = false;
@@ -1737,7 +1727,7 @@
LayerTreeSettings settings;
settings.scrollbar_fade_delay_ms = 500;
settings.scrollbar_fade_duration_ms = 300;
- settings.scrollbar_animator = LayerTreeSettings::Thinning;
+ settings.scrollbar_animator = LayerTreeSettings::THINNING;
gfx::Size viewport_size(300, 200);
gfx::Size device_viewport_size = gfx::ToFlooredSize(
@@ -1844,8 +1834,8 @@
}
// Scrolling should update metadata immediately.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
{
CompositorFrameMetadata metadata =
@@ -1878,7 +1868,7 @@
}
// Page scale should update metadata correctly (shrinking only the viewport).
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(2.f, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -2444,8 +2434,8 @@
DrawFrame();
// Scroll event is ignored because layer is not scrollable.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_FALSE(did_request_redraw_);
EXPECT_FALSE(did_request_commit_);
}
@@ -2602,8 +2592,8 @@
gfx::Size(10, 10), gfx::Size(10, 10), gfx::Size(10, 10));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Make the test scroll delta a fractional amount, to verify that the
// fixed container size delta is (1) non-zero, and (2) fractional, and
@@ -2643,8 +2633,8 @@
outer_scroll->SetDrawsContent(true);
host_impl_->active_tree()->PushPageScaleFromMainThread(2.f, 1.f, 2.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, 50.f));
// The entire scroll delta should have been used to hide the top controls.
@@ -2662,8 +2652,8 @@
host_impl_->ScrollEnd();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -50.f));
@@ -2709,8 +2699,8 @@
// not be scaled.
host_impl_->active_tree()->PushPageScaleFromMainThread(page_scale, 1.f, 2.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
// Scroll down, the top controls hiding should expand the viewport size so
// the delta should be equal to the scroll distance.
@@ -2781,8 +2771,8 @@
// Scroll 25px to hide top controls
gfx::Vector2dF scroll_delta(0.f, 25.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -2930,8 +2920,8 @@
// Hide the top controls by 25px.
gfx::Vector2dF scroll_delta(0.f, 25.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
// scrolling down at the max extents no longer hides the top controls
@@ -2956,8 +2946,8 @@
// Bring the top controls down by 25px.
scroll_delta = gfx::Vector2dF(0.f, -25.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -2983,8 +2973,8 @@
host_impl_->top_controls_manager()->ContentTopOffset());
gfx::Vector2dF scroll_delta(0.f, 25.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3021,8 +3011,8 @@
// Send a gesture scroll that will scroll the outer viewport, make sure the
// top controls get scrolled.
gfx::Vector2dF scroll_delta(0.f, 15.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->OuterViewportScrollLayer(),
host_impl_->CurrentlyScrollingLayer());
@@ -3033,8 +3023,8 @@
host_impl_->top_controls_manager()->ContentTopOffset());
scroll_delta = gfx::Vector2dF(0.f, 50.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(0, host_impl_->top_controls_manager()->ContentTopOffset());
@@ -3049,8 +3039,8 @@
host_impl_->InnerViewportScrollLayer()->SetScrollDelta(inner_viewport_offset);
scroll_delta = gfx::Vector2dF(0.f, -65.f);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(top_controls_height_,
@@ -3068,8 +3058,8 @@
SetupTopControlsAndScrollLayer();
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->top_controls_manager()->ScrollBegin();
host_impl_->top_controls_manager()->ScrollBy(gfx::Vector2dF(0.f, 50.f));
@@ -3081,8 +3071,8 @@
host_impl_->ScrollEnd();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
float scroll_increment_y = -25.f;
host_impl_->top_controls_manager()->ScrollBegin();
@@ -3110,8 +3100,8 @@
gfx::ScrollOffset(),
host_impl_->active_tree()->InnerViewportScrollLayer()->MaxScrollOffset());
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
}
TEST_F(LayerTreeHostImplTest, ScrollNonCompositedRoot) {
@@ -3146,9 +3136,8 @@
host_impl_->SetViewportSize(surface_size);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->ScrollEnd();
EXPECT_TRUE(did_request_redraw_);
@@ -3167,9 +3156,8 @@
host_impl_->SetViewportSize(surface_size);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
host_impl_->ScrollEnd();
EXPECT_TRUE(did_request_redraw_);
@@ -3187,9 +3175,8 @@
// Scroll event is ignored because the input coordinate is outside the layer
// boundaries.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(15, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(15, 5), InputHandler::WHEEL));
EXPECT_FALSE(did_request_redraw_);
EXPECT_FALSE(did_request_commit_);
}
@@ -3213,9 +3200,8 @@
// Scroll event is ignored because the scrollable layer is not facing the
// viewer and there is nothing scrollable behind it.
- EXPECT_EQ(InputHandler::ScrollIgnored,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_IGNORED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
EXPECT_FALSE(did_request_redraw_);
EXPECT_FALSE(did_request_commit_);
}
@@ -3243,9 +3229,8 @@
// Scrolling fails because the content layer is asking to be scrolled on the
// main thread.
- EXPECT_EQ(InputHandler::ScrollOnMainThread,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_ON_MAIN_THREAD,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollRootAndChangePageScaleOnMainThread) {
@@ -3278,9 +3263,8 @@
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3330,14 +3314,13 @@
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta = scroll_delta;
gfx::ScrollOffset expected_max_scroll = root_scroll->MaxScrollOffset();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
// Set new page scale on impl thread by pinching.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -3379,7 +3362,7 @@
LayerImpl* grand_child = child->children()[0];
// Set new page scale on impl thread by pinching.
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(new_page_scale, gfx::Point());
host_impl_->PinchGestureEnd();
@@ -3442,9 +3425,8 @@
gfx::Vector2d scroll_delta(0, 10);
gfx::Vector2d expected_scroll_delta(scroll_delta);
gfx::ScrollOffset expected_max_scroll(child->MaxScrollOffset());
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3494,9 +3476,8 @@
DrawFrame();
{
gfx::Vector2d scroll_delta(-8, -7);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3548,9 +3529,9 @@
DrawFrame();
{
gfx::Vector2d scroll_delta(0, -10);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3568,9 +3549,9 @@
// The next time we scroll we should only scroll the parent.
scroll_delta = gfx::Vector2d(0, -3);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
@@ -3587,9 +3568,9 @@
// After scrolling the parent, another scroll on the opposite direction
// should still scroll the child.
scroll_delta = gfx::Vector2d(0, 7);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child);
@@ -3609,9 +3590,9 @@
host_impl_->SetPageScaleOnActiveTree(2.f);
scroll_delta = gfx::Vector2d(0, -2);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(1, 1),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(grand_child, host_impl_->CurrentlyScrollingLayer());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3651,9 +3632,8 @@
DrawFrame();
{
gfx::Vector2d scroll_delta(0, 4);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3698,9 +3678,8 @@
host_impl_->active_tree()->DidBecomeActive();
// Scrolling should still work even though we did not draw yet.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollAxisAlignedRotatedLayer) {
@@ -3717,9 +3696,8 @@
// Scroll to the right in screen coordinates with a gesture.
gfx::Vector2d gesture_scroll_delta(10, 0);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
host_impl_->ScrollEnd();
@@ -3731,9 +3709,8 @@
// Reset and scroll down with the wheel.
scroll_layer->SetScrollDelta(gfx::Vector2dF());
gfx::Vector2d wheel_scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
host_impl_->ScrollEnd();
@@ -3779,9 +3756,8 @@
{
// Scroll down in screen coordinates with a gesture.
gfx::Vector2d gesture_scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(1, 1),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(1, 1), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
host_impl_->ScrollEnd();
@@ -3802,9 +3778,8 @@
// Now reset and scroll the same amount horizontally.
child_ptr->SetScrollDelta(gfx::Vector2dF());
gfx::Vector2d gesture_scroll_delta(10, 0);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(1, 1),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(1, 1), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), gesture_scroll_delta);
host_impl_->ScrollEnd();
@@ -3845,8 +3820,8 @@
// Scroll down in screen coordinates with a gesture.
gfx::Vector2d scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
host_impl_->ScrollEnd();
@@ -3860,8 +3835,8 @@
// Reset and scroll down with the wheel.
scroll_layer->SetScrollDelta(gfx::Vector2dF());
gfx::Vector2d wheel_scroll_delta(0, 10);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), wheel_scroll_delta);
host_impl_->ScrollEnd();
@@ -4000,7 +3975,7 @@
// The pinch gesture doesn't put the delegate into a state where the scroll
// offset is outside of the scroll range. (this is verified by DCHECKs in the
// delegate).
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(2.f, gfx::Point());
host_impl_->PinchGestureUpdate(.5f, gfx::Point());
@@ -4012,8 +3987,8 @@
gfx::ScrollOffset current_offset(7.f, 8.f);
scroll_delegate.set_getter_return_value(current_offset);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(ScrollOffsetWithDelta(current_offset, scroll_delta),
@@ -4094,8 +4069,8 @@
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
// In-bounds scrolling does not affect overscroll.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
scroll_result = host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_TRUE(scroll_result.did_scroll);
EXPECT_FALSE(scroll_result.did_overscroll_root);
@@ -4229,9 +4204,9 @@
DrawFrame();
{
gfx::Vector2d scroll_delta(0, -10);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollEnd();
@@ -4239,9 +4214,9 @@
// The next time we scroll we should only scroll the parent, but overscroll
// should still not reach the root layer.
scroll_delta = gfx::Vector2d(0, -30);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -4252,9 +4227,9 @@
// After scrolling the parent, another scroll on the opposite direction
// should scroll the child.
scroll_delta = gfx::Vector2d(0, 70);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::NonBubblingGesture));
+ InputHandler::NON_BUBBLING_GESTURE));
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), grand_child_layer);
@@ -4291,9 +4266,8 @@
DrawFrame();
{
gfx::Vector2d scroll_delta(0, 8);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(5, 5),
- InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(5, 5), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -4317,8 +4291,8 @@
EXPECT_EQ(gfx::Vector2dF(), host_impl_->accumulated_root_overscroll());
// Even though the layer can't scroll the overscroll still happens.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10));
EXPECT_EQ(gfx::Vector2dF(0, 10), host_impl_->accumulated_root_overscroll());
}
@@ -4355,8 +4329,8 @@
// Horizontal & Vertical GlowEffect should not be applied when
// content size is less then view port size. For Example Horizontal &
// vertical GlowEffect should not be applied in about:blank page.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, -1));
EXPECT_EQ(gfx::Vector2dF().ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4392,8 +4366,8 @@
// Edge glow effect should be applicable only upon reaching Edges
// of the content. unnecessary glow effect calls shouldn't be
// called while scrolling up without reaching the edge of the content.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 100));
EXPECT_EQ(gfx::Vector2dF().ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4403,10 +4377,10 @@
host_impl_->ScrollEnd();
// unusedrootDelta should be subtracted from applied delta so that
// unwanted glow effect calls are not called.
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollBegin(gfx::Point(0, 0),
- InputHandler::NonBubblingGesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ InputHandler::NON_BUBBLING_GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0, 20));
EXPECT_EQ(gfx::Vector2dF(0.000000f, 17.699997f).ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4417,8 +4391,8 @@
host_impl_->ScrollEnd();
// TestCase to check kEpsilon, which prevents minute values to trigger
// gloweffect without reaching edge.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(0, 0), InputHandler::WHEEL));
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(-0.12f, 0.1f));
EXPECT_EQ(gfx::Vector2dF().ToString(),
host_impl_->accumulated_root_overscroll().ToString());
@@ -4493,7 +4467,7 @@
resource_id_(resource_provider->CreateResource(
gfx::Size(1, 1),
GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE,
RGBA_8888)) {
resource_provider->AllocateForTesting(resource_id_);
SetBounds(gfx::Size(10, 10));
@@ -6436,7 +6410,8 @@
host_impl_->ActivateSyncTree();
- host_impl_->active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ host_impl_->active_tree()->UpdateDrawProperties(update_lcd_text);
ASSERT_EQ(1u, host_impl_->active_tree()->RenderSurfaceLayerList().size());
LayerTreeHostImpl::FrameData frame;
@@ -6917,12 +6892,10 @@
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(),
- InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
gfx::Vector2d scroll_delta(0, 100);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -6970,8 +6943,8 @@
LayerImpl* grand_child = child->children()[0];
gfx::Vector2d scroll_delta(0, -2);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
// The grand child should have scrolled up to its limit.
@@ -6991,7 +6964,7 @@
// The first |ScrollBy| after the fling should re-lock the scrolling
// layer to the first layer that scrolled, which is the child.
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), child);
@@ -7030,11 +7003,10 @@
host_impl_->active_tree()->DidBecomeActive();
DrawFrame();
{
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
gfx::Vector2d scroll_delta(0, 100);
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -7053,7 +7025,7 @@
TEST_F(LayerTreeHostImplTest, ScrollUnknownNotOnAncestorChain) {
// If we ray cast a scroller that is not on the first layer's ancestor chain,
- // we should return ScrollUnknown.
+ // we should return SCROLL_UNKNOWN.
gfx::Size content_size(100, 100);
SetupScrollAndContentsLayers(content_size);
@@ -7079,14 +7051,14 @@
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollUnknown,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_UNKNOWN,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollUnknownScrollAncestorMismatch) {
// If we ray cast a scroller this is on the first layer's ancestor chain, but
// is not the first scroller we encounter when walking up from the layer, we
- // should also return ScrollUnknown.
+ // should also return SCROLL_UNKNOWN.
gfx::Size content_size(100, 100);
SetupScrollAndContentsLayers(content_size);
@@ -7118,8 +7090,8 @@
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollUnknown,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_UNKNOWN,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
}
TEST_F(LayerTreeHostImplTest, ScrollInvisibleScroller) {
@@ -7145,10 +7117,10 @@
// it. The reason for this is that if the scrolling the scroll would not move
// any layer that is a drawn RSLL member, then we can ignore the hit.
//
- // Why ScrollStarted? In this case, it's because we've bubbled out and started
- // overscrolling the inner viewport.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // Why SCROLL_STARTED? In this case, it's because we've bubbled out and
+ // started overscrolling the inner viewport.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_EQ(2, host_impl_->CurrentlyScrollingLayer()->id());
}
@@ -7202,10 +7174,10 @@
// it. The reason for this is that if the scrolling the scroll would not move
// any layer that is a drawn RSLL member, then we can ignore the hit.
//
- // Why ScrollStarted? In this case, it's because we've bubbled out and started
- // overscrolling the inner viewport.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ // Why SCROLL_STARTED? In this case, it's because we've bubbled out and
+ // started overscrolling the inner viewport.
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_EQ(7, host_impl_->CurrentlyScrollingLayer()->id());
}
@@ -7401,8 +7373,8 @@
LayerImpl* scroll_layer = SetupScrollAndContentsLayers(gfx::Size(100, 100));
// Scrolling normally should not trigger any forwarding.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_TRUE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
host_impl_->ScrollEnd();
@@ -7414,8 +7386,8 @@
// Scrolling with a scroll handler should defer the swap to the main
// thread.
scroll_layer->SetHaveScrollEventHandlers(true);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_TRUE(
host_impl_->ScrollBy(gfx::Point(), gfx::Vector2d(0, 10)).did_scroll);
host_impl_->ScrollEnd();
@@ -7490,8 +7462,8 @@
BOTH, SHOWN, false);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
scroll_layer->CurrentScrollOffset().ToString());
@@ -7549,8 +7521,8 @@
BOTH, SHOWN, false);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF().ToString(),
scroll_layer->CurrentScrollOffset().ToString());
@@ -7619,8 +7591,8 @@
gfx::ScrollOffset(0, initial_scroll_offset));
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
EXPECT_EQ(gfx::Vector2dF(0, initial_scroll_offset).ToString(),
scroll_layer->CurrentScrollOffset().ToString());
@@ -7680,8 +7652,8 @@
false);
DrawFrame();
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_EQ(0, host_impl_->top_controls_manager()->ControlsTopOffset());
float offset = 50;
@@ -7813,9 +7785,9 @@
EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
// Make sure the fling goes to the outer viewport first
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
@@ -7827,9 +7799,9 @@
EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
// Fling past the outer viewport boundry, make sure inner viewport scrolls.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
outer_expected += gfx::Vector2dF(scroll_delta.x(), scroll_delta.y());
@@ -7862,9 +7834,9 @@
EXPECT_VECTOR_EQ(outer_expected, outer_scroll->CurrentScrollOffset());
// Make sure the scroll goes to the outer viewport first.
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
// Scroll near the edge of the outer viewport.
gfx::Vector2d scroll_delta(inner_viewport.width(), inner_viewport.height());
@@ -7908,8 +7880,8 @@
scoped_ptr<ScrollAndScaleSet> scroll_info;
gfx::Vector2d scroll_delta(0, inner_viewport.height());
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE));
EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
// The child should have scrolled up to its limit.
@@ -7920,7 +7892,7 @@
// The first |ScrollBy| after the fling should re-lock the scrolling
// layer to the first layer that scrolled, the inner viewport scroll layer.
- EXPECT_EQ(InputHandler::ScrollStarted, host_impl_->FlingScrollBegin());
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, host_impl_->FlingScrollBegin());
EXPECT_TRUE(host_impl_->ScrollBy(gfx::Point(), scroll_delta).did_scroll);
EXPECT_EQ(host_impl_->CurrentlyScrollingLayer(), inner_scroll);
@@ -7996,7 +7968,7 @@
base::TimeTicks start_time =
base::TimeTicks() + base::TimeDelta::FromMilliseconds(100);
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
LayerImpl* scrolling_layer = host_impl_->CurrentlyScrollingLayer();
@@ -8013,7 +7985,7 @@
EXPECT_TRUE(y > 1 && y < 49);
// Update target.
- EXPECT_EQ(InputHandler::ScrollStarted,
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
host_impl_->ScrollAnimated(gfx::Point(), gfx::Vector2d(0, 50)));
host_impl_->Animate(start_time + base::TimeDelta::FromMilliseconds(200));
@@ -8356,15 +8328,15 @@
scroll_layer->SetScrollDelta(gfx::Vector2d());
float page_scale_delta = 2.f;
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Gesture);
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::GESTURE);
host_impl_->PinchGestureBegin();
host_impl_->PinchGestureUpdate(page_scale_delta, gfx::Point());
host_impl_->PinchGestureEnd();
host_impl_->ScrollEnd();
gfx::Vector2dF scroll_delta(0, 5);
- EXPECT_EQ(InputHandler::ScrollStarted,
- host_impl_->ScrollBegin(gfx::Point(), InputHandler::Wheel));
+ EXPECT_EQ(InputHandler::SCROLL_STARTED,
+ host_impl_->ScrollBegin(gfx::Point(), InputHandler::WHEEL));
EXPECT_VECTOR_EQ(gfx::Vector2dF(), scroll_layer->CurrentScrollOffset());
host_impl_->ScrollBy(gfx::Point(), scroll_delta);
diff --git a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
deleted file mode 100644
index d32817c..0000000
--- a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ /dev/null
@@ -1,116 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/layers/append_quads_data.h"
-#include "cc/layers/content_layer_client.h"
-#include "cc/layers/picture_layer.h"
-#include "cc/layers/picture_layer_impl.h"
-#include "cc/quads/draw_quad.h"
-#include "cc/test/layer_tree_pixel_test.h"
-#include "cc/trees/layer_tree_impl.h"
-#include "third_party/skia/include/core/SkCanvas.h"
-#include "third_party/skia/include/core/SkColor.h"
-#include "ui/gfx/geometry/rect.h"
-#include "ui/gfx/geometry/rect_f.h"
-
-#if !defined(OS_ANDROID)
-
-namespace cc {
-namespace {
-
-class LayerTreeHostOnDemandRasterPixelTest : public LayerTreePixelTest {
- public:
- void InitializeSettings(LayerTreeSettings* settings) override {
- settings->impl_side_painting = true;
- }
-
- void BeginCommitOnThread(LayerTreeHostImpl* impl) override {
- // Not enough memory available. Enforce on-demand rasterization.
- impl->SetMemoryPolicy(
- ManagedMemoryPolicy(1, gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
- 1000));
- }
-
- void SwapBuffersOnThread(LayerTreeHostImpl* host_impl, bool result) override {
- // Find the PictureLayerImpl ask it to append quads to check their material.
- // The PictureLayerImpl is assumed to be the first child of the root layer
- // in the active tree.
- PictureLayerImpl* picture_layer = static_cast<PictureLayerImpl*>(
- host_impl->active_tree()->root_layer()->child_at(0));
-
- scoped_ptr<RenderPass> render_pass = RenderPass::Create();
-
- AppendQuadsData data;
- picture_layer->AppendQuads(render_pass.get(), &data);
-
- for (const auto& quad : render_pass->quad_list)
- EXPECT_EQ(quad->material, DrawQuad::PICTURE_CONTENT);
-
- // Triggers pixel readback and ends the test.
- LayerTreePixelTest::SwapBuffersOnThread(host_impl, result);
- }
-
- void RunOnDemandRasterPixelTest();
-};
-
-class BlueYellowLayerClient : public ContentLayerClient {
- public:
- explicit BlueYellowLayerClient(gfx::Rect layer_rect)
- : layer_rect_(layer_rect) {}
-
- bool FillsBoundsCompletely() const override { return false; }
-
- void PaintContents(SkCanvas* canvas,
- const gfx::Rect& clip,
- PaintingControlSetting picture_control) override {
- SkPaint paint;
- paint.setColor(SK_ColorBLUE);
- canvas->drawRect(SkRect::MakeWH(layer_rect_.width(),
- layer_rect_.height() / 2),
- paint);
-
- paint.setColor(SK_ColorYELLOW);
- canvas->drawRect(
- SkRect::MakeXYWH(0,
- layer_rect_.height() / 2,
- layer_rect_.width(),
- layer_rect_.height() / 2),
- paint);
- }
-
- scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
- const gfx::Rect& clip,
- PaintingControlSetting picture_control) override {
- NOTIMPLEMENTED();
- return DisplayItemList::Create();
- }
-
- private:
- gfx::Rect layer_rect_;
-};
-
-void LayerTreeHostOnDemandRasterPixelTest::RunOnDemandRasterPixelTest() {
- // Use multiple colors in a single layer to prevent bypassing on-demand
- // rasterization if a single solid color is detected in picture analysis.
- gfx::Rect layer_rect(200, 200);
- BlueYellowLayerClient client(layer_rect);
- scoped_refptr<PictureLayer> layer = PictureLayer::Create(&client);
-
- layer->SetIsDrawable(true);
- layer->SetBounds(layer_rect.size());
- layer->SetPosition(layer_rect.origin());
-
- RunPixelTest(PIXEL_TEST_GL,
- layer,
- base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")));
-}
-
-TEST_F(LayerTreeHostOnDemandRasterPixelTest, RasterPictureLayer) {
- RunOnDemandRasterPixelTest();
-}
-
-} // namespace
-} // namespace cc
-
-#endif // OS_ANDROID
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index bb6dc17..f9b690d 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1320,7 +1320,7 @@
// Make sure partial texture updates are turned off.
settings->max_partial_texture_updates = 0;
// Linear fade animator prevents scrollbars from drawing immediately.
- settings->scrollbar_animator = LayerTreeSettings::NoAnimator;
+ settings->scrollbar_animator = LayerTreeSettings::NO_ANIMATOR;
}
void SetupTree() override {
@@ -2323,40 +2323,10 @@
class LayerTreeHostTestLCDChange : public LayerTreeHostTest {
public:
- class PaintClient : public FakeContentLayerClient {
- public:
- PaintClient() : paint_count_(0) {}
-
- int paint_count() const { return paint_count_; }
-
- void PaintContents(SkCanvas* canvas,
- const gfx::Rect& clip,
- PaintingControlSetting picture_control) override {
- FakeContentLayerClient::PaintContents(canvas, clip, picture_control);
- ++paint_count_;
- }
-
- scoped_refptr<DisplayItemList> PaintContentsToDisplayList(
- const gfx::Rect& clip,
- PaintingControlSetting picture_control) override {
- NOTIMPLEMENTED();
- return DisplayItemList::Create();
- }
-
- bool FillsBoundsCompletely() const override { return false; }
-
- private:
- int paint_count_;
- };
-
void SetupTree() override {
num_tiles_rastered_ = 0;
- scoped_refptr<Layer> root_layer;
- if (layer_tree_host()->settings().impl_side_painting)
- root_layer = PictureLayer::Create(&client_);
- else
- root_layer = ContentLayer::Create(&client_);
+ scoped_refptr<Layer> root_layer = PictureLayer::Create(&client_);
client_.set_fill_with_nonsolid_color(true);
root_layer->SetIsDrawable(true);
root_layer->SetBounds(gfx::Size(10, 10));
@@ -2364,10 +2334,9 @@
layer_tree_host()->SetRootLayer(root_layer);
- // The expecations are based on the assumption that the default
+ // The expectations are based on the assumption that the default
// LCD settings are:
EXPECT_TRUE(layer_tree_host()->settings().can_use_lcd_text);
- EXPECT_FALSE(root_layer->can_use_lcd_text());
LayerTreeHostTest::SetupTree();
}
@@ -2377,33 +2346,17 @@
void DidCommitAndDrawFrame() override {
switch (layer_tree_host()->source_frame_number()) {
case 1:
- // The first update consists of a paint of the whole layer.
- EXPECT_EQ(1, client_.paint_count());
- // LCD text must have been enabled on the layer.
- EXPECT_TRUE(layer_tree_host()->root_layer()->can_use_lcd_text());
PostSetNeedsCommitToMainThread();
break;
case 2:
- // Since nothing changed on layer, there should be no paint.
- EXPECT_EQ(1, client_.paint_count());
- // LCD text must not have changed.
- EXPECT_TRUE(layer_tree_host()->root_layer()->can_use_lcd_text());
// Change layer opacity that should trigger lcd change.
layer_tree_host()->root_layer()->SetOpacity(.5f);
break;
case 3:
- // LCD text doesn't require re-recording, so no painting should occur.
- EXPECT_EQ(1, client_.paint_count());
- // LCD text must have been disabled on the layer due to opacity.
- EXPECT_FALSE(layer_tree_host()->root_layer()->can_use_lcd_text());
// Change layer opacity that should not trigger lcd change.
layer_tree_host()->root_layer()->SetOpacity(1.f);
break;
case 4:
- // LCD text doesn't require re-recording, so no painting should occur.
- EXPECT_EQ(1, client_.paint_count());
- // Even though LCD text could be allowed.
- EXPECT_TRUE(layer_tree_host()->root_layer()->can_use_lcd_text());
EndTest();
break;
}
@@ -2415,22 +2368,34 @@
}
void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+ PictureLayerImpl* root_layer =
+ static_cast<PictureLayerImpl*>(host_impl->active_tree()->root_layer());
+ bool can_use_lcd_text =
+ host_impl->active_tree()->root_layer()->can_use_lcd_text();
switch (host_impl->active_tree()->source_frame_number()) {
case 0:
// The first draw.
EXPECT_EQ(1, num_tiles_rastered_);
+ EXPECT_TRUE(can_use_lcd_text);
+ EXPECT_TRUE(root_layer->RasterSourceUsesLCDText());
break;
case 1:
// Nothing changed on the layer.
EXPECT_EQ(1, num_tiles_rastered_);
+ EXPECT_TRUE(can_use_lcd_text);
+ EXPECT_TRUE(root_layer->RasterSourceUsesLCDText());
break;
case 2:
- // LCD text was disabled, it should be re-rastered with LCD text off.
+ // LCD text was disabled; it should be re-rastered with LCD text off.
EXPECT_EQ(2, num_tiles_rastered_);
+ EXPECT_FALSE(can_use_lcd_text);
+ EXPECT_FALSE(root_layer->RasterSourceUsesLCDText());
break;
case 3:
- // LCD text was enabled but it's sticky and stays off.
+ // LCD text was enabled, but it's sticky and stays off.
EXPECT_EQ(2, num_tiles_rastered_);
+ EXPECT_TRUE(can_use_lcd_text);
+ EXPECT_FALSE(root_layer->RasterSourceUsesLCDText());
break;
}
}
@@ -2438,7 +2403,7 @@
void AfterTest() override {}
private:
- PaintClient client_;
+ FakeContentLayerClient client_;
int num_tiles_rastered_;
};
@@ -6296,4 +6261,83 @@
SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestNoTasksBetweenWillAndDidCommit);
+// Verify that if a LayerImpl holds onto a copy request for multiple
+// frames that it will continue to have a render surface through
+// multiple commits, even though the Layer itself has no reason
+// to have a render surface.
+class LayerPreserveRenderSurfaceFromOutputRequests : public LayerTreeHostTest {
+ protected:
+ void SetupTree() override {
+ scoped_refptr<Layer> root = Layer::Create();
+ root->CreateRenderSurface();
+ root->SetBounds(gfx::Size(10, 10));
+ child_ = Layer::Create();
+ child_->SetBounds(gfx::Size(20, 20));
+ root->AddChild(child_);
+
+ layer_tree_host()->SetRootLayer(root);
+ LayerTreeHostTest::SetupTree();
+ }
+
+ static void CopyOutputCallback(scoped_ptr<CopyOutputResult> result) {}
+
+ void BeginTest() override {
+ child_->RequestCopyOfOutput(
+ CopyOutputRequest::CreateBitmapRequest(base::Bind(CopyOutputCallback)));
+ EXPECT_TRUE(child_->HasCopyRequest());
+ PostSetNeedsCommitToMainThread();
+ }
+
+ void DidCommit() override { EXPECT_FALSE(child_->HasCopyRequest()); }
+
+ void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
+ LayerImpl* child_impl = host_impl->sync_tree()->LayerById(child_->id());
+
+ switch (host_impl->sync_tree()->source_frame_number()) {
+ case 0:
+ EXPECT_TRUE(child_impl->HasCopyRequest());
+ EXPECT_TRUE(child_impl->render_surface());
+ break;
+ case 1:
+ if (host_impl->proxy()->CommitToActiveTree()) {
+ EXPECT_TRUE(child_impl->HasCopyRequest());
+ EXPECT_TRUE(child_impl->render_surface());
+ } else {
+ EXPECT_FALSE(child_impl->HasCopyRequest());
+ EXPECT_FALSE(child_impl->render_surface());
+ }
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
+ LayerImpl* child_impl = host_impl->active_tree()->LayerById(child_->id());
+ EXPECT_TRUE(child_impl->HasCopyRequest());
+ EXPECT_TRUE(child_impl->render_surface());
+
+ switch (host_impl->active_tree()->source_frame_number()) {
+ case 0:
+ // Lose output surface to prevent drawing and cause another commit.
+ host_impl->DidLoseOutputSurface();
+ break;
+ case 1:
+ EndTest();
+ break;
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ void AfterTest() override {}
+
+ private:
+ scoped_refptr<Layer> child_;
+};
+
+SINGLE_AND_MULTI_THREAD_TEST_F(LayerPreserveRenderSurfaceFromOutputRequests);
+
} // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index e36f6a0..b8d0320 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -130,7 +130,7 @@
LayerAnimationController* controller =
layer_tree_host()->root_layer()->layer_animation_controller();
- Animation* animation = controller->GetAnimation(Animation::Opacity);
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
if (animation)
controller->RemoveAnimation(animation->id());
@@ -471,8 +471,7 @@
LayerAnimationController* controller_impl =
host_impl->active_tree()->root_layer()->children()[0]->
layer_animation_controller();
- Animation* animation =
- controller_impl->GetAnimation(Animation::Opacity);
+ Animation* animation = controller_impl->GetAnimation(Animation::OPACITY);
if (!animation)
return;
@@ -523,8 +522,7 @@
LayerAnimationController* controller =
layer_tree_host()->root_layer()->children()[0]->
layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
main_start_time_ = animation->start_time();
controller->RemoveAnimation(animation->id());
EndTest();
@@ -535,8 +533,7 @@
LayerAnimationController* controller =
impl_host->active_tree()->root_layer()->children()[0]->
layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
if (!animation)
return;
@@ -573,8 +570,7 @@
int group) override {
LayerAnimationController* controller =
layer_tree_host()->root_layer()->layer_animation_controller();
- Animation* animation =
- controller->GetAnimation(Animation::Opacity);
+ Animation* animation = controller->GetAnimation(Animation::OPACITY);
if (animation)
controller->RemoveAnimation(animation->id());
EndTest();
@@ -609,7 +605,7 @@
LayerAnimationController* controller_impl =
host_impl->active_tree()->root_layer()->layer_animation_controller();
Animation* animation_impl =
- controller_impl->GetAnimation(Animation::Opacity);
+ controller_impl->GetAnimation(Animation::OPACITY);
controller_impl->RemoveAnimation(animation_impl->id());
EndTest();
}
@@ -648,8 +644,7 @@
// Any valid AnimationCurve will do here.
scoped_ptr<AnimationCurve> curve(new FakeFloatAnimationCurve());
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 1,
- Animation::Opacity));
+ Animation::Create(curve.Pass(), 1, 1, Animation::OPACITY));
layer->layer_animation_controller()->AddAnimation(animation.Pass());
// We add the animation *before* attaching the layer to the tree.
@@ -986,7 +981,7 @@
gfx::ScrollOffset(500.f, 550.f),
EaseInOutTimingFunction::Create()));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
bool animation_added = scroll_layer_->AddAnimation(animation.Pass());
bool impl_scrolling_supported =
@@ -1036,7 +1031,7 @@
ScrollOffsetAnimationCurve::Create(gfx::ScrollOffset(6500.f, 7500.f),
EaseInOutTimingFunction::Create()));
scoped_ptr<Animation> animation(
- Animation::Create(curve.Pass(), 1, 0, Animation::ScrollOffset));
+ Animation::Create(curve.Pass(), 1, 0, Animation::SCROLL_OFFSET));
animation->set_needs_synchronized_start_time(true);
scroll_layer_->AddAnimation(animation.Pass());
}
@@ -1050,7 +1045,7 @@
case 1: {
Animation* animation =
scroll_layer_->layer_animation_controller()->GetAnimation(
- Animation::ScrollOffset);
+ Animation::SCROLL_OFFSET);
scroll_layer_->layer_animation_controller()->RemoveAnimation(
animation->id());
scroll_layer_->SetScrollOffset(final_postion_);
@@ -1080,9 +1075,9 @@
host_impl->active_tree()->root_layer()->children()[0];
Animation* animation =
scroll_layer_impl->layer_animation_controller()->GetAnimation(
- Animation::ScrollOffset);
+ Animation::SCROLL_OFFSET);
- if (!animation || animation->run_state() != Animation::Running) {
+ if (!animation || animation->run_state() != Animation::RUNNING) {
host_impl->BlockNotifyReadyToActivateForTesting(false);
return;
}
@@ -1187,20 +1182,20 @@
LayerAnimationController* root_controller_impl =
host_impl->active_tree()->root_layer()->layer_animation_controller();
Animation* root_animation =
- root_controller_impl->GetAnimation(Animation::Opacity);
- if (!root_animation || root_animation->run_state() != Animation::Running)
+ root_controller_impl->GetAnimation(Animation::OPACITY);
+ if (!root_animation || root_animation->run_state() != Animation::RUNNING)
return;
LayerAnimationController* child_controller_impl =
host_impl->active_tree()->root_layer()->children()
[0]->layer_animation_controller();
Animation* child_animation =
- child_controller_impl->GetAnimation(Animation::Opacity);
- EXPECT_EQ(Animation::Running, child_animation->run_state());
+ child_controller_impl->GetAnimation(Animation::OPACITY);
+ EXPECT_EQ(Animation::RUNNING, child_animation->run_state());
EXPECT_EQ(root_animation->start_time(), child_animation->start_time());
- root_controller_impl->AbortAnimations(Animation::Opacity);
- root_controller_impl->AbortAnimations(Animation::Transform);
- child_controller_impl->AbortAnimations(Animation::Opacity);
+ root_controller_impl->AbortAnimations(Animation::OPACITY);
+ root_controller_impl->AbortAnimations(Animation::TRANSFORM);
+ child_controller_impl->AbortAnimations(Animation::OPACITY);
EndTest();
}
@@ -1257,10 +1252,10 @@
++iter) {
int id = ((*iter).second->id());
if (id == host_impl->RootLayer()->id()) {
- Animation* anim = (*iter).second->GetAnimation(Animation::Transform);
+ Animation* anim = (*iter).second->GetAnimation(Animation::TRANSFORM);
EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
} else if (id == host_impl->RootLayer()->children()[0]->id()) {
- Animation* anim = (*iter).second->GetAnimation(Animation::Opacity);
+ Animation* anim = (*iter).second->GetAnimation(Animation::OPACITY);
EXPECT_GT((anim->start_time() - base::TimeTicks()).InSecondsF(), 0);
}
}
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
index fb0c9c8..cc536f4 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -993,10 +993,8 @@
ResourceProvider::ResourceId resource =
child_resource_provider_->CreateResource(
- gfx::Size(4, 4),
- GL_CLAMP_TO_EDGE,
- ResourceProvider::TextureHintImmutable,
- RGBA_8888);
+ gfx::Size(4, 4), GL_CLAMP_TO_EDGE,
+ ResourceProvider::TEXTURE_HINT_IMMUTABLE, RGBA_8888);
ResourceProvider::ScopedWriteLockGL lock(child_resource_provider_.get(),
resource);
diff --git a/cc/trees/layer_tree_host_unittest_no_message_loop.cc b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
index d2014ea..06b3674 100644
--- a/cc/trees/layer_tree_host_unittest_no_message_loop.cc
+++ b/cc/trees/layer_tree_host_unittest_no_message_loop.cc
@@ -56,6 +56,7 @@
// LayerTreeHostClient overrides.
void WillBeginMainFrame() override {}
void BeginMainFrame(const BeginFrameArgs& args) override {}
+ void BeginMainFrameNotExpectedSoon() override {}
void DidBeginMainFrame() override {}
void Layout() override {}
void ApplyViewportDeltas(const gfx::Vector2dF& inner_delta,
diff --git a/cc/trees/layer_tree_host_unittest_scroll.cc b/cc/trees/layer_tree_host_unittest_scroll.cc
index 03a0860..547ece7 100644
--- a/cc/trees/layer_tree_host_unittest_scroll.cc
+++ b/cc/trees/layer_tree_host_unittest_scroll.cc
@@ -582,12 +582,12 @@
EXPECT_EQ(device_scale_factor_, impl->active_tree()->device_scale_factor());
switch (impl->active_tree()->source_frame_number()) {
case 0: {
- // Gesture scroll on impl thread.
+ // GESTURE scroll on impl thread.
InputHandler::ScrollStatus status = impl->ScrollBegin(
gfx::ToCeiledPoint(expected_scroll_layer_impl->position() -
gfx::Vector2dF(0.5f, 0.5f)),
- InputHandler::Gesture);
- EXPECT_EQ(InputHandler::ScrollStarted, status);
+ InputHandler::GESTURE);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, status);
impl->ScrollBy(gfx::Point(), scroll_amount_);
impl->ScrollEnd();
@@ -599,12 +599,12 @@
break;
}
case 1: {
- // Wheel scroll on impl thread.
+ // WHEEL scroll on impl thread.
InputHandler::ScrollStatus status = impl->ScrollBegin(
gfx::ToCeiledPoint(expected_scroll_layer_impl->position() +
gfx::Vector2dF(0.5f, 0.5f)),
- InputHandler::Wheel);
- EXPECT_EQ(InputHandler::ScrollStarted, status);
+ InputHandler::WHEEL);
+ EXPECT_EQ(InputHandler::SCROLL_STARTED, status);
impl->ScrollBy(gfx::Point(), scroll_amount_);
impl->ScrollEnd();
@@ -1040,23 +1040,23 @@
scroll_layer->SetBounds(
gfx::Size(root->bounds().width() + 100, root->bounds().height() + 100));
EXPECT_EQ(
- InputHandler::ScrollStarted,
- scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture,
- ScrollBlocksOnNone));
+ InputHandler::SCROLL_STARTED,
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
// Set max_scroll_offset = (0, 0).
scroll_layer->SetBounds(root->bounds());
EXPECT_EQ(
- InputHandler::ScrollIgnored,
- scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture,
- ScrollBlocksOnNone));
+ InputHandler::SCROLL_IGNORED,
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
// Set max_scroll_offset = (-100, -100).
scroll_layer->SetBounds(gfx::Size());
EXPECT_EQ(
- InputHandler::ScrollIgnored,
- scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::Gesture,
- ScrollBlocksOnNone));
+ InputHandler::SCROLL_IGNORED,
+ scroll_layer->TryScroll(gfx::PointF(0.0f, 1.0f), InputHandler::GESTURE,
+ SCROLL_BLOCKS_ON_NONE));
EndTest();
}
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 4093c42..e86e785 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -534,20 +534,27 @@
outer_viewport_scroll_layer_ = NULL;
}
-bool LayerTreeImpl::UpdateDrawProperties() {
+bool LayerTreeImpl::UpdateDrawProperties(bool update_lcd_text) {
if (!needs_update_draw_properties_)
return true;
- // For max_texture_size.
+ // Calling UpdateDrawProperties must clear this flag, so there can be no
+ // early outs before this.
+ needs_update_draw_properties_ = false;
+
+ // For max_texture_size. When the renderer is re-created in
+ // CreateAndSetRenderer, the needs update draw properties flag is set
+ // again.
if (!layer_tree_host_impl_->renderer())
return false;
+ // Clear this after the renderer early out, as it should still be
+ // possible to hit test even without a renderer.
+ render_surface_layer_list_.clear();
+
if (!root_layer())
return false;
- needs_update_draw_properties_ = false;
- render_surface_layer_list_.clear();
-
{
TRACE_EVENT2(
"cc", "LayerTreeImpl::UpdateDrawProperties::CalculateDrawProperties",
@@ -647,6 +654,25 @@
occlusion_tracker.ComputeVisibleRegionInScreen();
}
+ // It'd be ideal if this could be done earlier, but when the raster source
+ // is updated from the main thread during push properties, update draw
+ // properties has not occurred yet and so it's not clear whether or not the
+ // layer can or cannot use lcd text. So, this is the cleanup pass to
+ // determine if the raster source needs to be replaced with a non-lcd
+ // raster source due to draw properties.
+ if (update_lcd_text) {
+ // TODO(enne): Make LTHI::sync_tree return this value.
+ LayerTreeImpl* sync_tree =
+ layer_tree_host_impl_->proxy()->CommitToActiveTree()
+ ? layer_tree_host_impl_->active_tree()
+ : layer_tree_host_impl_->pending_tree();
+ // If this is not the sync tree, then it is not safe to update lcd text
+ // as it causes invalidations and the tiles may be in use.
+ DCHECK_EQ(this, sync_tree);
+ for (const auto& layer : picture_layers_)
+ layer->UpdateCanUseLCDTextAfterCommit();
+ }
+
{
TRACE_EVENT_BEGIN2("cc", "LayerTreeImpl::UpdateDrawProperties::UpdateTiles",
"IsActive", IsActiveTree(), "SourceFrameNumber",
@@ -859,6 +885,10 @@
return layer_tree_host_impl_->recycle_tree() == this;
}
+bool LayerTreeImpl::IsSyncTree() const {
+ return layer_tree_host_impl_->sync_tree() == this;
+}
+
LayerImpl* LayerTreeImpl::FindActiveTreeLayerById(int id) {
LayerTreeImpl* tree = layer_tree_host_impl_->active_tree();
if (!tree)
@@ -912,7 +942,7 @@
base::TimeDelta duration =
base::TimeDelta::FromMilliseconds(settings().scrollbar_fade_duration_ms);
switch (settings().scrollbar_animator) {
- case LayerTreeSettings::LinearFade: {
+ case LayerTreeSettings::LINEAR_FADE: {
return ScrollbarAnimationControllerLinearFade::Create(
scrolling_layer,
layer_tree_host_impl_,
@@ -920,14 +950,14 @@
resize_delay,
duration);
}
- case LayerTreeSettings::Thinning: {
+ case LayerTreeSettings::THINNING: {
return ScrollbarAnimationControllerThinning::Create(scrolling_layer,
layer_tree_host_impl_,
delay,
resize_delay,
duration);
}
- case LayerTreeSettings::NoAnimator:
+ case LayerTreeSettings::NO_ANIMATOR:
NOTREACHED();
break;
}
@@ -1161,13 +1191,13 @@
void LayerTreeImpl::ProcessUIResourceRequestQueue() {
for (const auto& req : ui_resource_request_queue_) {
switch (req.GetType()) {
- case UIResourceRequest::UIResourceCreate:
+ case UIResourceRequest::UI_RESOURCE_CREATE:
layer_tree_host_impl_->CreateUIResource(req.GetId(), req.GetBitmap());
break;
- case UIResourceRequest::UIResourceDelete:
+ case UIResourceRequest::UI_RESOURCE_DELETE:
layer_tree_host_impl_->DeleteUIResource(req.GetId());
break;
- case UIResourceRequest::UIResourceInvalidRequest:
+ case UIResourceRequest::UI_RESOURCE_INVALID_REQUEST:
NOTREACHED();
break;
}
@@ -1461,7 +1491,8 @@
const gfx::PointF& screen_space_point) {
if (!root_layer())
return NULL;
- if (!UpdateDrawProperties())
+ bool update_lcd_text = false;
+ if (!UpdateDrawProperties(update_lcd_text))
return NULL;
FindClosestMatchingLayerDataForRecursion data_for_recursion;
FindClosestMatchingLayer(screen_space_point,
@@ -1503,7 +1534,8 @@
const gfx::PointF& screen_space_point) {
if (!root_layer())
return NULL;
- if (!UpdateDrawProperties())
+ bool update_lcd_text = false;
+ if (!UpdateDrawProperties(update_lcd_text))
return NULL;
FindWheelEventLayerFunctor func;
FindClosestMatchingLayerDataForRecursion data_for_recursion;
@@ -1523,7 +1555,8 @@
const gfx::PointF& screen_space_point) {
if (!root_layer())
return NULL;
- if (!UpdateDrawProperties())
+ bool update_lcd_text = false;
+ if (!UpdateDrawProperties(update_lcd_text))
return NULL;
FindTouchEventLayerFunctor func = {screen_space_point};
FindClosestMatchingLayerDataForRecursion data_for_recursion;
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 54c8660..5935d29 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -87,6 +87,7 @@
bool IsActiveTree() const;
bool IsPendingTree() const;
bool IsRecycleTree() const;
+ bool IsSyncTree() const;
LayerImpl* FindActiveTreeLayerById(int id);
LayerImpl* FindPendingTreeLayerById(int id);
bool PinchGestureActive() const;
@@ -197,8 +198,9 @@
}
// Updates draw properties and render surface layer list, as well as tile
- // priorities. Returns false if it was unable to update.
- bool UpdateDrawProperties();
+ // priorities. Returns false if it was unable to update. Updating lcd
+ // text may cause invalidations, so should only be done after a commit.
+ bool UpdateDrawProperties(bool update_lcd_text);
void set_needs_update_draw_properties() {
needs_update_draw_properties_ = true;
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index d3afbe2..9d605ae 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -33,7 +33,7 @@
gpu_rasterization_skewport_target_time_in_seconds(0.0f),
threaded_gpu_rasterization_enabled(false),
create_low_res_tiling(false),
- scrollbar_animator(NoAnimator),
+ scrollbar_animator(NO_ANIMATOR),
scrollbar_fade_delay_ms(0),
scrollbar_fade_resize_delay_ms(0),
scrollbar_fade_duration_ms(0),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index fd108f4..a0fbeaa 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -43,9 +43,9 @@
bool create_low_res_tiling;
enum ScrollbarAnimator {
- NoAnimator,
- LinearFade,
- Thinning,
+ NO_ANIMATOR,
+ LINEAR_FADE,
+ THINNING,
};
ScrollbarAnimator scrollbar_animator;
int scrollbar_fade_delay_ms;
diff --git a/cc/trees/occlusion_tracker_perftest.cc b/cc/trees/occlusion_tracker_perftest.cc
index 4639b9c..e53a05f 100644
--- a/cc/trees/occlusion_tracker_perftest.cc
+++ b/cc/trees/occlusion_tracker_perftest.cc
@@ -93,7 +93,8 @@
opaque_layer->SetContentBounds(viewport_rect.size());
active_tree()->root_layer()->AddChild(opaque_layer.Pass());
- active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ active_tree()->UpdateDrawProperties(update_lcd_text);
const LayerImplList& rsll = active_tree()->RenderSurfaceLayerList();
ASSERT_EQ(1u, rsll.size());
EXPECT_EQ(1u, rsll[0]->render_surface()->layer_list().size());
@@ -164,7 +165,8 @@
active_tree()->root_layer()->AddChild(opaque_layer.Pass());
}
- active_tree()->UpdateDrawProperties();
+ bool update_lcd_text = false;
+ active_tree()->UpdateDrawProperties(update_lcd_text);
const LayerImplList& rsll = active_tree()->RenderSurfaceLayerList();
ASSERT_EQ(1u, rsll.size());
EXPECT_EQ(static_cast<size_t>(kNumOpaqueLayers),
diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
index ae39f03..7fe0494 100644
--- a/cc/trees/property_tree_builder.cc
+++ b/cc/trees/property_tree_builder.cc
@@ -118,7 +118,7 @@
const bool has_animated_transform =
layer->layer_animation_controller()->IsAnimatingProperty(
- Animation::Transform);
+ Animation::TRANSFORM);
const bool has_transform_origin = layer->transform_origin() != gfx::Point3F();
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index 4a079f3..e45b182 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -532,7 +532,8 @@
DebugScopedSetImplThread impl(const_cast<SingleThreadProxy*>(this));
if (layer_tree_host_impl_->settings().impl_side_painting) {
layer_tree_host_impl_->ActivateSyncTree();
- layer_tree_host_impl_->active_tree()->UpdateDrawProperties();
+ DCHECK(!layer_tree_host_impl_->active_tree()
+ ->needs_update_draw_properties());
layer_tree_host_impl_->PrepareTiles();
layer_tree_host_impl_->SynchronouslyInitializeAllTiles();
}
@@ -685,6 +686,10 @@
weak_factory_.GetWeakPtr()));
}
+void SingleThreadProxy::SendBeginMainFrameNotExpectedSoon() {
+ layer_tree_host_->BeginMainFrameNotExpectedSoon();
+}
+
void SingleThreadProxy::BeginMainFrame() {
if (defer_commits_) {
TRACE_EVENT_INSTANT0("cc", "EarlyOut_DeferCommit",
diff --git a/cc/trees/single_thread_proxy.h b/cc/trees/single_thread_proxy.h
index 52dd876..f463db1 100644
--- a/cc/trees/single_thread_proxy.h
+++ b/cc/trees/single_thread_proxy.h
@@ -79,6 +79,7 @@
base::TimeDelta CommitToActivateDurationEstimate() override;
void DidBeginImplFrameDeadline() override;
void SendBeginFramesToChildren(const BeginFrameArgs& args) override;
+ void SendBeginMainFrameNotExpectedSoon() override;
// LayerTreeHostImplClient implementation
void UpdateRendererCapabilitiesOnImplThread() override;
diff --git a/cc/trees/thread_proxy.cc b/cc/trees/thread_proxy.cc
index 167cca9..1097805 100644
--- a/cc/trees/thread_proxy.cc
+++ b/cc/trees/thread_proxy.cc
@@ -154,9 +154,9 @@
}
bool ThreadProxy::CommitToActiveTree() const {
- // With ThreadProxy we use a pending tree and activate it once it's ready to
- // draw.
- return false;
+ // With ThreadProxy and impl-side painting, we use a pending tree and activate
+ // it once it's ready to draw.
+ return !impl().layer_tree_host_impl->settings().impl_side_painting;
}
void ThreadProxy::SetLayerTreeHostClientReady() {
@@ -701,6 +701,12 @@
impl().timing_history.DidBeginMainFrame();
}
+void ThreadProxy::SendBeginMainFrameNotExpectedSoon() {
+ Proxy::MainThreadTaskRunner()->PostTask(
+ FROM_HERE, base::Bind(&ThreadProxy::BeginMainFrameNotExpectedSoon,
+ main_thread_weak_ptr_));
+}
+
void ThreadProxy::BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state) {
benchmark_instrumentation::ScopedBeginFrameTask begin_frame_task(
@@ -861,6 +867,12 @@
layer_tree_host()->DidBeginMainFrame();
}
+void ThreadProxy::BeginMainFrameNotExpectedSoon() {
+ TRACE_EVENT0("cc", "ThreadProxy::BeginMainFrameNotExpectedSoon");
+ DCHECK(IsMainThread());
+ layer_tree_host()->BeginMainFrameNotExpectedSoon();
+}
+
void ThreadProxy::StartCommitOnImplThread(CompletionEvent* completion,
ResourceUpdateQueue* raw_queue) {
TRACE_EVENT0("cc", "ThreadProxy::StartCommitOnImplThread");
@@ -1021,8 +1033,11 @@
impl().timing_history.DidStartDrawing();
base::AutoReset<bool> mark_inside(&impl().inside_draw, true);
- if (impl().layer_tree_host_impl->pending_tree())
- impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties();
+ if (impl().layer_tree_host_impl->pending_tree()) {
+ bool update_lcd_text = false;
+ impl().layer_tree_host_impl->pending_tree()->UpdateDrawProperties(
+ update_lcd_text);
+ }
// This method is called on a forced draw, regardless of whether we are able
// to produce a frame, as the calling site on main thread is blocked until its
diff --git a/cc/trees/thread_proxy.h b/cc/trees/thread_proxy.h
index 570d240..8b4c302 100644
--- a/cc/trees/thread_proxy.h
+++ b/cc/trees/thread_proxy.h
@@ -227,6 +227,7 @@
base::TimeDelta CommitToActivateDurationEstimate() override;
void DidBeginImplFrameDeadline() override;
void SendBeginFramesToChildren(const BeginFrameArgs& args) override;
+ void SendBeginMainFrameNotExpectedSoon() override;
// ResourceUpdateControllerClient implementation
void ReadyToFinalizeTextureUpdates() override;
@@ -244,6 +245,7 @@
const RendererCapabilities& capabilities);
void BeginMainFrame(
scoped_ptr<BeginMainFrameAndCommitState> begin_main_frame_state);
+ void BeginMainFrameNotExpectedSoon();
void DidCommitAndDrawFrame();
void DidCompleteSwapBuffers();
void SetAnimationEvents(scoped_ptr<AnimationEventsVector> queue);
diff --git a/gpu/BUILD.gn b/gpu/BUILD.gn
index e1d5348..5b39586 100644
--- a/gpu/BUILD.gn
+++ b/gpu/BUILD.gn
@@ -97,6 +97,8 @@
defines = [ "GL_GLEXT_PROTOTYPES" ]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
deps = [
":gpu",
":test_support",
@@ -226,6 +228,8 @@
"config/gpu_util_unittest.cc",
]
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
deps = [
":gpu",
":test_support",
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index a36a026..93f3c47 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -40,6 +40,7 @@
#define glClearColor GLES2_GET_FUN(ClearColor)
#define glClearDepthf GLES2_GET_FUN(ClearDepthf)
#define glClearStencil GLES2_GET_FUN(ClearStencil)
+#define glClientWaitSync GLES2_GET_FUN(ClientWaitSync)
#define glColorMask GLES2_GET_FUN(ColorMask)
#define glCompileShader GLES2_GET_FUN(CompileShader)
#define glCompressedTexImage2D GLES2_GET_FUN(CompressedTexImage2D)
@@ -222,6 +223,7 @@
#define glVertexAttribIPointer GLES2_GET_FUN(VertexAttribIPointer)
#define glVertexAttribPointer GLES2_GET_FUN(VertexAttribPointer)
#define glViewport GLES2_GET_FUN(Viewport)
+#define glWaitSync GLES2_GET_FUN(WaitSync)
#define glBlitFramebufferCHROMIUM GLES2_GET_FUN(BlitFramebufferCHROMIUM)
#define glRenderbufferStorageMultisampleCHROMIUM \
GLES2_GET_FUN(RenderbufferStorageMultisampleCHROMIUM)
diff --git a/gpu/PRESUBMIT.py b/gpu/PRESUBMIT.py
deleted file mode 100644
index 53fc153..0000000
--- a/gpu/PRESUBMIT.py
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright (c) 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Top-level presubmit script for gpu/.
-
-See http://dev.chromium.org/developers/how-tos/depottools/presubmit-scripts
-for more details about the presubmit API built into depot_tools.
-"""
-
-def GetPreferredTryMasters(project, change):
- return {
- 'tryserver.chromium.gpu': {
- 'win_gpu': set(['defaulttests']),
- }
- }
diff --git a/gpu/blink/BUILD.gn b/gpu/blink/BUILD.gn
index 464061c..7d08ba1 100644
--- a/gpu/blink/BUILD.gn
+++ b/gpu/blink/BUILD.gn
@@ -14,6 +14,9 @@
"webgraphicscontext3d_in_process_command_buffer_impl.h",
]
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
defines = [ "GPU_BLINK_IMPLEMENTATION" ]
deps = [
@@ -33,9 +36,4 @@
"//ui/gfx",
"//ui/gfx/geometry",
]
-
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ]
- }
}
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index ca39150..141d259 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -1429,6 +1429,17 @@
'1',
],
},
+ 'SyncFlushFlags': {
+ 'type': 'GLbitfield',
+ 'is_complete': True,
+ 'valid': [
+ 'GL_SYNC_FLUSH_COMMANDS_BIT',
+ '0',
+ ],
+ 'invalid': [
+ '0xFFFFFFFF',
+ ],
+ },
}
# This table specifies the different pepper interfaces that are supported for
@@ -1642,6 +1653,14 @@
'0': '0.5f'
},
},
+ 'ClientWaitSync': {
+ 'type': 'Custom',
+ 'data_transfer_methods': ['shm'],
+ 'cmd_args': 'GLuint sync, GLbitfieldSyncFlushFlags flags, '
+ 'GLuint timeout_0, GLuint timeout_1, GLenum* result',
+ 'unsafe': True,
+ 'result': ['GLenum'],
+ },
'ColorMask': {
'type': 'StateSet',
'state': 'ColorMask',
@@ -2909,6 +2928,14 @@
'GLsizei stride, GLuint offset',
'client_test': False,
},
+ 'WaitSync': {
+ 'type': 'Custom',
+ 'cmd_args': 'GLuint sync, GLbitfieldSyncFlushFlags flags, '
+ 'GLuint timeout_0, GLuint timeout_1',
+ 'impl_func': False,
+ 'client_test': False,
+ 'unsafe': True,
+ },
'Scissor': {
'type': 'StateSet',
'state': 'Scissor',
@@ -8971,11 +8998,12 @@
# Forward declaration of a few enums used in constant argument
# to avoid including GL header files.
enum_defines = {
- 'GL_SYNC_GPU_COMMANDS_COMPLETE': 0x9117,
+ 'GL_SYNC_GPU_COMMANDS_COMPLETE': '0x9117',
+ 'GL_SYNC_FLUSH_COMMANDS_BIT': '0x00000001',
}
file.Write('\n')
for enum in enum_defines:
- file.Write("#define %s 0x%x\n" % (enum, enum_defines[enum]))
+ file.Write("#define %s %s\n" % (enum, enum_defines[enum]))
file.Write('\n')
for func in self.functions:
if True:
diff --git a/gpu/command_buffer/client/BUILD.gn b/gpu/command_buffer/client/BUILD.gn
index 2d28d1a..a5532cb 100644
--- a/gpu/command_buffer/client/BUILD.gn
+++ b/gpu/command_buffer/client/BUILD.gn
@@ -19,10 +19,8 @@
defines = [ "GPU_IMPLEMENTATION" ]
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ] # size_t to int truncation.
- }
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
all_dependent_configs = [ "//third_party/khronos:khronos_headers" ]
@@ -56,10 +54,8 @@
defines = [ "GPU_IMPLEMENTATION" ]
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ] # size_t to int truncation.
- }
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
deps = [
":client",
@@ -129,14 +125,12 @@
component("gles2_implementation") {
sources = gles2_implementation_source_files
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
defines = [ "GLES2_IMPL_IMPLEMENTATION" ]
all_dependent_configs = [ "//third_party/khronos:khronos_headers" ]
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ] # size_t to int truncation.
- }
-
deps = [
":gles2_cmd_helper",
":gles2_interface",
@@ -171,10 +165,8 @@
sources = gles2_c_lib_source_files
defines = [ "GLES2_C_LIB_IMPLEMENTATION" ]
- if (is_win) {
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- cflags = [ "/wd4267" ] # size_t to int truncation.
- }
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
deps = [
":client",
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index 23d3d6e..803e66f 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -119,6 +119,9 @@
void GLES2ClearStencil(GLint s) {
gles2::GetGLContext()->ClearStencil(s);
}
+GLenum GLES2ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
+ return gles2::GetGLContext()->ClientWaitSync(sync, flags, timeout);
+}
void GLES2ColorMask(GLboolean red,
GLboolean green,
GLboolean blue,
@@ -929,6 +932,9 @@
void GLES2Viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
gles2::GetGLContext()->Viewport(x, y, width, height);
}
+void GLES2WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) {
+ gles2::GetGLContext()->WaitSync(sync, flags, timeout);
+}
void GLES2BlitFramebufferCHROMIUM(GLint srcX0,
GLint srcY0,
GLint srcX1,
@@ -1421,6 +1427,10 @@
reinterpret_cast<GLES2FunctionPointer>(glClearStencil),
},
{
+ "glClientWaitSync",
+ reinterpret_cast<GLES2FunctionPointer>(glClientWaitSync),
+ },
+ {
"glColorMask",
reinterpret_cast<GLES2FunctionPointer>(glColorMask),
},
@@ -2146,6 +2156,10 @@
reinterpret_cast<GLES2FunctionPointer>(glViewport),
},
{
+ "glWaitSync",
+ reinterpret_cast<GLES2FunctionPointer>(glWaitSync),
+ },
+ {
"glBlitFramebufferCHROMIUM",
reinterpret_cast<GLES2FunctionPointer>(glBlitFramebufferCHROMIUM),
},
diff --git a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
index bda8bb3..c58ce2c 100644
--- a/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
+++ b/gpu/command_buffer/client/gles2_cmd_helper_autogen.h
@@ -240,6 +240,19 @@
}
}
+void ClientWaitSync(GLuint sync,
+ GLbitfield flags,
+ GLuint timeout_0,
+ GLuint timeout_1,
+ uint32_t result_shm_id,
+ uint32_t result_shm_offset) {
+ gles2::cmds::ClientWaitSync* c = GetCmdSpace<gles2::cmds::ClientWaitSync>();
+ if (c) {
+ c->Init(sync, flags, timeout_0, timeout_1, result_shm_id,
+ result_shm_offset);
+ }
+}
+
void ColorMask(GLboolean red,
GLboolean green,
GLboolean blue,
@@ -1982,6 +1995,16 @@
}
}
+void WaitSync(GLuint sync,
+ GLbitfield flags,
+ GLuint timeout_0,
+ GLuint timeout_1) {
+ gles2::cmds::WaitSync* c = GetCmdSpace<gles2::cmds::WaitSync>();
+ if (c) {
+ c->Init(sync, flags, timeout_0, timeout_1);
+ }
+}
+
void BlitFramebufferCHROMIUM(GLint srcX0,
GLint srcY0,
GLint srcX1,
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index e853766..2dd95ec 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -4930,6 +4930,39 @@
CheckGLError();
}
+GLenum GLES2Implementation::ClientWaitSync(
+ GLsync sync, GLbitfield flags, GLuint64 timeout) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glClientWaitSync(" << sync
+ << ", " << flags << ", " << timeout << ")");
+ typedef cmds::ClientWaitSync::Result Result;
+ Result* result = GetResultAs<Result*>();
+ if (!result) {
+ SetGLError(GL_OUT_OF_MEMORY, "ClientWaitSync", "");
+ return GL_WAIT_FAILED;
+ }
+ *result = GL_WAIT_FAILED;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
+ helper_->ClientWaitSync(
+ ToGLuint(sync), flags, v32_0, v32_1,
+ GetResultShmId(), GetResultShmOffset());
+ WaitForCmd();
+ GPU_CLIENT_LOG("returned " << *result);
+ CheckGLError();
+ return *result;
+}
+
+void GLES2Implementation::WaitSync(
+ GLsync sync, GLbitfield flags, GLuint64 timeout) {
+ GPU_CLIENT_SINGLE_THREAD_CHECK();
+ GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glWaitSync(" << sync << ", "
+ << flags << ", " << timeout << ")");
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(timeout, &v32_0, &v32_1);
+ helper_->WaitSync(ToGLuint(sync), flags, v32_0, v32_1);
+ CheckGLError();
+}
// Include the auto-generated part of this file. We split this because it means
// we can easily edit the non-auto generated parts right here in this file
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index 9d2d8eb..5c994e3 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -97,6 +97,8 @@
void ClearStencil(GLint s) override;
+GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) override;
+
void ColorMask(GLboolean red,
GLboolean green,
GLboolean blue,
@@ -702,6 +704,8 @@
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) override;
+void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) override;
+
void BlitFramebufferCHROMIUM(GLint srcX0,
GLint srcY0,
GLint srcX1,
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest.cc b/gpu/command_buffer/client/gles2_implementation_unittest.cc
index 52a2cef..2acbc63 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest.cc
+++ b/gpu/command_buffer/client/gles2_implementation_unittest.cc
@@ -3583,7 +3583,7 @@
expected.cmd.Init(kCap, result1.id, result1.offset);
EXPECT_CALL(*command_buffer(), OnFlush())
- .WillOnce(SetMemory(result1.ptr, uint32_t(kCap)))
+ .WillOnce(SetMemory(result1.ptr, uint32_t(GL_TRUE)))
.RetiresOnSaturation();
GLboolean result = gl_->IsEnabled(kCap);
@@ -3591,6 +3591,47 @@
EXPECT_TRUE(result);
}
+TEST_F(GLES2ImplementationTest, ClientWaitSync) {
+ const GLuint client_sync_id = 36;
+ struct Cmds {
+ cmds::ClientWaitSync cmd;
+ };
+
+ Cmds expected;
+ ExpectedMemoryInfo result1 =
+ GetExpectedResultMemory(sizeof(cmds::ClientWaitSync::Result));
+ const GLuint64 kTimeout = 0xABCDEF0123456789;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(kTimeout, &v32_0, &v32_1);
+ expected.cmd.Init(client_sync_id, GL_SYNC_FLUSH_COMMANDS_BIT,
+ v32_0, v32_1, result1.id, result1.offset);
+
+ EXPECT_CALL(*command_buffer(), OnFlush())
+ .WillOnce(SetMemory(result1.ptr, uint32_t(GL_CONDITION_SATISFIED)))
+ .RetiresOnSaturation();
+
+ GLenum result = gl_->ClientWaitSync(
+ reinterpret_cast<GLsync>(client_sync_id), GL_SYNC_FLUSH_COMMANDS_BIT,
+ kTimeout);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+ EXPECT_EQ(static_cast<GLenum>(GL_CONDITION_SATISFIED), result);
+}
+
+TEST_F(GLES2ImplementationTest, WaitSync) {
+ const GLuint kClientSyncId = 36;
+ struct Cmds {
+ cmds::WaitSync cmd;
+ };
+ Cmds expected;
+ const GLuint64 kTimeout = GL_TIMEOUT_IGNORED;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(kTimeout, &v32_0, &v32_1);
+ expected.cmd.Init(kClientSyncId, 0, v32_0, v32_1);
+
+ gl_->WaitSync(reinterpret_cast<GLsync>(kClientSyncId), 0, kTimeout);
+ EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
+}
+
TEST_F(GLES2ImplementationManualInitTest, LoseContextOnOOM) {
ContextInitOptions init_options;
init_options.lose_context_when_out_of_memory = true;
diff --git a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
index 8b02ad9..8149a96 100644
--- a/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_unittest_autogen.h
@@ -287,6 +287,7 @@
gl_->ClearStencil(1);
EXPECT_EQ(0, memcmp(&expected, commands_, sizeof(expected)));
}
+// TODO(zmo): Implement unit test for ClientWaitSync
TEST_F(GLES2ImplementationTest, ColorMask) {
struct Cmds {
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 990e701..623c413 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -70,6 +70,9 @@
GLclampf alpha) = 0;
virtual void ClearDepthf(GLclampf depth) = 0;
virtual void ClearStencil(GLint s) = 0;
+virtual GLenum ClientWaitSync(GLsync sync,
+ GLbitfield flags,
+ GLuint64 timeout) = 0;
virtual void ColorMask(GLboolean red,
GLboolean green,
GLboolean blue,
@@ -514,6 +517,7 @@
GLsizei stride,
const void* ptr) = 0;
virtual void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) = 0;
+virtual void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) = 0;
virtual void BlitFramebufferCHROMIUM(GLint srcX0,
GLint srcY0,
GLint srcX1,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index f020e14..31d9636 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -69,6 +69,7 @@
GLclampf alpha) override;
void ClearDepthf(GLclampf depth) override;
void ClearStencil(GLint s) override;
+GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) override;
void ColorMask(GLboolean red,
GLboolean green,
GLboolean blue,
@@ -501,6 +502,7 @@
GLsizei stride,
const void* ptr) override;
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) override;
+void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) override;
void BlitFramebufferCHROMIUM(GLint srcX0,
GLint srcY0,
GLint srcX1,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index 15f2912..d7aa072 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -105,6 +105,11 @@
}
void GLES2InterfaceStub::ClearStencil(GLint /* s */) {
}
+GLenum GLES2InterfaceStub::ClientWaitSync(GLsync /* sync */,
+ GLbitfield /* flags */,
+ GLuint64 /* timeout */) {
+ return 0;
+}
void GLES2InterfaceStub::ColorMask(GLboolean /* red */,
GLboolean /* green */,
GLboolean /* blue */,
@@ -864,6 +869,10 @@
GLsizei /* width */,
GLsizei /* height */) {
}
+void GLES2InterfaceStub::WaitSync(GLsync /* sync */,
+ GLbitfield /* flags */,
+ GLuint64 /* timeout */) {
+}
void GLES2InterfaceStub::BlitFramebufferCHROMIUM(GLint /* srcX0 */,
GLint /* srcY0 */,
GLint /* srcX1 */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 66deca4..33626f7 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -69,6 +69,7 @@
GLclampf alpha) override;
void ClearDepthf(GLclampf depth) override;
void ClearStencil(GLint s) override;
+GLenum ClientWaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) override;
void ColorMask(GLboolean red,
GLboolean green,
GLboolean blue,
@@ -501,6 +502,7 @@
GLsizei stride,
const void* ptr) override;
void Viewport(GLint x, GLint y, GLsizei width, GLsizei height) override;
+void WaitSync(GLsync sync, GLbitfield flags, GLuint64 timeout) override;
void BlitFramebufferCHROMIUM(GLint srcX0,
GLint srcY0,
GLint srcX1,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index 79fd529..8e6faa7 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -183,6 +183,13 @@
gl_->ClearStencil(s);
}
+GLenum GLES2TraceImplementation::ClientWaitSync(GLsync sync,
+ GLbitfield flags,
+ GLuint64 timeout) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::ClientWaitSync");
+ return gl_->ClientWaitSync(sync, flags, timeout);
+}
+
void GLES2TraceImplementation::ColorMask(GLboolean red,
GLboolean green,
GLboolean blue,
@@ -1467,6 +1474,13 @@
gl_->Viewport(x, y, width, height);
}
+void GLES2TraceImplementation::WaitSync(GLsync sync,
+ GLbitfield flags,
+ GLuint64 timeout) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "GLES2Trace::WaitSync");
+ gl_->WaitSync(sync, flags, timeout);
+}
+
void GLES2TraceImplementation::BlitFramebufferCHROMIUM(GLint srcX0,
GLint srcY0,
GLint srcX1,
diff --git a/gpu/command_buffer/client/program_info_manager.cc b/gpu/command_buffer/client/program_info_manager.cc
index 779d914..89e8913 100644
--- a/gpu/command_buffer/client/program_info_manager.cc
+++ b/gpu/command_buffer/client/program_info_manager.cc
@@ -332,11 +332,10 @@
if (!link_status_) {
return;
}
- attrib_infos_.clear();
- uniform_infos_.clear();
- frag_data_locations_.clear();
- max_attrib_name_length_ = 0;
- max_uniform_name_length_ = 0;
+ DCHECK_EQ(0u, attrib_infos_.size());
+ DCHECK_EQ(0u, uniform_infos_.size());
+ DCHECK_EQ(0, max_attrib_name_length_);
+ DCHECK_EQ(0, max_uniform_name_length_);
const ProgramInput* inputs = LocalGetAs<const ProgramInput*>(
result, sizeof(*header),
sizeof(ProgramInput) * (header->num_attribs + header->num_uniforms));
@@ -382,8 +381,8 @@
// This should only happen on a lost context.
return;
}
- uniform_blocks_.clear();
- active_uniform_block_max_name_length_ = 0;
+ DCHECK_EQ(0u, uniform_blocks_.size());
+ DCHECK_EQ(0u, active_uniform_block_max_name_length_);
// |result| comes from GPU process. We consider it trusted data. Therefore,
// no need to check for overflows as the GPU side did the checks already.
@@ -453,7 +452,7 @@
// This should only happen on a lost context.
return;
}
- uniforms_es3_.clear();
+ DCHECK_EQ(0u, uniforms_es3_.size());
// |result| comes from GPU process. We consider it trusted data. Therefore,
// no need to check for overflows as the GPU side did the checks already.
@@ -495,8 +494,8 @@
// This should only happen on a lost context.
return;
}
- transform_feedback_varyings_.clear();
- transform_feedback_varying_max_length_ = 0;
+ DCHECK_EQ(0u, transform_feedback_varyings_.size());
+ DCHECK_EQ(0u, transform_feedback_varying_max_length_);
// |result| comes from GPU process. We consider it trusted data. Therefore,
// no need to check for overflows as the GPU side did the checks already.
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 3e8d902..570eff1 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -31,6 +31,7 @@
GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth);
GL_APICALL void GL_APIENTRY glClearStencil (GLint s);
+GL_APICALL GLenum GL_APIENTRY glClientWaitSync (GLsync sync, GLbitfieldSyncFlushFlags flags, GLuint64 timeout);
GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
GL_APICALL void GL_APIENTRY glCompileShader (GLidShader shader);
GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenumTextureTarget target, GLint level, GLenumCompressedTextureFormat internalformat, GLsizei width, GLsizei height, GLintTextureBorder border, GLsizei imageSize, const void* data);
@@ -212,6 +213,7 @@
GL_APICALL void GL_APIENTRY glVertexAttribIPointer (GLuint indx, GLintVertexAttribSize size, GLenumVertexAttribType type, GLsizei stride, const void* ptr);
GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLintVertexAttribSize size, GLenumVertexAttribType type, GLboolean normalized, GLsizei stride, const void* ptr);
GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void GL_APIENTRY glWaitSync (GLsync sync, GLbitfieldSyncFlushFlags flags, GLuint64 timeout);
GL_APICALL void GL_APIENTRY glBlitFramebufferCHROMIUM (GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenumBlitFilter filter);
GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleCHROMIUM (GLenumRenderBufferTarget target, GLsizei samples, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
GL_APICALL void GL_APIENTRY glRenderbufferStorageMultisampleEXT (GLenumRenderBufferTarget target, GLsizei samples, GLenumRenderBufferFormat internalformat, GLsizei width, GLsizei height);
diff --git a/gpu/command_buffer/common/gles2_cmd_format.h b/gpu/command_buffer/common/gles2_cmd_format.h
index 944edfd..d0faf14 100644
--- a/gpu/command_buffer/common/gles2_cmd_format.h
+++ b/gpu/command_buffer/common/gles2_cmd_format.h
@@ -43,6 +43,7 @@
typedef khronos_intptr_t GLintptr;
typedef khronos_ssize_t GLsizeiptr;
typedef struct __GLsync *GLsync;
+typedef uint64_t GLuint64;
namespace gpu {
namespace gles2 {
diff --git a/gpu/command_buffer/common/gles2_cmd_format_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
index cb88581..76ca3dd 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_autogen.h
@@ -11,6 +11,7 @@
#ifndef GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
#define GPU_COMMAND_BUFFER_COMMON_GLES2_CMD_FORMAT_AUTOGEN_H_
+#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001
#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117
struct ActiveTexture {
@@ -1169,6 +1170,73 @@
static_assert(offsetof(ClearStencil, s) == 4,
"offset of ClearStencil s should be 4");
+struct ClientWaitSync {
+ typedef ClientWaitSync ValueType;
+ static const CommandId kCmdId = kClientWaitSync;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ typedef GLenum Result;
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLuint _sync,
+ GLbitfield _flags,
+ GLuint _timeout_0,
+ GLuint _timeout_1,
+ uint32_t _result_shm_id,
+ uint32_t _result_shm_offset) {
+ SetHeader();
+ sync = _sync;
+ flags = _flags;
+ timeout_0 = _timeout_0;
+ timeout_1 = _timeout_1;
+ result_shm_id = _result_shm_id;
+ result_shm_offset = _result_shm_offset;
+ }
+
+ void* Set(void* cmd,
+ GLuint _sync,
+ GLbitfield _flags,
+ GLuint _timeout_0,
+ GLuint _timeout_1,
+ uint32_t _result_shm_id,
+ uint32_t _result_shm_offset) {
+ static_cast<ValueType*>(cmd)->Init(_sync, _flags, _timeout_0, _timeout_1,
+ _result_shm_id, _result_shm_offset);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32_t sync;
+ uint32_t flags;
+ uint32_t timeout_0;
+ uint32_t timeout_1;
+ uint32_t result_shm_id;
+ uint32_t result_shm_offset;
+};
+
+static_assert(sizeof(ClientWaitSync) == 28,
+ "size of ClientWaitSync should be 28");
+static_assert(offsetof(ClientWaitSync, header) == 0,
+ "offset of ClientWaitSync header should be 0");
+static_assert(offsetof(ClientWaitSync, sync) == 4,
+ "offset of ClientWaitSync sync should be 4");
+static_assert(offsetof(ClientWaitSync, flags) == 8,
+ "offset of ClientWaitSync flags should be 8");
+static_assert(offsetof(ClientWaitSync, timeout_0) == 12,
+ "offset of ClientWaitSync timeout_0 should be 12");
+static_assert(offsetof(ClientWaitSync, timeout_1) == 16,
+ "offset of ClientWaitSync timeout_1 should be 16");
+static_assert(offsetof(ClientWaitSync, result_shm_id) == 20,
+ "offset of ClientWaitSync result_shm_id should be 20");
+static_assert(offsetof(ClientWaitSync, result_shm_offset) == 24,
+ "offset of ClientWaitSync result_shm_offset should be 24");
+
struct ColorMask {
typedef ColorMask ValueType;
static const CommandId kCmdId = kColorMask;
@@ -9786,6 +9854,57 @@
static_assert(offsetof(Viewport, height) == 16,
"offset of Viewport height should be 16");
+struct WaitSync {
+ typedef WaitSync ValueType;
+ static const CommandId kCmdId = kWaitSync;
+ static const cmd::ArgFlags kArgFlags = cmd::kFixed;
+ static const uint8 cmd_flags = CMD_FLAG_SET_TRACE_LEVEL(3);
+
+ static uint32_t ComputeSize() {
+ return static_cast<uint32_t>(sizeof(ValueType)); // NOLINT
+ }
+
+ void SetHeader() { header.SetCmd<ValueType>(); }
+
+ void Init(GLuint _sync,
+ GLbitfield _flags,
+ GLuint _timeout_0,
+ GLuint _timeout_1) {
+ SetHeader();
+ sync = _sync;
+ flags = _flags;
+ timeout_0 = _timeout_0;
+ timeout_1 = _timeout_1;
+ }
+
+ void* Set(void* cmd,
+ GLuint _sync,
+ GLbitfield _flags,
+ GLuint _timeout_0,
+ GLuint _timeout_1) {
+ static_cast<ValueType*>(cmd)->Init(_sync, _flags, _timeout_0, _timeout_1);
+ return NextCmdAddress<ValueType>(cmd);
+ }
+
+ gpu::CommandHeader header;
+ uint32_t sync;
+ uint32_t flags;
+ uint32_t timeout_0;
+ uint32_t timeout_1;
+};
+
+static_assert(sizeof(WaitSync) == 20, "size of WaitSync should be 20");
+static_assert(offsetof(WaitSync, header) == 0,
+ "offset of WaitSync header should be 0");
+static_assert(offsetof(WaitSync, sync) == 4,
+ "offset of WaitSync sync should be 4");
+static_assert(offsetof(WaitSync, flags) == 8,
+ "offset of WaitSync flags should be 8");
+static_assert(offsetof(WaitSync, timeout_0) == 12,
+ "offset of WaitSync timeout_0 should be 12");
+static_assert(offsetof(WaitSync, timeout_1) == 16,
+ "offset of WaitSync timeout_1 should be 16");
+
struct BlitFramebufferCHROMIUM {
typedef BlitFramebufferCHROMIUM ValueType;
static const CommandId kCmdId = kBlitFramebufferCHROMIUM;
diff --git a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
index a89683a..9422405 100644
--- a/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_format_test_autogen.h
@@ -394,6 +394,24 @@
CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
}
+TEST_F(GLES2FormatTest, ClientWaitSync) {
+ cmds::ClientWaitSync& cmd = *GetBufferAs<cmds::ClientWaitSync>();
+ void* next_cmd =
+ cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLbitfield>(12),
+ static_cast<GLuint>(13), static_cast<GLuint>(14),
+ static_cast<uint32_t>(15), static_cast<uint32_t>(16));
+ EXPECT_EQ(static_cast<uint32_t>(cmds::ClientWaitSync::kCmdId),
+ cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.sync);
+ EXPECT_EQ(static_cast<GLbitfield>(12), cmd.flags);
+ EXPECT_EQ(static_cast<GLuint>(13), cmd.timeout_0);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.timeout_1);
+ EXPECT_EQ(static_cast<uint32_t>(15), cmd.result_shm_id);
+ EXPECT_EQ(static_cast<uint32_t>(16), cmd.result_shm_offset);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
TEST_F(GLES2FormatTest, ColorMask) {
cmds::ColorMask& cmd = *GetBufferAs<cmds::ColorMask>();
void* next_cmd =
@@ -3423,6 +3441,20 @@
CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
}
+TEST_F(GLES2FormatTest, WaitSync) {
+ cmds::WaitSync& cmd = *GetBufferAs<cmds::WaitSync>();
+ void* next_cmd =
+ cmd.Set(&cmd, static_cast<GLuint>(11), static_cast<GLbitfield>(12),
+ static_cast<GLuint>(13), static_cast<GLuint>(14));
+ EXPECT_EQ(static_cast<uint32_t>(cmds::WaitSync::kCmdId), cmd.header.command);
+ EXPECT_EQ(sizeof(cmd), cmd.header.size * 4u);
+ EXPECT_EQ(static_cast<GLuint>(11), cmd.sync);
+ EXPECT_EQ(static_cast<GLbitfield>(12), cmd.flags);
+ EXPECT_EQ(static_cast<GLuint>(13), cmd.timeout_0);
+ EXPECT_EQ(static_cast<GLuint>(14), cmd.timeout_1);
+ CheckBytesWrittenMatchesExpectedSize(next_cmd, sizeof(cmd));
+}
+
TEST_F(GLES2FormatTest, BlitFramebufferCHROMIUM) {
cmds::BlitFramebufferCHROMIUM& cmd =
*GetBufferAs<cmds::BlitFramebufferCHROMIUM>();
diff --git a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
index db67f4f..d652511 100644
--- a/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_ids_autogen.h
@@ -39,253 +39,255 @@
OP(ClearColor) /* 280 */ \
OP(ClearDepthf) /* 281 */ \
OP(ClearStencil) /* 282 */ \
- OP(ColorMask) /* 283 */ \
- OP(CompileShader) /* 284 */ \
- OP(CompressedTexImage2DBucket) /* 285 */ \
- OP(CompressedTexImage2D) /* 286 */ \
- OP(CompressedTexSubImage2DBucket) /* 287 */ \
- OP(CompressedTexSubImage2D) /* 288 */ \
- OP(CopyBufferSubData) /* 289 */ \
- OP(CopyTexImage2D) /* 290 */ \
- OP(CopyTexSubImage2D) /* 291 */ \
- OP(CopyTexSubImage3D) /* 292 */ \
- OP(CreateProgram) /* 293 */ \
- OP(CreateShader) /* 294 */ \
- OP(CullFace) /* 295 */ \
- OP(DeleteBuffersImmediate) /* 296 */ \
- OP(DeleteFramebuffersImmediate) /* 297 */ \
- OP(DeleteProgram) /* 298 */ \
- OP(DeleteRenderbuffersImmediate) /* 299 */ \
- OP(DeleteSamplersImmediate) /* 300 */ \
- OP(DeleteSync) /* 301 */ \
- OP(DeleteShader) /* 302 */ \
- OP(DeleteTexturesImmediate) /* 303 */ \
- OP(DeleteTransformFeedbacksImmediate) /* 304 */ \
- OP(DepthFunc) /* 305 */ \
- OP(DepthMask) /* 306 */ \
- OP(DepthRangef) /* 307 */ \
- OP(DetachShader) /* 308 */ \
- OP(Disable) /* 309 */ \
- OP(DisableVertexAttribArray) /* 310 */ \
- OP(DrawArrays) /* 311 */ \
- OP(DrawElements) /* 312 */ \
- OP(Enable) /* 313 */ \
- OP(EnableVertexAttribArray) /* 314 */ \
- OP(FenceSync) /* 315 */ \
- OP(Finish) /* 316 */ \
- OP(Flush) /* 317 */ \
- OP(FramebufferRenderbuffer) /* 318 */ \
- OP(FramebufferTexture2D) /* 319 */ \
- OP(FramebufferTextureLayer) /* 320 */ \
- OP(FrontFace) /* 321 */ \
- OP(GenBuffersImmediate) /* 322 */ \
- OP(GenerateMipmap) /* 323 */ \
- OP(GenFramebuffersImmediate) /* 324 */ \
- OP(GenRenderbuffersImmediate) /* 325 */ \
- OP(GenSamplersImmediate) /* 326 */ \
- OP(GenTexturesImmediate) /* 327 */ \
- OP(GenTransformFeedbacksImmediate) /* 328 */ \
- OP(GetActiveAttrib) /* 329 */ \
- OP(GetActiveUniform) /* 330 */ \
- OP(GetActiveUniformBlockiv) /* 331 */ \
- OP(GetActiveUniformBlockName) /* 332 */ \
- OP(GetActiveUniformsiv) /* 333 */ \
- OP(GetAttachedShaders) /* 334 */ \
- OP(GetAttribLocation) /* 335 */ \
- OP(GetBooleanv) /* 336 */ \
- OP(GetBufferParameteriv) /* 337 */ \
- OP(GetError) /* 338 */ \
- OP(GetFloatv) /* 339 */ \
- OP(GetFragDataLocation) /* 340 */ \
- OP(GetFramebufferAttachmentParameteriv) /* 341 */ \
- OP(GetIntegerv) /* 342 */ \
- OP(GetInternalformativ) /* 343 */ \
- OP(GetProgramiv) /* 344 */ \
- OP(GetProgramInfoLog) /* 345 */ \
- OP(GetRenderbufferParameteriv) /* 346 */ \
- OP(GetSamplerParameterfv) /* 347 */ \
- OP(GetSamplerParameteriv) /* 348 */ \
- OP(GetShaderiv) /* 349 */ \
- OP(GetShaderInfoLog) /* 350 */ \
- OP(GetShaderPrecisionFormat) /* 351 */ \
- OP(GetShaderSource) /* 352 */ \
- OP(GetString) /* 353 */ \
- OP(GetTexParameterfv) /* 354 */ \
- OP(GetTexParameteriv) /* 355 */ \
- OP(GetTransformFeedbackVarying) /* 356 */ \
- OP(GetUniformBlockIndex) /* 357 */ \
- OP(GetUniformfv) /* 358 */ \
- OP(GetUniformiv) /* 359 */ \
- OP(GetUniformIndices) /* 360 */ \
- OP(GetUniformLocation) /* 361 */ \
- OP(GetVertexAttribfv) /* 362 */ \
- OP(GetVertexAttribiv) /* 363 */ \
- OP(GetVertexAttribPointerv) /* 364 */ \
- OP(Hint) /* 365 */ \
- OP(InvalidateFramebufferImmediate) /* 366 */ \
- OP(InvalidateSubFramebufferImmediate) /* 367 */ \
- OP(IsBuffer) /* 368 */ \
- OP(IsEnabled) /* 369 */ \
- OP(IsFramebuffer) /* 370 */ \
- OP(IsProgram) /* 371 */ \
- OP(IsRenderbuffer) /* 372 */ \
- OP(IsSampler) /* 373 */ \
- OP(IsShader) /* 374 */ \
- OP(IsSync) /* 375 */ \
- OP(IsTexture) /* 376 */ \
- OP(IsTransformFeedback) /* 377 */ \
- OP(LineWidth) /* 378 */ \
- OP(LinkProgram) /* 379 */ \
- OP(PauseTransformFeedback) /* 380 */ \
- OP(PixelStorei) /* 381 */ \
- OP(PolygonOffset) /* 382 */ \
- OP(ReadBuffer) /* 383 */ \
- OP(ReadPixels) /* 384 */ \
- OP(ReleaseShaderCompiler) /* 385 */ \
- OP(RenderbufferStorage) /* 386 */ \
- OP(ResumeTransformFeedback) /* 387 */ \
- OP(SampleCoverage) /* 388 */ \
- OP(SamplerParameterf) /* 389 */ \
- OP(SamplerParameterfvImmediate) /* 390 */ \
- OP(SamplerParameteri) /* 391 */ \
- OP(SamplerParameterivImmediate) /* 392 */ \
- OP(Scissor) /* 393 */ \
- OP(ShaderBinary) /* 394 */ \
- OP(ShaderSourceBucket) /* 395 */ \
- OP(StencilFunc) /* 396 */ \
- OP(StencilFuncSeparate) /* 397 */ \
- OP(StencilMask) /* 398 */ \
- OP(StencilMaskSeparate) /* 399 */ \
- OP(StencilOp) /* 400 */ \
- OP(StencilOpSeparate) /* 401 */ \
- OP(TexImage2D) /* 402 */ \
- OP(TexImage3D) /* 403 */ \
- OP(TexParameterf) /* 404 */ \
- OP(TexParameterfvImmediate) /* 405 */ \
- OP(TexParameteri) /* 406 */ \
- OP(TexParameterivImmediate) /* 407 */ \
- OP(TexStorage3D) /* 408 */ \
- OP(TexSubImage2D) /* 409 */ \
- OP(TexSubImage3D) /* 410 */ \
- OP(TransformFeedbackVaryingsBucket) /* 411 */ \
- OP(Uniform1f) /* 412 */ \
- OP(Uniform1fvImmediate) /* 413 */ \
- OP(Uniform1i) /* 414 */ \
- OP(Uniform1ivImmediate) /* 415 */ \
- OP(Uniform1ui) /* 416 */ \
- OP(Uniform1uivImmediate) /* 417 */ \
- OP(Uniform2f) /* 418 */ \
- OP(Uniform2fvImmediate) /* 419 */ \
- OP(Uniform2i) /* 420 */ \
- OP(Uniform2ivImmediate) /* 421 */ \
- OP(Uniform2ui) /* 422 */ \
- OP(Uniform2uivImmediate) /* 423 */ \
- OP(Uniform3f) /* 424 */ \
- OP(Uniform3fvImmediate) /* 425 */ \
- OP(Uniform3i) /* 426 */ \
- OP(Uniform3ivImmediate) /* 427 */ \
- OP(Uniform3ui) /* 428 */ \
- OP(Uniform3uivImmediate) /* 429 */ \
- OP(Uniform4f) /* 430 */ \
- OP(Uniform4fvImmediate) /* 431 */ \
- OP(Uniform4i) /* 432 */ \
- OP(Uniform4ivImmediate) /* 433 */ \
- OP(Uniform4ui) /* 434 */ \
- OP(Uniform4uivImmediate) /* 435 */ \
- OP(UniformBlockBinding) /* 436 */ \
- OP(UniformMatrix2fvImmediate) /* 437 */ \
- OP(UniformMatrix2x3fvImmediate) /* 438 */ \
- OP(UniformMatrix2x4fvImmediate) /* 439 */ \
- OP(UniformMatrix3fvImmediate) /* 440 */ \
- OP(UniformMatrix3x2fvImmediate) /* 441 */ \
- OP(UniformMatrix3x4fvImmediate) /* 442 */ \
- OP(UniformMatrix4fvImmediate) /* 443 */ \
- OP(UniformMatrix4x2fvImmediate) /* 444 */ \
- OP(UniformMatrix4x3fvImmediate) /* 445 */ \
- OP(UseProgram) /* 446 */ \
- OP(ValidateProgram) /* 447 */ \
- OP(VertexAttrib1f) /* 448 */ \
- OP(VertexAttrib1fvImmediate) /* 449 */ \
- OP(VertexAttrib2f) /* 450 */ \
- OP(VertexAttrib2fvImmediate) /* 451 */ \
- OP(VertexAttrib3f) /* 452 */ \
- OP(VertexAttrib3fvImmediate) /* 453 */ \
- OP(VertexAttrib4f) /* 454 */ \
- OP(VertexAttrib4fvImmediate) /* 455 */ \
- OP(VertexAttribI4i) /* 456 */ \
- OP(VertexAttribI4ivImmediate) /* 457 */ \
- OP(VertexAttribI4ui) /* 458 */ \
- OP(VertexAttribI4uivImmediate) /* 459 */ \
- OP(VertexAttribIPointer) /* 460 */ \
- OP(VertexAttribPointer) /* 461 */ \
- OP(Viewport) /* 462 */ \
- OP(BlitFramebufferCHROMIUM) /* 463 */ \
- OP(RenderbufferStorageMultisampleCHROMIUM) /* 464 */ \
- OP(RenderbufferStorageMultisampleEXT) /* 465 */ \
- OP(FramebufferTexture2DMultisampleEXT) /* 466 */ \
- OP(TexStorage2DEXT) /* 467 */ \
- OP(GenQueriesEXTImmediate) /* 468 */ \
- OP(DeleteQueriesEXTImmediate) /* 469 */ \
- OP(BeginQueryEXT) /* 470 */ \
- OP(BeginTransformFeedback) /* 471 */ \
- OP(EndQueryEXT) /* 472 */ \
- OP(EndTransformFeedback) /* 473 */ \
- OP(InsertEventMarkerEXT) /* 474 */ \
- OP(PushGroupMarkerEXT) /* 475 */ \
- OP(PopGroupMarkerEXT) /* 476 */ \
- OP(GenVertexArraysOESImmediate) /* 477 */ \
- OP(DeleteVertexArraysOESImmediate) /* 478 */ \
- OP(IsVertexArrayOES) /* 479 */ \
- OP(BindVertexArrayOES) /* 480 */ \
- OP(SwapBuffers) /* 481 */ \
- OP(GetMaxValueInBufferCHROMIUM) /* 482 */ \
- OP(EnableFeatureCHROMIUM) /* 483 */ \
- OP(ResizeCHROMIUM) /* 484 */ \
- OP(GetRequestableExtensionsCHROMIUM) /* 485 */ \
- OP(RequestExtensionCHROMIUM) /* 486 */ \
- OP(GetProgramInfoCHROMIUM) /* 487 */ \
- OP(GetUniformBlocksCHROMIUM) /* 488 */ \
- OP(GetTransformFeedbackVaryingsCHROMIUM) /* 489 */ \
- OP(GetUniformsES3CHROMIUM) /* 490 */ \
- OP(GetTranslatedShaderSourceANGLE) /* 491 */ \
- OP(PostSubBufferCHROMIUM) /* 492 */ \
- OP(TexImageIOSurface2DCHROMIUM) /* 493 */ \
- OP(CopyTextureCHROMIUM) /* 494 */ \
- OP(DrawArraysInstancedANGLE) /* 495 */ \
- OP(DrawElementsInstancedANGLE) /* 496 */ \
- OP(VertexAttribDivisorANGLE) /* 497 */ \
- OP(GenMailboxCHROMIUM) /* 498 */ \
- OP(ProduceTextureCHROMIUMImmediate) /* 499 */ \
- OP(ProduceTextureDirectCHROMIUMImmediate) /* 500 */ \
- OP(ConsumeTextureCHROMIUMImmediate) /* 501 */ \
- OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 502 */ \
- OP(BindUniformLocationCHROMIUMBucket) /* 503 */ \
- OP(GenValuebuffersCHROMIUMImmediate) /* 504 */ \
- OP(DeleteValuebuffersCHROMIUMImmediate) /* 505 */ \
- OP(IsValuebufferCHROMIUM) /* 506 */ \
- OP(BindValuebufferCHROMIUM) /* 507 */ \
- OP(SubscribeValueCHROMIUM) /* 508 */ \
- OP(PopulateSubscribedValuesCHROMIUM) /* 509 */ \
- OP(UniformValuebufferCHROMIUM) /* 510 */ \
- OP(BindTexImage2DCHROMIUM) /* 511 */ \
- OP(ReleaseTexImage2DCHROMIUM) /* 512 */ \
- OP(TraceBeginCHROMIUM) /* 513 */ \
- OP(TraceEndCHROMIUM) /* 514 */ \
- OP(AsyncTexSubImage2DCHROMIUM) /* 515 */ \
- OP(AsyncTexImage2DCHROMIUM) /* 516 */ \
- OP(WaitAsyncTexImage2DCHROMIUM) /* 517 */ \
- OP(WaitAllAsyncTexImage2DCHROMIUM) /* 518 */ \
- OP(DiscardFramebufferEXTImmediate) /* 519 */ \
- OP(LoseContextCHROMIUM) /* 520 */ \
- OP(InsertSyncPointCHROMIUM) /* 521 */ \
- OP(WaitSyncPointCHROMIUM) /* 522 */ \
- OP(DrawBuffersEXTImmediate) /* 523 */ \
- OP(DiscardBackbufferCHROMIUM) /* 524 */ \
- OP(ScheduleOverlayPlaneCHROMIUM) /* 525 */ \
- OP(SwapInterval) /* 526 */ \
- OP(MatrixLoadfCHROMIUMImmediate) /* 527 */ \
- OP(MatrixLoadIdentityCHROMIUM) /* 528 */ \
- OP(BlendBarrierKHR) /* 529 */
+ OP(ClientWaitSync) /* 283 */ \
+ OP(ColorMask) /* 284 */ \
+ OP(CompileShader) /* 285 */ \
+ OP(CompressedTexImage2DBucket) /* 286 */ \
+ OP(CompressedTexImage2D) /* 287 */ \
+ OP(CompressedTexSubImage2DBucket) /* 288 */ \
+ OP(CompressedTexSubImage2D) /* 289 */ \
+ OP(CopyBufferSubData) /* 290 */ \
+ OP(CopyTexImage2D) /* 291 */ \
+ OP(CopyTexSubImage2D) /* 292 */ \
+ OP(CopyTexSubImage3D) /* 293 */ \
+ OP(CreateProgram) /* 294 */ \
+ OP(CreateShader) /* 295 */ \
+ OP(CullFace) /* 296 */ \
+ OP(DeleteBuffersImmediate) /* 297 */ \
+ OP(DeleteFramebuffersImmediate) /* 298 */ \
+ OP(DeleteProgram) /* 299 */ \
+ OP(DeleteRenderbuffersImmediate) /* 300 */ \
+ OP(DeleteSamplersImmediate) /* 301 */ \
+ OP(DeleteSync) /* 302 */ \
+ OP(DeleteShader) /* 303 */ \
+ OP(DeleteTexturesImmediate) /* 304 */ \
+ OP(DeleteTransformFeedbacksImmediate) /* 305 */ \
+ OP(DepthFunc) /* 306 */ \
+ OP(DepthMask) /* 307 */ \
+ OP(DepthRangef) /* 308 */ \
+ OP(DetachShader) /* 309 */ \
+ OP(Disable) /* 310 */ \
+ OP(DisableVertexAttribArray) /* 311 */ \
+ OP(DrawArrays) /* 312 */ \
+ OP(DrawElements) /* 313 */ \
+ OP(Enable) /* 314 */ \
+ OP(EnableVertexAttribArray) /* 315 */ \
+ OP(FenceSync) /* 316 */ \
+ OP(Finish) /* 317 */ \
+ OP(Flush) /* 318 */ \
+ OP(FramebufferRenderbuffer) /* 319 */ \
+ OP(FramebufferTexture2D) /* 320 */ \
+ OP(FramebufferTextureLayer) /* 321 */ \
+ OP(FrontFace) /* 322 */ \
+ OP(GenBuffersImmediate) /* 323 */ \
+ OP(GenerateMipmap) /* 324 */ \
+ OP(GenFramebuffersImmediate) /* 325 */ \
+ OP(GenRenderbuffersImmediate) /* 326 */ \
+ OP(GenSamplersImmediate) /* 327 */ \
+ OP(GenTexturesImmediate) /* 328 */ \
+ OP(GenTransformFeedbacksImmediate) /* 329 */ \
+ OP(GetActiveAttrib) /* 330 */ \
+ OP(GetActiveUniform) /* 331 */ \
+ OP(GetActiveUniformBlockiv) /* 332 */ \
+ OP(GetActiveUniformBlockName) /* 333 */ \
+ OP(GetActiveUniformsiv) /* 334 */ \
+ OP(GetAttachedShaders) /* 335 */ \
+ OP(GetAttribLocation) /* 336 */ \
+ OP(GetBooleanv) /* 337 */ \
+ OP(GetBufferParameteriv) /* 338 */ \
+ OP(GetError) /* 339 */ \
+ OP(GetFloatv) /* 340 */ \
+ OP(GetFragDataLocation) /* 341 */ \
+ OP(GetFramebufferAttachmentParameteriv) /* 342 */ \
+ OP(GetIntegerv) /* 343 */ \
+ OP(GetInternalformativ) /* 344 */ \
+ OP(GetProgramiv) /* 345 */ \
+ OP(GetProgramInfoLog) /* 346 */ \
+ OP(GetRenderbufferParameteriv) /* 347 */ \
+ OP(GetSamplerParameterfv) /* 348 */ \
+ OP(GetSamplerParameteriv) /* 349 */ \
+ OP(GetShaderiv) /* 350 */ \
+ OP(GetShaderInfoLog) /* 351 */ \
+ OP(GetShaderPrecisionFormat) /* 352 */ \
+ OP(GetShaderSource) /* 353 */ \
+ OP(GetString) /* 354 */ \
+ OP(GetTexParameterfv) /* 355 */ \
+ OP(GetTexParameteriv) /* 356 */ \
+ OP(GetTransformFeedbackVarying) /* 357 */ \
+ OP(GetUniformBlockIndex) /* 358 */ \
+ OP(GetUniformfv) /* 359 */ \
+ OP(GetUniformiv) /* 360 */ \
+ OP(GetUniformIndices) /* 361 */ \
+ OP(GetUniformLocation) /* 362 */ \
+ OP(GetVertexAttribfv) /* 363 */ \
+ OP(GetVertexAttribiv) /* 364 */ \
+ OP(GetVertexAttribPointerv) /* 365 */ \
+ OP(Hint) /* 366 */ \
+ OP(InvalidateFramebufferImmediate) /* 367 */ \
+ OP(InvalidateSubFramebufferImmediate) /* 368 */ \
+ OP(IsBuffer) /* 369 */ \
+ OP(IsEnabled) /* 370 */ \
+ OP(IsFramebuffer) /* 371 */ \
+ OP(IsProgram) /* 372 */ \
+ OP(IsRenderbuffer) /* 373 */ \
+ OP(IsSampler) /* 374 */ \
+ OP(IsShader) /* 375 */ \
+ OP(IsSync) /* 376 */ \
+ OP(IsTexture) /* 377 */ \
+ OP(IsTransformFeedback) /* 378 */ \
+ OP(LineWidth) /* 379 */ \
+ OP(LinkProgram) /* 380 */ \
+ OP(PauseTransformFeedback) /* 381 */ \
+ OP(PixelStorei) /* 382 */ \
+ OP(PolygonOffset) /* 383 */ \
+ OP(ReadBuffer) /* 384 */ \
+ OP(ReadPixels) /* 385 */ \
+ OP(ReleaseShaderCompiler) /* 386 */ \
+ OP(RenderbufferStorage) /* 387 */ \
+ OP(ResumeTransformFeedback) /* 388 */ \
+ OP(SampleCoverage) /* 389 */ \
+ OP(SamplerParameterf) /* 390 */ \
+ OP(SamplerParameterfvImmediate) /* 391 */ \
+ OP(SamplerParameteri) /* 392 */ \
+ OP(SamplerParameterivImmediate) /* 393 */ \
+ OP(Scissor) /* 394 */ \
+ OP(ShaderBinary) /* 395 */ \
+ OP(ShaderSourceBucket) /* 396 */ \
+ OP(StencilFunc) /* 397 */ \
+ OP(StencilFuncSeparate) /* 398 */ \
+ OP(StencilMask) /* 399 */ \
+ OP(StencilMaskSeparate) /* 400 */ \
+ OP(StencilOp) /* 401 */ \
+ OP(StencilOpSeparate) /* 402 */ \
+ OP(TexImage2D) /* 403 */ \
+ OP(TexImage3D) /* 404 */ \
+ OP(TexParameterf) /* 405 */ \
+ OP(TexParameterfvImmediate) /* 406 */ \
+ OP(TexParameteri) /* 407 */ \
+ OP(TexParameterivImmediate) /* 408 */ \
+ OP(TexStorage3D) /* 409 */ \
+ OP(TexSubImage2D) /* 410 */ \
+ OP(TexSubImage3D) /* 411 */ \
+ OP(TransformFeedbackVaryingsBucket) /* 412 */ \
+ OP(Uniform1f) /* 413 */ \
+ OP(Uniform1fvImmediate) /* 414 */ \
+ OP(Uniform1i) /* 415 */ \
+ OP(Uniform1ivImmediate) /* 416 */ \
+ OP(Uniform1ui) /* 417 */ \
+ OP(Uniform1uivImmediate) /* 418 */ \
+ OP(Uniform2f) /* 419 */ \
+ OP(Uniform2fvImmediate) /* 420 */ \
+ OP(Uniform2i) /* 421 */ \
+ OP(Uniform2ivImmediate) /* 422 */ \
+ OP(Uniform2ui) /* 423 */ \
+ OP(Uniform2uivImmediate) /* 424 */ \
+ OP(Uniform3f) /* 425 */ \
+ OP(Uniform3fvImmediate) /* 426 */ \
+ OP(Uniform3i) /* 427 */ \
+ OP(Uniform3ivImmediate) /* 428 */ \
+ OP(Uniform3ui) /* 429 */ \
+ OP(Uniform3uivImmediate) /* 430 */ \
+ OP(Uniform4f) /* 431 */ \
+ OP(Uniform4fvImmediate) /* 432 */ \
+ OP(Uniform4i) /* 433 */ \
+ OP(Uniform4ivImmediate) /* 434 */ \
+ OP(Uniform4ui) /* 435 */ \
+ OP(Uniform4uivImmediate) /* 436 */ \
+ OP(UniformBlockBinding) /* 437 */ \
+ OP(UniformMatrix2fvImmediate) /* 438 */ \
+ OP(UniformMatrix2x3fvImmediate) /* 439 */ \
+ OP(UniformMatrix2x4fvImmediate) /* 440 */ \
+ OP(UniformMatrix3fvImmediate) /* 441 */ \
+ OP(UniformMatrix3x2fvImmediate) /* 442 */ \
+ OP(UniformMatrix3x4fvImmediate) /* 443 */ \
+ OP(UniformMatrix4fvImmediate) /* 444 */ \
+ OP(UniformMatrix4x2fvImmediate) /* 445 */ \
+ OP(UniformMatrix4x3fvImmediate) /* 446 */ \
+ OP(UseProgram) /* 447 */ \
+ OP(ValidateProgram) /* 448 */ \
+ OP(VertexAttrib1f) /* 449 */ \
+ OP(VertexAttrib1fvImmediate) /* 450 */ \
+ OP(VertexAttrib2f) /* 451 */ \
+ OP(VertexAttrib2fvImmediate) /* 452 */ \
+ OP(VertexAttrib3f) /* 453 */ \
+ OP(VertexAttrib3fvImmediate) /* 454 */ \
+ OP(VertexAttrib4f) /* 455 */ \
+ OP(VertexAttrib4fvImmediate) /* 456 */ \
+ OP(VertexAttribI4i) /* 457 */ \
+ OP(VertexAttribI4ivImmediate) /* 458 */ \
+ OP(VertexAttribI4ui) /* 459 */ \
+ OP(VertexAttribI4uivImmediate) /* 460 */ \
+ OP(VertexAttribIPointer) /* 461 */ \
+ OP(VertexAttribPointer) /* 462 */ \
+ OP(Viewport) /* 463 */ \
+ OP(WaitSync) /* 464 */ \
+ OP(BlitFramebufferCHROMIUM) /* 465 */ \
+ OP(RenderbufferStorageMultisampleCHROMIUM) /* 466 */ \
+ OP(RenderbufferStorageMultisampleEXT) /* 467 */ \
+ OP(FramebufferTexture2DMultisampleEXT) /* 468 */ \
+ OP(TexStorage2DEXT) /* 469 */ \
+ OP(GenQueriesEXTImmediate) /* 470 */ \
+ OP(DeleteQueriesEXTImmediate) /* 471 */ \
+ OP(BeginQueryEXT) /* 472 */ \
+ OP(BeginTransformFeedback) /* 473 */ \
+ OP(EndQueryEXT) /* 474 */ \
+ OP(EndTransformFeedback) /* 475 */ \
+ OP(InsertEventMarkerEXT) /* 476 */ \
+ OP(PushGroupMarkerEXT) /* 477 */ \
+ OP(PopGroupMarkerEXT) /* 478 */ \
+ OP(GenVertexArraysOESImmediate) /* 479 */ \
+ OP(DeleteVertexArraysOESImmediate) /* 480 */ \
+ OP(IsVertexArrayOES) /* 481 */ \
+ OP(BindVertexArrayOES) /* 482 */ \
+ OP(SwapBuffers) /* 483 */ \
+ OP(GetMaxValueInBufferCHROMIUM) /* 484 */ \
+ OP(EnableFeatureCHROMIUM) /* 485 */ \
+ OP(ResizeCHROMIUM) /* 486 */ \
+ OP(GetRequestableExtensionsCHROMIUM) /* 487 */ \
+ OP(RequestExtensionCHROMIUM) /* 488 */ \
+ OP(GetProgramInfoCHROMIUM) /* 489 */ \
+ OP(GetUniformBlocksCHROMIUM) /* 490 */ \
+ OP(GetTransformFeedbackVaryingsCHROMIUM) /* 491 */ \
+ OP(GetUniformsES3CHROMIUM) /* 492 */ \
+ OP(GetTranslatedShaderSourceANGLE) /* 493 */ \
+ OP(PostSubBufferCHROMIUM) /* 494 */ \
+ OP(TexImageIOSurface2DCHROMIUM) /* 495 */ \
+ OP(CopyTextureCHROMIUM) /* 496 */ \
+ OP(DrawArraysInstancedANGLE) /* 497 */ \
+ OP(DrawElementsInstancedANGLE) /* 498 */ \
+ OP(VertexAttribDivisorANGLE) /* 499 */ \
+ OP(GenMailboxCHROMIUM) /* 500 */ \
+ OP(ProduceTextureCHROMIUMImmediate) /* 501 */ \
+ OP(ProduceTextureDirectCHROMIUMImmediate) /* 502 */ \
+ OP(ConsumeTextureCHROMIUMImmediate) /* 503 */ \
+ OP(CreateAndConsumeTextureCHROMIUMImmediate) /* 504 */ \
+ OP(BindUniformLocationCHROMIUMBucket) /* 505 */ \
+ OP(GenValuebuffersCHROMIUMImmediate) /* 506 */ \
+ OP(DeleteValuebuffersCHROMIUMImmediate) /* 507 */ \
+ OP(IsValuebufferCHROMIUM) /* 508 */ \
+ OP(BindValuebufferCHROMIUM) /* 509 */ \
+ OP(SubscribeValueCHROMIUM) /* 510 */ \
+ OP(PopulateSubscribedValuesCHROMIUM) /* 511 */ \
+ OP(UniformValuebufferCHROMIUM) /* 512 */ \
+ OP(BindTexImage2DCHROMIUM) /* 513 */ \
+ OP(ReleaseTexImage2DCHROMIUM) /* 514 */ \
+ OP(TraceBeginCHROMIUM) /* 515 */ \
+ OP(TraceEndCHROMIUM) /* 516 */ \
+ OP(AsyncTexSubImage2DCHROMIUM) /* 517 */ \
+ OP(AsyncTexImage2DCHROMIUM) /* 518 */ \
+ OP(WaitAsyncTexImage2DCHROMIUM) /* 519 */ \
+ OP(WaitAllAsyncTexImage2DCHROMIUM) /* 520 */ \
+ OP(DiscardFramebufferEXTImmediate) /* 521 */ \
+ OP(LoseContextCHROMIUM) /* 522 */ \
+ OP(InsertSyncPointCHROMIUM) /* 523 */ \
+ OP(WaitSyncPointCHROMIUM) /* 524 */ \
+ OP(DrawBuffersEXTImmediate) /* 525 */ \
+ OP(DiscardBackbufferCHROMIUM) /* 526 */ \
+ OP(ScheduleOverlayPlaneCHROMIUM) /* 527 */ \
+ OP(SwapInterval) /* 528 */ \
+ OP(MatrixLoadfCHROMIUMImmediate) /* 529 */ \
+ OP(MatrixLoadIdentityCHROMIUM) /* 530 */ \
+ OP(BlendBarrierKHR) /* 531 */
enum CommandId {
kStartPoint = cmd::kLastCommonId, // All GLES2 commands start after this.
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.cc b/gpu/command_buffer/common/gles2_cmd_utils.cc
index 638245b..c16a962 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.cc
+++ b/gpu/command_buffer/common/gles2_cmd_utils.cc
@@ -846,6 +846,20 @@
}
}
+// static
+void GLES2Util::MapUint64ToTwoUint32(
+ uint64_t v64, uint32_t* v32_0, uint32_t* v32_1) {
+ DCHECK(v32_0 && v32_1);
+ *v32_0 = static_cast<uint32_t>(v64 & 0xFFFFFFFF);
+ *v32_1 = static_cast<uint32_t>((v64 & 0xFFFFFFFF00000000) >> 32);
+}
+
+// static
+uint64_t GLES2Util::MapTwoUint32ToUint64(uint32_t v32_0, uint32_t v32_1) {
+ uint64_t v64 = v32_1;
+ return (v64 << 32) | v32_0;
+}
+
namespace {
// WebGraphicsContext3DCommandBufferImpl configuration attributes. Those in
diff --git a/gpu/command_buffer/common/gles2_cmd_utils.h b/gpu/command_buffer/common/gles2_cmd_utils.h
index 127c2be..3528cfd 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils.h
@@ -187,6 +187,10 @@
static size_t CalcClearBufferivDataCount(int buffer);
static size_t CalcClearBufferfvDataCount(int buffer);
+ static void MapUint64ToTwoUint32(
+ uint64_t v64, uint32_t* v32_0, uint32_t* v32_1);
+ static uint64_t MapTwoUint32ToUint64(uint32_t v32_0, uint32_t v32_1);
+
#include "../common/gles2_cmd_utils_autogen.h"
private:
diff --git a/gpu/command_buffer/service/framebuffer_manager.cc b/gpu/command_buffer/service/framebuffer_manager.cc
index d766abb..3e9e0b2 100644
--- a/gpu/command_buffer/service/framebuffer_manager.cc
+++ b/gpu/command_buffer/service/framebuffer_manager.cc
@@ -631,6 +631,14 @@
}
}
+void Framebuffer::DoUnbindGLAttachmentsForWorkaround(GLenum target) {
+ // Replace all attachments with the default Renderbuffer.
+ for (AttachmentMap::const_iterator it = attachments_.begin();
+ it != attachments_.end(); ++it) {
+ glFramebufferRenderbufferEXT(target, it->first, GL_RENDERBUFFER, 0);
+ }
+}
+
void Framebuffer::AttachRenderbuffer(
GLenum attachment, Renderbuffer* renderbuffer) {
const Attachment* a = GetAttachment(attachment);
diff --git a/gpu/command_buffer/service/framebuffer_manager.h b/gpu/command_buffer/service/framebuffer_manager.h
index 78c11ad..75f7e2a 100644
--- a/gpu/command_buffer/service/framebuffer_manager.h
+++ b/gpu/command_buffer/service/framebuffer_manager.h
@@ -74,6 +74,11 @@
GLenum attachment,
bool cleared);
+ // Unbinds all attachments from this framebuffer for workaround
+ // 'unbind_attachments_on_bound_render_fbo_delete'. The Framebuffer must be
+ // bound when calling this.
+ void DoUnbindGLAttachmentsForWorkaround(GLenum target);
+
// Attaches a renderbuffer to a particlar attachment.
// Pass null to detach.
void AttachRenderbuffer(
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 52a9c43..6b254e0 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -3099,11 +3099,16 @@
GetFramebuffer(client_ids[ii]);
if (framebuffer && !framebuffer->IsDeleted()) {
if (framebuffer == framebuffer_state_.bound_draw_framebuffer.get()) {
- framebuffer_state_.bound_draw_framebuffer = NULL;
- framebuffer_state_.clear_state_dirty = true;
GLenum target = supports_separate_framebuffer_binds ?
GL_DRAW_FRAMEBUFFER_EXT : GL_FRAMEBUFFER;
+
+ // Unbind attachments on FBO before deletion.
+ if (workarounds().unbind_attachments_on_bound_render_fbo_delete)
+ framebuffer->DoUnbindGLAttachmentsForWorkaround(target);
+
glBindFramebufferEXT(target, GetBackbufferServiceId());
+ framebuffer_state_.bound_draw_framebuffer = NULL;
+ framebuffer_state_.clear_state_dirty = true;
}
if (framebuffer == framebuffer_state_.bound_read_framebuffer.get()) {
framebuffer_state_.bound_read_framebuffer = NULL;
@@ -12055,6 +12060,51 @@
return error::kNoError;
}
+error::Error GLES2DecoderImpl::HandleClientWaitSync(
+ uint32_t immediate_data_size, const void* cmd_data) {
+ if (!unsafe_es3_apis_enabled())
+ return error::kUnknownCommand;
+ const gles2::cmds::ClientWaitSync& c =
+ *static_cast<const gles2::cmds::ClientWaitSync*>(cmd_data);
+ GLuint sync = static_cast<GLuint>(c.sync);
+ GLbitfield flags = static_cast<GLbitfield>(c.flags);
+ GLuint64 timeout = GLES2Util::MapTwoUint32ToUint64(c.timeout_0, c.timeout_1);
+ typedef cmds::ClientWaitSync::Result Result;
+ Result* result_dst = GetSharedMemoryAs<Result*>(
+ c.result_shm_id, c.result_shm_offset, sizeof(*result_dst));
+ if (!result_dst) {
+ return error::kOutOfBounds;
+ }
+ if (*result_dst != GL_WAIT_FAILED) {
+ return error::kInvalidArguments;
+ }
+ GLsync service_sync = 0;
+ if (!group_->GetSyncServiceId(sync, &service_sync)) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "ClientWaitSync", "invalid sync");
+ return error::kNoError;
+ }
+ *result_dst = glClientWaitSync(service_sync, flags, timeout);
+ return error::kNoError;
+}
+
+error::Error GLES2DecoderImpl::HandleWaitSync(
+ uint32_t immediate_data_size, const void* cmd_data) {
+ if (!unsafe_es3_apis_enabled())
+ return error::kUnknownCommand;
+ const gles2::cmds::WaitSync& c =
+ *static_cast<const gles2::cmds::WaitSync*>(cmd_data);
+ GLuint sync = static_cast<GLuint>(c.sync);
+ GLbitfield flags = static_cast<GLbitfield>(c.flags);
+ GLuint64 timeout = GLES2Util::MapTwoUint32ToUint64(c.timeout_0, c.timeout_1);
+ GLsync service_sync = 0;
+ if (!group_->GetSyncServiceId(sync, &service_sync)) {
+ LOCAL_SET_GL_ERROR(GL_INVALID_VALUE, "WaitSync", "invalid sync");
+ return error::kNoError;
+ }
+ glWaitSync(service_sync, flags, timeout);
+ return error::kNoError;
+}
+
void GLES2DecoderImpl::OnTextureRefDetachedFromFramebuffer(
TextureRef* texture_ref) {
Texture* texture = texture_ref->texture();
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
index 905a390..e07a8ee 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest.cc
@@ -265,6 +265,115 @@
EXPECT_FALSE(DoIsTexture(client_texture_id_));
}
+TEST_P(GLES2DecoderTest, ClientWaitSyncValid) {
+ typedef cmds::ClientWaitSync::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ cmds::ClientWaitSync cmd;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(0, &v32_0, &v32_1);
+ cmd.Init(client_sync_id_, GL_SYNC_FLUSH_COMMANDS_BIT, v32_0, v32_1,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_,
+ ClientWaitSync(reinterpret_cast<GLsync>(kServiceSyncId),
+ GL_SYNC_FLUSH_COMMANDS_BIT, 0))
+ .WillOnce(Return(GL_CONDITION_SATISFIED))
+ .RetiresOnSaturation();
+ *result = GL_WAIT_FAILED;
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(static_cast<GLenum>(GL_CONDITION_SATISFIED), *result);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ decoder_->set_unsafe_es3_apis_enabled(false);
+ EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, ClientWaitSyncNonZeroTimeoutValid) {
+ typedef cmds::ClientWaitSync::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ cmds::ClientWaitSync cmd;
+ const GLuint64 kTimeout = 0xABCDEF0123456789;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(kTimeout, &v32_0, &v32_1);
+ cmd.Init(client_sync_id_, GL_SYNC_FLUSH_COMMANDS_BIT, v32_0, v32_1,
+ shared_memory_id_, shared_memory_offset_);
+ EXPECT_CALL(*gl_,
+ ClientWaitSync(reinterpret_cast<GLsync>(kServiceSyncId),
+ GL_SYNC_FLUSH_COMMANDS_BIT, kTimeout))
+ .WillOnce(Return(GL_CONDITION_SATISFIED))
+ .RetiresOnSaturation();
+ *result = GL_WAIT_FAILED;
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(static_cast<GLenum>(GL_CONDITION_SATISFIED), *result);
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ decoder_->set_unsafe_es3_apis_enabled(false);
+ EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, ClientWaitSyncInvalidSyncFails) {
+ typedef cmds::ClientWaitSync::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ cmds::ClientWaitSync cmd;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(0, &v32_0, &v32_1);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ cmd.Init(kInvalidClientId, GL_SYNC_FLUSH_COMMANDS_BIT, v32_0, v32_1,
+ shared_memory_id_, shared_memory_offset_);
+ *result = GL_WAIT_FAILED;
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(static_cast<GLenum>(GL_WAIT_FAILED), *result);
+ EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
+}
+
+TEST_P(GLES2DecoderTest, ClientWaitSyncResultNotInitFails) {
+ typedef cmds::ClientWaitSync::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ cmds::ClientWaitSync cmd;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(0, &v32_0, &v32_1);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ cmd.Init(client_sync_id_, GL_SYNC_FLUSH_COMMANDS_BIT, v32_0, v32_1,
+ shared_memory_id_, shared_memory_offset_);
+ *result = 1; // Any value other than GL_WAIT_FAILED
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, ClientWaitSyncBadSharedMemoryFails) {
+ typedef cmds::ClientWaitSync::Result Result;
+ Result* result = static_cast<Result*>(shared_memory_address_);
+ cmds::ClientWaitSync cmd;
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(0, &v32_0, &v32_1);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ *result = GL_WAIT_FAILED;
+ cmd.Init(client_sync_id_, GL_SYNC_FLUSH_COMMANDS_BIT, v32_0, v32_1,
+ kInvalidSharedMemoryId, shared_memory_offset_);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+
+ *result = GL_WAIT_FAILED;
+ cmd.Init(client_sync_id_, GL_SYNC_FLUSH_COMMANDS_BIT, v32_0, v32_1,
+ shared_memory_id_, kInvalidSharedMemoryOffset);
+ EXPECT_NE(error::kNoError, ExecuteCmd(cmd));
+}
+
+TEST_P(GLES2DecoderTest, WaitSyncValidArgs) {
+ const GLuint64 kTimeout = GL_TIMEOUT_IGNORED;
+ EXPECT_CALL(*gl_, WaitSync(reinterpret_cast<GLsync>(kServiceSyncId),
+ 0, kTimeout))
+ .Times(1)
+ .RetiresOnSaturation();
+
+ uint32_t v32_0 = 0, v32_1 = 0;
+ GLES2Util::MapUint64ToTwoUint32(kTimeout, &v32_0, &v32_1);
+ cmds::WaitSync cmd;
+ cmd.Init(client_sync_id_, 0, v32_0, v32_1);
+ decoder_->set_unsafe_es3_apis_enabled(true);
+ EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+ decoder_->set_unsafe_es3_apis_enabled(false);
+ EXPECT_EQ(error::kUnknownCommand, ExecuteCmd(cmd));
+}
+
TEST_P(GLES2DecoderManualInitTest, BindGeneratesResourceFalse) {
InitState init;
InitDecoder(init);
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
index a255fe8..f03d3a5 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_1_autogen.h
@@ -486,6 +486,7 @@
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
+// TODO(gman): ClientWaitSync
TEST_P(GLES2DecoderTest1, ColorMaskValidArgs) {
SpecializedSetup<cmds::ColorMask, 0>(true);
@@ -1810,6 +1811,4 @@
// TODO(gman): GetShaderPrecisionFormat
// TODO(gman): GetShaderSource
-// TODO(gman): GetString
-
#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_1_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
index 2e60219..447914c 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2_autogen.h
@@ -12,6 +12,8 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
+// TODO(gman): GetString
+
TEST_P(GLES2DecoderTest2, GetTexParameterfvValidArgs) {
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
@@ -1581,18 +1583,4 @@
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_NO_ERROR, GetGLError());
}
-
-TEST_P(GLES2DecoderTest2, VertexAttrib2fvImmediateValidArgs) {
- cmds::VertexAttrib2fvImmediate& cmd =
- *GetImmediateAs<cmds::VertexAttrib2fvImmediate>();
- SpecializedSetup<cmds::VertexAttrib2fvImmediate, 0>(true);
- GLfloat temp[2] = {
- 0,
- };
- cmd.Init(1, &temp[0]);
- EXPECT_CALL(*gl_, VertexAttrib2fv(1, reinterpret_cast<GLfloat*>(
- ImmediateDataAddress(&cmd))));
- EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
- EXPECT_EQ(GL_NO_ERROR, GetGLError());
-}
#endif // GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_2_AUTOGEN_H_
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
index 7a58038..1add369 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_3_autogen.h
@@ -12,6 +12,20 @@
#ifndef GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
#define GPU_COMMAND_BUFFER_SERVICE_GLES2_CMD_DECODER_UNITTEST_3_AUTOGEN_H_
+TEST_P(GLES2DecoderTest3, VertexAttrib2fvImmediateValidArgs) {
+ cmds::VertexAttrib2fvImmediate& cmd =
+ *GetImmediateAs<cmds::VertexAttrib2fvImmediate>();
+ SpecializedSetup<cmds::VertexAttrib2fvImmediate, 0>(true);
+ GLfloat temp[2] = {
+ 0,
+ };
+ cmd.Init(1, &temp[0]);
+ EXPECT_CALL(*gl_, VertexAttrib2fv(1, reinterpret_cast<GLfloat*>(
+ ImmediateDataAddress(&cmd))));
+ EXPECT_EQ(error::kNoError, ExecuteImmediateCmd(cmd, sizeof(temp)));
+ EXPECT_EQ(GL_NO_ERROR, GetGLError());
+}
+
TEST_P(GLES2DecoderTest3, VertexAttrib3fValidArgs) {
EXPECT_CALL(*gl_, VertexAttrib3f(1, 2, 3, 4));
SpecializedSetup<cmds::VertexAttrib3f, 0>(true);
@@ -145,6 +159,8 @@
EXPECT_EQ(error::kNoError, ExecuteCmd(cmd));
EXPECT_EQ(GL_INVALID_VALUE, GetGLError());
}
+// TODO(gman): WaitSync
+
// TODO(gman): TexStorage2DEXT
// TODO(gman): GenQueriesEXTImmediate
// TODO(gman): DeleteQueriesEXTImmediate
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index 27c61ad..abf1e90 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -64,6 +64,7 @@
ValueValidator<GLenum> stencil_op;
ValueValidator<GLenum> string_type;
ValueValidator<GLenum> subscription_target;
+ValueValidator<GLbitfield> sync_flush_flags;
ValueValidator<GLenum> texture_3_d_target;
ValueValidator<GLenum> texture_bind_target;
ValueValidator<GLenum> texture_format;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 97c3cdd..68df541 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -457,6 +457,11 @@
GL_MOUSE_POSITION_CHROMIUM,
};
+static const GLbitfield valid_sync_flush_flags_table[] = {
+ GL_SYNC_FLUSH_COMMANDS_BIT,
+ 0,
+};
+
static const GLenum valid_texture_3_d_target_table[] = {
GL_TEXTURE_3D,
GL_TEXTURE_2D_ARRAY,
@@ -688,6 +693,8 @@
string_type(valid_string_type_table, arraysize(valid_string_type_table)),
subscription_target(valid_subscription_target_table,
arraysize(valid_subscription_target_table)),
+ sync_flush_flags(valid_sync_flush_flags_table,
+ arraysize(valid_sync_flush_flags_table)),
texture_3_d_target(valid_texture_3_d_target_table,
arraysize(valid_texture_3_d_target_table)),
texture_bind_target(valid_texture_bind_target_table,
diff --git a/gpu/command_buffer/service/gpu_timing.cc b/gpu/command_buffer/service/gpu_timing.cc
index 8716448..6ab3e83 100644
--- a/gpu/command_buffer/service/gpu_timing.cc
+++ b/gpu/command_buffer/service/gpu_timing.cc
@@ -5,6 +5,7 @@
#include "gpu/command_buffer/service/gpu_timing.h"
#include "base/time/time.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_context.h"
#include "ui/gl/gl_version_info.h"
@@ -23,11 +24,11 @@
void GPUTimer::Start() {
// GL_TIMESTAMP and GL_TIMESTAMP_EXT both have the same value.
glQueryCounter(queries_[0], GL_TIMESTAMP);
- offset_ = gpu_timing_->CalculateTimerOffset();
}
void GPUTimer::End() {
end_requested_ = true;
+ offset_ = gpu_timing_->CalculateTimerOffset();
glQueryCounter(queries_[1], GL_TIMESTAMP);
}
diff --git a/gpu/command_buffer/service/gpu_timing.h b/gpu/command_buffer/service/gpu_timing.h
index 1d9ecf6..726ac4e 100644
--- a/gpu/command_buffer/service/gpu_timing.h
+++ b/gpu/command_buffer/service/gpu_timing.h
@@ -8,10 +8,12 @@
#include "base/callback.h"
#include "base/memory/scoped_ptr.h"
#include "gpu/gpu_export.h"
-#include "ui/gl/gl_bindings.h"
+
+namespace gfx {
+class GLContext;
+}
namespace gpu {
-
class GPUTiming;
// Class to compute the amount of time it takes to fully
@@ -30,7 +32,7 @@
int64 GetDeltaElapsed();
private:
- GLuint queries_[2];
+ unsigned int queries_[2];
int64 offset_ = 0;
bool end_requested_ = false;
GPUTiming* gpu_timing_;
diff --git a/gpu/command_buffer/service/gpu_tracer.cc b/gpu/command_buffer/service/gpu_tracer.cc
index 6bedb7f..cc484dc 100644
--- a/gpu/command_buffer/service/gpu_tracer.cc
+++ b/gpu/command_buffer/service/gpu_tracer.cc
@@ -12,6 +12,7 @@
#include "base/trace_event/trace_event.h"
#include "gpu/command_buffer/common/gles2_cmd_utils.h"
#include "gpu/command_buffer/service/context_group.h"
+#include "ui/gl/gl_bindings.h"
#include "ui/gl/gl_version_info.h"
namespace gpu {
diff --git a/gpu/command_buffer/service/gpu_tracer.h b/gpu/command_buffer/service/gpu_tracer.h
index c8ac9d7..7aba612 100644
--- a/gpu/command_buffer/service/gpu_tracer.h
+++ b/gpu/command_buffer/service/gpu_tracer.h
@@ -17,7 +17,6 @@
#include "gpu/command_buffer/service/gles2_cmd_decoder.h"
#include "gpu/command_buffer/service/gpu_timing.h"
#include "gpu/gpu_export.h"
-#include "ui/gl/gl_bindings.h"
namespace gpu {
namespace gles2 {
diff --git a/gpu/command_buffer/service/gpu_tracer_unittest.cc b/gpu/command_buffer/service/gpu_tracer_unittest.cc
index 9005421..ba61ba3 100644
--- a/gpu/command_buffer/service/gpu_tracer_unittest.cc
+++ b/gpu/command_buffer/service/gpu_tracer_unittest.cc
@@ -356,6 +356,7 @@
// Shouldn't be available before End() call
gl_fake_queries_.SetCurrentGLTime(end_timestamp);
+ g_fakeCPUTime = expect_end_time;
EXPECT_FALSE(trace->IsAvailable());
trace->End(true);
@@ -474,7 +475,7 @@
gl_fake_queries_.SetCurrentGLTime(
end_timestamp +
(i * base::Time::kNanosecondsPerMicrosecond));
- g_fakeCPUTime = expect_start_time + i;
+ g_fakeCPUTime = expect_end_time + i;
// Each trace name should be different to differentiate.
const char num_char = static_cast<char>('0' + i);
diff --git a/gpu/command_buffer/service/mailbox_manager_sync.cc b/gpu/command_buffer/service/mailbox_manager_sync.cc
index 4f24bd7..4cdc80d 100644
--- a/gpu/command_buffer/service/mailbox_manager_sync.cc
+++ b/gpu/command_buffer/service/mailbox_manager_sync.cc
@@ -22,18 +22,6 @@
namespace {
-bool SkipTextureWorkarounds(const Texture* texture) {
- // TODO(sievers): crbug.com/352274
- // Should probably only fail if it already *has* mipmaps, while allowing
- // incomplete textures here.
- bool needs_mips =
- texture->min_filter() != GL_NEAREST && texture->min_filter() != GL_LINEAR;
- if (texture->target() != GL_TEXTURE_2D || needs_mips || !texture->IsDefined())
- return true;
-
- return false;
-}
-
base::LazyInstance<base::Lock> g_lock = LAZY_INSTANCE_INITIALIZER;
typedef std::map<uint32, linked_ptr<gfx::GLFence>> SyncPointToFenceMap;
@@ -196,6 +184,15 @@
DCHECK_EQ(0U, texture_to_group_.size());
}
+// static
+bool MailboxManagerSync::SkipTextureWorkarounds(const Texture* texture) {
+ // Cannot support mips due to support mismatch between
+ // EGL_KHR_gl_texture_2D_image and glEGLImageTargetTexture2DOES for
+ // texture levels.
+ bool has_mips = texture->NeedsMips() && texture->texture_complete();
+ return texture->target() != GL_TEXTURE_2D || has_mips;
+}
+
bool MailboxManagerSync::UsesSync() {
return true;
}
@@ -294,6 +291,7 @@
if (definition.Matches(texture))
return;
+ DCHECK_IMPLIES(gl_image, image_buffer.get());
if (gl_image && !image_buffer->IsClient(gl_image)) {
LOG(ERROR) << "MailboxSync: Incompatible attachment";
return;
diff --git a/gpu/command_buffer/service/mailbox_manager_sync.h b/gpu/command_buffer/service/mailbox_manager_sync.h
index 4727f3b..4b3abf9 100644
--- a/gpu/command_buffer/service/mailbox_manager_sync.h
+++ b/gpu/command_buffer/service/mailbox_manager_sync.h
@@ -40,6 +40,8 @@
private:
friend class base::RefCounted<MailboxManager>;
+ static bool SkipTextureWorkarounds(const Texture* texture);
+
~MailboxManagerSync() override;
class TextureGroup : public base::RefCounted<TextureGroup> {
diff --git a/gpu/command_buffer/service/mailbox_manager_unittest.cc b/gpu/command_buffer/service/mailbox_manager_unittest.cc
index 388e1da..a22078c 100644
--- a/gpu/command_buffer/service/mailbox_manager_unittest.cc
+++ b/gpu/command_buffer/service/mailbox_manager_unittest.cc
@@ -595,6 +595,66 @@
EXPECT_EQ(NULL, manager2_->ConsumeTexture(name));
}
+TEST_F(MailboxManagerSyncTest, SyncIncompleteTexture) {
+ const GLuint kNewTextureId = 1234;
+
+ // Create but not define texture.
+ Texture* texture = CreateTexture();
+ SetTarget(texture, GL_TEXTURE_2D, 1);
+ EXPECT_FALSE(texture->IsDefined());
+
+ Mailbox name = Mailbox::Generate();
+ manager_->ProduceTexture(name, texture);
+ EXPECT_EQ(texture, manager_->ConsumeTexture(name));
+
+ // Synchronize
+ manager_->PushTextureUpdates(0);
+ manager2_->PullTextureUpdates(0);
+
+ // Should sync to new texture which is not defined.
+ EXPECT_CALL(*gl_, GenTextures(1, _))
+ .WillOnce(SetArgPointee<1>(kNewTextureId));
+ SetupUpdateTexParamExpectations(kNewTextureId, texture->min_filter(),
+ texture->mag_filter(), texture->wrap_s(),
+ texture->wrap_t());
+ Texture* new_texture = manager2_->ConsumeTexture(name);
+ ASSERT_TRUE(new_texture);
+ EXPECT_NE(texture, new_texture);
+ EXPECT_EQ(kNewTextureId, new_texture->service_id());
+ EXPECT_FALSE(new_texture->IsDefined());
+
+ // Change cleared to false.
+ SetLevelInfo(texture,
+ GL_TEXTURE_2D,
+ 0,
+ GL_RGBA,
+ 1,
+ 1,
+ 1,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ true);
+ SetParameter(texture, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ SetParameter(texture, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ EXPECT_TRUE(texture->IsDefined());
+
+ // Synchronize
+ manager_->PushTextureUpdates(0);
+ SetupUpdateTexParamExpectations(
+ kNewTextureId, GL_LINEAR, GL_LINEAR, GL_REPEAT, GL_REPEAT);
+ manager2_->PullTextureUpdates(0);
+
+ // Cleared state should be synced.
+ EXPECT_TRUE(new_texture->IsDefined());
+
+ DestroyTexture(texture);
+ DestroyTexture(new_texture);
+
+ EXPECT_EQ(NULL, manager_->ConsumeTexture(name));
+ EXPECT_EQ(NULL, manager2_->ConsumeTexture(name));
+}
+
// Putting the same texture into multiple mailboxes should result in sharing
// only a single texture also within a synchronized manager instance.
TEST_F(MailboxManagerSyncTest, SharedThroughMultipleMailboxes) {
@@ -671,8 +731,6 @@
DestroyTexture(new_texture);
}
-// TODO: Produce incomplete texture
-
// TODO: Texture::level_infos_[][].size()
// TODO: unsupported targets and formats
diff --git a/gpu/command_buffer/service/shader_manager.cc b/gpu/command_buffer/service/shader_manager.cc
index 055cd70..d88a628 100644
--- a/gpu/command_buffer/service/shader_manager.cc
+++ b/gpu/command_buffer/service/shader_manager.cc
@@ -81,15 +81,18 @@
glGetShaderiv(service_id_,
GL_TRANSLATED_SHADER_SOURCE_LENGTH_ANGLE,
&max_len);
+ source_for_driver = "\0";
translated_source_.resize(max_len);
- GLint len = 0;
- glGetTranslatedShaderSourceANGLE(
- service_id_, translated_source_.size(),
- &len, &translated_source_.at(0));
- DCHECK(max_len == 0 || len < max_len);
- DCHECK(len == 0 || translated_source_[len] == '\0');
- translated_source_.resize(len);
- source_for_driver = translated_source_.c_str();
+ if (max_len) {
+ GLint len = 0;
+ glGetTranslatedShaderSourceANGLE(
+ service_id_, translated_source_.size(),
+ &len, &translated_source_.at(0));
+ DCHECK(max_len == 0 || len < max_len);
+ DCHECK(len == 0 || translated_source_[len] == '\0');
+ translated_source_.resize(len);
+ source_for_driver = translated_source_.c_str();
+ }
}
GLint status = GL_FALSE;
@@ -97,18 +100,21 @@
if (status == GL_TRUE) {
valid_ = true;
} else {
+ valid_ = false;
+
// We cannot reach here if we are using the shader translator.
// All invalid shaders must be rejected by the translator.
// All translated shaders must compile.
GLint max_len = 0;
glGetShaderiv(service_id_, GL_INFO_LOG_LENGTH, &max_len);
log_info_.resize(max_len);
- GLint len = 0;
- glGetShaderInfoLog(service_id_, log_info_.size(), &len, &log_info_.at(0));
- DCHECK(max_len == 0 || len < max_len);
- DCHECK(len == 0 || log_info_[len] == '\0');
- valid_ = false;
- log_info_.resize(len);
+ if (max_len) {
+ GLint len = 0;
+ glGetShaderInfoLog(service_id_, log_info_.size(), &len, &log_info_.at(0));
+ DCHECK(max_len == 0 || len < max_len);
+ DCHECK(len == 0 || log_info_[len] == '\0');
+ log_info_.resize(len);
+ }
LOG_IF(ERROR, translator)
<< "Shader translator allowed/produced an invalid shader "
<< "unless the driver is buggy:"
diff --git a/gpu/command_buffer/service/texture_definition.cc b/gpu/command_buffer/service/texture_definition.cc
index 7af662c..f2091b5 100644
--- a/gpu/command_buffer/service/texture_definition.cc
+++ b/gpu/command_buffer/service/texture_definition.cc
@@ -159,8 +159,11 @@
EGLImageKHR egl_image = eglCreateImageKHR(
egl_display, egl_context, egl_target, egl_buffer, egl_attrib_list);
- if (egl_image == EGL_NO_IMAGE_KHR)
+ if (egl_image == EGL_NO_IMAGE_KHR) {
+ LOG(ERROR) << "eglCreateImageKHR for cross-thread sharing failed: 0x"
+ << std::hex << eglGetError();
return NULL;
+ }
return new NativeImageBufferEGL(egl_display, egl_image);
}
@@ -257,6 +260,18 @@
}
}
+TextureDefinition::LevelInfo::LevelInfo()
+ : target(0),
+ internal_format(0),
+ width(0),
+ height(0),
+ depth(0),
+ border(0),
+ format(0),
+ type(0),
+ cleared(false) {
+}
+
TextureDefinition::LevelInfo::LevelInfo(GLenum target,
GLenum internal_format,
GLsizei width,
@@ -295,53 +310,39 @@
const scoped_refptr<NativeImageBuffer>& image_buffer)
: version_(version),
target_(texture->target()),
- image_buffer_(image_buffer.get()
- ? image_buffer
- : NativeImageBuffer::Create(texture->service_id())),
+ image_buffer_(image_buffer),
min_filter_(texture->min_filter()),
mag_filter_(texture->mag_filter()),
wrap_s_(texture->wrap_s()),
wrap_t_(texture->wrap_t()),
usage_(texture->usage()),
- immutable_(texture->IsImmutable()) {
- // TODO
- DCHECK(!texture->face_infos_.empty());
- DCHECK(!texture->face_infos_[0].level_infos.empty());
- DCHECK(!texture->NeedsMips());
- DCHECK(texture->face_infos_[0].level_infos[0].width);
- DCHECK(texture->face_infos_[0].level_infos[0].height);
+ immutable_(texture->IsImmutable()),
+ defined_(texture->IsDefined()) {
+ DCHECK_IMPLIES(image_buffer_.get(), defined_);
+ if (!image_buffer_.get() && defined_) {
+ image_buffer_ = NativeImageBuffer::Create(texture->service_id());
+ DCHECK(image_buffer_.get());
+ }
const Texture::FaceInfo& first_face = texture->face_infos_[0];
- scoped_refptr<gfx::GLImage> gl_image(
- new GLImageSync(image_buffer_,
- gfx::Size(first_face.level_infos[0].width,
- first_face.level_infos[0].height)));
- texture->SetLevelImage(NULL, target_, 0, gl_image.get());
+ if (image_buffer_.get()) {
+ scoped_refptr<gfx::GLImage> gl_image(
+ new GLImageSync(image_buffer_,
+ gfx::Size(first_face.level_infos[0].width,
+ first_face.level_infos[0].height)));
+ texture->SetLevelImage(NULL, target_, 0, gl_image.get());
+ }
- // TODO: all levels
- level_infos_.clear();
const Texture::LevelInfo& level = first_face.level_infos[0];
- LevelInfo info(level.target,
- level.internal_format,
- level.width,
- level.height,
- level.depth,
- level.border,
- level.format,
- level.type,
- level.cleared);
- std::vector<LevelInfo> infos;
- infos.push_back(info);
- level_infos_.push_back(infos);
+ level_info_ = LevelInfo(level.target, level.internal_format, level.width,
+ level.height, level.depth, level.border, level.format,
+ level.type, level.cleared);
}
TextureDefinition::~TextureDefinition() {
}
Texture* TextureDefinition::CreateTexture() const {
- if (!image_buffer_.get())
- return NULL;
-
GLuint texture_id;
glGenTextures(1, &texture_id);
@@ -367,28 +368,16 @@
// though.
glFlush();
- texture->face_infos_.resize(1);
- for (size_t i = 0; i < level_infos_.size(); i++) {
- const LevelInfo& base_info = level_infos_[i][0];
- const size_t levels_needed = TextureManager::ComputeMipMapCount(
- base_info.target, base_info.width, base_info.height, base_info.depth);
- DCHECK(level_infos_.size() <= levels_needed);
- texture->face_infos_[0].level_infos.resize(levels_needed);
- for (size_t n = 0; n < level_infos_.size(); n++) {
- const LevelInfo& info = level_infos_[i][n];
- texture->SetLevelInfo(NULL,
- info.target,
- i,
- info.internal_format,
- info.width,
- info.height,
- info.depth,
- info.border,
- info.format,
- info.type,
- info.cleared);
- }
+ if (defined_) {
+ texture->face_infos_.resize(1);
+ texture->face_infos_[0].level_infos.resize(1);
+ texture->SetLevelInfo(NULL, level_info_.target, 0,
+ level_info_.internal_format, level_info_.width,
+ level_info_.height, level_info_.depth,
+ level_info_.border, level_info_.format,
+ level_info_.type, level_info_.cleared);
}
+
if (image_buffer_.get()) {
texture->SetLevelImage(
NULL,
@@ -396,7 +385,7 @@
0,
new GLImageSync(
image_buffer_,
- gfx::Size(level_infos_[0][0].width, level_infos_[0][0].height)));
+ gfx::Size(level_info_.width, level_info_.height)));
}
texture->target_ = target_;
@@ -418,6 +407,10 @@
return false;
}
+ // Texture became defined.
+ if (!image_buffer_.get() && texture->IsDefined())
+ return false;
+
// All structural changes should have orphaned the texture.
if (image_buffer_.get() && !texture->GetLevelImage(texture->target(), 0))
return false;
@@ -426,14 +419,7 @@
}
bool TextureDefinition::SafeToRenderFrom() const {
- for (const std::vector<LevelInfo>& face_info : level_infos_) {
- for (const LevelInfo& level_info : face_info) {
- if (!level_info.cleared) {
- return false;
- }
- }
- }
- return true;
+ return level_info_.cleared;
}
} // namespace gles2
diff --git a/gpu/command_buffer/service/texture_definition.h b/gpu/command_buffer/service/texture_definition.h
index 95f0fa2..dcab0b8 100644
--- a/gpu/command_buffer/service/texture_definition.h
+++ b/gpu/command_buffer/service/texture_definition.h
@@ -61,6 +61,7 @@
bool SafeToRenderFrom() const;
struct LevelInfo {
+ LevelInfo();
LevelInfo(GLenum target,
GLenum internal_format,
GLsizei width,
@@ -83,8 +84,6 @@
bool cleared;
};
- typedef std::vector<std::vector<LevelInfo> > LevelInfos;
-
unsigned int version_;
GLenum target_;
scoped_refptr<NativeImageBuffer> image_buffer_;
@@ -94,7 +93,10 @@
GLenum wrap_t_;
GLenum usage_;
bool immutable_;
- LevelInfos level_infos_;
+ bool defined_;
+
+ // Only support textures with one face and one level.
+ LevelInfo level_info_;
};
} // namespage gles2
diff --git a/gpu/config/BUILD.gn b/gpu/config/BUILD.gn
index 1d86e69..4d068ed 100644
--- a/gpu/config/BUILD.gn
+++ b/gpu/config/BUILD.gn
@@ -45,6 +45,9 @@
"software_rendering_list_json.cc",
]
+ # TODO(jschuh): size_t to int.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
defines = [ "GPU_IMPLEMENTATION" ]
deps = [
@@ -69,9 +72,6 @@
"//third_party/amd/amd_videocard_info_win.cc",
]
}
-
- # TODO(jschuh): size_t to int.
- cflags = [ "/wd4267" ]
}
if (use_libpci) {
defines += [ "USE_LIBPCI=1" ]
diff --git a/gpu/config/gpu_driver_bug_list_json.cc b/gpu/config/gpu_driver_bug_list_json.cc
index 53361eb..dfebf2b 100644
--- a/gpu/config/gpu_driver_bug_list_json.cc
+++ b/gpu/config/gpu_driver_bug_list_json.cc
@@ -19,7 +19,7 @@
{
"name": "gpu driver bug list",
// Please update the version number whenever you change this file.
- "version": "7.16",
+ "version": "7.17",
"entries": [
{
"id": 1,
@@ -1159,6 +1159,23 @@
"features": [
"disable_post_sub_buffers_for_onscreen_surfaces"
]
+ },
+ {
+ "id": 102,
+ "description": "Adreno 420 driver loses FBO attachment contents on bound FBO deletion",
+ "cr_bugs": [457027],
+ "os": {
+ "type": "android",
+ "version": {
+ "op": ">",
+ "value": "5.0.2"
+ }
+ },
+ "gl_vendor": "Qualcomm.*",
+ "gl_renderer": ".*420",
+ "features": [
+ "unbind_attachments_on_bound_render_fbo_delete"
+ ]
}
]
}
diff --git a/gpu/config/gpu_driver_bug_workaround_type.h b/gpu/config/gpu_driver_bug_workaround_type.h
index f03b7a2..9476bf2 100644
--- a/gpu/config/gpu_driver_bug_workaround_type.h
+++ b/gpu/config/gpu_driver_bug_workaround_type.h
@@ -100,6 +100,8 @@
swizzle_rgba_for_async_readpixels) \
GPU_OP(TEXSUBIMAGE2D_FASTER_THAN_TEXIMAGE2D, \
texsubimage2d_faster_than_teximage2d) \
+ GPU_OP(UNBIND_ATTACHMENTS_ON_BOUND_RENDER_FBO_DELETE, \
+ unbind_attachments_on_bound_render_fbo_delete) \
GPU_OP(UNBIND_FBO_ON_CONTEXT_SWITCH, \
unbind_fbo_on_context_switch) \
GPU_OP(UNFOLD_SHORT_CIRCUIT_AS_TERNARY_OPERATION, \
diff --git a/gpu/perftests/measurements.cc b/gpu/perftests/measurements.cc
index 270e459..f94d1cb 100644
--- a/gpu/perftests/measurements.cc
+++ b/gpu/perftests/measurements.cc
@@ -4,6 +4,8 @@
#include "gpu/perftests/measurements.h"
+#include "base/logging.h"
+#include "gpu/command_buffer/service/gpu_timing.h"
#include "testing/perf/perf_test.h"
namespace gpu {
diff --git a/gpu/perftests/measurements.h b/gpu/perftests/measurements.h
index 15be422..1f72b00 100644
--- a/gpu/perftests/measurements.h
+++ b/gpu/perftests/measurements.h
@@ -9,10 +9,10 @@
#include "base/memory/scoped_ptr.h"
#include "base/time/time.h"
-#include "gpu/command_buffer/service/gpu_timing.h"
-#include "ui/gl/gl_bindings.h"
namespace gpu {
+class GPUTiming;
+class GPUTimer;
struct Measurement {
Measurement();
Measurement(const Measurement& m);
diff --git a/gpu/perftests/texture_upload_perftest.cc b/gpu/perftests/texture_upload_perftest.cc
index f691c9e..2e9ef6c 100644
--- a/gpu/perftests/texture_upload_perftest.cc
+++ b/gpu/perftests/texture_upload_perftest.cc
@@ -6,8 +6,10 @@
#include <vector>
#include "base/containers/small_map.h"
+#include "base/logging.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
+#include "gpu/command_buffer/service/gpu_timing.h"
#include "gpu/perftests/measurements.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size.h"
@@ -31,7 +33,7 @@
varying vec2 v_texCoord;
void main() {
gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
- v_texCoord = vec2((a_position.x + 1) * 0.5, (a_position.y + 1) * 0.5);
+ v_texCoord = vec2((a_position.x + 1.0) * 0.5, (a_position.y + 1.0) * 0.5);
}
);
const char kFragmentShader[] =
@@ -96,12 +98,30 @@
void SetUp() override {
// Initialize an offscreen surface and a gl context.
gfx::GLSurface::InitializeOneOff();
- surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size_);
+ surface_ = gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(4, 4));
gl_context_ = gfx::GLContext::CreateGLContext(NULL, // share_group
surface_.get(),
gfx::PreferIntegratedGpu);
-
ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
+ glGenTextures(1, &color_texture_);
+ glBindTexture(GL_TEXTURE_2D, color_texture_);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), 0,
+ GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
+
+ glGenFramebuffersEXT(1, &framebuffer_object_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_object_);
+
+ glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+ GL_TEXTURE_2D, color_texture_, 0);
+ DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
+ glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
+
+ glViewport(0, 0, size_.width(), size_.height());
+
if (gpu_timing_.Initialize(gl_context_.get())) {
LOG(INFO) << "Gpu timing initialized with timer type: "
<< gpu_timing_.GetTimerTypeName();
@@ -110,7 +130,6 @@
} else {
LOG(WARNING) << "Can't initialize gpu timing";
}
-
// Prepare a simple program and a vertex buffer that will be
// used to draw a quad on the offscreen surface.
vertex_shader_ = LoadShader(GL_VERTEX_SHADER, kVertexShader);
@@ -142,18 +161,14 @@
void TearDown() override {
ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
- if (program_object_ != 0) {
- glDeleteProgram(program_object_);
- }
- if (vertex_shader_ != 0) {
- glDeleteShader(vertex_shader_);
- }
- if (fragment_shader_ != 0) {
- glDeleteShader(fragment_shader_);
- }
- if (vertex_buffer_ != 0) {
- glDeleteShader(vertex_buffer_);
- }
+ glDeleteProgram(program_object_);
+ glDeleteShader(vertex_shader_);
+ glDeleteShader(fragment_shader_);
+ glDeleteShader(vertex_buffer_);
+
+ glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
+ glDeleteFramebuffersEXT(1, &framebuffer_object_);
+ glDeleteTextures(1, &color_texture_);
gl_context_ = nullptr;
surface_ = nullptr;
@@ -167,6 +182,8 @@
const GLenum format,
const GLenum type) {
ui::ScopedMakeCurrent smc(gl_context_.get(), surface_.get());
+ DCHECK_NE(0u, framebuffer_object_);
+ glBindFramebufferEXT(GL_FRAMEBUFFER, framebuffer_object_);
MeasurementTimers total_timers(&gpu_timing_);
GLuint texture_id = 0;
@@ -178,8 +195,8 @@
glTexImage2D(GL_TEXTURE_2D, 0, format, size_.width(), size_.height(), 0,
format, type, &pixels[0]);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
CheckNoGlError();
@@ -222,11 +239,13 @@
return measurements;
}
- const gfx::Size size_; // for the offscreen surface and the texture
+ const gfx::Size size_; // for the fbo and the texture
scoped_refptr<gfx::GLContext> gl_context_;
scoped_refptr<gfx::GLSurface> surface_;
GPUTiming gpu_timing_;
+ GLuint color_texture_ = 0;
+ GLuint framebuffer_object_ = 0;
GLuint vertex_shader_ = 0;
GLuint fragment_shader_ = 0;
GLuint program_object_ = 0;
diff --git a/mojo/converters/surfaces/surfaces_type_converters.cc b/mojo/converters/surfaces/surfaces_type_converters.cc
index 0803ba6..fe40d32 100644
--- a/mojo/converters/surfaces/surfaces_type_converters.cc
+++ b/mojo/converters/surfaces/surfaces_type_converters.cc
@@ -42,9 +42,9 @@
cc::YUVVideoDrawQuad::REC_601 ==
static_cast<cc::YUVVideoDrawQuad::ColorSpace>(YUV_COLOR_SPACE_REC_601),
rec_601_enum_matches);
-COMPILE_ASSERT(cc::YUVVideoDrawQuad::REC_601_JPEG ==
+COMPILE_ASSERT(cc::YUVVideoDrawQuad::JPEG ==
static_cast<cc::YUVVideoDrawQuad::ColorSpace>(
- YUV_COLOR_SPACE_REC_601_JPEG),
+ YUV_COLOR_SPACE_JPEG),
rec_601_jpeg_enum_matches);
namespace {
diff --git a/mojo/services/surfaces/public/interfaces/quads.mojom b/mojo/services/surfaces/public/interfaces/quads.mojom
index 58f85e0..2418d51 100644
--- a/mojo/services/surfaces/public/interfaces/quads.mojom
+++ b/mojo/services/surfaces/public/interfaces/quads.mojom
@@ -79,7 +79,8 @@
enum YUVColorSpace {
REC_601, // SDTV standard with restricted "studio swing" color range.
- REC_601_JPEG, // Full color range [0, 255] variant of the above.
+ REC_709, // HDTV standard with restricted "studio swing" color range.
+ JPEG, // Full color range [0, 255] JPEG color space.
};
struct YUVVideoQuadState {
diff --git a/mojo/tools/android_mojo_shell.py b/mojo/tools/android_mojo_shell.py
index 019d083..74225fa 100755
--- a/mojo/tools/android_mojo_shell.py
+++ b/mojo/tools/android_mojo_shell.py
@@ -39,13 +39,13 @@
default=True, action='store_true')
debug_group.add_argument('--release', help='Release build', default=False,
dest='debug', action='store_false')
- debug_group.add_argument('--target-arch',
+ debug_group.add_argument('--target-cpu',
help='CPU architecture to run for.',
choices=['x64', 'x86', 'arm'])
launcher_args, args = parser.parse_known_args()
config = Config(target_os=Config.OS_ANDROID,
- target_arch=launcher_args.target_arch,
+ target_cpu=launcher_args.target_cpu,
is_debug=launcher_args.debug)
args.append(android.PrepareShellRun(config))
diff --git a/mojo/tools/get_test_list.py b/mojo/tools/get_test_list.py
index 77e1744..70b4f2b 100755
--- a/mojo/tools/get_test_list.py
+++ b/mojo/tools/get_test_list.py
@@ -180,9 +180,9 @@
if ShouldRunTest("nacl"):
AddEntry("NaCl tests",
[os.path.join(build_dir, "monacl_shell"),
- os.path.join(build_dir, "irt_" + config.target_arch,
+ os.path.join(build_dir, "irt_" + config.target_cpu,
"irt_mojo.nexe"),
- os.path.join(build_dir, "clang_newlib_" + config.target_arch,
+ os.path.join(build_dir, "clang_newlib_" + config.target_cpu,
"monacl_test.nexe")])
# ----------------------------------------------------------------------------
diff --git a/mojo/tools/mojob.py b/mojo/tools/mojob.py
index 645171a..fb9e144 100755
--- a/mojo/tools/mojob.py
+++ b/mojo/tools/mojob.py
@@ -25,7 +25,7 @@
elif args.chromeos:
target_os = Config.OS_CHROMEOS
- target_arch = args.target_arch
+ target_cpu = args.target_cpu
additional_args = {}
@@ -64,7 +64,7 @@
if 'test_results_server' in args:
additional_args['test_results_server'] = args.test_results_server
- return Config(target_os=target_os, target_arch=target_arch,
+ return Config(target_os=target_os, target_cpu=target_cpu,
is_debug=args.debug, dcheck_always_on=args.dcheck_always_on,
**additional_args)
@@ -191,7 +191,7 @@
os_group.add_argument('--chromeos', help='Build for ChromeOS',
action='store_true')
- parent_parser.add_argument('--target-arch',
+ parent_parser.add_argument('--target-cpu',
help='CPU architecture to build for.',
choices=['x64', 'x86', 'arm'])
diff --git a/mojo/tools/mopy/config.py b/mojo/tools/mopy/config.py
index c518988..7c8cadd 100644
--- a/mojo/tools/mopy/config.py
+++ b/mojo/tools/mopy/config.py
@@ -24,7 +24,7 @@
OS_MAC = "mac"
OS_WINDOWS = "windows"
- # Valid values for target_arch (None is also valid):
+ # Valid values for target_cpu (None is also valid):
ARCH_X86 = "x86"
ARCH_X64 = "x64"
ARCH_ARM = "arm"
@@ -39,7 +39,7 @@
TEST_TYPE_PERF = "perf"
TEST_TYPE_INTEGRATION = "integration"
- def __init__(self, target_os=None, target_arch=None, is_debug=True,
+ def __init__(self, target_os=None, target_cpu=None, is_debug=True,
is_clang=None, sanitizer=None, dcheck_always_on=False,
**kwargs):
"""Constructs a Config with key-value pairs specified via keyword arguments.
@@ -47,7 +47,7 @@
assert target_os in (None, Config.OS_ANDROID, Config.OS_CHROMEOS,
Config.OS_LINUX, Config.OS_MAC, Config.OS_WINDOWS)
- assert target_arch in (None, Config.ARCH_X86, Config.ARCH_X64,
+ assert target_cpu in (None, Config.ARCH_X86, Config.ARCH_X64,
Config.ARCH_ARM)
assert isinstance(is_debug, bool)
assert is_clang is None or isinstance(is_clang, bool)
@@ -59,12 +59,12 @@
self.values["target_os"] = (self.GetHostOS() if target_os is None else
target_os)
- if target_arch is None:
+ if target_cpu is None:
if target_os == Config.OS_ANDROID:
- target_arch = Config.ARCH_ARM
+ target_cpu = Config.ARCH_ARM
else:
- target_arch = self.GetHostCPUArch()
- self.values["target_arch"] = target_arch
+ target_cpu = self.GetHostCPUArch()
+ self.values["target_cpu"] = target_cpu
self.values["is_debug"] = is_debug
self.values["is_clang"] = is_clang
@@ -104,9 +104,9 @@
return self.values["target_os"]
@property
- def target_arch(self):
+ def target_cpu(self):
"""CPU arch of the build/test target."""
- return self.values["target_arch"]
+ return self.values["target_cpu"]
@property
def is_debug(self):
diff --git a/mojo/tools/mopy/gn.py b/mojo/tools/mopy/gn.py
index aeaa135..831711b 100644
--- a/mojo/tools/mopy/gn.py
+++ b/mojo/tools/mopy/gn.py
@@ -22,8 +22,8 @@
subdir = ""
if config.target_os == Config.OS_ANDROID:
subdir += "android_"
- if config.target_arch != Config.ARCH_ARM:
- subdir += config.target_arch + "_"
+ if config.target_cpu != Config.ARCH_ARM:
+ subdir += config.target_cpu + "_"
elif config.target_os == Config.OS_CHROMEOS:
subdir += "chromeos_"
subdir += "Debug" if config.is_debug else "Release"
@@ -72,7 +72,7 @@
gn_args["use_glib"] = False
gn_args["use_system_harfbuzz"] = False
- gn_args["target_arch"] = config.target_arch
+ gn_args["target_cpu"] = config.target_cpu
return gn_args
@@ -103,7 +103,7 @@
config_args["goma_dir"] = args.get("goma_dir")
config_args["use_nacl"] = args.get("mojo_use_nacl", False)
config_args["target_os"] = args.get("os")
- config_args["target_arch"] = args.get("target_arch")
+ config_args["target_cpu"] = args.get("target_cpu")
config_args["dcheck_always_on"] = args.get("dcheck_always_on")
return Config(**config_args)
diff --git a/mojo/tools/mopy/gn_unittest.py b/mojo/tools/mopy/gn_unittest.py
index 815a63d..3773027 100644
--- a/mojo/tools/mopy/gn_unittest.py
+++ b/mojo/tools/mopy/gn_unittest.py
@@ -18,7 +18,7 @@
"""Tests that config to gn to config is the identity"""
configs_to_test = {
"target_os": [None, "android", "chromeos", "linux"],
- "target_arch": [None, "x86", "x64", "arm"],
+ "target_cpu": [None, "x86", "x64", "arm"],
"is_debug": [False, True],
"is_clang": [False, True],
"sanitizer": [None, Config.SANITIZER_ASAN],
@@ -37,7 +37,7 @@
"""Tests that gn to config to gn is the identity"""
configs_to_test = {
"os": [None, "android", "chromeos"],
- "target_arch": ["x86", "x64", "arm"],
+ "target_cpu": ["x86", "x64", "arm"],
"is_debug": [False, True],
"is_clang": [False, True],
"is_asan": [False, True],
diff --git a/mojo/tools/roll/cc_strip_video.patch b/mojo/tools/roll/cc_strip_video.patch
index 2d3fb51..827171b 100644
--- a/mojo/tools/roll/cc_strip_video.patch
+++ b/mojo/tools/roll/cc_strip_video.patch
@@ -1,5 +1,5 @@
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
-index 41f99e2..d6fd028 100644
+index 6fe0694..803b0f9 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -222,13 +222,6 @@ component("cc") {
@@ -31,9 +31,9 @@
"test/fake_ui_resource_layer_tree_host_impl.h",
- "test/fake_video_frame_provider.cc",
- "test/fake_video_frame_provider.h",
- "test/failure_output_surface.cc",
- "test/failure_output_surface.h",
"test/geometry_test_utils.cc",
+ "test/geometry_test_utils.h",
+ "test/impl_side_painting_settings.h",
@@ -783,7 +772,6 @@ if (!is_win || link_chrome_on_windows) {
"layers/tiled_layer_unittest.cc",
"layers/ui_resource_layer_impl_unittest.cc",
@@ -42,10 +42,10 @@
"output/begin_frame_args_unittest.cc",
"output/delegating_renderer_unittest.cc",
"output/filter_operations_unittest.cc",
-@@ -815,7 +803,6 @@ if (!is_win || link_chrome_on_windows) {
- "resources/texture_uploader_unittest.cc",
+@@ -816,7 +804,6 @@ if (!is_win || link_chrome_on_windows) {
"resources/tile_manager_unittest.cc",
"resources/tile_priority_unittest.cc",
+ "resources/tile_task_worker_pool_unittest.cc",
- "resources/video_resource_updater_unittest.cc",
"scheduler/begin_frame_source_unittest.cc",
"scheduler/delay_based_time_source_unittest.cc",
@@ -250,7 +250,7 @@
-
-} // namespace cc
diff --git a/cc/output/gl_renderer.cc b/cc/output/gl_renderer.cc
-index a394a1a..2612f10 100644
+index 6142d96..5c560dc 100644
--- a/cc/output/gl_renderer.cc
+++ b/cc/output/gl_renderer.cc
@@ -13,7 +13,6 @@
@@ -262,7 +262,7 @@
#include "cc/output/compositor_frame_metadata.h"
#include "cc/output/context_provider.h"
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
-index 36765ce..d7d1211 100644
+index 743e1cf..9e9175e 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -12,7 +12,6 @@
@@ -273,7 +273,7 @@
#include "third_party/skia/include/core/SkColorPriv.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "third_party/skia/include/core/SkMatrix.h"
-@@ -386,453 +385,6 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
+@@ -388,453 +387,6 @@ TEST_F(GLRendererPixelTest, NonPremultipliedTextureWithBackground) {
FuzzyPixelOffByOneComparator(true)));
}
@@ -457,7 +457,7 @@
- const bool with_alpha = (video_frame->format() == media::VideoFrame::YV12A);
- const YUVVideoDrawQuad::ColorSpace color_space =
- (video_frame->format() == media::VideoFrame::YV12J
-- ? YUVVideoDrawQuad::REC_601_JPEG
+- ? YUVVideoDrawQuad::JPEG
- : YUVVideoDrawQuad::REC_601);
- const gfx::Rect rect(shared_state->content_bounds);
- const gfx::Rect opaque_rect(0, 0, 0, 0);
@@ -728,7 +728,7 @@
gfx::Rect viewport_rect(this->device_viewport_size_);
diff --git a/cc/quads/yuv_video_draw_quad.h b/cc/quads/yuv_video_draw_quad.h
-index 99ed7e2..d57d56f 100644
+index 358929e..15bce98 100644
--- a/cc/quads/yuv_video_draw_quad.h
+++ b/cc/quads/yuv_video_draw_quad.h
@@ -8,7 +8,6 @@
@@ -740,7 +740,7 @@
namespace cc {
diff --git a/cc/resources/drawing_display_item.cc b/cc/resources/drawing_display_item.cc
-index 0fe86f4..1ef149f 100644
+index 648f9de..6dffad9 100644
--- a/cc/resources/drawing_display_item.cc
+++ b/cc/resources/drawing_display_item.cc
@@ -6,6 +6,7 @@
@@ -752,7 +752,7 @@
#include "base/trace_event/trace_event_argument.h"
#include "cc/debug/picture_debug_util.h"
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
-index aa46125..07fb048 100644
+index 70fa92b..38b2d66 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -27,7 +27,6 @@
@@ -795,7 +795,7 @@
}
LayerTreeSettings DefaultSettings() {
-@@ -5489,18 +5484,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
+@@ -5463,18 +5458,6 @@ TEST_F(LayerTreeHostImplTest, LayersFreeTextures) {
root_layer->SetBounds(gfx::Size(10, 10));
root_layer->SetHasRenderSurface(true);
@@ -814,7 +814,7 @@
scoped_ptr<IOSurfaceLayerImpl> io_surface_layer =
IOSurfaceLayerImpl::Create(host_impl_->active_tree(), 5);
io_surface_layer->SetBounds(gfx::Size(10, 10));
-@@ -6580,16 +6563,6 @@ TEST_F(LayerTreeHostImplTest,
+@@ -6555,16 +6538,6 @@ TEST_F(LayerTreeHostImplTest,
scoped_ptr<SolidColorLayerImpl> root_layer =
SolidColorLayerImpl::Create(host_impl_->active_tree(), 1);
@@ -832,7 +832,7 @@
EXPECT_EQ(DRAW_SUCCESS, host_impl_->PrepareToDraw(&frame));
host_impl_->DrawLayers(&frame, gfx::FrameTime::Now());
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
-index bb315e7..bb6dc17 100644
+index 48be5b8..f9b690d 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -18,7 +18,6 @@
@@ -851,7 +851,7 @@
#include "cc/test/geometry_test_utils.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/layer_tree_test.h"
-@@ -4202,28 +4200,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
+@@ -4167,28 +4165,6 @@ class LayerInvalidateCausesDraw : public LayerTreeHostTest {
int num_draws_;
};
@@ -881,7 +881,7 @@
// to the compositor thread, even though no resources are updated in
// response to that invalidation.
diff --git a/cc/trees/layer_tree_host_unittest_context.cc b/cc/trees/layer_tree_host_unittest_context.cc
-index 596adc0..fb0c9c8 100644
+index c99180d..cc536f4 100644
--- a/cc/trees/layer_tree_host_unittest_context.cc
+++ b/cc/trees/layer_tree_host_unittest_context.cc
@@ -15,8 +15,6 @@
@@ -919,7 +919,7 @@
}
void LoseContext() {
-@@ -1057,41 +1050,6 @@ class LayerTreeHostContextTestDontUseLostResources
+@@ -1055,41 +1048,6 @@ class LayerTreeHostContextTestDontUseLostResources
layer_with_mask->SetMaskLayer(mask.get());
root->AddChild(layer_with_mask);
@@ -961,7 +961,7 @@
if (!delegating_renderer()) {
// TODO(danakj): IOSurface layer can not be transported. crbug.com/239335
scoped_refptr<IOSurfaceLayer> io_surface = IOSurfaceLayer::Create();
-@@ -1121,14 +1079,6 @@ class LayerTreeHostContextTestDontUseLostResources
+@@ -1119,14 +1077,6 @@ class LayerTreeHostContextTestDontUseLostResources
void CommitCompleteOnThread(LayerTreeHostImpl* host_impl) override {
LayerTreeHostContextTest::CommitCompleteOnThread(host_impl);
@@ -976,7 +976,7 @@
}
DrawResult PrepareToDrawOnThread(LayerTreeHostImpl* host_impl,
-@@ -1177,14 +1127,6 @@ class LayerTreeHostContextTestDontUseLostResources
+@@ -1175,14 +1125,6 @@ class LayerTreeHostContextTestDontUseLostResources
scoped_refptr<DelegatedFrameResourceCollection>
delegated_resource_collection_;
scoped_refptr<DelegatedFrameProvider> delegated_frame_provider_;
diff --git a/mojo/tools/roll/update_from_chromium.py b/mojo/tools/roll/update_from_chromium.py
index 9b67672..ace99d9 100755
--- a/mojo/tools/roll/update_from_chromium.py
+++ b/mojo/tools/roll/update_from_chromium.py
@@ -48,6 +48,7 @@
"third_party/markupsafe",
"third_party/mesa",
"third_party/modp_b64",
+ "third_party/ots",
"third_party/ply",
"third_party/protobuf",
"third_party/pymock",
diff --git a/mojo/tools/upload_binaries.py b/mojo/tools/upload_binaries.py
index 4acf03e..e0b86db 100755
--- a/mojo/tools/upload_binaries.py
+++ b/mojo/tools/upload_binaries.py
@@ -25,7 +25,7 @@
]
def target(config):
- return config.target_os + "-" + config.target_arch
+ return config.target_os + "-" + config.target_cpu
def find_apps_to_upload(build_dir):
apps = []
diff --git a/sandbox/linux/BUILD.gn b/sandbox/linux/BUILD.gn
index 8b18a3a..c4ce4fc 100644
--- a/sandbox/linux/BUILD.gn
+++ b/sandbox/linux/BUILD.gn
@@ -11,7 +11,7 @@
compile_credentials = is_linux
compile_seccomp_bpf_demo =
- is_linux && (cpu_arch == "x86" || cpu_arch == "x64")
+ is_linux && (current_cpu == "x86" || current_cpu == "x64")
}
# We have two principal targets: sandbox and sandbox_linux_unittests
@@ -63,8 +63,10 @@
}
}
-# The main sandboxing test target.
-test("sandbox_linux_unittests") {
+# Sources shared by sandbox_linux_unittests and sandbox_linux_jni_unittests.
+source_set("sandbox_linux_unittests_sources") {
+ testonly = true
+
sources = [
"services/proc_util_unittest.cc",
"services/resource_limits_unittests.cc",
@@ -127,23 +129,24 @@
}
}
-# TODO(GYP) Android version of this test.
-# {
-# # This target is the shared library used by Android APK (i.e.
-# # JNI-friendly) tests.
-# "target_name": "sandbox_linux_jni_unittests",
-# "includes": [
-# "sandbox_linux_test_sources.gypi",
-# ],
-# "type": "shared_library",
-# "conditions": [
-# [ "OS == "android"", {
-# "dependencies": [
-# "../testing/android/native_test.gyp:native_test_native_code",
-# ],
-# }],
-# ],
-# },
+# The main sandboxing test target.
+test("sandbox_linux_unittests") {
+ deps = [
+ ":sandbox_linux_unittests_sources",
+ ]
+}
+
+# This target is the shared library used by Android APK (i.e.
+# JNI-friendly) tests.
+shared_library("sandbox_linux_jni_unittests") {
+ testonly = true
+ deps = [
+ ":sandbox_linux_unittests_sources",
+ ]
+ if (is_android) {
+ deps += [ "//testing/android:native_test_native_code" ]
+ }
+}
component("seccomp_bpf") {
sources = [
diff --git a/sandbox/linux/services/credentials.cc b/sandbox/linux/services/credentials.cc
index e571dde..ed21fd1 100644
--- a/sandbox/linux/services/credentials.cc
+++ b/sandbox/linux/services/credentials.cc
@@ -114,7 +114,7 @@
int status = -1;
PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
- return kExitSuccess == status;
+ return WIFEXITED(status) && WEXITSTATUS(status) == kExitSuccess;
}
// CHECK() that an attempt to move to a new user namespace raised an expected
@@ -174,12 +174,14 @@
// have disappeared. Make sure to not do anything in the child, as this is a
// fragile execution environment.
if (pid == 0) {
- _exit(0);
+ _exit(kExitSuccess);
}
// Always reap the child.
- siginfo_t infop;
- PCHECK(0 == HANDLE_EINTR(waitid(P_PID, pid, &infop, WEXITED)));
+ int status = -1;
+ PCHECK(HANDLE_EINTR(waitpid(pid, &status, 0)) == pid);
+ CHECK(WIFEXITED(status));
+ CHECK_EQ(kExitSuccess, WEXITSTATUS(status));
// clone(2) succeeded, we can use CLONE_NEWUSER.
return true;
diff --git a/sandbox/linux/services/proc_util_unittest.cc b/sandbox/linux/services/proc_util_unittest.cc
index ee36c83..2bf37a0 100644
--- a/sandbox/linux/services/proc_util_unittest.cc
+++ b/sandbox/linux/services/proc_util_unittest.cc
@@ -28,9 +28,9 @@
// No open directory should exist at startup.
EXPECT_FALSE(ProcUtil::HasOpenDirectory(-1));
{
- // Have a "/dev" file descriptor around.
- int dev_fd = open("/dev", O_RDONLY | O_DIRECTORY);
- base::ScopedFD dev_fd_closer(dev_fd);
+ // Have a "/proc" file descriptor around.
+ int proc_fd = open("/proc", O_RDONLY | O_DIRECTORY);
+ base::ScopedFD proc_fd_closer(proc_fd);
EXPECT_TRUE(ProcUtil::HasOpenDirectory(-1));
}
EXPECT_FALSE(ProcUtil::HasOpenDirectory(-1));
@@ -48,14 +48,14 @@
EXPECT_FALSE(ProcUtil::HasOpenDirectory(proc_fd));
{
- // Have a "/dev" file descriptor around.
- int dev_fd = open("/dev", O_RDONLY | O_DIRECTORY);
- base::ScopedFD dev_fd_closer(dev_fd);
+ // Have a directory file descriptor around.
+ int open_directory_fd = open("/proc/self", O_RDONLY | O_DIRECTORY);
+ base::ScopedFD open_directory_fd_closer(open_directory_fd);
EXPECT_TRUE(ProcUtil::HasOpenDirectory(proc_fd));
}
- // The "/dev" file descriptor should now be closed, |proc_fd| is the only
- // directory file descriptor open.
+ // The "/proc/self" file descriptor should now be closed, |proc_fd| is the
+ // only directory file descriptor open.
EXPECT_FALSE(ProcUtil::HasOpenDirectory(proc_fd));
}
diff --git a/services/surfaces/surfaces_scheduler.cc b/services/surfaces/surfaces_scheduler.cc
index f048d26..0d04294 100644
--- a/services/surfaces/surfaces_scheduler.cc
+++ b/services/surfaces/surfaces_scheduler.cc
@@ -92,4 +92,7 @@
const cc::BeginFrameArgs& args) {
}
+void SurfacesScheduler::SendBeginMainFrameNotExpectedSoon() {
+}
+
} // namespace mojo
diff --git a/services/surfaces/surfaces_scheduler.h b/services/surfaces/surfaces_scheduler.h
index e985973..6a1d4b3 100644
--- a/services/surfaces/surfaces_scheduler.h
+++ b/services/surfaces/surfaces_scheduler.h
@@ -43,6 +43,7 @@
base::TimeDelta CommitToActivateDurationEstimate() override;
void DidBeginImplFrameDeadline() override;
void SendBeginFramesToChildren(const cc::BeginFrameArgs& args) override;
+ void SendBeginMainFrameNotExpectedSoon() override;
Client* client_;
scoped_ptr<cc::Scheduler> scheduler_;
diff --git a/shell/android/library_loader.cc b/shell/android/library_loader.cc
index 42e02df..0aff50b 100644
--- a/shell/android/library_loader.cc
+++ b/shell/android/library_loader.cc
@@ -2,11 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include "base/android/base_jni_onload.h"
#include "base/android/base_jni_registrar.h"
#include "base/android/jni_android.h"
#include "base/android/jni_registrar.h"
-#include "base/android/library_loader/library_loader_hooks.h"
-#include "base/logging.h"
+#include "base/bind.h"
#include "services/native_viewport/platform_viewport_android.h"
#include "shell/android/android_handler.h"
#include "shell/android/keyboard_impl.h"
@@ -22,7 +22,10 @@
native_viewport::PlatformViewportAndroid::Register},
};
-bool RegisterMojoJni(JNIEnv* env) {
+bool RegisterJNI(JNIEnv* env) {
+ if (!base::android::RegisterJni(env))
+ return false;
+
return RegisterNativeMethods(env, kMojoRegisteredMethods,
arraysize(kMojoRegisteredMethods));
}
@@ -31,17 +34,13 @@
// This is called by the VM when the shared library is first loaded.
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
- base::android::InitVM(vm);
- JNIEnv* env = base::android::AttachCurrentThread();
-
- if (!base::android::RegisterLibraryLoaderEntryHook(env))
+ std::vector<base::android::RegisterCallback> register_callbacks;
+ register_callbacks.push_back(base::Bind(&RegisterJNI));
+ if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks) ||
+ !base::android::OnJNIOnLoadInit(
+ std::vector<base::android::InitCallback>())) {
return -1;
-
- if (!base::android::RegisterJni(env))
- return -1;
-
- if (!RegisterMojoJni(env))
- return -1;
+ }
return JNI_VERSION_1_4;
}
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 85ccce7..aede7dc 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -5,7 +5,7 @@
import("//build/config/features.gni")
import("//build/config/ui.gni")
import("//testing/test.gni")
-if (cpu_arch == "arm") {
+if (current_cpu == "arm") {
import("//build/config/arm.gni")
}
@@ -178,7 +178,7 @@
defines += [ "SKIA_IMPLEMENTATION=1" ]
}
- if (cpu_arch == "arm") {
+ if (current_cpu == "arm") {
if (arm_use_neon) {
defines += [ "SK_ARM_HAS_NEON" ]
}
@@ -298,7 +298,10 @@
sources += gypi_skia_utils.sources
sources += gypi_values.skia_library_sources
- if (cpu_arch == "arm") {
+ # This and skia_opts are really the same conceptual target so share headers.
+ allow_circular_includes_from = [ ":skia_opts" ]
+
+ if (current_cpu == "arm") {
sources += [
"//third_party/skia/src/core/SkUtilsArm.cpp",
"//third_party/skia/src/core/SkUtilsArm.h",
@@ -532,7 +535,7 @@
cflags = []
defines = []
- if (cpu_arch == "x86" || cpu_arch == "x64") {
+ if (current_cpu == "x86" || current_cpu == "x64") {
sources = gypi_skia_opts.sse2_sources + gypi_skia_opts.ssse3_sources +
gypi_skia_opts.sse41_sources +
[
@@ -543,7 +546,7 @@
if (is_linux || is_mac) {
cflags += [ "-msse4.1" ]
}
- } else if (cpu_arch == "arm") {
+ } else if (current_cpu == "arm") {
# The assembly uses the frame pointer register (r7 in Thumb/r11 in
# ARM), the compiler doesn't like that.
cflags += [ "-fomit-frame-pointer" ]
@@ -563,7 +566,7 @@
} else {
sources = gypi_skia_opts.none_sourcees
}
- } else if (cpu_arch == "mipsel") {
+ } else if (current_cpu == "mipsel") {
cflags += [ "-fomit-frame-pointer" ]
sources = gypi_skia_opts.none_sources
} else {
@@ -611,6 +614,7 @@
":skia",
"//base",
"//base/test:run_all_unittests",
+ "//cc:test_support", # TODO: Fix this test to not depend on cc.
"//testing/gtest",
"//ui/gfx",
"//ui/gfx/geometry",
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 84a02d7..54c5f07 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -253,6 +253,10 @@
# define SK_IGNORE_ETC1_SUPPORT
#endif
+#ifndef SK_SUPPORT_LEGACY_MIPMAP_EFFECTIVE_SCALE
+# define SK_SUPPORT_LEGACY_MIPMAP_EFFECTIVE_SCALE
+#endif
+
#ifndef SK_IGNORE_GPU_DITHER
# define SK_IGNORE_GPU_DITHER
#endif
diff --git a/skia/ext/analysis_canvas.cc b/skia/ext/analysis_canvas.cc
index 376d173..fe447c7 100644
--- a/skia/ext/analysis_canvas.cc
+++ b/skia/ext/analysis_canvas.cc
@@ -9,7 +9,6 @@
#include "third_party/skia/include/core/SkRRect.h"
#include "third_party/skia/include/core/SkShader.h"
#include "third_party/skia/src/core/SkRasterClip.h"
-#include "ui/gfx/geometry/rect_conversions.h"
namespace {
diff --git a/skia/ext/bitmap_platform_device_mac.cc b/skia/ext/bitmap_platform_device_mac.cc
index ff7c2ad..9c7966d 100644
--- a/skia/ext/bitmap_platform_device_mac.cc
+++ b/skia/ext/bitmap_platform_device_mac.cc
@@ -71,6 +71,78 @@
config_dirty_ = true;
}
+// Loads the specified Skia transform into the device context
+static void LoadTransformToCGContext(CGContextRef context,
+ const SkMatrix& matrix) {
+ // CoreGraphics can concatenate transforms, but not reset the current one.
+ // So in order to get the required behavior here, we need to first make
+ // the current transformation matrix identity and only then load the new one.
+
+ // Reset matrix to identity.
+ CGAffineTransform orig_cg_matrix = CGContextGetCTM(context);
+ CGAffineTransform orig_cg_matrix_inv =
+ CGAffineTransformInvert(orig_cg_matrix);
+ CGContextConcatCTM(context, orig_cg_matrix_inv);
+
+ // assert that we have indeed returned to the identity Matrix.
+ SkASSERT(CGAffineTransformIsIdentity(CGContextGetCTM(context)));
+
+ // Convert xform to CG-land.
+ // Our coordinate system is flipped to match WebKit's so we need to modify
+ // the xform to match that.
+ SkMatrix transformed_matrix = matrix;
+ SkScalar sy = -matrix.getScaleY();
+ transformed_matrix.setScaleY(sy);
+ size_t height = CGBitmapContextGetHeight(context);
+ SkScalar ty = -matrix.getTranslateY(); // y axis is flipped.
+ transformed_matrix.setTranslateY(ty + (SkScalar)height);
+
+ CGAffineTransform cg_matrix =
+ gfx::SkMatrixToCGAffineTransform(transformed_matrix);
+
+ // Load final transform into context.
+ CGContextConcatCTM(context, cg_matrix);
+}
+
+// Loads a SkRegion into the CG context.
+static void LoadClippingRegionToCGContext(CGContextRef context,
+ const SkRegion& region,
+ const SkMatrix& transformation) {
+ if (region.isEmpty()) {
+ // region can be empty, in which case everything will be clipped.
+ SkRect rect;
+ rect.setEmpty();
+ CGContextClipToRect(context, gfx::SkRectToCGRect(rect));
+ } else if (region.isRect()) {
+ // CoreGraphics applies the current transform to clip rects, which is
+ // unwanted. Inverse-transform the rect before sending it to CG. This only
+ // works for translations and scaling, but not for rotations (but the
+ // viewport is never rotated anyway).
+ SkMatrix t;
+ bool did_invert = transformation.invert(&t);
+ if (!did_invert)
+ t.reset();
+ // Do the transformation.
+ SkRect rect;
+ rect.set(region.getBounds());
+ t.mapRect(&rect);
+ SkIRect irect;
+ rect.round(&irect);
+ CGContextClipToRect(context, gfx::SkIRectToCGRect(irect));
+ } else {
+ // It is complex.
+ SkPath path;
+ region.getBoundaryPath(&path);
+ // Clip. Note that windows clipping regions are not affected by the
+ // transform so apply it manually.
+ path.transform(transformation);
+ // TODO(playmobil): Implement.
+ SkASSERT(false);
+ // LoadPathToDC(context, path);
+ // hrgn = PathToRegion(context);
+ }
+}
+
void BitmapPlatformDevice::LoadConfig() {
if (!config_dirty_ || !bitmap_context_)
return; // Nothing to do.
diff --git a/skia/ext/platform_canvas_unittest.cc b/skia/ext/platform_canvas_unittest.cc
index 9ab5667..530d722 100644
--- a/skia/ext/platform_canvas_unittest.cc
+++ b/skia/ext/platform_canvas_unittest.cc
@@ -418,7 +418,9 @@
EXPECT_EQ(kN32_SkColorType, // Same for all platforms.
platform_bitmap->GetBitmap().colorType());
EXPECT_TRUE(platform_bitmap->GetBitmap().lockPixelsAreWritable());
+#if defined(SK_DEBUG)
EXPECT_TRUE(platform_bitmap->GetBitmap().pixelRef()->isLocked());
+#endif
EXPECT_TRUE(platform_bitmap->GetBitmap().pixelRef()->unique());
*(platform_bitmap->GetBitmap().getAddr32(10, 20)) = 0xDEED1020;
diff --git a/skia/ext/platform_device.h b/skia/ext/platform_device.h
index 8486102..c903c87 100644
--- a/skia/ext/platform_device.h
+++ b/skia/ext/platform_device.h
@@ -131,19 +131,6 @@
// have to be created twice. If src_rect is null, then the entirety of the
// source device will be copied.
virtual void DrawToHDC(HDC, int x, int y, const RECT* src_rect);
-
-#elif defined(OS_MACOSX)
- // Loads a SkPath into the CG context. The path can there after be used for
- // clipping or as a stroke.
- static void LoadPathToCGContext(CGContextRef context, const SkPath& path);
-
- // Initializes the default settings and colors in a device context.
- static void InitializeCGContext(CGContextRef context);
-
- // Loads a SkRegion into the CG context.
- static void LoadClippingRegionToCGContext(CGContextRef context,
- const SkRegion& region,
- const SkMatrix& transformation);
#endif
protected:
@@ -161,10 +148,6 @@
// Transforms SkPath's paths into a series of cubic path.
static bool SkPathToCubicPaths(CubicPaths* paths, const SkPath& skpath);
-#elif defined(OS_MACOSX)
- // Loads the specified Skia transform into the device context
- static void LoadTransformToCGContext(CGContextRef context,
- const SkMatrix& matrix);
#endif
};
diff --git a/skia/ext/platform_device_mac.cc b/skia/ext/platform_device_mac.cc
index f66372b..065b767 100644
--- a/skia/ext/platform_device_mac.cc
+++ b/skia/ext/platform_device_mac.cc
@@ -30,126 +30,4 @@
// Flushing will be done in onAccessBitmap.
}
-// Set up the CGContextRef for peaceful coexistence with Skia
-void PlatformDevice::InitializeCGContext(CGContextRef context) {
- // CG defaults to the same settings as Skia
-}
-
-// static
-void PlatformDevice::LoadPathToCGContext(CGContextRef context,
- const SkPath& path) {
- // instead of a persistent attribute of the context, CG specifies the fill
- // type per call, so we just have to load up the geometry.
- CGContextBeginPath(context);
-
- SkPoint points[4] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
- SkPath::Iter iter(path, false);
- for (SkPath::Verb verb = iter.next(points); verb != SkPath::kDone_Verb;
- verb = iter.next(points)) {
- switch (verb) {
- case SkPath::kMove_Verb: { // iter.next returns 1 point
- CGContextMoveToPoint(context, points[0].fX, points[0].fY);
- break;
- }
- case SkPath::kLine_Verb: { // iter.next returns 2 points
- CGContextAddLineToPoint(context, points[1].fX, points[1].fY);
- break;
- }
- case SkPath::kQuad_Verb: { // iter.next returns 3 points
- CGContextAddQuadCurveToPoint(context, points[1].fX, points[1].fY,
- points[2].fX, points[2].fY);
- break;
- }
- case SkPath::kCubic_Verb: { // iter.next returns 4 points
- CGContextAddCurveToPoint(context, points[1].fX, points[1].fY,
- points[2].fX, points[2].fY,
- points[3].fX, points[3].fY);
- break;
- }
- case SkPath::kClose_Verb: { // iter.next returns 1 point (the last point)
- break;
- }
- case SkPath::kDone_Verb: // iter.next returns 0 points
- default: {
- SkASSERT(false);
- break;
- }
- }
- }
- CGContextClosePath(context);
-}
-
-// static
-void PlatformDevice::LoadTransformToCGContext(CGContextRef context,
- const SkMatrix& matrix) {
- // CoreGraphics can concatenate transforms, but not reset the current one.
- // So in order to get the required behavior here, we need to first make
- // the current transformation matrix identity and only then load the new one.
-
- // Reset matrix to identity.
- CGAffineTransform orig_cg_matrix = CGContextGetCTM(context);
- CGAffineTransform orig_cg_matrix_inv = CGAffineTransformInvert(
- orig_cg_matrix);
- CGContextConcatCTM(context, orig_cg_matrix_inv);
-
- // assert that we have indeed returned to the identity Matrix.
- SkASSERT(CGAffineTransformIsIdentity(CGContextGetCTM(context)));
-
- // Convert xform to CG-land.
- // Our coordinate system is flipped to match WebKit's so we need to modify
- // the xform to match that.
- SkMatrix transformed_matrix = matrix;
- SkScalar sy = matrix.getScaleY() * (SkScalar)-1;
- transformed_matrix.setScaleY(sy);
- size_t height = CGBitmapContextGetHeight(context);
- SkScalar ty = -matrix.getTranslateY(); // y axis is flipped.
- transformed_matrix.setTranslateY(ty + (SkScalar)height);
-
- CGAffineTransform cg_matrix = gfx::SkMatrixToCGAffineTransform(
- transformed_matrix);
-
- // Load final transform into context.
- CGContextConcatCTM(context, cg_matrix);
-}
-
-// static
-void PlatformDevice::LoadClippingRegionToCGContext(
- CGContextRef context,
- const SkRegion& region,
- const SkMatrix& transformation) {
- if (region.isEmpty()) {
- // region can be empty, in which case everything will be clipped.
- SkRect rect;
- rect.setEmpty();
- CGContextClipToRect(context, gfx::SkRectToCGRect(rect));
- } else if (region.isRect()) {
- // CoreGraphics applies the current transform to clip rects, which is
- // unwanted. Inverse-transform the rect before sending it to CG. This only
- // works for translations and scaling, but not for rotations (but the
- // viewport is never rotated anyway).
- SkMatrix t;
- bool did_invert = transformation.invert(&t);
- if (!did_invert)
- t.reset();
- // Do the transformation.
- SkRect rect;
- rect.set(region.getBounds());
- t.mapRect(&rect);
- SkIRect irect;
- rect.round(&irect);
- CGContextClipToRect(context, gfx::SkIRectToCGRect(irect));
- } else {
- // It is complex.
- SkPath path;
- region.getBoundaryPath(&path);
- // Clip. Note that windows clipping regions are not affected by the
- // transform so apply it manually.
- path.transform(transformation);
- // TODO(playmobil): Implement.
- SkASSERT(false);
- // LoadPathToDC(context, path);
- // hrgn = PathToRegion(context);
- }
-}
-
} // namespace skia
diff --git a/skia/ext/skia_utils_ios_unittest.mm b/skia/ext/skia_utils_ios_unittest.mm
index c199304..8d0c9be 100644
--- a/skia/ext/skia_utils_ios_unittest.mm
+++ b/skia/ext/skia_utils_ios_unittest.mm
@@ -8,7 +8,6 @@
#import <UIKit/UIKit.h>
#include "base/base64.h"
-#include "base/ios/ios_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
diff --git a/skia/skia_test_expectations.txt b/skia/skia_test_expectations.txt
index 4327f6e..5927d5c 100644
--- a/skia/skia_test_expectations.txt
+++ b/skia/skia_test_expectations.txt
@@ -48,4 +48,7 @@
#
# START OVERRIDES HERE
+# We fixed a blending bug.
+crbug.com/459579 virtual/gpu/fast/canvas/canvas-composite-transformclip.html [ ImageOnlyFailure ]
+
# END OVERRIDES HERE (this line ensures that the file is newline-terminated)
diff --git a/sky/engine/platform/graphics/DecodingImageGenerator.cpp b/sky/engine/platform/graphics/DecodingImageGenerator.cpp
index 599e77c..f2e152c 100644
--- a/sky/engine/platform/graphics/DecodingImageGenerator.cpp
+++ b/sky/engine/platform/graphics/DecodingImageGenerator.cpp
@@ -65,7 +65,7 @@
return true;
}
-bool DecodingImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount)
+SkImageGenerator::Result DecodingImageGenerator::onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount)
{
TRACE_EVENT1("blink", "DecodingImageGenerator::getPixels", "index", static_cast<int>(m_frameIndex));
@@ -73,11 +73,11 @@
if (info.width() != m_imageInfo.width() || info.height() != m_imageInfo.height() || info.colorType() != m_imageInfo.colorType()) {
// ImageFrame may have changed the owning SkBitmap to kOpaque_SkAlphaType after sniffing the encoded data, so if we see a request
// for opaque, that is ok even if our initial alphatype was not opaque.
- return false;
+ return Result::kInvalidScale;
}
bool decoded = m_frameGenerator->decodeAndScale(m_imageInfo, m_frameIndex, pixels, rowBytes);
- return decoded;
+ return decoded ? Result::kSuccess : Result::kInvalidInput;
}
bool DecodingImageGenerator::onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3])
diff --git a/sky/engine/platform/graphics/DecodingImageGenerator.h b/sky/engine/platform/graphics/DecodingImageGenerator.h
index 3d6ae39..a2e948e 100644
--- a/sky/engine/platform/graphics/DecodingImageGenerator.h
+++ b/sky/engine/platform/graphics/DecodingImageGenerator.h
@@ -51,7 +51,7 @@
protected:
virtual SkData* onRefEncodedData() override;
virtual bool onGetInfo(SkImageInfo*) override;
- virtual bool onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override;
+ virtual Result onGetPixels(const SkImageInfo&, void* pixels, size_t rowBytes, SkPMColor ctable[], int* ctableCount) override;
virtual bool onGetYUV8Planes(SkISize sizes[3], void* planes[3], size_t rowBytes[3]) override;
private:
diff --git a/testing/android/native_test.gyp b/testing/android/native_test.gyp
index 7d0ebc8..632d687 100644
--- a/testing/android/native_test.gyp
+++ b/testing/android/native_test.gyp
@@ -16,13 +16,6 @@
'native_test_launcher.cc',
'native_test_launcher.h',
],
- 'direct_dependent_settings': {
- 'ldflags!': [
- # JNI_OnLoad is implemented in a .a and we need to
- # re-export in the .so.
- '-Wl,--exclude-libs=ALL',
- ],
- },
'dependencies': [
'../../base/base.gyp:base',
'../../base/base.gyp:test_support_base',
diff --git a/testing/android/native_test_jni_onload.cc b/testing/android/native_test_jni_onload.cc
index bfab3c9..de42356 100644
--- a/testing/android/native_test_jni_onload.cc
+++ b/testing/android/native_test_jni_onload.cc
@@ -4,22 +4,16 @@
#include "base/android/base_jni_onload.h"
#include "base/android/jni_android.h"
-#include "base/android/jni_onload_delegate.h"
+#include "base/bind.h"
#include "testing/android/native_test_launcher.h"
namespace {
-class NativeTestJNIOnLoadDelegate : public base::android::JNIOnLoadDelegate {
- public:
- bool RegisterJNI(JNIEnv* env) override;
- bool Init() override;
-};
-
-bool NativeTestJNIOnLoadDelegate::RegisterJNI(JNIEnv* env) {
+bool RegisterJNI(JNIEnv* env) {
return RegisterNativeTestJNI(env);
}
-bool NativeTestJNIOnLoadDelegate::Init() {
+bool Init() {
InstallHandlers();
return true;
}
@@ -29,11 +23,15 @@
// This is called by the VM when the shared library is first loaded.
JNI_EXPORT jint JNI_OnLoad(JavaVM* vm, void* reserved) {
- NativeTestJNIOnLoadDelegate delegate;
- std::vector<base::android::JNIOnLoadDelegate*> delegates;
- delegates.push_back(&delegate);
+ std::vector<base::android::RegisterCallback> register_callbacks;
+ register_callbacks.push_back(base::Bind(&RegisterJNI));
- if (!base::android::OnJNIOnLoad(vm, &delegates))
+ if (!base::android::OnJNIOnLoadRegisterJNI(vm, register_callbacks))
+ return -1;
+
+ std::vector<base::android::InitCallback> init_callbacks;
+ init_callbacks.push_back(base::Bind(&Init));
+ if (!base::android::OnJNIOnLoadInit(init_callbacks))
return -1;
return JNI_VERSION_1_4;
diff --git a/testing/buildbot/chromium.fyi.json b/testing/buildbot/chromium.fyi.json
index 1d15ec1..71e67ad 100644
--- a/testing/buildbot/chromium.fyi.json
+++ b/testing/buildbot/chromium.fyi.json
@@ -1048,5 +1048,85 @@
"script": "nacl_integration.py"
}
]
+ },
+ "ClangToTLinuxASan tester": {
+ "gtest_tests": [
+ "accessibility_unittests",
+ "extensions_browsertests",
+ {
+ "test": "base_unittests",
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ }
+ },
+ {
+ "test": "browser_tests",
+ "swarming": {
+ "can_use_on_swarming_builders": true,
+ "shards": 5
+ }
+ },
+ "cacheinvalidation_unittests",
+ "cast_unittests",
+ "cc_unittests",
+ "components_unittests",
+ {
+ "test": "content_browsertests",
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ }
+ },
+ {
+ "test": "content_unittests",
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ }
+ },
+ {
+ "test": "crypto_unittests",
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ }
+ },
+ "device_unittests",
+ "display_unittests",
+ "extensions_unittests",
+ "gcm_unit_tests",
+ "gfx_unittests",
+ "google_apis_unittests",
+ "gpu_unittests",
+ {
+ "test": "interactive_ui_tests",
+ "swarming": {
+ "can_use_on_swarming_builders": true
+ }
+ },
+ "ipc_tests",
+ "jingle_unittests",
+ "media_unittests",
+ {
+ "test": "net_unittests",
+ "swarming": {
+ "can_use_on_swarming_builders": true,
+ "shards": 4
+ }
+ },
+ "ppapi_unittests",
+ "printing_unittests",
+ "remoting_unittests",
+ "sandbox_linux_unittests",
+ "skia_unittests",
+ "sql_unittests",
+ "sync_unit_tests",
+ "ui_base_unittests",
+ {
+ "test": "unit_tests",
+ "swarming": {
+ "can_use_on_swarming_builders": true,
+ "shards": 2
+ }
+ },
+ "url_unittests"
+ ]
}
}
diff --git a/testing/chromoting/browser_test_commands_linux.txt b/testing/chromoting/browser_test_commands_linux.txt
index d6f2bf5..49f503e 100644
--- a/testing/chromoting/browser_test_commands_linux.txt
+++ b/testing/chromoting/browser_test_commands_linux.txt
@@ -3,6 +3,9 @@
/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gafyd
/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=non-gmail
/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Launch --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=RemoteDesktopBrowserTest.MANUAL_Auth --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail
/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_Connect_Local_Host --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
+/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=Me2MeBrowserTest.MANUAL_Me2Me_v2_Alive_OnLostFocus --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp.v2 --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --me2me-pin=123456 --override-user-data-dir=/tmp/chromoting_test_profile
/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_Connect --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
/usr/bin/python ../xvfb.py #PROD_DIR# #PROD_DIR#/browser_tests --gtest_filter=It2MeBrowserTest.MANUAL_InvalidAccessCode --run-manual --ui-test-action-timeout=100000 --webapp-unpacked=#PROD_DIR#/remoting/remoting.webapp --extension-name=Chromoting --accounts-file=../../remoting/tools/internal/test_accounts.json --account-type=gmail --override-user-data-dir=/tmp/chromoting_test_profile
\ No newline at end of file
diff --git a/testing/commit_queue/config.json b/testing/commit_queue/config.json
index 1b05f1c..da48bda 100644
--- a/testing/commit_queue/config.json
+++ b/testing/commit_queue/config.json
@@ -8,7 +8,8 @@
"cast_shell": ["defaulttests"],
"cast_shell_apk": ["defaulttests"],
"linux_android_rel_ng": ["defaulttests"],
- "linux_chromium_asan_rel_ng": ["defaulttests"]
+ "linux_chromium_asan_rel_ng": ["defaulttests"],
+ "linux_chromium_clobber_rel_ng": ["defaulttests"]
},
"tryserver.chromium.mac": {
"mac_chromium_gn_rel": ["defaulttests"]
diff --git a/testing/legion/common_lib.py b/testing/legion/common_lib.py
index 2f527ea..c752e0f 100644
--- a/testing/legion/common_lib.py
+++ b/testing/legion/common_lib.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Common library methods used by both host and client controllers."""
+"""Common library methods used by both coordinator and task machines."""
import argparse
import logging
diff --git a/testing/legion/discovery_server.py b/testing/legion/discovery_server.py
deleted file mode 100644
index 94786ce..0000000
--- a/testing/legion/discovery_server.py
+++ /dev/null
@@ -1,55 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""The discovery server used to register clients.
-
-The discovery server is started by the host controller and allows the clients
-to register themselves when they start. Authentication of the client controllers
-is based on an OTP passed to the client controller binary on startup.
-"""
-
-import logging
-import threading
-import xmlrpclib
-import SimpleXMLRPCServer
-
-#pylint: disable=relative-import
-import common_lib
-
-
-class DiscoveryServer(object):
- """Discovery server run on the host."""
-
- def __init__(self):
- self._expected_clients = {}
- self._rpc_server = None
- self._thread = None
-
- def _RegisterClientRPC(self, otp, ip):
- """The RPC used by a client to register with the discovery server."""
- assert otp in self._expected_clients
- cb = self._expected_clients.pop(otp)
- cb(ip)
-
- def RegisterClientCallback(self, otp, callback):
- """Registers a callback associated with an OTP."""
- assert callable(callback)
- self._expected_clients[otp] = callback
-
- def Start(self):
- """Starts the discovery server."""
- logging.debug('Starting discovery server')
- self._rpc_server = SimpleXMLRPCServer.SimpleXMLRPCServer(
- (common_lib.SERVER_ADDRESS, common_lib.SERVER_PORT),
- allow_none=True, logRequests=False)
- self._rpc_server.register_function(
- self._RegisterClientRPC, 'RegisterClient')
- self._thread = threading.Thread(target=self._rpc_server.serve_forever)
- self._thread.start()
-
- def Shutdown(self):
- """Shuts the discovery server down."""
- if self._thread and self._thread.is_alive():
- logging.debug('Shutting down discovery server')
- self._rpc_server.shutdown()
diff --git a/testing/legion/examples/hello_world/client_test.isolate b/testing/legion/examples/hello_world/client_test.isolate
deleted file mode 100644
index 7135ef2..0000000
--- a/testing/legion/examples/hello_world/client_test.isolate
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'includes': [
- '../../legion.isolate'
- ],
- 'conditions': [
- ['multi_machine == 1', {
- 'variables': {
- 'command': [
- 'python',
- '../../client_controller.py',
- ],
- 'files': [
- 'client_test.py',
- 'client_test.isolate'
- ],
- },
- }],
- ],
-}
diff --git a/testing/legion/examples/hello_world/host_test.isolate b/testing/legion/examples/hello_world/host_test.isolate
deleted file mode 100644
index da4ee4e..0000000
--- a/testing/legion/examples/hello_world/host_test.isolate
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
- 'includes': [
- '../../legion.isolate',
- 'client_test.isolate'
- ],
- 'conditions': [
- ['multi_machine == 1', {
- 'variables': {
- 'command': [
- 'host_test.py',
- ],
- 'files': [
- 'host_test.py',
- ],
- },
- }],
- ]
-}
diff --git a/testing/legion/examples/hello_world/host_test.py b/testing/legion/examples/hello_world/host_test.py
deleted file mode 100755
index 7a7875b..0000000
--- a/testing/legion/examples/hello_world/host_test.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""A simple host test module.
-
-This module runs on the host machine and is responsible for creating 2
-client machines, waiting for them, and running RPC calls on them.
-"""
-
-# Map the legion directory so we can import the host controller.
-import sys
-sys.path.append('../../')
-
-import logging
-import time
-
-import host_controller
-
-
-class ExampleController(host_controller.HostController):
- """A simple example controller for a test."""
-
- def __init__(self):
- super(ExampleController, self).__init__()
- self.client1 = None
- self.client2 = None
-
- def CreateClient(self):
- """Create a client object and set the proper values."""
- client = self.NewClient(
- isolate_file='client_test.isolate',
- config_vars={'multi_machine': '1'},
- dimensions={'os': 'legion-linux'}, priority=200,
- idle_timeout_secs=90, connection_timeout_secs=90,
- verbosity=logging.INFO)
- client.Create()
- return client
-
- def SetUp(self):
- """Create the client machines and wait until they connect.
-
- In this call the actual creation of the client machines is done in parallel
- by the system. The WaitForConnect calls are performed in series but will
- return as soon as the clients connect.
- """
- self.client1 = self.CreateClient()
- self.client2 = self.CreateClient()
- self.client1.WaitForConnection()
- self.client2.WaitForConnection()
-
- def Task(self):
- """Main method to run the task code."""
- self.CallEcho(self.client1)
- self.CallEcho(self.client2)
- self.CallClientTest(self.client1)
- self.CallClientTest(self.client2)
-
- def CallEcho(self, client):
- """Call rpc.Echo on a client."""
- logging.info('Calling Echo on %s', client.name)
- logging.info(client.rpc.Echo(client.name))
-
- def CallClientTest(self, client):
- """Call client_test.py name on a client."""
- logging.info('Calling Subprocess to run "./client_test.py %s"', client.name)
- proc = client.rpc.subprocess.Popen(['./client_test.py', client.name])
- client.rpc.subprocess.Wait(proc)
- retcode = client.rpc.subprocess.GetReturncode(proc)
- stdout = client.rpc.subprocess.ReadStdout(proc)
- stderr = client.rpc.subprocess.ReadStderr(proc)
- logging.info('retcode: %s, stdout: %s, stderr: %s', retcode, stdout, stderr)
-
-
-if __name__ == '__main__':
- ExampleController().RunController()
diff --git a/testing/legion/examples/subprocess/client.isolate b/testing/legion/examples/hello_world/task_test.isolate
similarity index 81%
copy from testing/legion/examples/subprocess/client.isolate
copy to testing/legion/examples/hello_world/task_test.isolate
index 611562c..1322f31 100644
--- a/testing/legion/examples/subprocess/client.isolate
+++ b/testing/legion/examples/hello_world/task_test.isolate
@@ -11,10 +11,11 @@
'variables': {
'command': [
'python',
- '../../client_controller.py',
+ '../../run_task.py',
],
'files': [
- 'client.isolate'
+ 'task_test.isolate',
+ 'task_test.py',
],
},
}],
diff --git a/testing/legion/examples/hello_world/client_test.py b/testing/legion/examples/hello_world/task_test.py
similarity index 100%
rename from testing/legion/examples/hello_world/client_test.py
rename to testing/legion/examples/hello_world/task_test.py
diff --git a/testing/legion/examples/subprocess/subprocess_test.isolate b/testing/legion/examples/subprocess/subprocess_test.isolate
index 5b20167..6b4561f 100644
--- a/testing/legion/examples/subprocess/subprocess_test.isolate
+++ b/testing/legion/examples/subprocess/subprocess_test.isolate
@@ -5,7 +5,7 @@
{
'includes': [
'../../legion.isolate',
- 'client.isolate'
+ 'task.isolate'
],
'conditions': [
['multi_machine == 1', {
diff --git a/testing/legion/examples/subprocess/subprocess_test.py b/testing/legion/examples/subprocess/subprocess_test.py
index 6d8ce87..28e3fb8 100755
--- a/testing/legion/examples/subprocess/subprocess_test.py
+++ b/testing/legion/examples/subprocess/subprocess_test.py
@@ -13,29 +13,29 @@
import time
import xmlrpclib
-import host_controller
+import test_controller
-class ExampleController(host_controller.HostController):
+class ExampleTestController(test_controller.TestController):
"""An example controller using the remote subprocess functions."""
def __init__(self):
- super(ExampleController, self).__init__()
- self.client = None
+ super(ExampleTestController, self).__init__()
+ self.task = None
def SetUp(self):
- """Creates the client machine and waits until it connects."""
- self.client = self.NewClient(
- isolate_file='client.isolate',
+ """Creates the task machine and waits until it connects."""
+ self.task = self.CreateNewTask(
+ isolate_file='task.isolate',
config_vars={'multi_machine': '1'},
dimensions={'os': 'legion-linux'},
idle_timeout_secs=90, connection_timeout_secs=90,
verbosity=logging.DEBUG)
- self.client.Create()
- self.client.WaitForConnection()
+ self.task.Create()
+ self.task.WaitForConnection()
- def Task(self):
- """Main method to run the task code."""
+ def RunTest(self):
+ """Main method to run the test code."""
self.TestLs()
self.TestTerminate()
self.TestMultipleProcesses()
@@ -43,37 +43,37 @@
def TestMultipleProcesses(self):
start = time.time()
- sleep20 = self.client.rpc.subprocess.Popen(['sleep', '20'])
- sleep10 = self.client.rpc.subprocess.Popen(['sleep', '10'])
+ sleep20 = self.task.rpc.subprocess.Popen(['sleep', '20'])
+ sleep10 = self.task.rpc.subprocess.Popen(['sleep', '10'])
- self.client.rpc.subprocess.Wait(sleep10)
+ self.task.rpc.subprocess.Wait(sleep10)
elapsed = time.time() - start
assert elapsed >= 10 and elapsed < 11
- self.client.rpc.subprocess.Wait(sleep20)
+ self.task.rpc.subprocess.Wait(sleep20)
elapsed = time.time() - start
assert elapsed >= 20
- self.client.rpc.subprocess.Delete(sleep20)
- self.client.rpc.subprocess.Delete(sleep10)
+ self.task.rpc.subprocess.Delete(sleep20)
+ self.task.rpc.subprocess.Delete(sleep10)
def TestTerminate(self):
start = time.time()
- proc = self.client.rpc.subprocess.Popen(['sleep', '20'])
- self.client.rpc.subprocess.Terminate(proc) # Implicitly deleted
+ proc = self.task.rpc.subprocess.Popen(['sleep', '20'])
+ self.task.rpc.subprocess.Terminate(proc) # Implicitly deleted
try:
- self.client.rpc.subprocess.Wait(proc)
+ self.task.rpc.subprocess.Wait(proc)
except xmlrpclib.Fault:
pass
assert time.time() - start < 20
def TestLs(self):
- proc = self.client.rpc.subprocess.Popen(['ls'])
- self.client.rpc.subprocess.Wait(proc)
- assert self.client.rpc.subprocess.GetReturncode(proc) == 0
- assert 'client.isolate' in self.client.rpc.subprocess.ReadStdout(proc)
- self.client.rpc.subprocess.Delete(proc)
+ proc = self.task.rpc.subprocess.Popen(['ls'])
+ self.task.rpc.subprocess.Wait(proc)
+ assert self.task.rpc.subprocess.GetReturncode(proc) == 0
+ assert 'task.isolate' in self.task.rpc.subprocess.ReadStdout(proc)
+ self.task.rpc.subprocess.Delete(proc)
if __name__ == '__main__':
- ExampleController().RunController()
+ ExampleTestController().RunController()
diff --git a/testing/legion/examples/subprocess/client.isolate b/testing/legion/examples/subprocess/task.isolate
similarity index 85%
rename from testing/legion/examples/subprocess/client.isolate
rename to testing/legion/examples/subprocess/task.isolate
index 611562c..534275d 100644
--- a/testing/legion/examples/subprocess/client.isolate
+++ b/testing/legion/examples/subprocess/task.isolate
@@ -11,10 +11,10 @@
'variables': {
'command': [
'python',
- '../../client_controller.py',
+ '../../run_task.py',
],
'files': [
- 'client.isolate'
+ 'task.isolate'
],
},
}],
diff --git a/testing/legion/host_controller.py b/testing/legion/host_controller.py
deleted file mode 100644
index dadcba4..0000000
--- a/testing/legion/host_controller.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Defines the host controller base library.
-
-This module is the basis on which host controllers are built and executed.
-"""
-
-import logging
-import sys
-
-#pylint: disable=relative-import
-import client_lib
-import common_lib
-import discovery_server
-
-
-class HostController(object):
- """The base host controller class."""
-
- def __init__(self):
- self._discovery_server = discovery_server.DiscoveryServer()
-
- def SetUp(self):
- """Setup method used by the subclass."""
- pass
-
- def Task(self):
- """Main task method used by the subclass."""
- pass
-
- def TearDown(self):
- """Teardown method used by the subclass."""
- pass
-
- def NewClient(self, *args, **kwargs):
- controller = client_lib.ClientController(*args, **kwargs)
- self._discovery_server.RegisterClientCallback(
- controller.otp, controller.OnConnect)
- return controller
-
- def RunController(self):
- """Main entry point for the controller."""
- print ' '.join(sys.argv)
- common_lib.InitLogging()
- self._discovery_server.Start()
-
- error = None
- tb = None
- try:
- self.SetUp()
- self.Task()
- except Exception as e:
- # Defer raising exceptions until after TearDown and _TearDown are called.
- error = e
- tb = sys.exc_info()[-1]
- try:
- self.TearDown()
- except Exception as e:
- # Defer raising exceptions until after _TearDown is called.
- # Note that an error raised here will obscure any errors raised
- # previously.
- error = e
- tb = sys.exc_info()[-1]
-
- self._discovery_server.Shutdown()
- client_lib.ClientController.ReleaseAllControllers()
- if error:
- raise error, None, tb #pylint: disable=raising-bad-type
diff --git a/testing/legion/legion.isolate b/testing/legion/legion.isolate
index 463764d..774b27a 100644
--- a/testing/legion/legion.isolate
+++ b/testing/legion/legion.isolate
@@ -6,14 +6,14 @@
'variables': {
'files': [
'__init__.py',
- 'client_controller.py',
- 'client_lib.py',
- 'client_rpc_methods.py',
- 'client_rpc_server.py',
'common_lib.py',
- 'discovery_server.py',
- 'host_controller.py',
'legion.isolate',
+ 'rpc_methods.py',
+ 'rpc_server.py',
+ 'run_task.py',
+ 'task_controller.py',
+ 'task_registration_server.py',
+ 'test_controller.py',
'../../tools/swarming_client/',
],
},
diff --git a/testing/legion/client_rpc_methods.py b/testing/legion/rpc_methods.py
similarity index 98%
rename from testing/legion/client_rpc_methods.py
rename to testing/legion/rpc_methods.py
index e43a7d8..7f17e23 100644
--- a/testing/legion/client_rpc_methods.py
+++ b/testing/legion/rpc_methods.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Defines the client RPC methods."""
+"""Defines the task RPC methods."""
import os
import sys
diff --git a/testing/legion/client_rpc_server.py b/testing/legion/rpc_server.py
similarity index 93%
rename from testing/legion/client_rpc_server.py
rename to testing/legion/rpc_server.py
index 7a5f565..43b4317 100644
--- a/testing/legion/client_rpc_server.py
+++ b/testing/legion/rpc_server.py
@@ -2,10 +2,10 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""The client RPC server code.
+"""The task RPC server code.
This server is an XML-RPC server which serves code from
-client_rpc_methods.RPCMethods.
+rpc_methods.RPCMethods.
This server will run until shutdown is called on the server object. This can
be achieved in 2 ways:
@@ -22,8 +22,8 @@
import SocketServer
#pylint: disable=relative-import
-import client_rpc_methods
import common_lib
+import rpc_methods
class RequestHandler(SimpleXMLRPCServer.SimpleXMLRPCRequestHandler):
@@ -33,10 +33,10 @@
"""
def do_POST(self):
- """Verifies the client is authorized to perform RPCs."""
+ """Verifies the task is authorized to perform RPCs."""
if self.client_address[0] != self.server.authorized_address:
logging.error('Received unauthorized RPC request from %s',
- self.client_address[0])
+ self.task_address[0])
self.send_response(403)
response = 'Forbidden'
self.send_header('Content-type', 'text/plain')
@@ -60,7 +60,7 @@
self.authorized_address = authorized_address
self.idle_timeout_secs = idle_timeout_secs
- self.register_instance(client_rpc_methods.RPCMethods(self))
+ self.register_instance(rpc_methods.RPCMethods(self))
self._shutdown_requested_event = threading.Event()
self._rpc_received_event = threading.Event()
diff --git a/testing/legion/client_controller.py b/testing/legion/run_task.py
similarity index 61%
rename from testing/legion/client_controller.py
rename to testing/legion/run_task.py
index dd80c29..6a55073 100755
--- a/testing/legion/client_controller.py
+++ b/testing/legion/run_task.py
@@ -3,11 +3,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""The main client_controller code.
-
-This code is the main entry point for the client machines and handles
-registering with the host server and running the local RPC server.
-"""
+"""The main task entrypoint."""
import argparse
import logging
@@ -16,32 +12,32 @@
import time
#pylint: disable=relative-import
-import client_rpc_server
import common_lib
+import rpc_server
def main():
print ' '.join(sys.argv)
common_lib.InitLogging()
- logging.info('Client controller starting')
+ logging.info('Task starting')
parser = argparse.ArgumentParser()
parser.add_argument('--otp',
help='One time token used to authenticate with the host')
- parser.add_argument('--host',
- help='The ip address of the host')
+ parser.add_argument('--controller',
+ help='The ip address of the controller machine')
parser.add_argument('--idle-timeout', type=int,
default=common_lib.DEFAULT_TIMEOUT_SECS,
help='The idle timeout for the rpc server in seconds')
args, _ = parser.parse_known_args()
logging.info(
- 'Registering with discovery server at %s using OTP %s', args.host,
- args.otp)
- server = common_lib.ConnectToServer(args.host).RegisterClient(
+ 'Registering with registration server at %s using OTP "%s"',
+ args.controller, args.otp)
+ server = common_lib.ConnectToServer(args.controller).RegisterTask(
args.otp, common_lib.MY_IP)
- server = client_rpc_server.RPCServer(args.host, args.idle_timeout)
+ server = rpc_server.RPCServer(args.controller, args.idle_timeout)
server.serve_forever()
return 0
diff --git a/testing/legion/client_lib.py b/testing/legion/task_controller.py
similarity index 78%
rename from testing/legion/client_lib.py
rename to testing/legion/task_controller.py
index 4656cac..e0812b4 100644
--- a/testing/legion/client_lib.py
+++ b/testing/legion/task_controller.py
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-"""Defines the client library."""
+"""Defines the task controller library."""
import argparse
import datetime
@@ -30,11 +30,24 @@
pass
-class ClientController(object):
- """Creates, configures, and controls a client machine."""
+class TaskController(object):
+ """Provisions, configures, and controls a task machine.
- _client_count = 0
- _controllers = []
+ This class is an abstraction of a physical task machine. It provides an
+ end to end API for controlling a task machine. Operations on the task machine
+ are performed using the instance's "rpc" property. A simple end to end
+ scenario is as follows:
+
+ task = TaskController(...)
+ task.Create()
+ task.WaitForConnection()
+ proc = task.rpc.subprocess.Popen(['ls'])
+ print task.rpc.subprocess.GetStdout(proc)
+ task.Release()
+ """
+
+ _task_count = 0
+ _tasks = []
def __init__(self, isolate_file, config_vars, dimensions, priority=100,
idle_timeout_secs=common_lib.DEFAULT_TIMEOUT_SECS,
@@ -42,10 +55,10 @@
verbosity='ERROR', name=None):
assert isinstance(config_vars, dict)
assert isinstance(dimensions, dict)
- type(self)._controllers.append(self)
- type(self)._client_count += 1
+ type(self)._tasks.append(self)
+ type(self)._task_count += 1
self.verbosity = verbosity
- self._name = name or 'Client%d' % type(self)._client_count
+ self._name = name or 'Task%d' % type(self)._task_count
self._priority = priority
self._isolate_file = isolate_file
self._isolated_file = isolate_file + 'd'
@@ -61,14 +74,14 @@
parser = argparse.ArgumentParser()
parser.add_argument('--isolate-server')
parser.add_argument('--swarming-server')
- parser.add_argument('--client-connection-timeout-secs',
+ parser.add_argument('--task-connection-timeout-secs',
default=common_lib.DEFAULT_TIMEOUT_SECS)
args, _ = parser.parse_known_args()
self._isolate_server = args.isolate_server
self._swarming_server = args.swarming_server
self._connection_timeout_secs = (connection_timeout_secs or
- args.client_connection_timeout_secs)
+ args.task_connection_timeout_secs)
@property
def name(self):
@@ -107,31 +120,31 @@
self._verbosity = level #pylint: disable=attribute-defined-outside-init
@classmethod
- def ReleaseAllControllers(cls):
- for controller in cls._controllers:
- controller.Release()
+ def ReleaseAllTasks(cls):
+ for task in cls._tasks:
+ task.Release()
def _CreateOTP(self):
"""Creates the OTP."""
- host_name = socket.gethostname()
+ controller_name = socket.gethostname()
test_name = os.path.basename(sys.argv[0])
creation_time = datetime.datetime.utcnow()
- otp = 'client:%s-host:%s-test:%s-creation:%s' % (
- self._name, host_name, test_name, creation_time)
+ otp = 'task:%s controller:%s test:%s creation:%s' % (
+ self._name, controller_name, test_name, creation_time)
return otp
def Create(self):
- """Creates the client machine."""
+ """Creates the task machine."""
logging.info('Creating %s', self.name)
self._connect_event.clear()
self._ExecuteIsolate()
self._ExecuteSwarming()
def WaitForConnection(self):
- """Waits for the client machine to connect.
+ """Waits for the task machine to connect.
Raises:
- ConnectionTimeoutError if the client doesn't connect in time.
+ ConnectionTimeoutError if the task doesn't connect in time.
"""
logging.info('Waiting for %s to connect with a timeout of %d seconds',
self._name, self._connection_timeout_secs)
@@ -140,7 +153,7 @@
raise ConnectionTimeoutError('%s failed to connect' % self.name)
def Release(self):
- """Quits the client's RPC server so it can release the machine."""
+ """Quits the task's RPC server so it can release the machine."""
if self._rpc is not None and self._connected:
logging.info('Releasing %s', self._name)
try:
@@ -186,7 +199,7 @@
cmd.extend([
'--',
- '--host', common_lib.MY_IP,
+ '--controller', common_lib.MY_IP,
'--otp', self._otp,
'--verbosity', self._verbosity,
'--idle-timeout', str(self._idle_timeout_secs),
@@ -203,7 +216,7 @@
raise Error(stderr)
def OnConnect(self, ip_address):
- """Receives client ip address on connection."""
+ """Receives task ip address on connection."""
self._ip_address = ip_address
self._connected = True
self._rpc = common_lib.ConnectToServer(self._ip_address)
diff --git a/testing/legion/task_registration_server.py b/testing/legion/task_registration_server.py
new file mode 100644
index 0000000..52ba727
--- /dev/null
+++ b/testing/legion/task_registration_server.py
@@ -0,0 +1,55 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""The registration server used to register tasks.
+
+The registration server is started by the test controller and allows the tasks
+to register themselves when they start. Authentication of the tasks controllers
+is based on an OTP passed to the run_task binary on startup.
+"""
+
+import logging
+import threading
+import xmlrpclib
+import SimpleXMLRPCServer
+
+#pylint: disable=relative-import
+import common_lib
+
+
+class TaskRegistrationServer(object):
+ """Discovery server run on the host."""
+
+ def __init__(self):
+ self._expected_tasks = {}
+ self._rpc_server = None
+ self._thread = None
+
+ def _RegisterTaskRPC(self, otp, ip):
+ """The RPC used by a task to register with the registration server."""
+ assert otp in self._expected_tasks
+ cb = self._expected_tasks.pop(otp)
+ cb(ip)
+
+ def RegisterTaskCallback(self, otp, callback):
+ """Registers a callback associated with an OTP."""
+ assert callable(callback)
+ self._expected_tasks[otp] = callback
+
+ def Start(self):
+ """Starts the registration server."""
+ logging.debug('Starting task registration server')
+ self._rpc_server = SimpleXMLRPCServer.SimpleXMLRPCServer(
+ (common_lib.SERVER_ADDRESS, common_lib.SERVER_PORT),
+ allow_none=True, logRequests=False)
+ self._rpc_server.register_function(
+ self._RegisterTaskRPC, 'RegisterTask')
+ self._thread = threading.Thread(target=self._rpc_server.serve_forever)
+ self._thread.start()
+
+ def Shutdown(self):
+ """Shuts the discovery server down."""
+ if self._thread and self._thread.is_alive():
+ logging.debug('Shutting down task registration server')
+ self._rpc_server.shutdown()
diff --git a/testing/legion/test_controller.py b/testing/legion/test_controller.py
new file mode 100644
index 0000000..2703fad
--- /dev/null
+++ b/testing/legion/test_controller.py
@@ -0,0 +1,69 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+"""Defines the test controller base library.
+
+This module is the basis on which test controllers are built and executed.
+"""
+
+import logging
+import sys
+
+#pylint: disable=relative-import
+import common_lib
+import task_controller
+import task_registration_server
+
+
+class TestController(object):
+ """The base test controller class."""
+
+ def __init__(self):
+ self._registration_server = (
+ task_registration_server.TaskRegistrationServer())
+
+ def SetUp(self):
+ """Setup method used by the subclass."""
+ pass
+
+ def RunTest(self):
+ """Main test method used by the subclass."""
+ raise NotImplementedError()
+
+ def TearDown(self):
+ """Teardown method used by the subclass."""
+ pass
+
+ def CreateNewTask(self, *args, **kwargs):
+ task = task_controller.TaskController(*args, **kwargs)
+ self._registration_server.RegisterTaskCallback(
+ task.otp, task.OnConnect)
+ return task
+
+ def RunController(self):
+ """Main entry point for the controller."""
+ print ' '.join(sys.argv)
+ common_lib.InitLogging()
+ self._registration_server.Start()
+
+ error = None
+ tb = None
+ try:
+ self.SetUp()
+ self.RunTest()
+ except Exception as e:
+ # Defer raising exceptions until after TearDown is called.
+ error = e
+ tb = sys.exc_info()[-1]
+ try:
+ self.TearDown()
+ except Exception as e:
+ if not tb:
+ error = e
+ tb = sys.exc_info()[-1]
+
+ self._registration_server.Shutdown()
+ task_controller.TaskController.ReleaseAllTasks()
+ if error:
+ raise error, None, tb #pylint: disable=raising-bad-type
diff --git a/third_party/boringssl/BUILD.gn b/third_party/boringssl/BUILD.gn
index d245868..e147754 100644
--- a/third_party/boringssl/BUILD.gn
+++ b/third_party/boringssl/BUILD.gn
@@ -28,9 +28,9 @@
if (is_win) {
import("//third_party/yasm/yasm_assemble.gni")
yasm_assemble("boringssl_asm") {
- if (cpu_arch == "x64") {
+ if (current_cpu == "x64") {
sources = gypi_values.boringssl_win_x86_64_sources
- } else if (cpu_arch == "x86") {
+ } else if (current_cpu == "x86") {
sources = gypi_values.boringssl_win_x86_sources
}
}
@@ -52,7 +52,13 @@
}
configs -= [ "//build/config/compiler:chromium_code" ]
- configs += [ "//build/config/compiler:no_chromium_code" ]
+ configs += [
+ "//build/config/compiler:no_chromium_code",
+
+ # TODO(davidben): Fix size_t truncations in BoringSSL.
+ # https://crbug.com/429039
+ "//build/config/compiler:no_size_t_to_int_warning",
+ ]
# Also gets the include dirs from :openssl_config
include_dirs = [
@@ -64,13 +70,7 @@
"src/crypto",
]
- if (is_win) {
- # TODO(davidben): Fix size_t truncations in BoringSSL.
- # https://crbug.com/429039
- cflags += [ "/wd4267" ]
- }
-
- if (cpu_arch == "x64") {
+ if (current_cpu == "x64") {
if (is_mac) {
sources += gypi_values.boringssl_mac_x86_64_sources
} else if (is_linux || is_android) {
@@ -80,7 +80,7 @@
} else {
defines += [ "OPENSSL_NO_ASM" ]
}
- } else if (cpu_arch == "x86") {
+ } else if (current_cpu == "x86") {
if (is_mac) {
sources += gypi_values.boringssl_mac_x86_sources
} else if (is_linux || is_android) {
@@ -90,9 +90,9 @@
} else {
defines += [ "OPENSSL_NO_ASM" ]
}
- } else if (cpu_arch == "arm") {
+ } else if (current_cpu == "arm") {
sources += gypi_values.boringssl_linux_arm_sources
- } else if (cpu_arch == "arm64") {
+ } else if (current_cpu == "arm64") {
sources += gypi_values.boringssl_linux_aarch64_sources
} else {
defines += [ "OPENSSL_NO_ASM" ]
diff --git a/third_party/harfbuzz-ng/BUILD.gn b/third_party/harfbuzz-ng/BUILD.gn
index 000a9cc..71213fd 100644
--- a/third_party/harfbuzz-ng/BUILD.gn
+++ b/third_party/harfbuzz-ng/BUILD.gn
@@ -28,7 +28,7 @@
} else {
use_system_harfbuzz = false
}
- if (is_linux && cpu_arch == "arm" && !is_chromeos) {
+ if (is_linux && current_cpu == "arm" && !is_chromeos) {
# Override use_system_harfbuzz for ARM cross compiling so system
# harfbuzz is not used because the corresponding package is not
# available.
@@ -161,10 +161,7 @@
cflags += [ "-Wno-unused-value" ]
}
if (is_win) {
- cflags += [
- "/wd4267", # size_t to 'type' converion.
- "/wd4334", # Result of 32-bit shift implicitly converted to 64 bits.
- ]
+ cflags += [ "/wd4334" ] # Result of 32-bit shift implicitly converted to 64 bits.
}
if (is_mac) {
sources += [
diff --git a/third_party/jstemplate/README.chromium b/third_party/jstemplate/README.chromium
index 6fd6f26..14b92f3 100644
--- a/third_party/jstemplate/README.chromium
+++ b/third_party/jstemplate/README.chromium
@@ -1,6 +1,8 @@
Name: google-jstemplate
URL: http://code.google.com/p/google-jstemplate/
License: Apache 2.0
+Security Critical: yes
+Version: unknown
"Template processing that is more suitable for the specific development-time
and runtime requirements of AJAX based web applications.
@@ -16,3 +18,7 @@
jstemplate_compiled.js is the output after passing the code through
compile.sh.
+
+Local modifications:
+Changed JSDoc annotations and subtle code changes to make it compile with modern
+versions of Closure Compiler. TODO(dbeam): upstream to google code project.
diff --git a/third_party/jstemplate/jsevalcontext.js b/third_party/jstemplate/jsevalcontext.js
index 52bbc62..f958a1e 100644
--- a/third_party/jstemplate/jsevalcontext.js
+++ b/third_party/jstemplate/jsevalcontext.js
@@ -243,7 +243,7 @@
*
* @param {Object} data The new context object.
*
- * @param {number} index Position of the new context when multiply
+ * @param {number|string} index Position of the new context when multiply
* instantiated. (See implementation of jstSelect().)
*
* @param {number} count The total number of contexts that were multiply
diff --git a/third_party/jstemplate/jstemplate.js b/third_party/jstemplate/jstemplate.js
index b4c154f..449a31c 100644
--- a/third_party/jstemplate/jstemplate.js
+++ b/third_party/jstemplate/jstemplate.js
@@ -552,9 +552,6 @@
* @param {Element} template The currently processed node of the template.
*
* @param {Function} select The javascript expression to evaluate.
- *
- * @notypecheck FIXME(hmitchell): See OCL6434950. instance and value need
- * type checks.
*/
JstProcessor.prototype.jstSelect_ = function(context, template, select) {
var me = this;
@@ -586,6 +583,7 @@
var multipleEmpty = (multiple && count == 0);
if (multiple) {
+ value = /** @type Array */(value);
if (multipleEmpty) {
// For an empty array, keep the first template instance and mark
// it last. Remove all other template instances.
@@ -938,7 +936,7 @@
* @param {Array} values The current input context, the array of
* values of which the template node will render one instance.
*
- * @param {number} index The index of this template node in values.
+ * @param {number|string} index The index of this template node in values.
*/
function jstSetInstance(template, values, index) {
if (index == jsLength(values) - 1) {
diff --git a/third_party/libpng/BUILD.gn b/third_party/libpng/BUILD.gn
index 488ef43..787d4fa 100644
--- a/third_party/libpng/BUILD.gn
+++ b/third_party/libpng/BUILD.gn
@@ -52,12 +52,8 @@
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
- if (is_win) {
- cflags = [ "/wd4267" ] # TODO(jschuh): http://crbug.com/167187
-
- if (component_mode == "shared_library") {
- defines = [ "PNG_BUILD_DLL" ]
- }
+ if (is_win && is_component_build) {
+ defines = [ "PNG_BUILD_DLL" ]
}
public_configs = [ ":libpng_config" ]
diff --git a/third_party/ots/BUILD.gn b/third_party/ots/BUILD.gn
new file mode 100644
index 0000000..513dce6
--- /dev/null
+++ b/third_party/ots/BUILD.gn
@@ -0,0 +1,90 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+config("ots_config") {
+ include_dirs = [ "include" ]
+}
+
+source_set("ots") {
+ sources = [
+ "include/ots-memory-stream.h",
+ "include/opentype-sanitiser.h",
+ "src/cff.cc",
+ "src/cff.h",
+ "src/cff_type2_charstring.cc",
+ "src/cff_type2_charstring.h",
+ "src/cmap.cc",
+ "src/cmap.h",
+ "src/cvt.cc",
+ "src/cvt.h",
+ "src/fpgm.cc",
+ "src/fpgm.h",
+ "src/gasp.cc",
+ "src/gasp.h",
+ "src/gdef.cc",
+ "src/gdef.h",
+ "src/glyf.cc",
+ "src/glyf.h",
+ "src/gpos.cc",
+ "src/gpos.h",
+ "src/gsub.cc",
+ "src/gsub.h",
+ "src/hdmx.cc",
+ "src/hdmx.h",
+ "src/head.cc",
+ "src/head.h",
+ "src/hhea.cc",
+ "src/hhea.h",
+ "src/hmtx.cc",
+ "src/hmtx.h",
+ "src/kern.cc",
+ "src/kern.h",
+ "src/layout.cc",
+ "src/layout.h",
+ "src/loca.cc",
+ "src/loca.h",
+ "src/ltsh.cc",
+ "src/ltsh.h",
+ "src/maxp.cc",
+ "src/maxp.h",
+ "src/math.cc",
+ "src/math_.h",
+ "src/metrics.cc",
+ "src/metrics.h",
+ "src/name.cc",
+ "src/name.h",
+ "src/os2.cc",
+ "src/os2.h",
+ "src/ots.cc",
+ "src/ots.h",
+ "src/post.cc",
+ "src/post.h",
+ "src/prep.cc",
+ "src/prep.h",
+ "src/vdmx.cc",
+ "src/vdmx.h",
+ "src/vhea.cc",
+ "src/vhea.h",
+ "src/vmtx.cc",
+ "src/vmtx.h",
+ "src/vorg.cc",
+ "src/vorg.h",
+ "src/woff2.cc",
+ "src/woff2.h",
+ ]
+
+ direct_dependent_configs = [ ":ots_config" ]
+
+ deps = [
+ "//third_party/brotli",
+ "//third_party/zlib",
+ ]
+
+ if (is_win) {
+ cflags = [
+ "/wd4267", # Conversion from size_t to 'type'.
+ "/wd4334", # 32-bit shift implicitly converted to 64-bits.
+ ]
+ }
+}
diff --git a/third_party/ots/INSTALL b/third_party/ots/INSTALL
new file mode 100644
index 0000000..dbb1d94
--- /dev/null
+++ b/third_party/ots/INSTALL
@@ -0,0 +1,38 @@
+How to build (using gyp):
+
+ (Note: test programs which require gtest can't build with gyp for now)
+
+ 1. If you are building OTS on Windows, download both the source
+ code and compiled driver for zlib from http://www.zlib.net/
+ and put them in third_party/zlib.
+
+ 2. If you are building from cloned Git repository, make sure to update the
+ submodules as well:
+
+ $ git submodule init
+ $ git submodule update
+
+ 3. Run gyp_ots
+
+ $ python gyp_ots
+
+ This will fetch gyp and generate build files. By default, following
+ files will be generated:
+ - MSVS solution file on Windows
+ - Xcode project file on Mac
+ - Makefile on Linux
+
+ If you want to generate Makefile on Mac, you can use -f option:
+
+ $ python gyp_ots -f make
+
+ 4. Build OTS
+
+ Using MSVS:
+ Open ots-standalone.sln and build the solution.
+
+ Using Xcode:
+ $ xcodebuild -target ots-standalone.xcodeproj -target all
+
+ Using Makefile:
+ $ make
diff --git a/third_party/ots/LICENSE b/third_party/ots/LICENSE
new file mode 100644
index 0000000..a7531cf
--- /dev/null
+++ b/third_party/ots/LICENSE
@@ -0,0 +1,27 @@
+// Copyright (c) 2009 The Chromium Authors. 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.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// 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/ots/OWNERS b/third_party/ots/OWNERS
new file mode 100644
index 0000000..96e5d87
--- /dev/null
+++ b/third_party/ots/OWNERS
@@ -0,0 +1,4 @@
+bashi@chromium.org
+behdad@chromium.org
+behdad@google.com
+jshin@chromium.org
diff --git a/third_party/ots/README b/third_party/ots/README
new file mode 100644
index 0000000..8dc1ebb
--- /dev/null
+++ b/third_party/ots/README
@@ -0,0 +1,21 @@
+Sanitiser for OpenType
+----------------------
+
+(Idea from Alex Russell)
+
+The CSS font-face property[1] is great for web typography. Having to use images
+in order to get the correct typeface is a great sadness; one should be able to
+use vectors.
+
+However, the TrueType renderers on many platforms have never been part of the
+attack surface before and putting them on the front line is a scary proposition.
+Esp on platforms like Windows where it's a closed-source blob running with high
+privilege.
+
+Thus, the OpenType Sanitiser (OTS) is designed to parse and serialise OpenType
+files, validating them and sanitising them as it goes.
+
+
+See INSTALL for build instructions.
+
+[1] http://www.w3.org/TR/CSS2/fonts.html#font-descriptions
diff --git a/third_party/ots/README.chromium b/third_party/ots/README.chromium
new file mode 100644
index 0000000..c828813
--- /dev/null
+++ b/third_party/ots/README.chromium
@@ -0,0 +1,5 @@
+Name: OTS
+URL: https://github.com/khaledhosny/ots.git
+Version: ea88f974e00e7fe0b4fbfe8d0adad8cfedf49c57
+Security Critical: yes
+License: BSD
diff --git a/third_party/ots/docs/DesignDoc.md b/third_party/ots/docs/DesignDoc.md
new file mode 100644
index 0000000..ffcc035
--- /dev/null
+++ b/third_party/ots/docs/DesignDoc.md
@@ -0,0 +1,136 @@
+What's OTS?
+===========
+
+Sanitiser for OpenType (OTS) is a small library which parses OpenType files
+(usually from `@font-face`) and attempts to validate and sanitise them. This
+library is primarily intended to be used with Chromium. We hope this reduces
+the attack surface of the system font libraries.
+
+What the sanitiser does is as follows:
+
+1. Parses an original font. If the parsing fails, OTS rejects the original
+ font.
+2. Validates the parsed data structure. If the validation fails, it rejects the
+ original font as well.
+3. Creates a new font on memory by serializing the data structure, and we call
+ this "transcoding".
+
+By transcoding fonts in this way, it is ensured that:
+
+1. All information in an original font that OTS doesn't know or can't parse is
+ dropped from the transcoded font.
+2. All information in the transcoded font is valid (standard compliant).
+ Particularly 'length' and 'offset' values, that are often used as attack
+ vectors, are ensured to be correct.
+
+Supported OpenType tables
+=========================
+
+| Name | Mandatory table? | Supported by OTS? | Note |
+|--------|-----------------------------|-------------------|--------|
+| `sfnt` | Yes | Yes | Overlapped tables are not allowed; it is treated as a fatal parser error.|
+| `maxp` | Yes | Yes | |
+| `head` | Yes | Yes | |
+| `hhea` | Yes | Yes | |
+| `hmtx` | Yes | Yes | |
+| `name` | Yes | Yes | |
+| `OS/2` | Yes | Yes | |
+| `post` | Yes | Yes | |
+| `cmap` | Yes | Partialy | see below |
+| `glyf` | Yes, for TrueType fonts | Yes | TrueType bytecode is supported, but OTS does **not** validate it.|
+| `loca` | Yes, when glyf table exists | Yes | |
+| `CFF ` | Yes, for OpenType fonts | Yes | OpenType bytecode is also supported, and OTS **does** validate it.|
+| `cvt ` | No | Yes | Though this table is not mandatory, OTS can't drop the table from a transcoded font since it might be referred from other hinting-related tables. Errors on this table should be treated as fatal.|
+| `fpgm` | No | Yes | Ditto. |
+| `prep` | No | Yes | Ditto. |
+| `VDMX` | No | Yes | This table is important for calculating the correct line spacing, at least on Chromium Windows and Chromium Linux.|
+| `hdmx` | No | Yes | |
+| `gasp` | No | Yes | |
+| `VORG` | No | Yes | |
+| `LTSH` | No | Yes | |
+| `kern` | No | Yes | |
+| `GDEF` | No | Yes | |
+| `GSUB` | No | Yes | |
+| `GPOS` | No | Yes | |
+| `morx` | No | No | |
+| `jstf` | No | No | |
+| `vmtx` | No | Yes | |
+| `vhea` | No | Yes | |
+| `EBDT` | No | No | We don't support embedded bitmap strikes.|
+| `EBLC` | No | No | Ditto. |
+| `EBSC` | No | No | Ditto. |
+| `bdat` | No | No | Ditto. |
+| `bhed` | No | No | Ditto. |
+| `bloc` | No | No | Ditto. |
+| `DSIG` | No | No | |
+| All other tables | - | No | |
+
+Please note that OTS library does not parse "unsupported" tables. These
+unsupported tables never appear in a transcoded font.
+
+Supported cmap formats
+----------------------
+
+The following 9 formats are supported:
+
+* "MS Unicode" (platform 3 encoding 1 format 4)
+ * BMP
+* "MS UCS-4" (platform 3 encoding 10 format 12)
+* "MS UCS-4 fallback" (platform 3 encoding 10 format 13)
+* "MS Symbol" (platform 3 encoding 0 format 4)
+* "Mac Roman" (platform 1 encoding 0 format 0)
+ * 1-0-0 format is supported while 1-0-6 is not.
+* "Unicode default" format (platform 0 encoding 0 format 4)
+ * treated as 3-1-4 format
+* "Unicode 1.1" format (platform 0 encoding 1 format 4)
+ * ditto
+* "Unicode 2.0+" format (platform 0 encoding 3 format 4)
+* "Unicode UCS-4" format (platform 0 encoding 4 format 12)
+ * treated as 3-10-12 format
+* Unicode Variation Sequences (platform 0 encoding 5 format 14)
+
+All other types of subtables are not supported and do not appear in transcoded fonts.
+
+Validation strategies
+=====================
+
+With regards to 8 mandatory tables, glyph-related tables (`glyf`, `loca` and `CFF`),
+and hinting-related tables (`cvt`, `prep`, and `fpgm`):
+
+* If OTS finds table-length, table-offset, or table-alignment errors, in other
+ words it cannot continue parsing, OTS treats the error as fatal.
+* If OTS finds simple value error which could be automatically fixed (e.g.,
+ font weight is greater than 900 - that's undefined), and if the error is
+ considered common among non-malicious fonts, OTS rewrites the value and
+ continues transcoding.
+* If OTS finds a value error which is hard to fix (e.g., values which should be
+ sorted are left unsorted), OTS treats the error as fatal.
+
+With regards to optional tables (`VORG`, `gasp`, `hdmx`, `LTSH`, and `VDMX`):
+
+* If OTS finds table-length, table-offset, or table-alignment errors, OTS
+ treats the error as fatal.
+* If OTS finds other errors, it simply drops the table from a transcoded font.
+
+Files
+=====
+
+* include/opentype-sanitiser.h
+ * Declaration for the public API, `ots::Process()`.
+ * Definition of the `OTSStream` interface, a write-only memory stream.
+* include/ots-memory-stream.h
+ * Definition of the `MemoryStream` class which implements the `OTSStream`
+ interface above.
+* src/ots.h
+ * Debug macros.
+ * Definition of a `Buffer` class which is a read-only memory stream.
+* src/ots.cc
+ * Definition of the `ots::Process()` function.
+ * `sfnt` table parser.
+* test/\*.cc
+ * test tools. see test/README for details.
+
+Known issues
+============
+
+Please check the [issues](https://github.com/khaledhosny/ots/issues) page.
diff --git a/third_party/ots/docs/HowToTest.md b/third_party/ots/docs/HowToTest.md
new file mode 100644
index 0000000..a18ee34
--- /dev/null
+++ b/third_party/ots/docs/HowToTest.md
@@ -0,0 +1,68 @@
+Prerequisites
+=============
+
+You can use your Ubuntu box (>= 8.04. 9.10 is recommended) to test OTS library.
+
+First, install TrueType and OpenType fonts to the Ubuntu box as many as
+possible.
+
+ % sudo apt-get install ttf-.*[^0]$
+
+Then, put malicious TrueType fonts on `~/malicious/`. For details, please check
+http://code.google.com/p/chromium/issues/detail?id=27139#c2. Currently access
+to the issue is limited to chromium-security team members for security reasons.
+
+ % cd
+ % tar xjf ~/ttf-testsuite.tar.bz2
+
+Test
+====
+
+In order to verify that:
+
+1. OTS does not reject these unmalicious fonts.
+2. and transcoded fonts OTS generates can be loaded by a system font renderer (FreeType2).
+
+Run `test_unmalicious_fonts.sh` script:
+
+ % cd /path/to/ots/tests
+ % ./test_unmalicious_fonts.sh
+ ............................................... (verify that no FAIL: is displayed)
+
+Then in order to verify that:
+
+1. OTS can reject malicious fonts
+2. or transcoded fonts generated by OTS do not crash a system font renderer (FreeType2).
+
+Run `test_malicious_fonts.sh` script:
+
+ % cd /path/to/ots/tests
+ % ./test_malicious_fonts.sh
+ ............................................... (verify that no FAIL: is displayed)
+
+Command line tools
+==================
+
+We have some command line tools for tests. To build them:
+
+- On Linux:
+
+ % gyp --depth=. -f make ots-standalone.gyp
+ % make
+ (tool is located at build/Default directory)
+
+- On Windows (VC++ is needed):
+
+ % gyp --depth=. -f msvs ots-standalone.gyp
+ % devenv.exe /build Default ots-standalone.sln /project idempotent.vcproj
+ (tool is located at Default directory)
+
+- On Mac (XCode is needed):
+
+ % gyp --depth=. -f xcode ots-standalone.gyp
+ % xcodebuild -configuration Default -project ots-standalone.xcodeproj -target All
+ (tool is located at build/Default directory)
+
+You can use `idempotent` tool to check whether a font will be rejected or not.
+You can also use `ot-sanitise` tool to get sanitised font (it is available on
+Linux for now). See README file in the test directory for more details.
diff --git a/third_party/ots/gyp_ots b/third_party/ots/gyp_ots
new file mode 100755
index 0000000..9a4056e
--- /dev/null
+++ b/third_party/ots/gyp_ots
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import os
+import subprocess
+import sys
+
+_GYP_REVISION = '1344'
+_GYP_FETCH_URL = 'https://gyp.googlecode.com/svn/trunk@' + _GYP_REVISION
+
+def _fetch_gyp():
+ gyp_dir = os.path.join('third_party', 'gyp')
+ if not os.path.exists(gyp_dir):
+ retcode = subprocess.call(['svn', 'checkout', _GYP_FETCH_URL, gyp_dir])
+ if retcode < 0:
+ raise "Couldn't fetch gyp"
+ # TODO(bashi): Check revision, etc
+ sys.path.insert(0, os.path.abspath(os.path.join(gyp_dir, 'pylib')))
+
+def main():
+ script_dir = os.path.abspath(os.path.dirname(__file__))
+ os.chdir(script_dir)
+ _fetch_gyp()
+ import gyp
+
+ args = []
+ args.extend(['--depth', '.'])
+ args.extend(sys.argv[1:])
+ args.append(os.path.join(script_dir, 'ots-standalone.gyp'))
+ sys.exit(gyp.main(args))
+
+if __name__ == '__main__':
+ main()
diff --git a/third_party/ots/include/opentype-sanitiser.h b/third_party/ots/include/opentype-sanitiser.h
new file mode 100644
index 0000000..c454f1e
--- /dev/null
+++ b/third_party/ots/include/opentype-sanitiser.h
@@ -0,0 +1,231 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OPENTYPE_SANITISER_H_
+#define OPENTYPE_SANITISER_H_
+
+#if defined(_WIN32)
+#include <stdlib.h>
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;
+typedef unsigned short uint16_t;
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#define ntohl(x) _byteswap_ulong (x)
+#define ntohs(x) _byteswap_ushort (x)
+#define htonl(x) _byteswap_ulong (x)
+#define htons(x) _byteswap_ushort (x)
+#else
+#include <arpa/inet.h>
+#include <stdint.h>
+#endif
+
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstring>
+
+namespace ots {
+
+// -----------------------------------------------------------------------------
+// This is an interface for an abstract stream class which is used for writing
+// the serialised results out.
+// -----------------------------------------------------------------------------
+class OTSStream {
+ public:
+ OTSStream() {
+ ResetChecksum();
+ }
+
+ virtual ~OTSStream() {}
+
+ // This should be implemented to perform the actual write.
+ virtual bool WriteRaw(const void *data, size_t length) = 0;
+
+ bool Write(const void *data, size_t length) {
+ if (!length) return false;
+
+ const size_t orig_length = length;
+ size_t offset = 0;
+ if (chksum_buffer_offset_) {
+ const size_t l =
+ std::min(length, static_cast<size_t>(4) - chksum_buffer_offset_);
+ std::memcpy(chksum_buffer_ + chksum_buffer_offset_, data, l);
+ chksum_buffer_offset_ += l;
+ offset += l;
+ length -= l;
+ }
+
+ if (chksum_buffer_offset_ == 4) {
+ uint32_t tmp;
+ std::memcpy(&tmp, chksum_buffer_, 4);
+ chksum_ += ntohl(tmp);
+ chksum_buffer_offset_ = 0;
+ }
+
+ while (length >= 4) {
+ uint32_t tmp;
+ std::memcpy(&tmp, reinterpret_cast<const uint8_t *>(data) + offset,
+ sizeof(uint32_t));
+ chksum_ += ntohl(tmp);
+ length -= 4;
+ offset += 4;
+ }
+
+ if (length) {
+ if (chksum_buffer_offset_ != 0) return false; // not reached
+ if (length > 4) return false; // not reached
+ std::memcpy(chksum_buffer_,
+ reinterpret_cast<const uint8_t*>(data) + offset, length);
+ chksum_buffer_offset_ = length;
+ }
+
+ return WriteRaw(data, orig_length);
+ }
+
+ virtual bool Seek(off_t position) = 0;
+ virtual off_t Tell() const = 0;
+
+ virtual bool Pad(size_t bytes) {
+ static const uint32_t kZero = 0;
+ while (bytes >= 4) {
+ if (!WriteTag(kZero)) return false;
+ bytes -= 4;
+ }
+ while (bytes) {
+ static const uint8_t kZerob = 0;
+ if (!Write(&kZerob, 1)) return false;
+ bytes--;
+ }
+ return true;
+ }
+
+ bool WriteU8(uint8_t v) {
+ return Write(&v, sizeof(v));
+ }
+
+ bool WriteU16(uint16_t v) {
+ v = htons(v);
+ return Write(&v, sizeof(v));
+ }
+
+ bool WriteS16(int16_t v) {
+ v = htons(v);
+ return Write(&v, sizeof(v));
+ }
+
+ bool WriteU24(uint32_t v) {
+ v = htonl(v);
+ return Write(reinterpret_cast<uint8_t*>(&v)+1, 3);
+ }
+
+ bool WriteU32(uint32_t v) {
+ v = htonl(v);
+ return Write(&v, sizeof(v));
+ }
+
+ bool WriteS32(int32_t v) {
+ v = htonl(v);
+ return Write(&v, sizeof(v));
+ }
+
+ bool WriteR64(uint64_t v) {
+ return Write(&v, sizeof(v));
+ }
+
+ bool WriteTag(uint32_t v) {
+ return Write(&v, sizeof(v));
+ }
+
+ void ResetChecksum() {
+ chksum_ = 0;
+ chksum_buffer_offset_ = 0;
+ }
+
+ uint32_t chksum() const {
+ assert(chksum_buffer_offset_ == 0);
+ return chksum_;
+ }
+
+ struct ChecksumState {
+ uint32_t chksum;
+ uint8_t chksum_buffer[4];
+ unsigned chksum_buffer_offset;
+ };
+
+ ChecksumState SaveChecksumState() const {
+ ChecksumState s;
+ s.chksum = chksum_;
+ s.chksum_buffer_offset = chksum_buffer_offset_;
+ std::memcpy(s.chksum_buffer, chksum_buffer_, 4);
+
+ return s;
+ }
+
+ void RestoreChecksum(const ChecksumState &s) {
+ assert(chksum_buffer_offset_ == 0);
+ chksum_ += s.chksum;
+ chksum_buffer_offset_ = s.chksum_buffer_offset;
+ std::memcpy(chksum_buffer_, s.chksum_buffer, 4);
+ }
+
+ protected:
+ uint32_t chksum_;
+ uint8_t chksum_buffer_[4];
+ unsigned chksum_buffer_offset_;
+};
+
+#ifdef __GCC__
+#define MSGFUNC_FMT_ATTR __attribute__((format(printf, 2, 3)))
+#else
+#define MSGFUNC_FMT_ATTR
+#endif
+
+enum TableAction {
+ TABLE_ACTION_DEFAULT, // Use OTS's default action for that table
+ TABLE_ACTION_SANITIZE, // Sanitize the table, potentially droping it
+ TABLE_ACTION_PASSTHRU, // Serialize the table unchanged
+ TABLE_ACTION_DROP // Drop the table
+};
+
+class OTSContext {
+ public:
+ OTSContext() {}
+ virtual ~OTSContext() {}
+
+ // Process a given OpenType file and write out a sanitised version
+ // output: a pointer to an object implementing the OTSStream interface. The
+ // sanitisied output will be written to this. In the even of a failure,
+ // partial output may have been written.
+ // input: the OpenType file
+ // length: the size, in bytes, of |input|
+ // context: optional context that holds various OTS settings like user callbacks
+ bool Process(OTSStream *output, const uint8_t *input, size_t length);
+
+ // This function will be called when OTS is reporting an error.
+ // level: the severity of the generated message:
+ // 0: error messages in case OTS fails to sanitize the font.
+ // 1: warning messages about issue OTS fixed in the sanitized font.
+ virtual void Message(int level, const char *format, ...) MSGFUNC_FMT_ATTR {}
+
+ // This function will be called when OTS needs to decide what to do for a
+ // font table.
+ // tag: table tag as an integer in big-endian byte order, independent of
+ // platform endianness
+ virtual TableAction GetTableAction(uint32_t tag) { return ots::TABLE_ACTION_DEFAULT; }
+};
+
+// For backward compatibility - remove once Chrome switches over to the new API.
+bool Process(OTSStream *output, const uint8_t *input, size_t length);
+
+// For backward compatibility - remove once https://codereview.chromium.org/774253008/
+// is submitted.
+void EnableWOFF2();
+
+} // namespace ots
+
+#endif // OPENTYPE_SANITISER_H_
diff --git a/third_party/ots/include/ots-memory-stream.h b/third_party/ots/include/ots-memory-stream.h
new file mode 100644
index 0000000..579da61
--- /dev/null
+++ b/third_party/ots/include/ots-memory-stream.h
@@ -0,0 +1,105 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_MEMORY_STREAM_H_
+#define OTS_MEMORY_STREAM_H_
+
+#include <cstring>
+#include <limits>
+
+#include "opentype-sanitiser.h"
+
+namespace ots {
+
+class MemoryStream : public OTSStream {
+ public:
+ MemoryStream(void *ptr, size_t length)
+ : ptr_(ptr), length_(length), off_(0) {
+ }
+
+ virtual bool WriteRaw(const void *data, size_t length) {
+ if ((off_ + length > length_) ||
+ (length > std::numeric_limits<size_t>::max() - off_)) {
+ return false;
+ }
+ std::memcpy(static_cast<char*>(ptr_) + off_, data, length);
+ off_ += length;
+ return true;
+ }
+
+ virtual bool Seek(off_t position) {
+ if (position < 0) return false;
+ if (static_cast<size_t>(position) > length_) return false;
+ off_ = position;
+ return true;
+ }
+
+ virtual off_t Tell() const {
+ return off_;
+ }
+
+ private:
+ void* const ptr_;
+ size_t length_;
+ off_t off_;
+};
+
+class ExpandingMemoryStream : public OTSStream {
+ public:
+ ExpandingMemoryStream(size_t initial, size_t limit)
+ : length_(initial), limit_(limit), off_(0) {
+ ptr_ = new uint8_t[length_];
+ }
+
+ ~ExpandingMemoryStream() {
+ delete[] static_cast<uint8_t*>(ptr_);
+ }
+
+ void* get() const {
+ return ptr_;
+ }
+
+ bool WriteRaw(const void *data, size_t length) {
+ if ((off_ + length > length_) ||
+ (length > std::numeric_limits<size_t>::max() - off_)) {
+ if (length_ == limit_)
+ return false;
+ size_t new_length = (length_ + 1) * 2;
+ if (new_length < length_)
+ return false;
+ if (new_length > limit_)
+ new_length = limit_;
+ uint8_t* new_buf = new uint8_t[new_length];
+ std::memcpy(new_buf, ptr_, length_);
+ length_ = new_length;
+ delete[] static_cast<uint8_t*>(ptr_);
+ ptr_ = new_buf;
+ return WriteRaw(data, length);
+ }
+ std::memcpy(static_cast<char*>(ptr_) + off_, data, length);
+ off_ += length;
+ return true;
+ }
+
+ bool Seek(off_t position) {
+ if (position < 0) return false;
+ if (static_cast<size_t>(position) > length_) return false;
+ off_ = position;
+ return true;
+ }
+
+ off_t Tell() const {
+ return off_;
+ }
+
+ private:
+ void* ptr_;
+ size_t length_;
+ const size_t limit_;
+ off_t off_;
+};
+
+} // namespace ots
+
+#endif // OTS_MEMORY_STREAM_H_
diff --git a/third_party/ots/ots-common.gypi b/third_party/ots/ots-common.gypi
new file mode 100644
index 0000000..9cb539c
--- /dev/null
+++ b/third_party/ots/ots-common.gypi
@@ -0,0 +1,77 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'ots_sources': [
+ 'include/ots-memory-stream.h',
+ 'include/opentype-sanitiser.h',
+ 'src/cff.cc',
+ 'src/cff.h',
+ 'src/cff_type2_charstring.cc',
+ 'src/cff_type2_charstring.h',
+ 'src/cmap.cc',
+ 'src/cmap.h',
+ 'src/cvt.cc',
+ 'src/cvt.h',
+ 'src/fpgm.cc',
+ 'src/fpgm.h',
+ 'src/gasp.cc',
+ 'src/gasp.h',
+ 'src/gdef.cc',
+ 'src/gdef.h',
+ 'src/glyf.cc',
+ 'src/glyf.h',
+ 'src/gpos.cc',
+ 'src/gpos.h',
+ 'src/gsub.cc',
+ 'src/gsub.h',
+ 'src/hdmx.cc',
+ 'src/hdmx.h',
+ 'src/head.cc',
+ 'src/head.h',
+ 'src/hhea.cc',
+ 'src/hhea.h',
+ 'src/hmtx.cc',
+ 'src/hmtx.h',
+ 'src/kern.cc',
+ 'src/kern.h',
+ 'src/layout.cc',
+ 'src/layout.h',
+ 'src/loca.cc',
+ 'src/loca.h',
+ 'src/ltsh.cc',
+ 'src/ltsh.h',
+ 'src/maxp.cc',
+ 'src/maxp.h',
+ 'src/math.cc',
+ 'src/math_.h',
+ 'src/metrics.cc',
+ 'src/metrics.h',
+ 'src/name.cc',
+ 'src/name.h',
+ 'src/os2.cc',
+ 'src/os2.h',
+ 'src/ots.cc',
+ 'src/ots.h',
+ 'src/post.cc',
+ 'src/post.h',
+ 'src/prep.cc',
+ 'src/prep.h',
+ 'src/vdmx.cc',
+ 'src/vdmx.h',
+ 'src/vhea.cc',
+ 'src/vhea.h',
+ 'src/vmtx.cc',
+ 'src/vmtx.h',
+ 'src/vorg.cc',
+ 'src/vorg.h',
+ 'src/woff2.cc',
+ 'src/woff2.h',
+ ],
+ 'ots_include_dirs': [
+ 'include',
+ ],
+ },
+}
diff --git a/third_party/ots/ots-standalone.gyp b/third_party/ots/ots-standalone.gyp
new file mode 100644
index 0000000..a45ec4a
--- /dev/null
+++ b/third_party/ots/ots-standalone.gyp
@@ -0,0 +1,256 @@
+# Copyright (c) 2012 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'gcc_cflags': [
+ '-ggdb',
+ '-W',
+ '-Wall',
+ '-Wshadow',
+ '-Wno-unused-parameter',
+ '-fPIE',
+ '-fstack-protector',
+ ],
+ 'gcc_ldflags': [
+ '-ggdb',
+ '-fpie',
+ '-Wl,-z,relro',
+ '-Wl,-z,now',
+ ],
+ },
+ 'includes': [
+ 'ots-common.gypi',
+ ],
+ 'target_defaults': {
+ 'include_dirs': [
+ '.',
+ 'third_party/brotli/dec',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'cflags': [
+ '<@(gcc_cflags)',
+ '-O',
+ ],
+ 'ldflags': [
+ '<@(gcc_ldflags)',
+ ],
+ 'defines': [
+ '_FORTIFY_SOURCE=2',
+ ],
+ 'link_settings': {
+ 'libraries': ['-lz'],
+ },
+ }],
+ ['OS=="mac"', {
+ 'xcode_settings': {
+ 'GCC_DYNAMIC_NO_PIC': 'NO', # No -mdynamic-no-pic
+ 'GCC_SYMBOLS_PRIVATE_EXTERN': 'YES', # -fvisibility=hidden
+ 'OTHER_CFLAGS': [
+ '<@(gcc_cflags)',
+ ],
+ },
+ 'link_settings': {
+ 'libraries': [
+ '/System/Library/Frameworks/ApplicationServices.framework',
+ '/usr/lib/libz.dylib'
+ ],
+ },
+ }],
+ ['OS=="win"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lzdll.lib',
+ ],
+ },
+ 'msvs_settings': {
+ 'VCLinkerTool': {
+ 'AdditionalLibraryDirectories': ['third_party/zlib'],
+ 'DelayLoadDLLs': ['zlib1.dll'],
+ },
+ },
+ 'include_dirs': [
+ 'third_party/zlib',
+ ],
+ 'defines': [
+ 'NOMINMAX', # To suppress max/min macro definition.
+ 'WIN32',
+ ],
+ }],
+ ],
+ },
+ 'targets': [
+ {
+ 'target_name': 'ots',
+ 'type': 'static_library',
+ 'sources': [
+ '<@(ots_sources)',
+ ],
+ 'dependencies': [
+ 'third_party/brotli.gyp:brotli',
+ ],
+ 'include_dirs': [
+ '<@(ots_include_dirs)',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<@(ots_include_dirs)',
+ ],
+ },
+ },
+ {
+ 'target_name': 'freetype2',
+ 'type': 'none',
+ 'conditions': [
+ ['OS=="linux"', {
+ 'direct_dependent_settings': {
+ 'cflags': [
+ '<!(pkg-config freetype2 --cflags)',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '<!(pkg-config freetype2 --libs)',
+ ],
+ },
+ },
+ }],
+ ],
+ },
+ {
+ 'target_name': 'idempotent',
+ 'type': 'executable',
+ 'sources': [
+ 'test/idempotent.cc',
+ ],
+ 'dependencies': [
+ 'ots',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'dependencies': [
+ 'freetype2',
+ ]
+ }],
+ ['OS=="win"', {
+ 'link_settings': {
+ 'libraries': [
+ '-lgdi32.lib',
+ ],
+ },
+ }],
+ ],
+ },
+ {
+ 'target_name': 'ot-sanitise',
+ 'type': 'executable',
+ 'sources': [
+ 'test/ot-sanitise.cc',
+ 'test/file-stream.h',
+ ],
+ 'dependencies': [
+ 'ots',
+ ],
+ },
+ ],
+ 'conditions': [
+ ['OS=="linux" or OS=="mac"', {
+ 'targets': [
+ {
+ 'target_name': 'validator_checker',
+ 'type': 'executable',
+ 'sources': [
+ 'test/validator-checker.cc',
+ ],
+ 'dependencies': [
+ 'ots',
+ ],
+ 'conditions': [
+ ['OS=="linux"', {
+ 'dependencies': [
+ 'freetype2',
+ ]
+ }],
+ ],
+ },
+ {
+ 'target_name': 'perf',
+ 'type': 'executable',
+ 'sources': [
+ 'test/perf.cc',
+ ],
+ 'dependencies': [
+ 'ots',
+ ],
+ },
+ {
+ 'target_name': 'cff_type2_charstring_test',
+ 'type': 'executable',
+ 'sources': [
+ 'test/cff_type2_charstring_test.cc',
+ ],
+ 'dependencies': [
+ 'ots',
+ ],
+ 'libraries': [
+ '-lgtest',
+ '-lgtest_main',
+ ],
+ 'include_dirs': [
+ 'src',
+ ],
+ },
+ {
+ 'target_name': 'layout_common_table_test',
+ 'type': 'executable',
+ 'sources': [
+ 'test/layout_common_table_test.cc',
+ ],
+ 'dependencies': [
+ 'ots',
+ ],
+ 'libraries': [
+ '-lgtest',
+ '-lgtest_main',
+ ],
+ 'include_dirs': [
+ 'src',
+ ],
+ },
+ {
+ 'target_name': 'table_dependencies_test',
+ 'type': 'executable',
+ 'sources': [
+ 'test/table_dependencies_test.cc',
+ ],
+ 'dependencies': [
+ 'ots',
+ ],
+ 'libraries': [
+ '-lgtest',
+ '-lgtest_main',
+ ],
+ 'include_dirs': [
+ 'src',
+ ],
+ },
+ ],
+ }],
+ ['OS=="linux"', {
+ 'targets': [
+ {
+ 'target_name': 'side_by_side',
+ 'type': 'executable',
+ 'sources': [
+ 'test/side-by-side.cc',
+ ],
+ 'dependencies': [
+ 'freetype2',
+ 'ots',
+ ],
+ },
+ ],
+ }],
+ ],
+}
diff --git a/third_party/ots/ots.gyp b/third_party/ots/ots.gyp
new file mode 100644
index 0000000..288e41c
--- /dev/null
+++ b/third_party/ots/ots.gyp
@@ -0,0 +1,39 @@
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'includes': [
+ 'ots-common.gypi',
+ ],
+ 'targets': [
+ {
+ 'target_name': 'ots',
+ 'type': 'static_library',
+ 'sources': [
+ '<@(ots_sources)',
+ ],
+ 'include_dirs': [
+ '../..',
+ '<@(ots_include_dirs)',
+ ],
+ 'direct_dependent_settings': {
+ 'include_dirs': [
+ '<@(ots_include_dirs)',
+ ],
+ },
+ 'dependencies': [
+ '../brotli/brotli.gyp:brotli',
+ '../zlib/zlib.gyp:zlib',
+ ],
+ # TODO(jschuh): http://crbug.com/167187
+ 'msvs_disabled_warnings': [
+ 4267,
+ 4334,
+ ],
+ },
+ ],
+}
diff --git a/third_party/ots/src/cff.cc b/third_party/ots/src/cff.cc
new file mode 100644
index 0000000..9c7204d
--- /dev/null
+++ b/third_party/ots/src/cff.cc
@@ -0,0 +1,1041 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cff.h"
+
+#include <cstring>
+#include <utility>
+#include <vector>
+
+#include "maxp.h"
+#include "cff_type2_charstring.h"
+
+// CFF - PostScript font program (Compact Font Format) table
+// http://www.microsoft.com/typography/otspec/cff.htm
+// http://www.microsoft.com/typography/otspec/cffspec.htm
+
+#define TABLE_NAME "CFF"
+
+namespace {
+
+enum DICT_OPERAND_TYPE {
+ DICT_OPERAND_INTEGER,
+ DICT_OPERAND_REAL,
+ DICT_OPERATOR,
+};
+
+enum DICT_DATA_TYPE {
+ DICT_DATA_TOPLEVEL,
+ DICT_DATA_FDARRAY,
+};
+
+enum FONT_FORMAT {
+ FORMAT_UNKNOWN,
+ FORMAT_CID_KEYED,
+ FORMAT_OTHER, // Including synthetic fonts
+};
+
+// see Appendix. A
+const size_t kNStdString = 390;
+
+bool ReadOffset(ots::Buffer *table, uint8_t off_size, uint32_t *offset) {
+ if (off_size > 4) {
+ return OTS_FAILURE();
+ }
+
+ uint32_t tmp32 = 0;
+ for (unsigned i = 0; i < off_size; ++i) {
+ uint8_t tmp8 = 0;
+ if (!table->ReadU8(&tmp8)) {
+ return OTS_FAILURE();
+ }
+ tmp32 <<= 8;
+ tmp32 += tmp8;
+ }
+ *offset = tmp32;
+ return true;
+}
+
+bool ParseIndex(ots::Buffer *table, ots::CFFIndex *index) {
+ index->off_size = 0;
+ index->offsets.clear();
+
+ if (!table->ReadU16(&(index->count))) {
+ return OTS_FAILURE();
+ }
+ if (index->count == 0) {
+ // An empty INDEX.
+ index->offset_to_next = table->offset();
+ return true;
+ }
+
+ if (!table->ReadU8(&(index->off_size))) {
+ return OTS_FAILURE();
+ }
+ if ((index->off_size == 0) ||
+ (index->off_size > 4)) {
+ return OTS_FAILURE();
+ }
+
+ const size_t array_size = (index->count + 1) * index->off_size;
+ // less than ((64k + 1) * 4), thus does not overflow.
+ const size_t object_data_offset = table->offset() + array_size;
+ // does not overflow too, since offset() <= 1GB.
+
+ if (object_data_offset >= table->length()) {
+ return OTS_FAILURE();
+ }
+
+ for (unsigned i = 0; i <= index->count; ++i) { // '<=' is not a typo.
+ uint32_t rel_offset = 0;
+ if (!ReadOffset(table, index->off_size, &rel_offset)) {
+ return OTS_FAILURE();
+ }
+ if (rel_offset < 1) {
+ return OTS_FAILURE();
+ }
+ if (i == 0 && rel_offset != 1) {
+ return OTS_FAILURE();
+ }
+
+ if (rel_offset > table->length()) {
+ return OTS_FAILURE();
+ }
+
+ // does not underflow.
+ if (object_data_offset > table->length() - (rel_offset - 1)) {
+ return OTS_FAILURE();
+ }
+
+ index->offsets.push_back(
+ object_data_offset + (rel_offset - 1)); // less than length(), 1GB.
+ }
+
+ for (unsigned i = 1; i < index->offsets.size(); ++i) {
+ // We allow consecutive identical offsets here for zero-length strings.
+ // See http://crbug.com/69341 for more details.
+ if (index->offsets[i] < index->offsets[i - 1]) {
+ return OTS_FAILURE();
+ }
+ }
+
+ index->offset_to_next = index->offsets.back();
+ return true;
+}
+
+bool ParseNameData(
+ ots::Buffer *table, const ots::CFFIndex &index, std::string* out_name) {
+ uint8_t name[256] = {0};
+ if (index.offsets.size() == 0) { // just in case.
+ return OTS_FAILURE();
+ }
+ for (unsigned i = 1; i < index.offsets.size(); ++i) {
+ const size_t length = index.offsets[i] - index.offsets[i - 1];
+ // font names should be no longer than 127 characters.
+ if (length > 127) {
+ return OTS_FAILURE();
+ }
+
+ table->set_offset(index.offsets[i - 1]);
+ if (!table->Read(name, length)) {
+ return OTS_FAILURE();
+ }
+
+ for (size_t j = 0; j < length; ++j) {
+ // setting the first byte to NUL is allowed.
+ if (j == 0 && name[j] == 0) continue;
+ // non-ASCII characters are not recommended (except the first character).
+ if (name[j] < 33 || name[j] > 126) {
+ return OTS_FAILURE();
+ }
+ // [, ], ... are not allowed.
+ if (std::strchr("[](){}<>/% ", name[j])) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+
+ *out_name = reinterpret_cast<char *>(name);
+ return true;
+}
+
+bool CheckOffset(const std::pair<uint32_t, DICT_OPERAND_TYPE>& operand,
+ size_t table_length) {
+ if (operand.second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ if (operand.first >= table_length) {
+ return OTS_FAILURE();
+ }
+ return true;
+}
+
+bool CheckSid(const std::pair<uint32_t, DICT_OPERAND_TYPE>& operand,
+ size_t sid_max) {
+ if (operand.second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ if (operand.first > sid_max) {
+ return OTS_FAILURE();
+ }
+ return true;
+}
+
+bool ParseDictDataBcd(
+ ots::Buffer *table,
+ std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+ bool read_decimal_point = false;
+ bool read_e = false;
+
+ uint8_t nibble = 0;
+ size_t count = 0;
+ while (true) {
+ if (!table->ReadU8(&nibble)) {
+ return OTS_FAILURE();
+ }
+ if ((nibble & 0xf0) == 0xf0) {
+ if ((nibble & 0xf) == 0xf) {
+ // TODO(yusukes): would be better to store actual double value,
+ // rather than the dummy integer.
+ operands->push_back(std::make_pair(static_cast<uint32_t>(0),
+ DICT_OPERAND_REAL));
+ return true;
+ }
+ return OTS_FAILURE();
+ }
+ if ((nibble & 0x0f) == 0x0f) {
+ operands->push_back(std::make_pair(static_cast<uint32_t>(0),
+ DICT_OPERAND_REAL));
+ return true;
+ }
+
+ // check number format
+ uint8_t nibbles[2];
+ nibbles[0] = (nibble & 0xf0) >> 8;
+ nibbles[1] = (nibble & 0x0f);
+ for (unsigned i = 0; i < 2; ++i) {
+ if (nibbles[i] == 0xd) { // reserved number
+ return OTS_FAILURE();
+ }
+ if ((nibbles[i] == 0xe) && // minus
+ ((count > 0) || (i > 0))) {
+ return OTS_FAILURE(); // minus sign should be the first character.
+ }
+ if (nibbles[i] == 0xa) { // decimal point
+ if (!read_decimal_point) {
+ read_decimal_point = true;
+ } else {
+ return OTS_FAILURE(); // two or more points.
+ }
+ }
+ if ((nibbles[i] == 0xb) || // E+
+ (nibbles[i] == 0xc)) { // E-
+ if (!read_e) {
+ read_e = true;
+ } else {
+ return OTS_FAILURE(); // two or more E's.
+ }
+ }
+ }
+ ++count;
+ }
+}
+
+bool ParseDictDataEscapedOperator(
+ ots::Buffer *table,
+ std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+ uint8_t op = 0;
+ if (!table->ReadU8(&op)) {
+ return OTS_FAILURE();
+ }
+
+ if ((op <= 14) ||
+ (op >= 17 && op <= 23) ||
+ (op >= 30 && op <= 38)) {
+ operands->push_back(std::make_pair((12U << 8) + op, DICT_OPERATOR));
+ return true;
+ }
+
+ // reserved area.
+ return OTS_FAILURE();
+}
+
+bool ParseDictDataNumber(
+ ots::Buffer *table, uint8_t b0,
+ std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+ uint8_t b1 = 0;
+ uint8_t b2 = 0;
+ uint8_t b3 = 0;
+ uint8_t b4 = 0;
+
+ switch (b0) {
+ case 28: // shortint
+ if (!table->ReadU8(&b1) ||
+ !table->ReadU8(&b2)) {
+ return OTS_FAILURE();
+ }
+ operands->push_back(std::make_pair(
+ static_cast<uint32_t>((b1 << 8) + b2), DICT_OPERAND_INTEGER));
+ return true;
+
+ case 29: // longint
+ if (!table->ReadU8(&b1) ||
+ !table->ReadU8(&b2) ||
+ !table->ReadU8(&b3) ||
+ !table->ReadU8(&b4)) {
+ return OTS_FAILURE();
+ }
+ operands->push_back(std::make_pair(
+ static_cast<uint32_t>((b1 << 24) + (b2 << 16) + (b3 << 8) + b4),
+ DICT_OPERAND_INTEGER));
+ return true;
+
+ case 30: // binary coded decimal
+ return ParseDictDataBcd(table, operands);
+
+ default:
+ break;
+ }
+
+ uint32_t result;
+ if (b0 >=32 && b0 <=246) {
+ result = b0 - 139;
+ } else if (b0 >=247 && b0 <= 250) {
+ if (!table->ReadU8(&b1)) {
+ return OTS_FAILURE();
+ }
+ result = (b0 - 247) * 256 + b1 + 108;
+ } else if (b0 >= 251 && b0 <= 254) {
+ if (!table->ReadU8(&b1)) {
+ return OTS_FAILURE();
+ }
+ result = -(b0 - 251) * 256 + b1 - 108;
+ } else {
+ return OTS_FAILURE();
+ }
+
+ operands->push_back(std::make_pair(result, DICT_OPERAND_INTEGER));
+ return true;
+}
+
+bool ParseDictDataReadNext(
+ ots::Buffer *table,
+ std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > *operands) {
+ uint8_t op = 0;
+ if (!table->ReadU8(&op)) {
+ return OTS_FAILURE();
+ }
+ if (op <= 21) {
+ if (op == 12) {
+ return ParseDictDataEscapedOperator(table, operands);
+ }
+ operands->push_back(std::make_pair(
+ static_cast<uint32_t>(op), DICT_OPERATOR));
+ return true;
+ } else if (op <= 27 || op == 31 || op == 255) {
+ // reserved area.
+ return OTS_FAILURE();
+ }
+
+ return ParseDictDataNumber(table, op, operands);
+}
+
+bool ParsePrivateDictData(
+ const uint8_t *data,
+ size_t table_length, size_t offset, size_t dict_length,
+ DICT_DATA_TYPE type, ots::OpenTypeCFF *out_cff) {
+ ots::Buffer table(data + offset, dict_length);
+ std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
+
+ // Since a Private DICT for FDArray might not have a Local Subr (e.g. Hiragino
+ // Kaku Gothic Std W8), we create an empty Local Subr here to match the size
+ // of FDArray the size of |local_subrs_per_font|.
+ if (type == DICT_DATA_FDARRAY) {
+ out_cff->local_subrs_per_font.push_back(new ots::CFFIndex);
+ }
+
+ while (table.offset() < dict_length) {
+ if (!ParseDictDataReadNext(&table, &operands)) {
+ return OTS_FAILURE();
+ }
+ if (operands.empty()) {
+ return OTS_FAILURE();
+ }
+ if (operands.size() > 48) {
+ // An operator may be preceded by up to a maximum of 48 operands.
+ return OTS_FAILURE();
+ }
+ if (operands.back().second != DICT_OPERATOR) {
+ continue;
+ }
+
+ // got operator
+ const uint32_t op = operands.back().first;
+ operands.pop_back();
+
+ switch (op) {
+ // array
+ case 6: // BlueValues
+ case 7: // OtherBlues
+ case 8: // FamilyBlues
+ case 9: // FamilyOtherBlues
+ case (12U << 8) + 12: // StemSnapH (delta)
+ case (12U << 8) + 13: // StemSnapV (delta)
+ if (operands.empty()) {
+ return OTS_FAILURE();
+ }
+ break;
+
+ // number
+ case 10: // StdHW
+ case 11: // StdVW
+ case 20: // defaultWidthX
+ case 21: // nominalWidthX
+ case (12U << 8) + 9: // BlueScale
+ case (12U << 8) + 10: // BlueShift
+ case (12U << 8) + 11: // BlueFuzz
+ case (12U << 8) + 17: // LanguageGroup
+ case (12U << 8) + 18: // ExpansionFactor
+ case (12U << 8) + 19: // initialRandomSeed
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ break;
+
+ // Local Subrs INDEX, offset(self)
+ case 19: {
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().first >= 1024 * 1024 * 1024) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().first + offset >= table_length) {
+ return OTS_FAILURE();
+ }
+ // parse "16. Local Subrs INDEX"
+ ots::Buffer cff_table(data, table_length);
+ cff_table.set_offset(operands.back().first + offset);
+ ots::CFFIndex *local_subrs_index = NULL;
+ if (type == DICT_DATA_FDARRAY) {
+ if (out_cff->local_subrs_per_font.empty()) {
+ return OTS_FAILURE(); // not reached.
+ }
+ local_subrs_index = out_cff->local_subrs_per_font.back();
+ } else { // type == DICT_DATA_TOPLEVEL
+ if (out_cff->local_subrs) {
+ return OTS_FAILURE(); // two or more local_subrs?
+ }
+ local_subrs_index = new ots::CFFIndex;
+ out_cff->local_subrs = local_subrs_index;
+ }
+ if (!ParseIndex(&cff_table, local_subrs_index)) {
+ return OTS_FAILURE();
+ }
+ break;
+ }
+
+ // boolean
+ case (12U << 8) + 14: // ForceBold
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().first >= 2) {
+ return OTS_FAILURE();
+ }
+ break;
+
+ default:
+ return OTS_FAILURE();
+ }
+ operands.clear();
+ }
+
+ return true;
+}
+
+bool ParseDictData(const uint8_t *data, size_t table_length,
+ const ots::CFFIndex &index, uint16_t glyphs,
+ size_t sid_max, DICT_DATA_TYPE type,
+ ots::OpenTypeCFF *out_cff) {
+ for (unsigned i = 1; i < index.offsets.size(); ++i) {
+ if (type == DICT_DATA_TOPLEVEL) {
+ out_cff->char_strings_array.push_back(new ots::CFFIndex);
+ }
+ size_t dict_length = index.offsets[i] - index.offsets[i - 1];
+ ots::Buffer table(data + index.offsets[i - 1], dict_length);
+
+ std::vector<std::pair<uint32_t, DICT_OPERAND_TYPE> > operands;
+
+ FONT_FORMAT font_format = FORMAT_UNKNOWN;
+ bool have_ros = false;
+ uint16_t charstring_glyphs = 0;
+ size_t charset_offset = 0;
+
+ while (table.offset() < dict_length) {
+ if (!ParseDictDataReadNext(&table, &operands)) {
+ return OTS_FAILURE();
+ }
+ if (operands.empty()) {
+ return OTS_FAILURE();
+ }
+ if (operands.size() > 48) {
+ // An operator may be preceded by up to a maximum of 48 operands.
+ return OTS_FAILURE();
+ }
+ if (operands.back().second != DICT_OPERATOR) continue;
+
+ // got operator
+ const uint32_t op = operands.back().first;
+ operands.pop_back();
+
+ switch (op) {
+ // SID
+ case 0: // version
+ case 1: // Notice
+ case 2: // Copyright
+ case 3: // FullName
+ case 4: // FamilyName
+ case (12U << 8) + 0: // Copyright
+ case (12U << 8) + 21: // PostScript
+ case (12U << 8) + 22: // BaseFontName
+ case (12U << 8) + 38: // FontName
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (!CheckSid(operands.back(), sid_max)) {
+ return OTS_FAILURE();
+ }
+ break;
+
+ // array
+ case 5: // FontBBox
+ case 14: // XUID
+ case (12U << 8) + 7: // FontMatrix
+ case (12U << 8) + 23: // BaseFontBlend (delta)
+ if (operands.empty()) {
+ return OTS_FAILURE();
+ }
+ break;
+
+ // number
+ case 13: // UniqueID
+ case (12U << 8) + 2: // ItalicAngle
+ case (12U << 8) + 3: // UnderlinePosition
+ case (12U << 8) + 4: // UnderlineThickness
+ case (12U << 8) + 5: // PaintType
+ case (12U << 8) + 8: // StrokeWidth
+ case (12U << 8) + 20: // SyntheticBase
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ break;
+ case (12U << 8) + 31: // CIDFontVersion
+ case (12U << 8) + 32: // CIDFontRevision
+ case (12U << 8) + 33: // CIDFontType
+ case (12U << 8) + 34: // CIDCount
+ case (12U << 8) + 35: // UIDBase
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (font_format != FORMAT_CID_KEYED) {
+ return OTS_FAILURE();
+ }
+ break;
+ case (12U << 8) + 6: // CharstringType
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if(operands.back().second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().first != 2) {
+ // We only support the "Type 2 Charstring Format."
+ // TODO(yusukes): Support Type 1 format? Is that still in use?
+ return OTS_FAILURE();
+ }
+ break;
+
+ // boolean
+ case (12U << 8) + 1: // isFixedPitch
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().first >= 2) {
+ return OTS_FAILURE();
+ }
+ break;
+
+ // offset(0)
+ case 15: // charset
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().first <= 2) {
+ // predefined charset, ISOAdobe, Expert or ExpertSubset, is used.
+ break;
+ }
+ if (!CheckOffset(operands.back(), table_length)) {
+ return OTS_FAILURE();
+ }
+ if (charset_offset) {
+ return OTS_FAILURE(); // multiple charset tables?
+ }
+ charset_offset = operands.back().first;
+ break;
+
+ case 16: { // Encoding
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().first <= 1) {
+ break; // predefined encoding, "Standard" or "Expert", is used.
+ }
+ if (!CheckOffset(operands.back(), table_length)) {
+ return OTS_FAILURE();
+ }
+
+ // parse sub dictionary INDEX.
+ ots::Buffer cff_table(data, table_length);
+ cff_table.set_offset(operands.back().first);
+ uint8_t format = 0;
+ if (!cff_table.ReadU8(&format)) {
+ return OTS_FAILURE();
+ }
+ if (format & 0x80) {
+ // supplemental encoding is not supported at the moment.
+ return OTS_FAILURE();
+ }
+ // TODO(yusukes): support & parse supplemental encoding tables.
+ break;
+ }
+
+ case 17: { // CharStrings
+ if (type != DICT_DATA_TOPLEVEL) {
+ return OTS_FAILURE();
+ }
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (!CheckOffset(operands.back(), table_length)) {
+ return OTS_FAILURE();
+ }
+ // parse "14. CharStrings INDEX"
+ ots::Buffer cff_table(data, table_length);
+ cff_table.set_offset(operands.back().first);
+ ots::CFFIndex *charstring_index = out_cff->char_strings_array.back();
+ if (!ParseIndex(&cff_table, charstring_index)) {
+ return OTS_FAILURE();
+ }
+ if (charstring_index->count < 2) {
+ return OTS_FAILURE();
+ }
+ if (charstring_glyphs) {
+ return OTS_FAILURE(); // multiple charstring tables?
+ }
+ charstring_glyphs = charstring_index->count;
+ if (charstring_glyphs != glyphs) {
+ return OTS_FAILURE(); // CFF and maxp have different number of glyphs?
+ }
+ break;
+ }
+
+ case (12U << 8) + 36: { // FDArray
+ if (type != DICT_DATA_TOPLEVEL) {
+ return OTS_FAILURE();
+ }
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (!CheckOffset(operands.back(), table_length)) {
+ return OTS_FAILURE();
+ }
+
+ // parse sub dictionary INDEX.
+ ots::Buffer cff_table(data, table_length);
+ cff_table.set_offset(operands.back().first);
+ ots::CFFIndex sub_dict_index;
+ if (!ParseIndex(&cff_table, &sub_dict_index)) {
+ return OTS_FAILURE();
+ }
+ if (!ParseDictData(data, table_length,
+ sub_dict_index,
+ glyphs, sid_max, DICT_DATA_FDARRAY,
+ out_cff)) {
+ return OTS_FAILURE();
+ }
+ if (out_cff->font_dict_length != 0) {
+ return OTS_FAILURE(); // two or more FDArray found.
+ }
+ out_cff->font_dict_length = sub_dict_index.count;
+ break;
+ }
+
+ case (12U << 8) + 37: { // FDSelect
+ if (type != DICT_DATA_TOPLEVEL) {
+ return OTS_FAILURE();
+ }
+ if (operands.size() != 1) {
+ return OTS_FAILURE();
+ }
+ if (!CheckOffset(operands.back(), table_length)) {
+ return OTS_FAILURE();
+ }
+
+ // parse FDSelect data structure
+ ots::Buffer cff_table(data, table_length);
+ cff_table.set_offset(operands.back().first);
+ uint8_t format = 0;
+ if (!cff_table.ReadU8(&format)) {
+ return OTS_FAILURE();
+ }
+ if (format == 0) {
+ for (uint16_t j = 0; j < glyphs; ++j) {
+ uint8_t fd_index = 0;
+ if (!cff_table.ReadU8(&fd_index)) {
+ return OTS_FAILURE();
+ }
+ (out_cff->fd_select)[j] = fd_index;
+ }
+ } else if (format == 3) {
+ uint16_t n_ranges = 0;
+ if (!cff_table.ReadU16(&n_ranges)) {
+ return OTS_FAILURE();
+ }
+ if (n_ranges == 0) {
+ return OTS_FAILURE();
+ }
+
+ uint16_t last_gid = 0;
+ uint8_t fd_index = 0;
+ for (unsigned j = 0; j < n_ranges; ++j) {
+ uint16_t first = 0; // GID
+ if (!cff_table.ReadU16(&first)) {
+ return OTS_FAILURE();
+ }
+
+ // Sanity checks.
+ if ((j == 0) && (first != 0)) {
+ return OTS_FAILURE();
+ }
+ if ((j != 0) && (last_gid >= first)) {
+ return OTS_FAILURE(); // not increasing order.
+ }
+
+ // Copy the mapping to |out_cff->fd_select|.
+ if (j != 0) {
+ for (uint16_t k = last_gid; k < first; ++k) {
+ if (!out_cff->fd_select.insert(
+ std::make_pair(k, fd_index)).second) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+
+ if (!cff_table.ReadU8(&fd_index)) {
+ return OTS_FAILURE();
+ }
+ last_gid = first;
+ // TODO(yusukes): check GID?
+ }
+ uint16_t sentinel = 0;
+ if (!cff_table.ReadU16(&sentinel)) {
+ return OTS_FAILURE();
+ }
+ if (last_gid >= sentinel) {
+ return OTS_FAILURE();
+ }
+ for (uint16_t k = last_gid; k < sentinel; ++k) {
+ if (!out_cff->fd_select.insert(
+ std::make_pair(k, fd_index)).second) {
+ return OTS_FAILURE();
+ }
+ }
+ } else {
+ // unknown format
+ return OTS_FAILURE();
+ }
+ break;
+ }
+
+ // Private DICT (2 * number)
+ case 18: {
+ if (operands.size() != 2) {
+ return OTS_FAILURE();
+ }
+ if (operands.back().second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ const uint32_t private_offset = operands.back().first;
+ operands.pop_back();
+ if (operands.back().second != DICT_OPERAND_INTEGER) {
+ return OTS_FAILURE();
+ }
+ const uint32_t private_length = operands.back().first;
+ if (private_offset > table_length) {
+ return OTS_FAILURE();
+ }
+ if (private_length >= table_length) {
+ return OTS_FAILURE();
+ }
+ if (private_length + private_offset > table_length) {
+ return OTS_FAILURE();
+ }
+ // parse "15. Private DICT Data"
+ if (!ParsePrivateDictData(data, table_length,
+ private_offset, private_length,
+ type, out_cff)) {
+ return OTS_FAILURE();
+ }
+ break;
+ }
+
+ // ROS
+ case (12U << 8) + 30:
+ if (font_format != FORMAT_UNKNOWN) {
+ return OTS_FAILURE();
+ }
+ font_format = FORMAT_CID_KEYED;
+ if (operands.size() != 3) {
+ return OTS_FAILURE();
+ }
+ // check SIDs
+ operands.pop_back(); // ignore the first number.
+ if (!CheckSid(operands.back(), sid_max)) {
+ return OTS_FAILURE();
+ }
+ operands.pop_back();
+ if (!CheckSid(operands.back(), sid_max)) {
+ return OTS_FAILURE();
+ }
+ if (have_ros) {
+ return OTS_FAILURE(); // multiple ROS tables?
+ }
+ have_ros = true;
+ break;
+
+ default:
+ return OTS_FAILURE();
+ }
+ operands.clear();
+
+ if (font_format == FORMAT_UNKNOWN) {
+ font_format = FORMAT_OTHER;
+ }
+ }
+
+ // parse "13. Charsets"
+ if (charset_offset) {
+ ots::Buffer cff_table(data, table_length);
+ cff_table.set_offset(charset_offset);
+ uint8_t format = 0;
+ if (!cff_table.ReadU8(&format)) {
+ return OTS_FAILURE();
+ }
+ switch (format) {
+ case 0:
+ for (uint16_t j = 1 /* .notdef is omitted */; j < glyphs; ++j) {
+ uint16_t sid = 0;
+ if (!cff_table.ReadU16(&sid)) {
+ return OTS_FAILURE();
+ }
+ if (!have_ros && (sid > sid_max)) {
+ return OTS_FAILURE();
+ }
+ // TODO(yusukes): check CIDs when have_ros is true.
+ }
+ break;
+
+ case 1:
+ case 2: {
+ uint32_t total = 1; // .notdef is omitted.
+ while (total < glyphs) {
+ uint16_t sid = 0;
+ if (!cff_table.ReadU16(&sid)) {
+ return OTS_FAILURE();
+ }
+ if (!have_ros && (sid > sid_max)) {
+ return OTS_FAILURE();
+ }
+ // TODO(yusukes): check CIDs when have_ros is true.
+
+ if (format == 1) {
+ uint8_t left = 0;
+ if (!cff_table.ReadU8(&left)) {
+ return OTS_FAILURE();
+ }
+ total += (left + 1);
+ } else {
+ uint16_t left = 0;
+ if (!cff_table.ReadU16(&left)) {
+ return OTS_FAILURE();
+ }
+ total += (left + 1);
+ }
+ }
+ break;
+ }
+
+ default:
+ return OTS_FAILURE();
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace
+
+namespace ots {
+
+bool ots_cff_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ file->cff = new OpenTypeCFF;
+ file->cff->data = data;
+ file->cff->length = length;
+ file->cff->font_dict_length = 0;
+ file->cff->local_subrs = NULL;
+
+ // parse "6. Header" in the Adobe Compact Font Format Specification
+ uint8_t major = 0;
+ uint8_t minor = 0;
+ uint8_t hdr_size = 0;
+ uint8_t off_size = 0;
+ if (!table.ReadU8(&major)) {
+ return OTS_FAILURE();
+ }
+ if (!table.ReadU8(&minor)) {
+ return OTS_FAILURE();
+ }
+ if (!table.ReadU8(&hdr_size)) {
+ return OTS_FAILURE();
+ }
+ if (!table.ReadU8(&off_size)) {
+ return OTS_FAILURE();
+ }
+ if ((off_size == 0) || (off_size > 4)) {
+ return OTS_FAILURE();
+ }
+
+ if ((major != 1) ||
+ (minor != 0) ||
+ (hdr_size != 4)) {
+ return OTS_FAILURE();
+ }
+ if (hdr_size >= length) {
+ return OTS_FAILURE();
+ }
+
+ // parse "7. Name INDEX"
+ table.set_offset(hdr_size);
+ CFFIndex name_index;
+ if (!ParseIndex(&table, &name_index)) {
+ return OTS_FAILURE();
+ }
+ if (!ParseNameData(&table, name_index, &(file->cff->name))) {
+ return OTS_FAILURE();
+ }
+
+ // parse "8. Top DICT INDEX"
+ table.set_offset(name_index.offset_to_next);
+ CFFIndex top_dict_index;
+ if (!ParseIndex(&table, &top_dict_index)) {
+ return OTS_FAILURE();
+ }
+ if (name_index.count != top_dict_index.count) {
+ return OTS_FAILURE();
+ }
+
+ // parse "10. String INDEX"
+ table.set_offset(top_dict_index.offset_to_next);
+ CFFIndex string_index;
+ if (!ParseIndex(&table, &string_index)) {
+ return OTS_FAILURE();
+ }
+ if (string_index.count >= 65000 - kNStdString) {
+ return OTS_FAILURE();
+ }
+
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+ const size_t sid_max = string_index.count + kNStdString;
+ // string_index.count == 0 is allowed.
+
+ // parse "9. Top DICT Data"
+ if (!ParseDictData(data, length, top_dict_index,
+ num_glyphs, sid_max,
+ DICT_DATA_TOPLEVEL, file->cff)) {
+ return OTS_FAILURE();
+ }
+
+ // parse "16. Global Subrs INDEX"
+ table.set_offset(string_index.offset_to_next);
+ CFFIndex global_subrs_index;
+ if (!ParseIndex(&table, &global_subrs_index)) {
+ return OTS_FAILURE();
+ }
+
+ // Check if all fd_index in FDSelect are valid.
+ std::map<uint16_t, uint8_t>::const_iterator iter;
+ std::map<uint16_t, uint8_t>::const_iterator end = file->cff->fd_select.end();
+ for (iter = file->cff->fd_select.begin(); iter != end; ++iter) {
+ if (iter->second >= file->cff->font_dict_length) {
+ return OTS_FAILURE();
+ }
+ }
+
+ // Check if all charstrings (font hinting code for each glyph) are valid.
+ for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
+ if (!ValidateType2CharStringIndex(file,
+ *(file->cff->char_strings_array.at(i)),
+ global_subrs_index,
+ file->cff->fd_select,
+ file->cff->local_subrs_per_font,
+ file->cff->local_subrs,
+ &table)) {
+ return OTS_FAILURE_MSG("Failed validating charstring set %d", (int) i);
+ }
+ }
+
+ return true;
+}
+
+bool ots_cff_should_serialise(OpenTypeFile *file) {
+ return file->cff != NULL;
+}
+
+bool ots_cff_serialise(OTSStream *out, OpenTypeFile *file) {
+ // TODO(yusukes): would be better to transcode the data,
+ // rather than simple memcpy.
+ if (!out->Write(file->cff->data, file->cff->length)) {
+ return OTS_FAILURE();
+ }
+ return true;
+}
+
+void ots_cff_free(OpenTypeFile *file) {
+ if (file->cff) {
+ for (size_t i = 0; i < file->cff->char_strings_array.size(); ++i) {
+ delete (file->cff->char_strings_array)[i];
+ }
+ for (size_t i = 0; i < file->cff->local_subrs_per_font.size(); ++i) {
+ delete (file->cff->local_subrs_per_font)[i];
+ }
+ delete file->cff->local_subrs;
+ delete file->cff;
+ }
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/cff.h b/third_party/ots/src/cff.h
new file mode 100644
index 0000000..5584acc
--- /dev/null
+++ b/third_party/ots/src/cff.h
@@ -0,0 +1,46 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CFF_H_
+#define OTS_CFF_H_
+
+#include "ots.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace ots {
+
+struct CFFIndex {
+ CFFIndex()
+ : count(0), off_size(0), offset_to_next(0) {}
+ uint16_t count;
+ uint8_t off_size;
+ std::vector<uint32_t> offsets;
+ uint32_t offset_to_next;
+};
+
+struct OpenTypeCFF {
+ const uint8_t *data;
+ size_t length;
+ // Name INDEX. This name is used in name.cc as a postscript font name.
+ std::string name;
+
+ // The number of fonts the file has.
+ size_t font_dict_length;
+ // A map from glyph # to font #.
+ std::map<uint16_t, uint8_t> fd_select;
+
+ // A list of char strings.
+ std::vector<CFFIndex *> char_strings_array;
+ // A list of Local Subrs associated with FDArrays. Can be empty.
+ std::vector<CFFIndex *> local_subrs_per_font;
+ // A Local Subrs associated with Top DICT. Can be NULL.
+ CFFIndex *local_subrs;
+};
+
+} // namespace ots
+
+#endif // OTS_CFF_H_
diff --git a/third_party/ots/src/cff_type2_charstring.cc b/third_party/ots/src/cff_type2_charstring.cc
new file mode 100644
index 0000000..6dd4766
--- /dev/null
+++ b/third_party/ots/src/cff_type2_charstring.cc
@@ -0,0 +1,914 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A parser for the Type 2 Charstring Format.
+// http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
+
+#include "cff_type2_charstring.h"
+
+#include <climits>
+#include <cstdio>
+#include <cstring>
+#include <stack>
+#include <string>
+#include <utility>
+
+#define TABLE_NAME "CFF"
+
+namespace {
+
+// Type 2 Charstring Implementation Limits. See Appendix. B in Adobe Technical
+// Note #5177.
+const int32_t kMaxSubrsCount = 65536;
+const size_t kMaxCharStringLength = 65535;
+const size_t kMaxArgumentStack = 48;
+const size_t kMaxNumberOfStemHints = 96;
+const size_t kMaxSubrNesting = 10;
+
+// |dummy_result| should be a huge positive integer so callsubr and callgsubr
+// will fail with the dummy value.
+const int32_t dummy_result = INT_MAX;
+
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
+ size_t call_depth,
+ const ots::CFFIndex& global_subrs_index,
+ const ots::CFFIndex& local_subrs_index,
+ ots::Buffer *cff_table,
+ ots::Buffer *char_string,
+ std::stack<int32_t> *argument_stack,
+ bool *out_found_endchar,
+ bool *out_found_width,
+ size_t *in_out_num_stems);
+
+#ifdef DUMP_T2CHARSTRING
+// Converts |op| to a string and returns it.
+const char *Type2CharStringOperatorToString(ots::Type2CharStringOperator op) {
+ switch (op) {
+ case ots::kHStem:
+ return "HStem";
+ case ots::kVStem:
+ return "VStem";
+ case ots::kVMoveTo:
+ return "VMoveTo";
+ case ots::kRLineTo:
+ return "RLineTo";
+ case ots::kHLineTo:
+ return "HLineTo";
+ case ots::kVLineTo:
+ return "VLineTo";
+ case ots::kRRCurveTo:
+ return "RRCurveTo";
+ case ots::kCallSubr:
+ return "CallSubr";
+ case ots::kReturn:
+ return "Return";
+ case ots::kEndChar:
+ return "EndChar";
+ case ots::kHStemHm:
+ return "HStemHm";
+ case ots::kHintMask:
+ return "HintMask";
+ case ots::kCntrMask:
+ return "CntrMask";
+ case ots::kRMoveTo:
+ return "RMoveTo";
+ case ots::kHMoveTo:
+ return "HMoveTo";
+ case ots::kVStemHm:
+ return "VStemHm";
+ case ots::kRCurveLine:
+ return "RCurveLine";
+ case ots::kRLineCurve:
+ return "RLineCurve";
+ case ots::kVVCurveTo:
+ return "VVCurveTo";
+ case ots::kHHCurveTo:
+ return "HHCurveTo";
+ case ots::kCallGSubr:
+ return "CallGSubr";
+ case ots::kVHCurveTo:
+ return "VHCurveTo";
+ case ots::kHVCurveTo:
+ return "HVCurveTo";
+ case ots::kDotSection:
+ return "DotSection";
+ case ots::kAnd:
+ return "And";
+ case ots::kOr:
+ return "Or";
+ case ots::kNot:
+ return "Not";
+ case ots::kAbs:
+ return "Abs";
+ case ots::kAdd:
+ return "Add";
+ case ots::kSub:
+ return "Sub";
+ case ots::kDiv:
+ return "Div";
+ case ots::kNeg:
+ return "Neg";
+ case ots::kEq:
+ return "Eq";
+ case ots::kDrop:
+ return "Drop";
+ case ots::kPut:
+ return "Put";
+ case ots::kGet:
+ return "Get";
+ case ots::kIfElse:
+ return "IfElse";
+ case ots::kRandom:
+ return "Random";
+ case ots::kMul:
+ return "Mul";
+ case ots::kSqrt:
+ return "Sqrt";
+ case ots::kDup:
+ return "Dup";
+ case ots::kExch:
+ return "Exch";
+ case ots::kIndex:
+ return "Index";
+ case ots::kRoll:
+ return "Roll";
+ case ots::kHFlex:
+ return "HFlex";
+ case ots::kFlex:
+ return "Flex";
+ case ots::kHFlex1:
+ return "HFlex1";
+ case ots::kFlex1:
+ return "Flex1";
+ }
+
+ return "UNKNOWN";
+}
+#endif
+
+// Read one or more bytes from the |char_string| buffer and stores the number
+// read on |out_number|. If the number read is an operator (ex 'vstem'), sets
+// true on |out_is_operator|. Returns true if the function read a number.
+bool ReadNextNumberFromType2CharString(ots::Buffer *char_string,
+ int32_t *out_number,
+ bool *out_is_operator) {
+ uint8_t v = 0;
+ if (!char_string->ReadU8(&v)) {
+ return OTS_FAILURE();
+ }
+ *out_is_operator = false;
+
+ // The conversion algorithm is described in Adobe Technical Note #5177, page
+ // 13, Table 1.
+ if (v <= 11) {
+ *out_number = v;
+ *out_is_operator = true;
+ } else if (v == 12) {
+ uint16_t result = (v << 8);
+ if (!char_string->ReadU8(&v)) {
+ return OTS_FAILURE();
+ }
+ result += v;
+ *out_number = result;
+ *out_is_operator = true;
+ } else if (v <= 27) {
+ // Special handling for v==19 and v==20 are implemented in
+ // ExecuteType2CharStringOperator().
+ *out_number = v;
+ *out_is_operator = true;
+ } else if (v == 28) {
+ if (!char_string->ReadU8(&v)) {
+ return OTS_FAILURE();
+ }
+ uint16_t result = (v << 8);
+ if (!char_string->ReadU8(&v)) {
+ return OTS_FAILURE();
+ }
+ result += v;
+ *out_number = result;
+ } else if (v <= 31) {
+ *out_number = v;
+ *out_is_operator = true;
+ } else if (v <= 246) {
+ *out_number = static_cast<int32_t>(v) - 139;
+ } else if (v <= 250) {
+ uint8_t w = 0;
+ if (!char_string->ReadU8(&w)) {
+ return OTS_FAILURE();
+ }
+ *out_number = ((static_cast<int32_t>(v) - 247) * 256) +
+ static_cast<int32_t>(w) + 108;
+ } else if (v <= 254) {
+ uint8_t w = 0;
+ if (!char_string->ReadU8(&w)) {
+ return OTS_FAILURE();
+ }
+ *out_number = -((static_cast<int32_t>(v) - 251) * 256) -
+ static_cast<int32_t>(w) - 108;
+ } else if (v == 255) {
+ // TODO(yusukes): We should not skip the 4 bytes. Note that when v is 255,
+ // we should treat the following 4-bytes as a 16.16 fixed-point number
+ // rather than 32bit signed int.
+ if (!char_string->Skip(4)) {
+ return OTS_FAILURE();
+ }
+ *out_number = dummy_result;
+ } else {
+ return OTS_FAILURE();
+ }
+
+ return true;
+}
+
+// Executes |op| and updates |argument_stack|. Returns true if the execution
+// succeeds. If the |op| is kCallSubr or kCallGSubr, the function recursively
+// calls ExecuteType2CharString() function. The arguments other than |op| and
+// |argument_stack| are passed for that reason.
+bool ExecuteType2CharStringOperator(ots::OpenTypeFile *file,
+ int32_t op,
+ size_t call_depth,
+ const ots::CFFIndex& global_subrs_index,
+ const ots::CFFIndex& local_subrs_index,
+ ots::Buffer *cff_table,
+ ots::Buffer *char_string,
+ std::stack<int32_t> *argument_stack,
+ bool *out_found_endchar,
+ bool *in_out_found_width,
+ size_t *in_out_num_stems) {
+ const size_t stack_size = argument_stack->size();
+
+ switch (op) {
+ case ots::kCallSubr:
+ case ots::kCallGSubr: {
+ const ots::CFFIndex& subrs_index =
+ (op == ots::kCallSubr ? local_subrs_index : global_subrs_index);
+
+ if (stack_size < 1) {
+ return OTS_FAILURE();
+ }
+ int32_t subr_number = argument_stack->top();
+ argument_stack->pop();
+ if (subr_number == dummy_result) {
+ // For safety, we allow subr calls only with immediate subr numbers for
+ // now. For example, we allow "123 callgsubr", but does not allow "100 12
+ // add callgsubr". Please note that arithmetic and conditional operators
+ // always push the |dummy_result| in this implementation.
+ return OTS_FAILURE();
+ }
+
+ // See Adobe Technical Note #5176 (CFF), "16. Local/GlobalSubrs INDEXes."
+ int32_t bias = 32768;
+ if (subrs_index.count < 1240) {
+ bias = 107;
+ } else if (subrs_index.count < 33900) {
+ bias = 1131;
+ }
+ subr_number += bias;
+
+ // Sanity checks of |subr_number|.
+ if (subr_number < 0) {
+ return OTS_FAILURE();
+ }
+ if (subr_number >= kMaxSubrsCount) {
+ return OTS_FAILURE();
+ }
+ if (subrs_index.offsets.size() <= static_cast<size_t>(subr_number + 1)) {
+ return OTS_FAILURE(); // The number is out-of-bounds.
+ }
+
+ // Prepare ots::Buffer where we're going to jump.
+ const size_t length =
+ subrs_index.offsets[subr_number + 1] - subrs_index.offsets[subr_number];
+ if (length > kMaxCharStringLength) {
+ return OTS_FAILURE();
+ }
+ const size_t offset = subrs_index.offsets[subr_number];
+ cff_table->set_offset(offset);
+ if (!cff_table->Skip(length)) {
+ return OTS_FAILURE();
+ }
+ ots::Buffer char_string_to_jump(cff_table->buffer() + offset, length);
+
+ return ExecuteType2CharString(file,
+ call_depth + 1,
+ global_subrs_index,
+ local_subrs_index,
+ cff_table,
+ &char_string_to_jump,
+ argument_stack,
+ out_found_endchar,
+ in_out_found_width,
+ in_out_num_stems);
+ }
+
+ case ots::kReturn:
+ return true;
+
+ case ots::kEndChar:
+ *out_found_endchar = true;
+ *in_out_found_width = true; // just in case.
+ return true;
+
+ case ots::kHStem:
+ case ots::kVStem:
+ case ots::kHStemHm:
+ case ots::kVStemHm: {
+ bool successful = false;
+ if (stack_size < 2) {
+ return OTS_FAILURE();
+ }
+ if ((stack_size % 2) == 0) {
+ successful = true;
+ } else if ((!(*in_out_found_width)) && (((stack_size - 1) % 2) == 0)) {
+ // The -1 is for "width" argument. For details, see Adobe Technical Note
+ // #5177, page 16, note 4.
+ successful = true;
+ }
+ (*in_out_num_stems) += (stack_size / 2);
+ if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ *in_out_found_width = true; // always set true since "w" might be 0 byte.
+ return successful ? true : OTS_FAILURE();
+ }
+
+ case ots::kRMoveTo: {
+ bool successful = false;
+ if (stack_size == 2) {
+ successful = true;
+ } else if ((!(*in_out_found_width)) && (stack_size - 1 == 2)) {
+ successful = true;
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ *in_out_found_width = true;
+ return successful ? true : OTS_FAILURE();
+ }
+
+ case ots::kVMoveTo:
+ case ots::kHMoveTo: {
+ bool successful = false;
+ if (stack_size == 1) {
+ successful = true;
+ } else if ((!(*in_out_found_width)) && (stack_size - 1 == 1)) {
+ successful = true;
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ *in_out_found_width = true;
+ return successful ? true : OTS_FAILURE();
+ }
+
+ case ots::kHintMask:
+ case ots::kCntrMask: {
+ bool successful = false;
+ if (stack_size == 0) {
+ successful = true;
+ } else if ((!(*in_out_found_width)) && (stack_size == 1)) {
+ // A number for "width" is found.
+ successful = true;
+ } else if ((!(*in_out_found_width)) || // in this case, any sizes are ok.
+ ((stack_size % 2) == 0)) {
+ // The numbers are vstem definition.
+ // See Adobe Technical Note #5177, page 24, hintmask.
+ (*in_out_num_stems) += (stack_size / 2);
+ if ((*in_out_num_stems) > kMaxNumberOfStemHints) {
+ return OTS_FAILURE();
+ }
+ successful = true;
+ }
+ if (!successful) {
+ return OTS_FAILURE();
+ }
+
+ if ((*in_out_num_stems) == 0) {
+ return OTS_FAILURE();
+ }
+ const size_t mask_bytes = (*in_out_num_stems + 7) / 8;
+ if (!char_string->Skip(mask_bytes)) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ *in_out_found_width = true;
+ return true;
+ }
+
+ case ots::kRLineTo:
+ if (!(*in_out_found_width)) {
+ // The first stack-clearing operator should be one of hstem, hstemhm,
+ // vstem, vstemhm, cntrmask, hintmask, hmoveto, vmoveto, rmoveto, or
+ // endchar. For details, see Adobe Technical Note #5177, page 16, note 4.
+ return OTS_FAILURE();
+ }
+ if (stack_size < 2) {
+ return OTS_FAILURE();
+ }
+ if ((stack_size % 2) != 0) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kHLineTo:
+ case ots::kVLineTo:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size < 1) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kRRCurveTo:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size < 6) {
+ return OTS_FAILURE();
+ }
+ if ((stack_size % 6) != 0) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kRCurveLine:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size < 8) {
+ return OTS_FAILURE();
+ }
+ if (((stack_size - 2) % 6) != 0) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kRLineCurve:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size < 8) {
+ return OTS_FAILURE();
+ }
+ if (((stack_size - 6) % 2) != 0) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kVVCurveTo:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size < 4) {
+ return OTS_FAILURE();
+ }
+ if (((stack_size % 4) != 0) &&
+ (((stack_size - 1) % 4) != 0)) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kHHCurveTo: {
+ bool successful = false;
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size < 4) {
+ return OTS_FAILURE();
+ }
+ if ((stack_size % 4) == 0) {
+ // {dxa dxb dyb dxc}+
+ successful = true;
+ } else if (((stack_size - 1) % 4) == 0) {
+ // dy1? {dxa dxb dyb dxc}+
+ successful = true;
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return successful ? true : OTS_FAILURE();
+ }
+
+ case ots::kVHCurveTo:
+ case ots::kHVCurveTo: {
+ bool successful = false;
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size < 4) {
+ return OTS_FAILURE();
+ }
+ if (((stack_size - 4) % 8) == 0) {
+ // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}*
+ successful = true;
+ } else if ((stack_size >= 5) &&
+ ((stack_size - 5) % 8) == 0) {
+ // dx1 dx2 dy2 dy3 {dya dxb dyb dxc dxd dxe dye dyf}* dxf
+ successful = true;
+ } else if ((stack_size >= 8) &&
+ ((stack_size - 8) % 8) == 0) {
+ // {dxa dxb dyb dyc dyd dxe dye dxf}+
+ successful = true;
+ } else if ((stack_size >= 9) &&
+ ((stack_size - 9) % 8) == 0) {
+ // {dxa dxb dyb dyc dyd dxe dye dxf}+ dyf?
+ successful = true;
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return successful ? true : OTS_FAILURE();
+ }
+
+ case ots::kDotSection:
+ // Deprecated operator but harmless, we probably should drop it some how.
+ if (stack_size != 0) {
+ return OTS_FAILURE();
+ }
+ return true;
+
+ case ots::kAnd:
+ case ots::kOr:
+ case ots::kEq:
+ case ots::kAdd:
+ case ots::kSub:
+ if (stack_size < 2) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kNot:
+ case ots::kAbs:
+ case ots::kNeg:
+ if (stack_size < 1) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kDiv:
+ // TODO(yusukes): Should detect div-by-zero errors.
+ if (stack_size < 2) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kDrop:
+ if (stack_size < 1) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ return true;
+
+ case ots::kPut:
+ case ots::kGet:
+ case ots::kIndex:
+ // For now, just call OTS_FAILURE since there is no way to check whether the
+ // index argument, |i|, is out-of-bounds or not. Fortunately, no OpenType
+ // fonts I have (except malicious ones!) use the operators.
+ // TODO(yusukes): Implement them in a secure way.
+ return OTS_FAILURE();
+
+ case ots::kRoll:
+ // Likewise, just call OTS_FAILURE for kRoll since there is no way to check
+ // whether |N| is smaller than the current stack depth or not.
+ // TODO(yusukes): Implement them in a secure way.
+ return OTS_FAILURE();
+
+ case ots::kRandom:
+ // For now, we don't handle the 'random' operator since the operator makes
+ // it hard to analyze hinting code statically.
+ return OTS_FAILURE();
+
+ case ots::kIfElse:
+ if (stack_size < 4) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->pop();
+ argument_stack->pop();
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kMul:
+ // TODO(yusukes): Should detect overflows.
+ if (stack_size < 2) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kSqrt:
+ // TODO(yusukes): Should check if the argument is negative.
+ if (stack_size < 1) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kDup:
+ if (stack_size < 1) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ argument_stack->push(dummy_result);
+ if (argument_stack->size() > kMaxArgumentStack) {
+ return OTS_FAILURE();
+ }
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kExch:
+ if (stack_size < 2) {
+ return OTS_FAILURE();
+ }
+ argument_stack->pop();
+ argument_stack->pop();
+ argument_stack->push(dummy_result);
+ argument_stack->push(dummy_result);
+ // TODO(yusukes): Implement this. We should push a real value for all
+ // arithmetic and conditional operations.
+ return true;
+
+ case ots::kHFlex:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size != 7) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kFlex:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size != 13) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kHFlex1:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size != 9) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+
+ case ots::kFlex1:
+ if (!(*in_out_found_width)) {
+ return OTS_FAILURE();
+ }
+ if (stack_size != 11) {
+ return OTS_FAILURE();
+ }
+ while (!argument_stack->empty())
+ argument_stack->pop();
+ return true;
+ }
+
+ return OTS_FAILURE_MSG("Undefined operator: %d (0x%x)", op, op);
+}
+
+// Executes |char_string| and updates |argument_stack|.
+//
+// call_depth: The current call depth. Initial value is zero.
+// global_subrs_index: Global subroutines.
+// local_subrs_index: Local subroutines for the current glyph.
+// cff_table: A whole CFF table which contains all global and local subroutines.
+// char_string: A charstring we'll execute. |char_string| can be a main routine
+// in CharString INDEX, or a subroutine in GlobalSubr/LocalSubr.
+// argument_stack: The stack which an operator in |char_string| operates.
+// out_found_endchar: true is set if |char_string| contains 'endchar'.
+// in_out_found_width: true is set if |char_string| contains 'width' byte (which
+// is 0 or 1 byte.)
+// in_out_num_stems: total number of hstems and vstems processed so far.
+bool ExecuteType2CharString(ots::OpenTypeFile *file,
+ size_t call_depth,
+ const ots::CFFIndex& global_subrs_index,
+ const ots::CFFIndex& local_subrs_index,
+ ots::Buffer *cff_table,
+ ots::Buffer *char_string,
+ std::stack<int32_t> *argument_stack,
+ bool *out_found_endchar,
+ bool *in_out_found_width,
+ size_t *in_out_num_stems) {
+ if (call_depth > kMaxSubrNesting) {
+ return OTS_FAILURE();
+ }
+ *out_found_endchar = false;
+
+ const size_t length = char_string->length();
+ while (char_string->offset() < length) {
+ int32_t operator_or_operand = 0;
+ bool is_operator = false;
+ if (!ReadNextNumberFromType2CharString(char_string,
+ &operator_or_operand,
+ &is_operator)) {
+ return OTS_FAILURE();
+ }
+
+#ifdef DUMP_T2CHARSTRING
+ /*
+ You can dump all operators and operands (except mask bytes for hintmask
+ and cntrmask) by the following code:
+ */
+
+ if (!is_operator) {
+ std::fprintf(stderr, "#%d# ", operator_or_operand);
+ } else {
+ std::fprintf(stderr, "#%s#\n",
+ Type2CharStringOperatorToString(
+ ots::Type2CharStringOperator(operator_or_operand))
+ );
+ }
+#endif
+
+ if (!is_operator) {
+ argument_stack->push(operator_or_operand);
+ if (argument_stack->size() > kMaxArgumentStack) {
+ return OTS_FAILURE();
+ }
+ continue;
+ }
+
+ // An operator is found. Execute it.
+ if (!ExecuteType2CharStringOperator(file,
+ operator_or_operand,
+ call_depth,
+ global_subrs_index,
+ local_subrs_index,
+ cff_table,
+ char_string,
+ argument_stack,
+ out_found_endchar,
+ in_out_found_width,
+ in_out_num_stems)) {
+ return OTS_FAILURE();
+ }
+ if (*out_found_endchar) {
+ return true;
+ }
+ if (operator_or_operand == ots::kReturn) {
+ return true;
+ }
+ }
+
+ // No endchar operator is found.
+ return OTS_FAILURE();
+}
+
+// Selects a set of subroutings for |glyph_index| from |cff| and sets it on
+// |out_local_subrs_to_use|. Returns true on success.
+bool SelectLocalSubr(const std::map<uint16_t, uint8_t> &fd_select,
+ const std::vector<ots::CFFIndex *> &local_subrs_per_font,
+ const ots::CFFIndex *local_subrs,
+ uint16_t glyph_index, // 0-origin
+ const ots::CFFIndex **out_local_subrs_to_use) {
+ *out_local_subrs_to_use = NULL;
+
+ // First, find local subrs from |local_subrs_per_font|.
+ if ((fd_select.size() > 0) &&
+ (!local_subrs_per_font.empty())) {
+ // Look up FDArray index for the glyph.
+ std::map<uint16_t, uint8_t>::const_iterator iter =
+ fd_select.find(glyph_index);
+ if (iter == fd_select.end()) {
+ return OTS_FAILURE();
+ }
+ const uint8_t fd_index = iter->second;
+ if (fd_index >= local_subrs_per_font.size()) {
+ return OTS_FAILURE();
+ }
+ *out_local_subrs_to_use = local_subrs_per_font.at(fd_index);
+ } else if (local_subrs) {
+ // Second, try to use |local_subrs|. Most Latin fonts don't have FDSelect
+ // entries. If The font has a local subrs index associated with the Top
+ // DICT (not FDArrays), use it.
+ *out_local_subrs_to_use = local_subrs;
+ } else {
+ // Just return NULL.
+ *out_local_subrs_to_use = NULL;
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace ots {
+
+bool ValidateType2CharStringIndex(
+ ots::OpenTypeFile *file,
+ const CFFIndex& char_strings_index,
+ const CFFIndex& global_subrs_index,
+ const std::map<uint16_t, uint8_t> &fd_select,
+ const std::vector<CFFIndex *> &local_subrs_per_font,
+ const CFFIndex *local_subrs,
+ Buffer* cff_table) {
+ const uint16_t num_offsets =
+ static_cast<uint16_t>(char_strings_index.offsets.size());
+ if (num_offsets != char_strings_index.offsets.size() || num_offsets == 0) {
+ return OTS_FAILURE(); // no charstring.
+ }
+
+ // For each glyph, validate the corresponding charstring.
+ for (uint16_t i = 1; i < num_offsets; ++i) {
+ // Prepare a Buffer object, |char_string|, which contains the charstring
+ // for the |i|-th glyph.
+ const size_t length =
+ char_strings_index.offsets[i] - char_strings_index.offsets[i - 1];
+ if (length > kMaxCharStringLength) {
+ return OTS_FAILURE();
+ }
+ const size_t offset = char_strings_index.offsets[i - 1];
+ cff_table->set_offset(offset);
+ if (!cff_table->Skip(length)) {
+ return OTS_FAILURE();
+ }
+ Buffer char_string(cff_table->buffer() + offset, length);
+
+ // Get a local subrs for the glyph.
+ const uint16_t glyph_index = i - 1; // index in the map is 0-origin.
+ const CFFIndex *local_subrs_to_use = NULL;
+ if (!SelectLocalSubr(fd_select,
+ local_subrs_per_font,
+ local_subrs,
+ glyph_index,
+ &local_subrs_to_use)) {
+ return OTS_FAILURE();
+ }
+ // If |local_subrs_to_use| is still NULL, use an empty one.
+ CFFIndex default_empty_subrs;
+ if (!local_subrs_to_use){
+ local_subrs_to_use = &default_empty_subrs;
+ }
+
+ // Check a charstring for the |i|-th glyph.
+ std::stack<int32_t> argument_stack;
+ bool found_endchar = false;
+ bool found_width = false;
+ size_t num_stems = 0;
+ if (!ExecuteType2CharString(file,
+ 0 /* initial call_depth is zero */,
+ global_subrs_index, *local_subrs_to_use,
+ cff_table, &char_string, &argument_stack,
+ &found_endchar, &found_width, &num_stems)) {
+ return OTS_FAILURE();
+ }
+ if (!found_endchar) {
+ return OTS_FAILURE();
+ }
+ }
+ return true;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/cff_type2_charstring.h b/third_party/ots/src/cff_type2_charstring.h
new file mode 100644
index 0000000..6732342
--- /dev/null
+++ b/third_party/ots/src/cff_type2_charstring.h
@@ -0,0 +1,101 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CFF_TYPE2_CHARSTRING_H_
+#define OTS_CFF_TYPE2_CHARSTRING_H_
+
+#include "cff.h"
+#include "ots.h"
+
+#include <map>
+#include <vector>
+
+namespace ots {
+
+// Validates all charstrings in |char_strings_index|. Charstring is a small
+// language for font hinting defined in Adobe Technical Note #5177.
+// http://www.adobe.com/devnet/font/pdfs/5177.Type2.pdf
+//
+// The validation will fail if one of the following conditions is met:
+// 1. The code uses more than 48 values of argument stack.
+// 2. The code uses deeply nested subroutine calls (more than 10 levels.)
+// 3. The code passes invalid number of operands to an operator.
+// 4. The code calls an undefined global or local subroutine.
+// 5. The code uses one of the following operators that are unlikely used in
+// an ordinary fonts, and could be dangerous: random, put, get, index, roll.
+//
+// Arguments:
+// global_subrs_index: Global subroutines which could be called by a charstring
+// in |char_strings_index|.
+// fd_select: A map from glyph # to font #.
+// local_subrs_per_font: A list of Local Subrs associated with FDArrays. Can be
+// empty.
+// local_subrs: A Local Subrs associated with Top DICT. Can be NULL.
+// cff_table: A buffer which contains actual byte code of charstring, global
+// subroutines and local subroutines.
+bool ValidateType2CharStringIndex(
+ OpenTypeFile *file,
+ const CFFIndex &char_strings_index,
+ const CFFIndex &global_subrs_index,
+ const std::map<uint16_t, uint8_t> &fd_select,
+ const std::vector<CFFIndex *> &local_subrs_per_font,
+ const CFFIndex *local_subrs,
+ Buffer *cff_table);
+
+// The list of Operators. See Appendix. A in Adobe Technical Note #5177.
+enum Type2CharStringOperator {
+ kHStem = 1,
+ kVStem = 3,
+ kVMoveTo = 4,
+ kRLineTo = 5,
+ kHLineTo = 6,
+ kVLineTo = 7,
+ kRRCurveTo = 8,
+ kCallSubr = 10,
+ kReturn = 11,
+ kEndChar = 14,
+ kHStemHm = 18,
+ kHintMask = 19,
+ kCntrMask = 20,
+ kRMoveTo = 21,
+ kHMoveTo = 22,
+ kVStemHm = 23,
+ kRCurveLine = 24,
+ kRLineCurve = 25,
+ kVVCurveTo = 26,
+ kHHCurveTo = 27,
+ kCallGSubr = 29,
+ kVHCurveTo = 30,
+ kHVCurveTo = 31,
+ kDotSection = 12 << 8,
+ kAnd = (12 << 8) + 3,
+ kOr = (12 << 8) + 4,
+ kNot = (12 << 8) + 5,
+ kAbs = (12 << 8) + 9,
+ kAdd = (12 << 8) + 10,
+ kSub = (12 << 8) + 11,
+ kDiv = (12 << 8) + 12,
+ kNeg = (12 << 8) + 14,
+ kEq = (12 << 8) + 15,
+ kDrop = (12 << 8) + 18,
+ kPut = (12 << 8) + 20,
+ kGet = (12 << 8) + 21,
+ kIfElse = (12 << 8) + 22,
+ kRandom = (12 << 8) + 23,
+ kMul = (12 << 8) + 24,
+ kSqrt = (12 << 8) + 26,
+ kDup = (12 << 8) + 27,
+ kExch = (12 << 8) + 28,
+ kIndex = (12 << 8) + 29,
+ kRoll = (12 << 8) + 30,
+ kHFlex = (12 << 8) + 34,
+ kFlex = (12 << 8) + 35,
+ kHFlex1 = (12 << 8) + 36,
+ kFlex1 = (12 << 8) + 37,
+ // Operators that are undocumented, such as 'blend', will be rejected.
+};
+
+} // namespace ots
+
+#endif // OTS_CFF_TYPE2_CHARSTRING_H_
diff --git a/third_party/ots/src/cmap.cc b/third_party/ots/src/cmap.cc
new file mode 100644
index 0000000..d9ca9fa
--- /dev/null
+++ b/third_party/ots/src/cmap.cc
@@ -0,0 +1,1106 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cmap.h"
+
+#include <algorithm>
+#include <set>
+#include <utility>
+#include <vector>
+
+#include "maxp.h"
+#include "os2.h"
+
+// cmap - Character To Glyph Index Mapping Table
+// http://www.microsoft.com/typography/otspec/cmap.htm
+
+#define TABLE_NAME "cmap"
+
+namespace {
+
+struct CMAPSubtableHeader {
+ uint16_t platform;
+ uint16_t encoding;
+ uint32_t offset;
+ uint16_t format;
+ uint32_t length;
+ uint32_t language;
+};
+
+struct Subtable314Range {
+ uint16_t start_range;
+ uint16_t end_range;
+ int16_t id_delta;
+ uint16_t id_range_offset;
+ uint32_t id_range_offset_offset;
+};
+
+// The maximum number of groups in format 12, 13 or 14 subtables.
+// Note: 0xFFFF is the maximum number of glyphs in a single font file.
+const unsigned kMaxCMAPGroups = 0xFFFF;
+
+// Glyph array size for the Mac Roman (format 0) table.
+const size_t kFormat0ArraySize = 256;
+
+// The upper limit of the Unicode code point.
+const uint32_t kUnicodeUpperLimit = 0x10FFFF;
+
+// The maximum number of UVS records (See below).
+const uint32_t kMaxCMAPSelectorRecords = 259;
+// The range of UVSes are:
+// 0x180B-0x180D (3 code points)
+// 0xFE00-0xFE0F (16 code points)
+// 0xE0100-0xE01EF (240 code points)
+const uint32_t kMongolianVSStart = 0x180B;
+const uint32_t kMongolianVSEnd = 0x180D;
+const uint32_t kVSStart = 0xFE00;
+const uint32_t kVSEnd = 0xFE0F;
+const uint32_t kIVSStart = 0xE0100;
+const uint32_t kIVSEnd = 0xE01EF;
+const uint32_t kUVSUpperLimit = 0xFFFFFF;
+
+// Parses Format 4 tables
+bool ParseFormat4(ots::OpenTypeFile *file, int platform, int encoding,
+ const uint8_t *data, size_t length, uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // 0.3.4, 3.0.4 or 3.1.4 subtables are complex and, rather than expanding the
+ // whole thing and recompacting it, we validate it and include it verbatim
+ // in the output.
+
+ if (!file->os2) {
+ return OTS_FAILURE_MSG("Required OS/2 table missing");
+ }
+
+ if (!subtable.Skip(4)) {
+ return OTS_FAILURE_MSG("Can't read 4 bytes at start of cmap format 4 subtable");
+ }
+ uint16_t language = 0;
+ if (!subtable.ReadU16(&language)) {
+ return OTS_FAILURE_MSG("Can't read language");
+ }
+ if (language) {
+ // Platform ID 3 (windows) subtables should have language '0'.
+ return OTS_FAILURE_MSG("Languages should be 0 (%d)", language);
+ }
+
+ uint16_t segcountx2, search_range, entry_selector, range_shift;
+ segcountx2 = search_range = entry_selector = range_shift = 0;
+ if (!subtable.ReadU16(&segcountx2) ||
+ !subtable.ReadU16(&search_range) ||
+ !subtable.ReadU16(&entry_selector) ||
+ !subtable.ReadU16(&range_shift)) {
+ return OTS_FAILURE_MSG("Failed to read subcmap structure");
+ }
+
+ if (segcountx2 & 1 || search_range & 1) {
+ return OTS_FAILURE_MSG("Bad subcmap structure");
+ }
+ const uint16_t segcount = segcountx2 >> 1;
+ // There must be at least one segment according the spec.
+ if (segcount < 1) {
+ return OTS_FAILURE_MSG("Segcount < 1 (%d)", segcount);
+ }
+
+ // log2segcount is the maximal x s.t. 2^x < segcount
+ unsigned log2segcount = 0;
+ while (1u << (log2segcount + 1) <= segcount) {
+ log2segcount++;
+ }
+
+ const uint16_t expected_search_range = 2 * 1u << log2segcount;
+ if (expected_search_range != search_range) {
+ return OTS_FAILURE_MSG("expected search range != search range (%d != %d)", expected_search_range, search_range);
+ }
+
+ if (entry_selector != log2segcount) {
+ return OTS_FAILURE_MSG("entry selector != log2(segement count) (%d != %d)", entry_selector, log2segcount);
+ }
+
+ const uint16_t expected_range_shift = segcountx2 - search_range;
+ if (range_shift != expected_range_shift) {
+ return OTS_FAILURE_MSG("unexpected range shift (%d != %d)", range_shift, expected_range_shift);
+ }
+
+ std::vector<Subtable314Range> ranges(segcount);
+
+ for (unsigned i = 0; i < segcount; ++i) {
+ if (!subtable.ReadU16(&ranges[i].end_range)) {
+ return OTS_FAILURE_MSG("Failed to read segment %d", i);
+ }
+ }
+
+ uint16_t padding;
+ if (!subtable.ReadU16(&padding)) {
+ return OTS_FAILURE_MSG("Failed to read cmap subtable segment padding");
+ }
+ if (padding) {
+ return OTS_FAILURE_MSG("Non zero cmap subtable segment padding (%d)", padding);
+ }
+
+ for (unsigned i = 0; i < segcount; ++i) {
+ if (!subtable.ReadU16(&ranges[i].start_range)) {
+ return OTS_FAILURE_MSG("Failed to read segment start range %d", i);
+ }
+ }
+ for (unsigned i = 0; i < segcount; ++i) {
+ if (!subtable.ReadS16(&ranges[i].id_delta)) {
+ return OTS_FAILURE_MSG("Failed to read segment delta %d", i);
+ }
+ }
+ for (unsigned i = 0; i < segcount; ++i) {
+ ranges[i].id_range_offset_offset = subtable.offset();
+ if (!subtable.ReadU16(&ranges[i].id_range_offset)) {
+ return OTS_FAILURE_MSG("Failed to read segment range offset %d", i);
+ }
+
+ if (ranges[i].id_range_offset & 1) {
+ // Some font generators seem to put 65535 on id_range_offset
+ // for 0xFFFF-0xFFFF range.
+ // (e.g., many fonts in http://www.princexml.com/fonts/)
+ if (i == segcount - 1u) {
+ OTS_WARNING("bad id_range_offset");
+ ranges[i].id_range_offset = 0;
+ // The id_range_offset value in the transcoded font will not change
+ // since this table is not actually "transcoded" yet.
+ } else {
+ return OTS_FAILURE_MSG("Bad segment offset (%d)", ranges[i].id_range_offset);
+ }
+ }
+ }
+
+ // ranges must be ascending order, based on the end_code. Ranges may not
+ // overlap.
+ for (unsigned i = 1; i < segcount; ++i) {
+ if ((i == segcount - 1u) &&
+ (ranges[i - 1].start_range == 0xffff) &&
+ (ranges[i - 1].end_range == 0xffff) &&
+ (ranges[i].start_range == 0xffff) &&
+ (ranges[i].end_range == 0xffff)) {
+ // Some fonts (e.g., Germania.ttf) have multiple 0xffff terminators.
+ // We'll accept them as an exception.
+ OTS_WARNING("multiple 0xffff terminators found");
+ continue;
+ }
+
+ // Note: some Linux fonts (e.g., LucidaSansOblique.ttf, bsmi00lp.ttf) have
+ // unsorted table...
+ if (ranges[i].end_range <= ranges[i - 1].end_range) {
+ return OTS_FAILURE_MSG("Out of order end range (%d <= %d)", ranges[i].end_range, ranges[i-1].end_range);
+ }
+ if (ranges[i].start_range <= ranges[i - 1].end_range) {
+ return OTS_FAILURE_MSG("out of order start range (%d <= %d)", ranges[i].start_range, ranges[i-1].end_range);
+ }
+
+ // On many fonts, the value of {first, last}_char_index are incorrect.
+ // Fix them.
+ if (file->os2->first_char_index != 0xFFFF &&
+ ranges[i].start_range != 0xFFFF &&
+ file->os2->first_char_index > ranges[i].start_range) {
+ file->os2->first_char_index = ranges[i].start_range;
+ }
+ if (file->os2->last_char_index != 0xFFFF &&
+ ranges[i].end_range != 0xFFFF &&
+ file->os2->last_char_index < ranges[i].end_range) {
+ file->os2->last_char_index = ranges[i].end_range;
+ }
+ }
+
+ // The last range must end at 0xffff
+ if (ranges[segcount - 1].start_range != 0xffff || ranges[segcount - 1].end_range != 0xffff) {
+ return OTS_FAILURE_MSG("Final segment start and end must be 0xFFFF (0x%04X-0x%04X)",
+ ranges[segcount - 1].start_range, ranges[segcount - 1].end_range);
+ }
+
+ // A format 4 CMAP subtable is complex. To be safe we simulate a lookup of
+ // each code-point defined in the table and make sure that they are all valid
+ // glyphs and that we don't access anything out-of-bounds.
+ for (unsigned i = 0; i < segcount; ++i) {
+ for (unsigned cp = ranges[i].start_range; cp <= ranges[i].end_range; ++cp) {
+ const uint16_t code_point = static_cast<uint16_t>(cp);
+ if (ranges[i].id_range_offset == 0) {
+ // this is explictly allowed to overflow in the spec
+ const uint16_t glyph = code_point + ranges[i].id_delta;
+ if (glyph >= num_glyphs) {
+ return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
+ }
+ } else {
+ const uint16_t range_delta = code_point - ranges[i].start_range;
+ // this might seem odd, but it's true. The offset is relative to the
+ // location of the offset value itself.
+ const uint32_t glyph_id_offset = ranges[i].id_range_offset_offset +
+ ranges[i].id_range_offset +
+ range_delta * 2;
+ // We need to be able to access a 16-bit value from this offset
+ if (glyph_id_offset + 1 >= length) {
+ return OTS_FAILURE_MSG("bad glyph id offset (%d > %ld)", glyph_id_offset, length);
+ }
+ uint16_t glyph;
+ std::memcpy(&glyph, data + glyph_id_offset, 2);
+ glyph = ntohs(glyph);
+ if (glyph >= num_glyphs) {
+ return OTS_FAILURE_MSG("Range glyph reference too high (%d > %d)", glyph, num_glyphs - 1);
+ }
+ }
+ }
+ }
+
+ // We accept the table.
+ // TODO(yusukes): transcode the subtable.
+ if (platform == 3 && encoding == 0) {
+ file->cmap->subtable_3_0_4_data = data;
+ file->cmap->subtable_3_0_4_length = length;
+ } else if (platform == 3 && encoding == 1) {
+ file->cmap->subtable_3_1_4_data = data;
+ file->cmap->subtable_3_1_4_length = length;
+ } else if (platform == 0 && encoding == 3) {
+ file->cmap->subtable_0_3_4_data = data;
+ file->cmap->subtable_0_3_4_length = length;
+ } else {
+ return OTS_FAILURE_MSG("Unknown cmap subtable type (platform=%d, encoding=%d)", platform, encoding);
+ }
+
+ return true;
+}
+
+bool Parse31012(ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length, uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Format 12 tables are simple. We parse these and fully serialise them
+ // later.
+
+ if (!subtable.Skip(8)) {
+ return OTS_FAILURE_MSG("failed to skip the first 8 bytes of format 12 subtable");
+ }
+ uint32_t language = 0;
+ if (!subtable.ReadU32(&language)) {
+ return OTS_FAILURE_MSG("can't read format 12 subtable language");
+ }
+ if (language) {
+ return OTS_FAILURE_MSG("format 12 subtable language should be zero (%d)", language);
+ }
+
+ uint32_t num_groups = 0;
+ if (!subtable.ReadU32(&num_groups)) {
+ return OTS_FAILURE_MSG("can't read number of format 12 subtable groups");
+ }
+ if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
+ return OTS_FAILURE_MSG("bad format 12 subtable group count %d", num_groups);
+ }
+
+ std::vector<ots::OpenTypeCMAPSubtableRange> &groups
+ = file->cmap->subtable_3_10_12;
+ groups.resize(num_groups);
+
+ for (unsigned i = 0; i < num_groups; ++i) {
+ if (!subtable.ReadU32(&groups[i].start_range) ||
+ !subtable.ReadU32(&groups[i].end_range) ||
+ !subtable.ReadU32(&groups[i].start_glyph_id)) {
+ return OTS_FAILURE_MSG("can't read format 12 subtable group");
+ }
+
+ if (groups[i].start_range > kUnicodeUpperLimit ||
+ groups[i].end_range > kUnicodeUpperLimit ||
+ groups[i].start_glyph_id > 0xFFFF) {
+ return OTS_FAILURE_MSG("bad format 12 subtable group (startCharCode=0x%4X, endCharCode=0x%4X, startGlyphID=%d)",
+ groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
+ }
+
+ // [0xD800, 0xDFFF] are surrogate code points.
+ if (groups[i].start_range >= 0xD800 &&
+ groups[i].start_range <= 0xDFFF) {
+ return OTS_FAILURE_MSG("format 12 subtable out of range group startCharCode (0x%4X)", groups[i].start_range);
+ }
+ if (groups[i].end_range >= 0xD800 &&
+ groups[i].end_range <= 0xDFFF) {
+ return OTS_FAILURE_MSG("format 12 subtable out of range group endCharCode (0x%4X)", groups[i].end_range);
+ }
+ if (groups[i].start_range < 0xD800 &&
+ groups[i].end_range > 0xDFFF) {
+ return OTS_FAILURE_MSG("bad format 12 subtable group startCharCode (0x%4X) or endCharCode (0x%4X)",
+ groups[i].start_range, groups[i].end_range);
+ }
+
+ // We assert that the glyph value is within range. Because of the range
+ // limits, above, we don't need to worry about overflow.
+ if (groups[i].end_range < groups[i].start_range) {
+ return OTS_FAILURE_MSG("format 12 subtable group endCharCode before startCharCode (0x%4X < 0x%4X)",
+ groups[i].end_range, groups[i].start_range);
+ }
+ if ((groups[i].end_range - groups[i].start_range) +
+ groups[i].start_glyph_id > num_glyphs) {
+ return OTS_FAILURE_MSG("bad format 12 subtable group startGlyphID (%d)", groups[i].start_glyph_id);
+ }
+ }
+
+ // the groups must be sorted by start code and may not overlap
+ for (unsigned i = 1; i < num_groups; ++i) {
+ if (groups[i].start_range <= groups[i - 1].start_range) {
+ return OTS_FAILURE_MSG("out of order format 12 subtable group (startCharCode=0x%4X <= startCharCode=0x%4X of previous group)",
+ groups[i].start_range, groups[i-1].start_range);
+ }
+ if (groups[i].start_range <= groups[i - 1].end_range) {
+ return OTS_FAILURE_MSG("overlapping format 12 subtable groups (startCharCode=0x%4X <= endCharCode=0x%4X of previous group)",
+ groups[i].start_range, groups[i-1].end_range);
+ }
+ }
+
+ return true;
+}
+
+bool Parse31013(ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length, uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Format 13 tables are simple. We parse these and fully serialise them
+ // later.
+
+ if (!subtable.Skip(8)) {
+ return OTS_FAILURE_MSG("Bad cmap subtable length");
+ }
+ uint32_t language = 0;
+ if (!subtable.ReadU32(&language)) {
+ return OTS_FAILURE_MSG("Can't read cmap subtable language");
+ }
+ if (language) {
+ return OTS_FAILURE_MSG("Cmap subtable language should be zero but is %d", language);
+ }
+
+ uint32_t num_groups = 0;
+ if (!subtable.ReadU32(&num_groups)) {
+ return OTS_FAILURE_MSG("Can't read number of groups in a cmap subtable");
+ }
+
+ // We limit the number of groups in the same way as in 3.10.12 tables. See
+ // the comment there in
+ if (num_groups == 0 || num_groups > kMaxCMAPGroups) {
+ return OTS_FAILURE_MSG("Bad number of groups (%d) in a cmap subtable", num_groups);
+ }
+
+ std::vector<ots::OpenTypeCMAPSubtableRange> &groups
+ = file->cmap->subtable_3_10_13;
+ groups.resize(num_groups);
+
+ for (unsigned i = 0; i < num_groups; ++i) {
+ if (!subtable.ReadU32(&groups[i].start_range) ||
+ !subtable.ReadU32(&groups[i].end_range) ||
+ !subtable.ReadU32(&groups[i].start_glyph_id)) {
+ return OTS_FAILURE_MSG("Can't read subrange structure in a cmap subtable");
+ }
+
+ // We conservatively limit all of the values to protect some parsers from
+ // overflows
+ if (groups[i].start_range > kUnicodeUpperLimit ||
+ groups[i].end_range > kUnicodeUpperLimit ||
+ groups[i].start_glyph_id > 0xFFFF) {
+ return OTS_FAILURE_MSG("Bad subrange with start_range=%d, end_range=%d, start_glyph_id=%d", groups[i].start_range, groups[i].end_range, groups[i].start_glyph_id);
+ }
+
+ if (groups[i].start_glyph_id >= num_glyphs) {
+ return OTS_FAILURE_MSG("Subrange starting glyph id too high (%d > %d)", groups[i].start_glyph_id, num_glyphs);
+ }
+ }
+
+ // the groups must be sorted by start code and may not overlap
+ for (unsigned i = 1; i < num_groups; ++i) {
+ if (groups[i].start_range <= groups[i - 1].start_range) {
+ return OTS_FAILURE_MSG("Overlapping subrange starts (%d >= %d)", groups[i]. start_range, groups[i-1].start_range);
+ }
+ if (groups[i].start_range <= groups[i - 1].end_range) {
+ return OTS_FAILURE_MSG("Overlapping subranges (%d <= %d)", groups[i].start_range, groups[i-1].end_range);
+ }
+ }
+
+ return true;
+}
+
+bool Parse0514(ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length, uint16_t num_glyphs) {
+ // Unicode Variation Selector table
+ ots::Buffer subtable(data, length);
+
+ // Format 14 tables are simple. We parse these and fully serialise them
+ // later.
+
+ // Skip format (USHORT) and length (ULONG)
+ if (!subtable.Skip(6)) {
+ return OTS_FAILURE_MSG("Can't read start of cmap subtable");
+ }
+
+ uint32_t num_records = 0;
+ if (!subtable.ReadU32(&num_records)) {
+ return OTS_FAILURE_MSG("Can't read number of records in cmap subtable");
+ }
+ if (num_records == 0 || num_records > kMaxCMAPSelectorRecords) {
+ return OTS_FAILURE_MSG("Bad number of records (%d) in cmap subtable", num_records);
+ }
+
+ std::vector<ots::OpenTypeCMAPSubtableVSRecord>& records
+ = file->cmap->subtable_0_5_14;
+ records.resize(num_records);
+
+ for (unsigned i = 0; i < num_records; ++i) {
+ if (!subtable.ReadU24(&records[i].var_selector) ||
+ !subtable.ReadU32(&records[i].default_offset) ||
+ !subtable.ReadU32(&records[i].non_default_offset)) {
+ return OTS_FAILURE_MSG("Can't read record structure of record %d in cmap subtale", i);
+ }
+ // Checks the value of variation selector
+ if (!((records[i].var_selector >= kMongolianVSStart &&
+ records[i].var_selector <= kMongolianVSEnd) ||
+ (records[i].var_selector >= kVSStart &&
+ records[i].var_selector <= kVSEnd) ||
+ (records[i].var_selector >= kIVSStart &&
+ records[i].var_selector <= kIVSEnd))) {
+ return OTS_FAILURE_MSG("Bad record variation selector (%04X) in record %i", records[i].var_selector, i);
+ }
+ if (i > 0 &&
+ records[i-1].var_selector >= records[i].var_selector) {
+ return OTS_FAILURE_MSG("Out of order variation selector (%04X >= %04X) in record %d", records[i-1].var_selector, records[i].var_selector, i);
+ }
+
+ // Checks offsets
+ if (!records[i].default_offset && !records[i].non_default_offset) {
+ return OTS_FAILURE_MSG("No default aoffset in variation selector record %d", i);
+ }
+ if (records[i].default_offset &&
+ records[i].default_offset >= length) {
+ return OTS_FAILURE_MSG("Default offset too high (%d >= %ld) in record %d", records[i].default_offset, length, i);
+ }
+ if (records[i].non_default_offset &&
+ records[i].non_default_offset >= length) {
+ return OTS_FAILURE_MSG("Non default offset too high (%d >= %ld) in record %d", records[i].non_default_offset, length, i);
+ }
+ }
+
+ for (unsigned i = 0; i < num_records; ++i) {
+ // Checks default UVS table
+ if (records[i].default_offset) {
+ subtable.set_offset(records[i].default_offset);
+ uint32_t num_ranges = 0;
+ if (!subtable.ReadU32(&num_ranges)) {
+ return OTS_FAILURE_MSG("Can't read number of ranges in record %d", i);
+ }
+ if (!num_ranges || num_ranges > kMaxCMAPGroups) {
+ return OTS_FAILURE_MSG("number of ranges too high (%d > %d) in record %d", num_ranges, kMaxCMAPGroups, i);
+ }
+
+ uint32_t last_unicode_value = 0;
+ std::vector<ots::OpenTypeCMAPSubtableVSRange>& ranges
+ = records[i].ranges;
+ ranges.resize(num_ranges);
+
+ for (unsigned j = 0; j < num_ranges; ++j) {
+ if (!subtable.ReadU24(&ranges[j].unicode_value) ||
+ !subtable.ReadU8(&ranges[j].additional_count)) {
+ return OTS_FAILURE_MSG("Can't read range info in variation selector record %d", i);
+ }
+ const uint32_t check_value =
+ ranges[j].unicode_value + ranges[j].additional_count;
+ if (ranges[j].unicode_value == 0 ||
+ ranges[j].unicode_value > kUnicodeUpperLimit ||
+ check_value > kUVSUpperLimit ||
+ (last_unicode_value &&
+ ranges[j].unicode_value <= last_unicode_value)) {
+ return OTS_FAILURE_MSG("Bad Unicode value *%04X) in variation selector range %d record %d", ranges[j].unicode_value, j, i);
+ }
+ last_unicode_value = check_value;
+ }
+ }
+
+ // Checks non default UVS table
+ if (records[i].non_default_offset) {
+ subtable.set_offset(records[i].non_default_offset);
+ uint32_t num_mappings = 0;
+ if (!subtable.ReadU32(&num_mappings)) {
+ return OTS_FAILURE_MSG("Can't read number of mappings in variation selector record %d", i);
+ }
+ if (!num_mappings || num_mappings > kMaxCMAPGroups) {
+ return OTS_FAILURE_MSG("Number of mappings too high (%d) in variation selector record %d", num_mappings, i);
+ }
+
+ uint32_t last_unicode_value = 0;
+ std::vector<ots::OpenTypeCMAPSubtableVSMapping>& mappings
+ = records[i].mappings;
+ mappings.resize(num_mappings);
+
+ for (unsigned j = 0; j < num_mappings; ++j) {
+ if (!subtable.ReadU24(&mappings[j].unicode_value) ||
+ !subtable.ReadU16(&mappings[j].glyph_id)) {
+ return OTS_FAILURE_MSG("Can't read mapping %d in variation selector record %d", j, i);
+ }
+ if (mappings[j].glyph_id == 0 ||
+ mappings[j].unicode_value == 0 ||
+ mappings[j].unicode_value > kUnicodeUpperLimit ||
+ (last_unicode_value &&
+ mappings[j].unicode_value <= last_unicode_value)) {
+ return OTS_FAILURE_MSG("Bad mapping (%04X -> %d) in mapping %d of variation selector %d", mappings[j].unicode_value, mappings[j].glyph_id, j, i);
+ }
+ last_unicode_value = mappings[j].unicode_value;
+ }
+ }
+ }
+
+ if (subtable.offset() != length) {
+ return OTS_FAILURE_MSG("Bad subtable offset (%ld != %ld)", subtable.offset(), length);
+ }
+ file->cmap->subtable_0_5_14_length = subtable.offset();
+ return true;
+}
+
+bool Parse100(ots::OpenTypeFile *file, const uint8_t *data, size_t length) {
+ // Mac Roman table
+ ots::Buffer subtable(data, length);
+
+ if (!subtable.Skip(4)) {
+ return OTS_FAILURE_MSG("Bad cmap subtable");
+ }
+ uint16_t language = 0;
+ if (!subtable.ReadU16(&language)) {
+ return OTS_FAILURE_MSG("Can't read language in cmap subtable");
+ }
+ if (language) {
+ // simsun.ttf has non-zero language id.
+ OTS_WARNING("language id should be zero: %u", language);
+ }
+
+ file->cmap->subtable_1_0_0.reserve(kFormat0ArraySize);
+ for (size_t i = 0; i < kFormat0ArraySize; ++i) {
+ uint8_t glyph_id = 0;
+ if (!subtable.ReadU8(&glyph_id)) {
+ return OTS_FAILURE_MSG("Can't read glyph id at array[%ld] in cmap subtable", i);
+ }
+ file->cmap->subtable_1_0_0.push_back(glyph_id);
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace ots {
+
+bool ots_cmap_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ file->cmap = new OpenTypeCMAP;
+
+ uint16_t version = 0;
+ uint16_t num_tables = 0;
+ if (!table.ReadU16(&version) ||
+ !table.ReadU16(&num_tables)) {
+ return OTS_FAILURE_MSG("Can't read structure of cmap");
+ }
+
+ if (version != 0) {
+ return OTS_FAILURE_MSG("Non zero cmap version (%d)", version);
+ }
+ if (!num_tables) {
+ return OTS_FAILURE_MSG("No subtables in cmap!");
+ }
+
+ std::vector<CMAPSubtableHeader> subtable_headers;
+
+ // read the subtable headers
+ subtable_headers.reserve(num_tables);
+ for (unsigned i = 0; i < num_tables; ++i) {
+ CMAPSubtableHeader subt;
+
+ if (!table.ReadU16(&subt.platform) ||
+ !table.ReadU16(&subt.encoding) ||
+ !table.ReadU32(&subt.offset)) {
+ return OTS_FAILURE_MSG("Can't read subtable information cmap subtable %d", i);
+ }
+
+ subtable_headers.push_back(subt);
+ }
+
+ const size_t data_offset = table.offset();
+
+ // make sure that all the offsets are valid.
+ for (unsigned i = 0; i < num_tables; ++i) {
+ if (subtable_headers[i].offset > 1024 * 1024 * 1024) {
+ return OTS_FAILURE_MSG("Bad subtable offset in cmap subtable %d", i);
+ }
+ if (subtable_headers[i].offset < data_offset ||
+ subtable_headers[i].offset >= length) {
+ return OTS_FAILURE_MSG("Bad subtable offset (%d) in cmap subtable %d", subtable_headers[i].offset, i);
+ }
+ }
+
+ // the format of the table is the first couple of bytes in the table. The
+ // length of the table is stored in a format-specific way.
+ for (unsigned i = 0; i < num_tables; ++i) {
+ table.set_offset(subtable_headers[i].offset);
+ if (!table.ReadU16(&subtable_headers[i].format)) {
+ return OTS_FAILURE_MSG("Can't read cmap subtable header format %d", i);
+ }
+
+ uint16_t len = 0;
+ uint16_t lang = 0;
+ switch (subtable_headers[i].format) {
+ case 0:
+ case 4:
+ if (!table.ReadU16(&len)) {
+ return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
+ }
+ if (!table.ReadU16(&lang)) {
+ return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
+ }
+ subtable_headers[i].length = len;
+ subtable_headers[i].language = lang;
+ break;
+ case 12:
+ case 13:
+ if (!table.Skip(2)) {
+ return OTS_FAILURE_MSG("Bad cmap subtable %d structure", i);
+ }
+ if (!table.ReadU32(&subtable_headers[i].length)) {
+ return OTS_FAILURE_MSG("Can read cmap subtable %d length", i);
+ }
+ if (!table.ReadU32(&subtable_headers[i].language)) {
+ return OTS_FAILURE_MSG("Can't read cmap subtable %d language", i);
+ }
+ break;
+ case 14:
+ if (!table.ReadU32(&subtable_headers[i].length)) {
+ return OTS_FAILURE_MSG("Can't read cmap subtable %d length", i);
+ }
+ subtable_headers[i].language = 0;
+ break;
+ default:
+ subtable_headers[i].length = 0;
+ subtable_headers[i].language = 0;
+ break;
+ }
+ }
+
+ // check if the table is sorted first by platform ID, then by encoding ID.
+ uint32_t last_id = 0;
+ for (unsigned i = 0; i < num_tables; ++i) {
+ uint32_t current_id
+ = (subtable_headers[i].platform << 24)
+ + (subtable_headers[i].encoding << 16)
+ + subtable_headers[i].language;
+ if ((i != 0) && (last_id >= current_id)) {
+ return OTS_FAILURE_MSG("subtable %d with platform ID %d, encoding ID %d, language ID %d "
+ "following subtable with platform ID %d, encoding ID %d, language ID %d",
+ i,
+ (uint8_t)(current_id >> 24), (uint8_t)(current_id >> 16), (uint8_t)(current_id),
+ (uint8_t)(last_id >> 24), (uint8_t)(last_id >> 16), (uint8_t)(last_id));
+ }
+ last_id = current_id;
+ }
+
+ // Now, verify that all the lengths are sane
+ for (unsigned i = 0; i < num_tables; ++i) {
+ if (!subtable_headers[i].length) continue;
+ if (subtable_headers[i].length > 1024 * 1024 * 1024) {
+ return OTS_FAILURE_MSG("Bad cmap subtable %d length", i);
+ }
+ // We know that both the offset and length are < 1GB, so the following
+ // addition doesn't overflow
+ const uint32_t end_byte
+ = subtable_headers[i].offset + subtable_headers[i].length;
+ if (end_byte > length) {
+ return OTS_FAILURE_MSG("Over long cmap subtable %d @ %d for %d", i, subtable_headers[i].offset, subtable_headers[i].length);
+ }
+ }
+
+ // check that the cmap subtables are not overlapping.
+ std::set<std::pair<uint32_t, uint32_t> > uniq_checker;
+ std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
+ for (unsigned i = 0; i < num_tables; ++i) {
+ const uint32_t end_byte
+ = subtable_headers[i].offset + subtable_headers[i].length;
+
+ if (!uniq_checker.insert(std::make_pair(subtable_headers[i].offset,
+ end_byte)).second) {
+ // Sometimes Unicode table and MS table share exactly the same data.
+ // We'll allow this.
+ continue;
+ }
+ overlap_checker.push_back(
+ std::make_pair(subtable_headers[i].offset,
+ static_cast<uint8_t>(1) /* start */));
+ overlap_checker.push_back(
+ std::make_pair(end_byte, static_cast<uint8_t>(0) /* end */));
+ }
+ std::sort(overlap_checker.begin(), overlap_checker.end());
+ int overlap_count = 0;
+ for (unsigned i = 0; i < overlap_checker.size(); ++i) {
+ overlap_count += (overlap_checker[i].second ? 1 : -1);
+ if (overlap_count > 1) {
+ return OTS_FAILURE_MSG("Excessive overlap count %d", overlap_count);
+ }
+ }
+
+ // we grab the number of glyphs in the file from the maxp table to make sure
+ // that the character map isn't referencing anything beyound this range.
+ if (!file->maxp) {
+ return OTS_FAILURE_MSG("No maxp table in font! Needed by cmap.");
+ }
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+
+ // We only support a subset of the possible character map tables. Microsoft
+ // 'strongly recommends' that everyone supports the Unicode BMP table with
+ // the UCS-4 table for non-BMP glyphs. We'll pass the following subtables:
+ // Platform ID Encoding ID Format
+ // 0 0 4 (Unicode Default)
+ // 0 1 4 (Unicode 1.1)
+ // 0 3 4 (Unicode BMP)
+ // 0 3 12 (Unicode UCS-4)
+ // 0 5 14 (Unicode Variation Sequences)
+ // 1 0 0 (Mac Roman)
+ // 3 0 4 (MS Symbol)
+ // 3 1 4 (MS Unicode BMP)
+ // 3 10 12 (MS Unicode UCS-4)
+ // 3 10 13 (MS UCS-4 Fallback mapping)
+ //
+ // Note:
+ // * 0-0-4 and 0-1-4 tables are (usually) written as a 3-1-4 table. If 3-1-4 table
+ // also exists, the 0-0-4 or 0-1-4 tables are ignored.
+ // * Unlike 0-0-4 table, 0-3-4 table is written as a 0-3-4 table.
+ // Some fonts which include 0-5-14 table seems to be required 0-3-4
+ // table. The 0-3-4 table will be wriiten even if 3-1-4 table also exists.
+ // * 0-3-12 table is written as a 3-10-12 table. If 3-10-12 table also
+ // exists, the 0-3-12 table is ignored.
+ //
+
+ for (unsigned i = 0; i < num_tables; ++i) {
+ if (subtable_headers[i].platform == 0) {
+ // Unicode platform
+
+ if ((subtable_headers[i].encoding == 0 || subtable_headers[i].encoding == 1) &&
+ (subtable_headers[i].format == 4)) {
+ // parse and output the 0-0-4 and 0-1-4 tables as 3-1-4 table. Sometimes the 0-0-4
+ // table actually points to MS symbol data and thus should be parsed as
+ // 3-0-4 table (e.g., marqueem.ttf and quixotic.ttf). This error will be
+ // recovered in ots_cmap_serialise().
+ if (!ParseFormat4(file, 3, 1, data + subtable_headers[i].offset,
+ subtable_headers[i].length, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
+ }
+ } else if ((subtable_headers[i].encoding == 3) &&
+ (subtable_headers[i].format == 4)) {
+ // parse and output the 0-3-4 table as 0-3-4 table.
+ if (!ParseFormat4(file, 0, 3, data + subtable_headers[i].offset,
+ subtable_headers[i].length, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse format 4 cmap subtable %d", i);
+ }
+ } else if ((subtable_headers[i].encoding == 3) &&
+ (subtable_headers[i].format == 12)) {
+ // parse and output the 0-3-12 table as 3-10-12 table.
+ if (!Parse31012(file, data + subtable_headers[i].offset,
+ subtable_headers[i].length, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse format 12 cmap subtable %d", i);
+ }
+ } else if ((subtable_headers[i].encoding == 5) &&
+ (subtable_headers[i].format == 14)) {
+ if (!Parse0514(file, data + subtable_headers[i].offset,
+ subtable_headers[i].length, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse format 14 cmap subtable %d", i);
+ }
+ }
+ } else if (subtable_headers[i].platform == 1) {
+ // Mac platform
+
+ if ((subtable_headers[i].encoding == 0) &&
+ (subtable_headers[i].format == 0)) {
+ // parse and output the 1-0-0 table.
+ if (!Parse100(file, data + subtable_headers[i].offset,
+ subtable_headers[i].length)) {
+ return OTS_FAILURE();
+ }
+ }
+ } else if (subtable_headers[i].platform == 3) {
+ // MS platform
+
+ switch (subtable_headers[i].encoding) {
+ case 0:
+ case 1:
+ if (subtable_headers[i].format == 4) {
+ // parse 3-0-4 or 3-1-4 table.
+ if (!ParseFormat4(file, subtable_headers[i].platform,
+ subtable_headers[i].encoding,
+ data + subtable_headers[i].offset,
+ subtable_headers[i].length, num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+ break;
+ case 10:
+ if (subtable_headers[i].format == 12) {
+ file->cmap->subtable_3_10_12.clear();
+ if (!Parse31012(file, data + subtable_headers[i].offset,
+ subtable_headers[i].length, num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ } else if (subtable_headers[i].format == 13) {
+ file->cmap->subtable_3_10_13.clear();
+ if (!Parse31013(file, data + subtable_headers[i].offset,
+ subtable_headers[i].length, num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ots_cmap_should_serialise(OpenTypeFile *file) {
+ return file->cmap != NULL;
+}
+
+bool ots_cmap_serialise(OTSStream *out, OpenTypeFile *file) {
+ const bool have_034 = file->cmap->subtable_0_3_4_data != NULL;
+ const bool have_0514 = file->cmap->subtable_0_5_14.size() != 0;
+ const bool have_100 = file->cmap->subtable_1_0_0.size() != 0;
+ const bool have_304 = file->cmap->subtable_3_0_4_data != NULL;
+ // MS Symbol and MS Unicode tables should not co-exist.
+ // See the comment above in 0-0-4 parser.
+ const bool have_314 = (!have_304) && file->cmap->subtable_3_1_4_data;
+ const bool have_31012 = file->cmap->subtable_3_10_12.size() != 0;
+ const bool have_31013 = file->cmap->subtable_3_10_13.size() != 0;
+ const uint16_t num_subtables = static_cast<uint16_t>(have_034) +
+ static_cast<uint16_t>(have_0514) +
+ static_cast<uint16_t>(have_100) +
+ static_cast<uint16_t>(have_304) +
+ static_cast<uint16_t>(have_314) +
+ static_cast<uint16_t>(have_31012) +
+ static_cast<uint16_t>(have_31013);
+ const off_t table_start = out->Tell();
+
+ // Some fonts don't have 3-0-4 MS Symbol nor 3-1-4 Unicode BMP tables
+ // (e.g., old fonts for Mac). We don't support them.
+ if (!have_304 && !have_314 && !have_034 && !have_31012 && !have_31013) {
+ return OTS_FAILURE_MSG("no supported subtables were found");
+ }
+
+ if (!out->WriteU16(0) ||
+ !out->WriteU16(num_subtables)) {
+ return OTS_FAILURE();
+ }
+
+ const off_t record_offset = out->Tell();
+ if (!out->Pad(num_subtables * 8)) {
+ return OTS_FAILURE();
+ }
+
+ const off_t offset_034 = out->Tell();
+ if (have_034) {
+ if (!out->Write(file->cmap->subtable_0_3_4_data,
+ file->cmap->subtable_0_3_4_length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ const off_t offset_0514 = out->Tell();
+ if (have_0514) {
+ const std::vector<ots::OpenTypeCMAPSubtableVSRecord> &records
+ = file->cmap->subtable_0_5_14;
+ const unsigned num_records = records.size();
+ if (!out->WriteU16(14) ||
+ !out->WriteU32(file->cmap->subtable_0_5_14_length) ||
+ !out->WriteU32(num_records)) {
+ return OTS_FAILURE();
+ }
+ for (unsigned i = 0; i < num_records; ++i) {
+ if (!out->WriteU24(records[i].var_selector) ||
+ !out->WriteU32(records[i].default_offset) ||
+ !out->WriteU32(records[i].non_default_offset)) {
+ return OTS_FAILURE();
+ }
+ }
+ for (unsigned i = 0; i < num_records; ++i) {
+ if (records[i].default_offset) {
+ const std::vector<ots::OpenTypeCMAPSubtableVSRange> &ranges
+ = records[i].ranges;
+ const unsigned num_ranges = ranges.size();
+ if (!out->Seek(records[i].default_offset + offset_0514) ||
+ !out->WriteU32(num_ranges)) {
+ return OTS_FAILURE();
+ }
+ for (unsigned j = 0; j < num_ranges; ++j) {
+ if (!out->WriteU24(ranges[j].unicode_value) ||
+ !out->WriteU8(ranges[j].additional_count)) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+ if (records[i].non_default_offset) {
+ const std::vector<ots::OpenTypeCMAPSubtableVSMapping> &mappings
+ = records[i].mappings;
+ const unsigned num_mappings = mappings.size();
+ if (!out->Seek(records[i].non_default_offset + offset_0514) ||
+ !out->WriteU32(num_mappings)) {
+ return OTS_FAILURE();
+ }
+ for (unsigned j = 0; j < num_mappings; ++j) {
+ if (!out->WriteU24(mappings[j].unicode_value) ||
+ !out->WriteU16(mappings[j].glyph_id)) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+ }
+ }
+
+ const off_t offset_100 = out->Tell();
+ if (have_100) {
+ if (!out->WriteU16(0) || // format
+ !out->WriteU16(6 + kFormat0ArraySize) || // length
+ !out->WriteU16(0)) { // language
+ return OTS_FAILURE();
+ }
+ if (!out->Write(&(file->cmap->subtable_1_0_0[0]), kFormat0ArraySize)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ const off_t offset_304 = out->Tell();
+ if (have_304) {
+ if (!out->Write(file->cmap->subtable_3_0_4_data,
+ file->cmap->subtable_3_0_4_length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ const off_t offset_314 = out->Tell();
+ if (have_314) {
+ if (!out->Write(file->cmap->subtable_3_1_4_data,
+ file->cmap->subtable_3_1_4_length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ const off_t offset_31012 = out->Tell();
+ if (have_31012) {
+ std::vector<OpenTypeCMAPSubtableRange> &groups
+ = file->cmap->subtable_3_10_12;
+ const unsigned num_groups = groups.size();
+ if (!out->WriteU16(12) ||
+ !out->WriteU16(0) ||
+ !out->WriteU32(num_groups * 12 + 16) ||
+ !out->WriteU32(0) ||
+ !out->WriteU32(num_groups)) {
+ return OTS_FAILURE();
+ }
+
+ for (unsigned i = 0; i < num_groups; ++i) {
+ if (!out->WriteU32(groups[i].start_range) ||
+ !out->WriteU32(groups[i].end_range) ||
+ !out->WriteU32(groups[i].start_glyph_id)) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+
+ const off_t offset_31013 = out->Tell();
+ if (have_31013) {
+ std::vector<OpenTypeCMAPSubtableRange> &groups
+ = file->cmap->subtable_3_10_13;
+ const unsigned num_groups = groups.size();
+ if (!out->WriteU16(13) ||
+ !out->WriteU16(0) ||
+ !out->WriteU32(num_groups * 12 + 16) ||
+ !out->WriteU32(0) ||
+ !out->WriteU32(num_groups)) {
+ return OTS_FAILURE();
+ }
+
+ for (unsigned i = 0; i < num_groups; ++i) {
+ if (!out->WriteU32(groups[i].start_range) ||
+ !out->WriteU32(groups[i].end_range) ||
+ !out->WriteU32(groups[i].start_glyph_id)) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+
+ const off_t table_end = out->Tell();
+ // We might have hanging bytes from the above's checksum which the OTSStream
+ // then merges into the table of offsets.
+ OTSStream::ChecksumState saved_checksum = out->SaveChecksumState();
+ out->ResetChecksum();
+
+ // Now seek back and write the table of offsets
+ if (!out->Seek(record_offset)) {
+ return OTS_FAILURE();
+ }
+
+ if (have_034) {
+ if (!out->WriteU16(0) ||
+ !out->WriteU16(3) ||
+ !out->WriteU32(offset_034 - table_start)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (have_0514) {
+ if (!out->WriteU16(0) ||
+ !out->WriteU16(5) ||
+ !out->WriteU32(offset_0514 - table_start)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (have_100) {
+ if (!out->WriteU16(1) ||
+ !out->WriteU16(0) ||
+ !out->WriteU32(offset_100 - table_start)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (have_304) {
+ if (!out->WriteU16(3) ||
+ !out->WriteU16(0) ||
+ !out->WriteU32(offset_304 - table_start)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (have_314) {
+ if (!out->WriteU16(3) ||
+ !out->WriteU16(1) ||
+ !out->WriteU32(offset_314 - table_start)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (have_31012) {
+ if (!out->WriteU16(3) ||
+ !out->WriteU16(10) ||
+ !out->WriteU32(offset_31012 - table_start)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (have_31013) {
+ if (!out->WriteU16(3) ||
+ !out->WriteU16(10) ||
+ !out->WriteU32(offset_31013 - table_start)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ if (!out->Seek(table_end)) {
+ return OTS_FAILURE();
+ }
+ out->RestoreChecksum(saved_checksum);
+
+ return true;
+}
+
+void ots_cmap_free(OpenTypeFile *file) {
+ delete file->cmap;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/cmap.h b/third_party/ots/src/cmap.h
new file mode 100644
index 0000000..5b09556
--- /dev/null
+++ b/third_party/ots/src/cmap.h
@@ -0,0 +1,74 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CMAP_H_
+#define OTS_CMAP_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeCMAPSubtableRange {
+ uint32_t start_range;
+ uint32_t end_range;
+ uint32_t start_glyph_id;
+};
+
+struct OpenTypeCMAPSubtableVSRange {
+ uint32_t unicode_value;
+ uint8_t additional_count;
+};
+
+struct OpenTypeCMAPSubtableVSMapping {
+ uint32_t unicode_value;
+ uint16_t glyph_id;
+};
+
+struct OpenTypeCMAPSubtableVSRecord {
+ uint32_t var_selector;
+ uint32_t default_offset;
+ uint32_t non_default_offset;
+ std::vector<OpenTypeCMAPSubtableVSRange> ranges;
+ std::vector<OpenTypeCMAPSubtableVSMapping> mappings;
+};
+
+struct OpenTypeCMAP {
+ OpenTypeCMAP()
+ : subtable_0_3_4_data(NULL),
+ subtable_0_3_4_length(0),
+ subtable_0_5_14_length(0),
+ subtable_3_0_4_data(NULL),
+ subtable_3_0_4_length(0),
+ subtable_3_1_4_data(NULL),
+ subtable_3_1_4_length(0) {
+ }
+
+ // Platform 0, Encoding 3, Format 4, Unicode BMP table.
+ const uint8_t *subtable_0_3_4_data;
+ size_t subtable_0_3_4_length;
+
+ // Platform 0, Encoding 5, Format 14, Unicode Variation Sequence table.
+ size_t subtable_0_5_14_length;
+ std::vector<OpenTypeCMAPSubtableVSRecord> subtable_0_5_14;
+
+ // Platform 3, Encoding 0, Format 4, MS Symbol table.
+ const uint8_t *subtable_3_0_4_data;
+ size_t subtable_3_0_4_length;
+ // Platform 3, Encoding 1, Format 4, MS Unicode BMP table.
+ const uint8_t *subtable_3_1_4_data;
+ size_t subtable_3_1_4_length;
+
+ // Platform 3, Encoding 10, Format 12, MS Unicode UCS-4 table.
+ std::vector<OpenTypeCMAPSubtableRange> subtable_3_10_12;
+ // Platform 3, Encoding 10, Format 13, MS UCS-4 Fallback table.
+ std::vector<OpenTypeCMAPSubtableRange> subtable_3_10_13;
+ // Platform 1, Encoding 0, Format 0, Mac Roman table.
+ std::vector<uint8_t> subtable_1_0_0;
+};
+
+} // namespace ots
+
+#endif
diff --git a/third_party/ots/src/cvt.cc b/third_party/ots/src/cvt.cc
new file mode 100644
index 0000000..f83ad0e
--- /dev/null
+++ b/third_party/ots/src/cvt.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cvt.h"
+
+// cvt - Control Value Table
+// http://www.microsoft.com/typography/otspec/cvt.htm
+
+#define TABLE_NAME "cvt"
+
+namespace ots {
+
+bool ots_cvt_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypeCVT *cvt = new OpenTypeCVT;
+ file->cvt = cvt;
+
+ if (length >= 128 * 1024u) {
+ return OTS_FAILURE_MSG("Length (%d) > 120K"); // almost all cvt tables are less than 4k bytes.
+ }
+
+ if (length % 2 != 0) {
+ return OTS_FAILURE_MSG("Uneven cvt length (%d)", length);
+ }
+
+ if (!table.Skip(length)) {
+ return OTS_FAILURE_MSG("Length too high");
+ }
+
+ cvt->data = data;
+ cvt->length = length;
+ return true;
+}
+
+bool ots_cvt_should_serialise(OpenTypeFile *file) {
+ if (!file->glyf) {
+ return false; // this table is not for CFF fonts.
+ }
+ return file->cvt != NULL;
+}
+
+bool ots_cvt_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeCVT *cvt = file->cvt;
+
+ if (!out->Write(cvt->data, cvt->length)) {
+ return OTS_FAILURE_MSG("Failed to write CVT table");
+ }
+
+ return true;
+}
+
+void ots_cvt_free(OpenTypeFile *file) {
+ delete file->cvt;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/cvt.h b/third_party/ots/src/cvt.h
new file mode 100644
index 0000000..3c25f06
--- /dev/null
+++ b/third_party/ots/src/cvt.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_CVT_H_
+#define OTS_CVT_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeCVT {
+ const uint8_t *data;
+ uint32_t length;
+};
+
+} // namespace ots
+
+#endif // OTS_CVT_H_
diff --git a/third_party/ots/src/fpgm.cc b/third_party/ots/src/fpgm.cc
new file mode 100644
index 0000000..eba03e7
--- /dev/null
+++ b/third_party/ots/src/fpgm.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "fpgm.h"
+
+// fpgm - Font Program
+// http://www.microsoft.com/typography/otspec/fpgm.htm
+
+#define TABLE_NAME "fpgm"
+
+namespace ots {
+
+bool ots_fpgm_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypeFPGM *fpgm = new OpenTypeFPGM;
+ file->fpgm = fpgm;
+
+ if (length >= 128 * 1024u) {
+ return OTS_FAILURE_MSG("length (%ld) > 120", length); // almost all fpgm tables are less than 5k bytes.
+ }
+
+ if (!table.Skip(length)) {
+ return OTS_FAILURE_MSG("Bad fpgm length");
+ }
+
+ fpgm->data = data;
+ fpgm->length = length;
+ return true;
+}
+
+bool ots_fpgm_should_serialise(OpenTypeFile *file) {
+ if (!file->glyf) return false; // this table is not for CFF fonts.
+ return file->fpgm != NULL;
+}
+
+bool ots_fpgm_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeFPGM *fpgm = file->fpgm;
+
+ if (!out->Write(fpgm->data, fpgm->length)) {
+ return OTS_FAILURE_MSG("Failed to write fpgm");
+ }
+
+ return true;
+}
+
+void ots_fpgm_free(OpenTypeFile *file) {
+ delete file->fpgm;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/fpgm.h b/third_party/ots/src/fpgm.h
new file mode 100644
index 0000000..8fabac3
--- /dev/null
+++ b/third_party/ots/src/fpgm.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_FPGM_H_
+#define OTS_FPGM_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeFPGM {
+ const uint8_t *data;
+ uint32_t length;
+};
+
+} // namespace ots
+
+#endif // OTS_FPGM_H_
diff --git a/third_party/ots/src/gasp.cc b/third_party/ots/src/gasp.cc
new file mode 100644
index 0000000..1e2327f
--- /dev/null
+++ b/third_party/ots/src/gasp.cc
@@ -0,0 +1,114 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gasp.h"
+
+// gasp - Grid-fitting And Scan-conversion Procedure
+// http://www.microsoft.com/typography/otspec/gasp.htm
+
+#define TABLE_NAME "gasp"
+
+#define DROP_THIS_TABLE(...) \
+ do { \
+ OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+ OTS_FAILURE_MSG("Table discarded"); \
+ delete file->gasp; \
+ file->gasp = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_gasp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypeGASP *gasp = new OpenTypeGASP;
+ file->gasp = gasp;
+
+ uint16_t num_ranges = 0;
+ if (!table.ReadU16(&gasp->version) ||
+ !table.ReadU16(&num_ranges)) {
+ return OTS_FAILURE_MSG("Failed to read table header");
+ }
+
+ if (gasp->version > 1) {
+ // Lots of Linux fonts have bad version numbers...
+ DROP_THIS_TABLE("bad version: %u", gasp->version);
+ return true;
+ }
+
+ if (num_ranges == 0) {
+ DROP_THIS_TABLE("num_ranges is zero");
+ return true;
+ }
+
+ gasp->gasp_ranges.reserve(num_ranges);
+ for (unsigned i = 0; i < num_ranges; ++i) {
+ uint16_t max_ppem = 0;
+ uint16_t behavior = 0;
+ if (!table.ReadU16(&max_ppem) ||
+ !table.ReadU16(&behavior)) {
+ return OTS_FAILURE_MSG("Failed to read subrange %d", i);
+ }
+ if ((i > 0) && (gasp->gasp_ranges[i - 1].first >= max_ppem)) {
+ // The records in the gaspRange[] array must be sorted in order of
+ // increasing rangeMaxPPEM value.
+ DROP_THIS_TABLE("ranges are not sorted");
+ return true;
+ }
+ if ((i == num_ranges - 1u) && // never underflow.
+ (max_ppem != 0xffffu)) {
+ DROP_THIS_TABLE("The last record should be 0xFFFF as a sentinel value "
+ "for rangeMaxPPEM");
+ return true;
+ }
+
+ if (behavior >> 8) {
+ OTS_WARNING("undefined bits are used: %x", behavior);
+ // mask undefined bits.
+ behavior &= 0x000fu;
+ }
+
+ if (gasp->version == 0 && (behavior >> 2) != 0) {
+ OTS_WARNING("changed the version number to 1");
+ gasp->version = 1;
+ }
+
+ gasp->gasp_ranges.push_back(std::make_pair(max_ppem, behavior));
+ }
+
+ return true;
+}
+
+bool ots_gasp_should_serialise(OpenTypeFile *file) {
+ return file->gasp != NULL;
+}
+
+bool ots_gasp_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeGASP *gasp = file->gasp;
+
+ const uint16_t num_ranges = static_cast<uint16_t>(gasp->gasp_ranges.size());
+ if (num_ranges != gasp->gasp_ranges.size() ||
+ !out->WriteU16(gasp->version) ||
+ !out->WriteU16(num_ranges)) {
+ return OTS_FAILURE_MSG("failed to write gasp header");
+ }
+
+ for (uint16_t i = 0; i < num_ranges; ++i) {
+ if (!out->WriteU16(gasp->gasp_ranges[i].first) ||
+ !out->WriteU16(gasp->gasp_ranges[i].second)) {
+ return OTS_FAILURE_MSG("Failed to write gasp subtable %d", i);
+ }
+ }
+
+ return true;
+}
+
+void ots_gasp_free(OpenTypeFile *file) {
+ delete file->gasp;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/gasp.h b/third_party/ots/src/gasp.h
new file mode 100644
index 0000000..48d7e7c
--- /dev/null
+++ b/third_party/ots/src/gasp.h
@@ -0,0 +1,24 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_GASP_H_
+#define OTS_GASP_H_
+
+#include <new>
+#include <utility>
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeGASP {
+ uint16_t version;
+ // A array of (max PPEM, GASP behavior) pairs.
+ std::vector<std::pair<uint16_t, uint16_t> > gasp_ranges;
+};
+
+} // namespace ots
+
+#endif // OTS_GASP_H_
diff --git a/third_party/ots/src/gdef.cc b/third_party/ots/src/gdef.cc
new file mode 100644
index 0000000..4553d58
--- /dev/null
+++ b/third_party/ots/src/gdef.cc
@@ -0,0 +1,388 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gdef.h"
+
+#include <limits>
+#include <vector>
+
+#include "gpos.h"
+#include "gsub.h"
+#include "layout.h"
+#include "maxp.h"
+
+// GDEF - The Glyph Definition Table
+// http://www.microsoft.com/typography/otspec/gdef.htm
+
+#define TABLE_NAME "GDEF"
+
+namespace {
+
+// The maximum class value in class definition tables.
+const uint16_t kMaxClassDefValue = 0xFFFF;
+// The maximum class value in the glyph class definision table.
+const uint16_t kMaxGlyphClassDefValue = 4;
+// The maximum format number of caret value tables.
+// We don't support format 3 for now. See the comment in
+// ParseLigCaretListTable() for the reason.
+const uint16_t kMaxCaretValueFormat = 2;
+
+bool ParseGlyphClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ return ots::ParseClassDefTable(file, data, length, num_glyphs,
+ kMaxGlyphClassDefValue);
+}
+
+bool ParseAttachListTable(ots::OpenTypeFile *file, const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_coverage = 0;
+ uint16_t glyph_count = 0;
+ if (!subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read gdef header");
+ }
+ const unsigned attach_points_end =
+ 2 * static_cast<unsigned>(glyph_count) + 4;
+ if (attach_points_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad glyph count in gdef");
+ }
+ if (offset_coverage == 0 || offset_coverage >= length ||
+ offset_coverage < attach_points_end) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
+ }
+ if (glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph count %u", glyph_count);
+ }
+
+ std::vector<uint16_t> attach_points;
+ attach_points.resize(glyph_count);
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ if (!subtable.ReadU16(&attach_points[i])) {
+ return OTS_FAILURE_MSG("Can't read attachment point %d", i);
+ }
+ if (attach_points[i] >= length ||
+ attach_points[i] < attach_points_end) {
+ return OTS_FAILURE_MSG("Bad attachment point %d of %d", i, attach_points[i]);
+ }
+ }
+
+ // Parse coverage table
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Bad coverage table");
+ }
+
+ // Parse attach point table
+ for (unsigned i = 0; i < attach_points.size(); ++i) {
+ subtable.set_offset(attach_points[i]);
+ uint16_t point_count = 0;
+ if (!subtable.ReadU16(&point_count)) {
+ return OTS_FAILURE_MSG("Can't read point count %d", i);
+ }
+ if (point_count == 0) {
+ return OTS_FAILURE_MSG("zero point count %d", i);
+ }
+ uint16_t last_point_index = 0;
+ uint16_t point_index = 0;
+ for (unsigned j = 0; j < point_count; ++j) {
+ if (!subtable.ReadU16(&point_index)) {
+ return OTS_FAILURE_MSG("Can't read point index %d in point %d", j, i);
+ }
+ // Contour point indeces are in increasing numerical order
+ if (last_point_index != 0 && last_point_index >= point_index) {
+ return OTS_FAILURE_MSG("bad contour indeces: %u >= %u",
+ last_point_index, point_index);
+ }
+ last_point_index = point_index;
+ }
+ }
+ return true;
+}
+
+bool ParseLigCaretListTable(ots::OpenTypeFile *file, const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+ uint16_t offset_coverage = 0;
+ uint16_t lig_glyph_count = 0;
+ if (!subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&lig_glyph_count)) {
+ return OTS_FAILURE_MSG("Can't read caret structure");
+ }
+ const unsigned lig_glyphs_end =
+ 2 * static_cast<unsigned>(lig_glyph_count) + 4;
+ if (lig_glyphs_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad caret structure");
+ }
+ if (offset_coverage == 0 || offset_coverage >= length ||
+ offset_coverage < lig_glyphs_end) {
+ return OTS_FAILURE_MSG("Bad caret coverate offset %d", offset_coverage);
+ }
+ if (lig_glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("bad ligature glyph count: %u", lig_glyph_count);
+ }
+
+ std::vector<uint16_t> lig_glyphs;
+ lig_glyphs.resize(lig_glyph_count);
+ for (unsigned i = 0; i < lig_glyph_count; ++i) {
+ if (!subtable.ReadU16(&lig_glyphs[i])) {
+ return OTS_FAILURE_MSG("Can't read ligature glyph location %d", i);
+ }
+ if (lig_glyphs[i] >= length || lig_glyphs[i] < lig_glyphs_end) {
+ return OTS_FAILURE_MSG("Bad ligature glyph location %d in glyph %d", lig_glyphs[i], i);
+ }
+ }
+
+ // Parse coverage table
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Can't parse caret coverage table");
+ }
+
+ // Parse ligature glyph table
+ for (unsigned i = 0; i < lig_glyphs.size(); ++i) {
+ subtable.set_offset(lig_glyphs[i]);
+ uint16_t caret_count = 0;
+ if (!subtable.ReadU16(&caret_count)) {
+ return OTS_FAILURE_MSG("Can't read caret count for glyph %d", i);
+ }
+ if (caret_count == 0) {
+ return OTS_FAILURE_MSG("bad caret value count: %u", caret_count);
+ }
+
+ std::vector<uint16_t> caret_value_offsets;
+ caret_value_offsets.resize(caret_count);
+ unsigned caret_value_offsets_end = 2 * static_cast<unsigned>(caret_count) + 2;
+ for (unsigned j = 0; j < caret_count; ++j) {
+ if (!subtable.ReadU16(&caret_value_offsets[j])) {
+ return OTS_FAILURE_MSG("Can't read caret offset %d for glyph %d", j, i);
+ }
+ if (caret_value_offsets[j] >= length || caret_value_offsets[j] < caret_value_offsets_end) {
+ return OTS_FAILURE_MSG("Bad caret offset %d for caret %d glyph %d", caret_value_offsets[j], j, i);
+ }
+ }
+
+ // Parse caret values table
+ for (unsigned j = 0; j < caret_count; ++j) {
+ subtable.set_offset(lig_glyphs[i] + caret_value_offsets[j]);
+ uint16_t caret_format = 0;
+ if (!subtable.ReadU16(&caret_format)) {
+ return OTS_FAILURE_MSG("Can't read caret values table %d in glyph %d", j, i);
+ }
+ // TODO(bashi): We only support caret value format 1 and 2 for now
+ // because there are no fonts which contain caret value format 3
+ // as far as we investigated.
+ if (caret_format == 0 || caret_format > kMaxCaretValueFormat) {
+ return OTS_FAILURE_MSG("bad caret value format: %u", caret_format);
+ }
+ // CaretValueFormats contain a 2-byte field which could be
+ // arbitrary value.
+ if (!subtable.Skip(2)) {
+ return OTS_FAILURE_MSG("Bad caret value table structure %d in glyph %d", j, i);
+ }
+ }
+ }
+ return true;
+}
+
+bool ParseMarkAttachClassDefTable(ots::OpenTypeFile *file, const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ return ots::ParseClassDefTable(file, data, length, num_glyphs, kMaxClassDefValue);
+}
+
+bool ParseMarkGlyphSetsDefTable(ots::OpenTypeFile *file, const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+ uint16_t format = 0;
+ uint16_t mark_set_count = 0;
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&mark_set_count)) {
+ return OTS_FAILURE_MSG("Can' read mark glyph table structure");
+ }
+ if (format != 1) {
+ return OTS_FAILURE_MSG("bad mark glyph set table format: %u", format);
+ }
+
+ const unsigned mark_sets_end = 2 * static_cast<unsigned>(mark_set_count) + 4;
+ if (mark_sets_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad mark_set %d", mark_sets_end);
+ }
+ for (unsigned i = 0; i < mark_set_count; ++i) {
+ uint32_t offset_coverage = 0;
+ if (!subtable.ReadU32(&offset_coverage)) {
+ return OTS_FAILURE_MSG("Can't read covrage location for mark set %d", i);
+ }
+ if (offset_coverage >= length ||
+ offset_coverage < mark_sets_end) {
+ return OTS_FAILURE_MSG("Bad coverage location %d for mark set %d", offset_coverage, i);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table for mark set %d", i);
+ }
+ }
+ file->gdef->num_mark_glyph_sets = mark_set_count;
+ return true;
+}
+
+} // namespace
+
+#define DROP_THIS_TABLE(msg_) \
+ do { \
+ OTS_FAILURE_MSG(msg_ ", table discarded"); \
+ file->gdef->data = 0; \
+ file->gdef->length = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_gdef_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ // Grab the number of glyphs in the file from the maxp table to check
+ // GlyphIDs in GDEF table.
+ if (!file->maxp) {
+ return OTS_FAILURE_MSG("No maxp table in font, needed by GDEF");
+ }
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+
+ Buffer table(data, length);
+
+ OpenTypeGDEF *gdef = new OpenTypeGDEF;
+ file->gdef = gdef;
+
+ uint32_t version = 0;
+ if (!table.ReadU32(&version)) {
+ DROP_THIS_TABLE("Incomplete table");
+ return true;
+ }
+ if (version < 0x00010000 || version == 0x00010001) {
+ DROP_THIS_TABLE("Bad version");
+ return true;
+ }
+
+ if (version >= 0x00010002) {
+ gdef->version_2 = true;
+ }
+
+ uint16_t offset_glyph_class_def = 0;
+ uint16_t offset_attach_list = 0;
+ uint16_t offset_lig_caret_list = 0;
+ uint16_t offset_mark_attach_class_def = 0;
+ if (!table.ReadU16(&offset_glyph_class_def) ||
+ !table.ReadU16(&offset_attach_list) ||
+ !table.ReadU16(&offset_lig_caret_list) ||
+ !table.ReadU16(&offset_mark_attach_class_def)) {
+ DROP_THIS_TABLE("Incomplete table");
+ return true;
+ }
+ uint16_t offset_mark_glyph_sets_def = 0;
+ if (gdef->version_2) {
+ if (!table.ReadU16(&offset_mark_glyph_sets_def)) {
+ DROP_THIS_TABLE("Incomplete table");
+ return true;
+ }
+ }
+
+ unsigned gdef_header_end = 4 + 4 * 2;
+ if (gdef->version_2)
+ gdef_header_end += 2;
+
+ // Parse subtables
+ if (offset_glyph_class_def) {
+ if (offset_glyph_class_def >= length ||
+ offset_glyph_class_def < gdef_header_end) {
+ DROP_THIS_TABLE("Invalid offset to glyph classes");
+ return true;
+ }
+ if (!ParseGlyphClassDefTable(file, data + offset_glyph_class_def,
+ length - offset_glyph_class_def,
+ num_glyphs)) {
+ DROP_THIS_TABLE("Invalid glyph classes");
+ return true;
+ }
+ gdef->has_glyph_class_def = true;
+ }
+
+ if (offset_attach_list) {
+ if (offset_attach_list >= length ||
+ offset_attach_list < gdef_header_end) {
+ DROP_THIS_TABLE("Invalid offset to attachment list");
+ return true;
+ }
+ if (!ParseAttachListTable(file, data + offset_attach_list,
+ length - offset_attach_list,
+ num_glyphs)) {
+ DROP_THIS_TABLE("Invalid attachment list");
+ return true;
+ }
+ }
+
+ if (offset_lig_caret_list) {
+ if (offset_lig_caret_list >= length ||
+ offset_lig_caret_list < gdef_header_end) {
+ DROP_THIS_TABLE("Invalid offset to ligature caret list");
+ return true;
+ }
+ if (!ParseLigCaretListTable(file, data + offset_lig_caret_list,
+ length - offset_lig_caret_list,
+ num_glyphs)) {
+ DROP_THIS_TABLE("Invalid ligature caret list");
+ return true;
+ }
+ }
+
+ if (offset_mark_attach_class_def) {
+ if (offset_mark_attach_class_def >= length ||
+ offset_mark_attach_class_def < gdef_header_end) {
+ return OTS_FAILURE_MSG("Invalid offset to mark attachment list");
+ }
+ if (!ParseMarkAttachClassDefTable(file,
+ data + offset_mark_attach_class_def,
+ length - offset_mark_attach_class_def,
+ num_glyphs)) {
+ DROP_THIS_TABLE("Invalid mark attachment list");
+ return true;
+ }
+ gdef->has_mark_attachment_class_def = true;
+ }
+
+ if (offset_mark_glyph_sets_def) {
+ if (offset_mark_glyph_sets_def >= length ||
+ offset_mark_glyph_sets_def < gdef_header_end) {
+ return OTS_FAILURE_MSG("invalid offset to mark glyph sets");
+ }
+ if (!ParseMarkGlyphSetsDefTable(file,
+ data + offset_mark_glyph_sets_def,
+ length - offset_mark_glyph_sets_def,
+ num_glyphs)) {
+ DROP_THIS_TABLE("Invalid mark glyph sets");
+ return true;
+ }
+ gdef->has_mark_glyph_sets_def = true;
+ }
+ gdef->data = data;
+ gdef->length = length;
+ return true;
+}
+
+bool ots_gdef_should_serialise(OpenTypeFile *file) {
+ return file->gdef != NULL && file->gdef->data != NULL;
+}
+
+bool ots_gdef_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!out->Write(file->gdef->data, file->gdef->length)) {
+ return OTS_FAILURE_MSG("Failed to write GDEF table");
+ }
+
+ return true;
+}
+
+void ots_gdef_free(OpenTypeFile *file) {
+ delete file->gdef;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/gdef.h b/third_party/ots/src/gdef.h
new file mode 100644
index 0000000..f46f419
--- /dev/null
+++ b/third_party/ots/src/gdef.h
@@ -0,0 +1,36 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_GDEF_H_
+#define OTS_GDEF_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeGDEF {
+ OpenTypeGDEF()
+ : version_2(false),
+ has_glyph_class_def(false),
+ has_mark_attachment_class_def(false),
+ has_mark_glyph_sets_def(false),
+ num_mark_glyph_sets(0),
+ data(NULL),
+ length(0) {
+ }
+
+ bool version_2;
+ bool has_glyph_class_def;
+ bool has_mark_attachment_class_def;
+ bool has_mark_glyph_sets_def;
+ uint16_t num_mark_glyph_sets;
+
+ const uint8_t *data;
+ size_t length;
+};
+
+} // namespace ots
+
+#endif
+
diff --git a/third_party/ots/src/glyf.cc b/third_party/ots/src/glyf.cc
new file mode 100644
index 0000000..3579397
--- /dev/null
+++ b/third_party/ots/src/glyf.cc
@@ -0,0 +1,298 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "glyf.h"
+
+#include <algorithm>
+#include <limits>
+
+#include "head.h"
+#include "loca.h"
+#include "maxp.h"
+
+// glyf - Glyph Data
+// http://www.microsoft.com/typography/otspec/glyf.htm
+
+#define TABLE_NAME "glyf"
+
+namespace {
+
+bool ParseFlagsForSimpleGlyph(ots::OpenTypeFile *file,
+ ots::Buffer *table,
+ uint32_t gly_length,
+ uint32_t num_flags,
+ uint32_t *flags_count_logical,
+ uint32_t *flags_count_physical,
+ uint32_t *xy_coordinates_length) {
+ uint8_t flag = 0;
+ if (!table->ReadU8(&flag)) {
+ return OTS_FAILURE_MSG("Can't read flag");
+ }
+
+ uint32_t delta = 0;
+ if (flag & (1u << 1)) { // x-Short
+ ++delta;
+ } else if (!(flag & (1u << 4))) {
+ delta += 2;
+ }
+
+ if (flag & (1u << 2)) { // y-Short
+ ++delta;
+ } else if (!(flag & (1u << 5))) {
+ delta += 2;
+ }
+
+ if (flag & (1u << 3)) { // repeat
+ if (*flags_count_logical + 1 >= num_flags) {
+ return OTS_FAILURE_MSG("Count too high (%d + 1 >= %d)", *flags_count_logical, num_flags);
+ }
+ uint8_t repeat = 0;
+ if (!table->ReadU8(&repeat)) {
+ return OTS_FAILURE_MSG("Can't read repeat value");
+ }
+ if (repeat == 0) {
+ return OTS_FAILURE_MSG("Zero repeat");
+ }
+ delta += (delta * repeat);
+
+ *flags_count_logical += repeat;
+ if (*flags_count_logical >= num_flags) {
+ return OTS_FAILURE_MSG("Count too high (%d >= %d)", *flags_count_logical, num_flags);
+ }
+ ++(*flags_count_physical);
+ }
+
+ if ((flag & (1u << 6)) || (flag & (1u << 7))) { // reserved flags
+ return OTS_FAILURE_MSG("Bad flag value (%d)", flag);
+ }
+
+ *xy_coordinates_length += delta;
+ if (gly_length < *xy_coordinates_length) {
+ return OTS_FAILURE_MSG("Glyph coordinates length too low (%d < %d)", gly_length, *xy_coordinates_length);
+ }
+
+ return true;
+}
+
+bool ParseSimpleGlyph(ots::OpenTypeFile *file, const uint8_t *data,
+ ots::Buffer *table, int16_t num_contours,
+ uint32_t gly_offset, uint32_t gly_length,
+ uint32_t *new_size) {
+ ots::OpenTypeGLYF *glyf = file->glyf;
+
+ // read the end-points array
+ uint16_t num_flags = 0;
+ for (int i = 0; i < num_contours; ++i) {
+ uint16_t tmp_index = 0;
+ if (!table->ReadU16(&tmp_index)) {
+ return OTS_FAILURE_MSG("Can't read contour index %d", i);
+ }
+ if (tmp_index == 0xffffu) {
+ return OTS_FAILURE_MSG("Bad contour index %d", i);
+ }
+ // check if the indices are monotonically increasing
+ if (i && (tmp_index + 1 <= num_flags)) {
+ return OTS_FAILURE_MSG("Decreasing contour index %d + 1 <= %d", tmp_index, num_flags);
+ }
+ num_flags = tmp_index + 1;
+ }
+
+ uint16_t bytecode_length = 0;
+ if (!table->ReadU16(&bytecode_length)) {
+ return OTS_FAILURE_MSG("Can't read bytecode length");
+ }
+ if ((file->maxp->version_1) &&
+ (file->maxp->max_size_glyf_instructions < bytecode_length)) {
+ return OTS_FAILURE_MSG("Bytecode length too high %d", bytecode_length);
+ }
+
+ const uint32_t gly_header_length = 10 + num_contours * 2 + 2;
+ if (gly_length < (gly_header_length + bytecode_length)) {
+ return OTS_FAILURE_MSG("Glyph header length too high %d", gly_header_length);
+ }
+
+ glyf->iov.push_back(std::make_pair(
+ data + gly_offset,
+ static_cast<size_t>(gly_header_length + bytecode_length)));
+
+ if (!table->Skip(bytecode_length)) {
+ return OTS_FAILURE_MSG("Can't skip bytecode of length %d", bytecode_length);
+ }
+
+ uint32_t flags_count_physical = 0; // on memory
+ uint32_t xy_coordinates_length = 0;
+ for (uint32_t flags_count_logical = 0;
+ flags_count_logical < num_flags;
+ ++flags_count_logical, ++flags_count_physical) {
+ if (!ParseFlagsForSimpleGlyph(file,
+ table,
+ gly_length,
+ num_flags,
+ &flags_count_logical,
+ &flags_count_physical,
+ &xy_coordinates_length)) {
+ return OTS_FAILURE_MSG("Failed to parse glyph flags %d", flags_count_logical);
+ }
+ }
+
+ if (gly_length < (gly_header_length + bytecode_length +
+ flags_count_physical + xy_coordinates_length)) {
+ return OTS_FAILURE_MSG("Glyph too short %d", gly_length);
+ }
+
+ if (gly_length - (gly_header_length + bytecode_length +
+ flags_count_physical + xy_coordinates_length) > 3) {
+ // We allow 0-3 bytes difference since gly_length is 4-bytes aligned,
+ // zero-padded length.
+ return OTS_FAILURE_MSG("Invalid glyph length %d", gly_length);
+ }
+
+ glyf->iov.push_back(std::make_pair(
+ data + gly_offset + gly_header_length + bytecode_length,
+ static_cast<size_t>(flags_count_physical + xy_coordinates_length)));
+
+ *new_size
+ = gly_header_length + flags_count_physical + xy_coordinates_length + bytecode_length;
+
+ return true;
+}
+
+} // namespace
+
+namespace ots {
+
+bool ots_glyf_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ if (!file->maxp || !file->loca || !file->head) {
+ return OTS_FAILURE_MSG("Missing maxp or loca or head table needed by glyf table");
+ }
+
+ OpenTypeGLYF *glyf = new OpenTypeGLYF;
+ file->glyf = glyf;
+
+ const unsigned num_glyphs = file->maxp->num_glyphs;
+ std::vector<uint32_t> &offsets = file->loca->offsets;
+
+ if (offsets.size() != num_glyphs + 1) {
+ return OTS_FAILURE_MSG("Invalide glyph offsets size %ld != %d", offsets.size(), num_glyphs + 1);
+ }
+
+ std::vector<uint32_t> resulting_offsets(num_glyphs + 1);
+ uint32_t current_offset = 0;
+
+ for (unsigned i = 0; i < num_glyphs; ++i) {
+ const unsigned gly_offset = offsets[i];
+ // The LOCA parser checks that these values are monotonic
+ const unsigned gly_length = offsets[i + 1] - offsets[i];
+ if (!gly_length) {
+ // this glyph has no outline (e.g. the space charactor)
+ resulting_offsets[i] = current_offset;
+ continue;
+ }
+
+ if (gly_offset >= length) {
+ return OTS_FAILURE_MSG("Glyph %d offset %d too high %ld", i, gly_offset, length);
+ }
+ // Since these are unsigned types, the compiler is not allowed to assume
+ // that they never overflow.
+ if (gly_offset + gly_length < gly_offset) {
+ return OTS_FAILURE_MSG("Glyph %d length (%d < 0)!", i, gly_length);
+ }
+ if (gly_offset + gly_length > length) {
+ return OTS_FAILURE_MSG("Glyph %d length %d too high", i, gly_length);
+ }
+
+ table.set_offset(gly_offset);
+ int16_t num_contours, xmin, ymin, xmax, ymax;
+ if (!table.ReadS16(&num_contours) ||
+ !table.ReadS16(&xmin) ||
+ !table.ReadS16(&ymin) ||
+ !table.ReadS16(&xmax) ||
+ !table.ReadS16(&ymax)) {
+ return OTS_FAILURE_MSG("Can't read glyph %d header", i);
+ }
+
+ if (num_contours <= -2) {
+ // -2, -3, -4, ... are reserved for future use.
+ return OTS_FAILURE_MSG("Bad number of contours %d in glyph %d", num_contours, i);
+ }
+
+ // workaround for fonts in http://www.princexml.com/fonts/
+ if ((xmin == 32767) &&
+ (xmax == -32767) &&
+ (ymin == 32767) &&
+ (ymax == -32767)) {
+ OTS_WARNING("bad xmin/xmax/ymin/ymax values");
+ xmin = xmax = ymin = ymax = 0;
+ }
+
+ if (xmin > xmax || ymin > ymax) {
+ return OTS_FAILURE_MSG("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
+ }
+
+ unsigned new_size = 0;
+ if (num_contours >= 0) {
+ // this is a simple glyph and might contain bytecode
+ if (!ParseSimpleGlyph(file, data, &table,
+ num_contours, gly_offset, gly_length, &new_size)) {
+ return OTS_FAILURE_MSG("Failed to parse glyph %d", i);
+ }
+ } else {
+ // it's a composite glyph without any bytecode. Enqueue the whole thing
+ glyf->iov.push_back(std::make_pair(data + gly_offset,
+ static_cast<size_t>(gly_length)));
+ new_size = gly_length;
+ }
+
+ resulting_offsets[i] = current_offset;
+ // glyphs must be four byte aligned
+ // TODO(yusukes): investigate whether this padding is really necessary.
+ // Which part of the spec requires this?
+ const unsigned padding = (4 - (new_size & 3)) % 4;
+ if (padding) {
+ glyf->iov.push_back(std::make_pair(
+ reinterpret_cast<const uint8_t*>("\x00\x00\x00\x00"),
+ static_cast<size_t>(padding)));
+ new_size += padding;
+ }
+ current_offset += new_size;
+ }
+ resulting_offsets[num_glyphs] = current_offset;
+
+ const uint16_t max16 = std::numeric_limits<uint16_t>::max();
+ if ((*std::max_element(resulting_offsets.begin(),
+ resulting_offsets.end()) >= (max16 * 2u)) &&
+ (file->head->index_to_loc_format != 1)) {
+ OTS_WARNING("2-bytes indexing is not possible (due to the padding above)");
+ file->head->index_to_loc_format = 1;
+ }
+
+ file->loca->offsets = resulting_offsets;
+ return true;
+}
+
+bool ots_glyf_should_serialise(OpenTypeFile *file) {
+ return file->glyf != NULL;
+}
+
+bool ots_glyf_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeGLYF *glyf = file->glyf;
+
+ for (unsigned i = 0; i < glyf->iov.size(); ++i) {
+ if (!out->Write(glyf->iov[i].first, glyf->iov[i].second)) {
+ return OTS_FAILURE_MSG("Falied to write glyph %d", i);
+ }
+ }
+
+ return true;
+}
+
+void ots_glyf_free(OpenTypeFile *file) {
+ delete file->glyf;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/glyf.h b/third_party/ots/src/glyf.h
new file mode 100644
index 0000000..9a8baf5
--- /dev/null
+++ b/third_party/ots/src/glyf.h
@@ -0,0 +1,22 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_GLYF_H_
+#define OTS_GLYF_H_
+
+#include <new>
+#include <utility>
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeGLYF {
+ std::vector<std::pair<const uint8_t*, size_t> > iov;
+};
+
+} // namespace ots
+
+#endif // OTS_GLYF_H_
diff --git a/third_party/ots/src/gpos.cc b/third_party/ots/src/gpos.cc
new file mode 100644
index 0000000..a2b9687
--- /dev/null
+++ b/third_party/ots/src/gpos.cc
@@ -0,0 +1,828 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gpos.h"
+
+#include <limits>
+#include <vector>
+
+#include "layout.h"
+#include "maxp.h"
+
+// GPOS - The Glyph Positioning Table
+// http://www.microsoft.com/typography/otspec/gpos.htm
+
+#define TABLE_NAME "GPOS"
+
+namespace {
+
+enum GPOS_TYPE {
+ GPOS_TYPE_SINGLE_ADJUSTMENT = 1,
+ GPOS_TYPE_PAIR_ADJUSTMENT = 2,
+ GPOS_TYPE_CURSIVE_ATTACHMENT = 3,
+ GPOS_TYPE_MARK_TO_BASE_ATTACHMENT = 4,
+ GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT = 5,
+ GPOS_TYPE_MARK_TO_MARK_ATTACHMENT = 6,
+ GPOS_TYPE_CONTEXT_POSITIONING = 7,
+ GPOS_TYPE_CHAINED_CONTEXT_POSITIONING = 8,
+ GPOS_TYPE_EXTENSION_POSITIONING = 9,
+ GPOS_TYPE_RESERVED = 10
+};
+
+// The size of gpos header.
+const unsigned kGposHeaderSize = 10;
+// The maximum format number for anchor tables.
+const uint16_t kMaxAnchorFormat = 3;
+// The maximum number of class value.
+const uint16_t kMaxClassDefValue = 0xFFFF;
+
+// Lookup type parsers.
+bool ParseSingleAdjustment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParsePairAdjustment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseCursiveAttachment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseContextPositioning(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseChainedContextPositioning(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseExtensionPositioning(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+
+const ots::LookupSubtableParser::TypeParser kGposTypeParsers[] = {
+ {GPOS_TYPE_SINGLE_ADJUSTMENT, ParseSingleAdjustment},
+ {GPOS_TYPE_PAIR_ADJUSTMENT, ParsePairAdjustment},
+ {GPOS_TYPE_CURSIVE_ATTACHMENT, ParseCursiveAttachment},
+ {GPOS_TYPE_MARK_TO_BASE_ATTACHMENT, ParseMarkToBaseAttachment},
+ {GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT, ParseMarkToLigatureAttachment},
+ {GPOS_TYPE_MARK_TO_MARK_ATTACHMENT, ParseMarkToMarkAttachment},
+ {GPOS_TYPE_CONTEXT_POSITIONING, ParseContextPositioning},
+ {GPOS_TYPE_CHAINED_CONTEXT_POSITIONING, ParseChainedContextPositioning},
+ {GPOS_TYPE_EXTENSION_POSITIONING, ParseExtensionPositioning}
+};
+
+const ots::LookupSubtableParser kGposLookupSubtableParser = {
+ arraysize(kGposTypeParsers),
+ GPOS_TYPE_EXTENSION_POSITIONING, kGposTypeParsers
+};
+
+// Shared Tables: ValueRecord, Anchor Table, and MarkArray
+
+bool ParseValueRecord(const ots::OpenTypeFile *file,
+ ots::Buffer* subtable, const uint8_t *data,
+ const size_t length, const uint16_t value_format) {
+ // Check existence of adjustment fields.
+ for (unsigned i = 0; i < 4; ++i) {
+ if ((value_format >> i) & 0x1) {
+ // Just read the field since these fileds could take an arbitrary values.
+ if (!subtable->Skip(2)) {
+ return OTS_FAILURE_MSG("Failed to read value reacord component");
+ }
+ }
+ }
+
+ // Check existence of offsets to device table.
+ for (unsigned i = 0; i < 4; ++i) {
+ if ((value_format >> (i + 4)) & 0x1) {
+ uint16_t offset = 0;
+ if (!subtable->ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read value record offset");
+ }
+ if (offset) {
+ // TODO(bashi): Is it possible that device tables locate before
+ // this record? No fonts contain such offset AKAIF.
+ if (offset >= length) {
+ return OTS_FAILURE_MSG("Value record offset too high %d >= %ld", offset, length);
+ }
+ if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
+ return OTS_FAILURE_MSG("Failed to parse device table in value record");
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool ParseAnchorTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ // Read format and skip 2 2-byte fields that could be arbitrary values.
+ if (!subtable.ReadU16(&format) ||
+ !subtable.Skip(4)) {
+ return OTS_FAILURE_MSG("Faled to read anchor table");
+ }
+
+ if (format == 0 || format > kMaxAnchorFormat) {
+ return OTS_FAILURE_MSG("Bad Anchor table format %d", format);
+ }
+
+ // Format 2 and 3 has additional fields.
+ if (format == 2) {
+ // Format 2 provides an index to a glyph contour point, which will take
+ // arbitrary value.
+ uint16_t anchor_point = 0;
+ if (!subtable.ReadU16(&anchor_point)) {
+ return OTS_FAILURE_MSG("Failed to read anchor point in format 2 Anchor Table");
+ }
+ } else if (format == 3) {
+ uint16_t offset_x_device = 0;
+ uint16_t offset_y_device = 0;
+ if (!subtable.ReadU16(&offset_x_device) ||
+ !subtable.ReadU16(&offset_y_device)) {
+ return OTS_FAILURE_MSG("Failed to read device table offsets in format 3 anchor table");
+ }
+ const unsigned format_end = static_cast<unsigned>(10);
+ if (offset_x_device) {
+ if (offset_x_device < format_end || offset_x_device >= length) {
+ return OTS_FAILURE_MSG("Bad x device table offset %d", offset_x_device);
+ }
+ if (!ots::ParseDeviceTable(file, data + offset_x_device,
+ length - offset_x_device)) {
+ return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
+ }
+ }
+ if (offset_y_device) {
+ if (offset_y_device < format_end || offset_y_device >= length) {
+ return OTS_FAILURE_MSG("Bad y device table offset %d", offset_y_device);
+ }
+ if (!ots::ParseDeviceTable(file, data + offset_y_device,
+ length - offset_y_device)) {
+ return OTS_FAILURE_MSG("Failed to parse device table in anchor table");
+ }
+ }
+ }
+ return true;
+}
+
+bool ParseMarkArrayTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t class_count) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t mark_count = 0;
+ if (!subtable.ReadU16(&mark_count)) {
+ return OTS_FAILURE_MSG("Can't read mark table length");
+ }
+
+ // MarkRecord consists of 4-bytes.
+ const unsigned mark_records_end = 4 * static_cast<unsigned>(mark_count) + 2;
+ if (mark_records_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad mark table length");
+ }
+ for (unsigned i = 0; i < mark_count; ++i) {
+ uint16_t class_value = 0;
+ uint16_t offset_mark_anchor = 0;
+ if (!subtable.ReadU16(&class_value) ||
+ !subtable.ReadU16(&offset_mark_anchor)) {
+ return OTS_FAILURE_MSG("Can't read mark table %d", i);
+ }
+ // |class_value| may take arbitrary values including 0 here so we don't
+ // check the value.
+ if (offset_mark_anchor < mark_records_end ||
+ offset_mark_anchor >= length) {
+ return OTS_FAILURE_MSG("Bad mark anchor offset %d for mark table %d", offset_mark_anchor, i);
+ }
+ if (!ParseAnchorTable(file, data + offset_mark_anchor,
+ length - offset_mark_anchor)) {
+ return OTS_FAILURE_MSG("Faled to parse anchor table for mark table %d", i);
+ }
+ }
+
+ return true;
+}
+
+// Lookup Type 1:
+// Single Adjustment Positioning Subtable
+bool ParseSingleAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
+ const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+ uint16_t value_format = 0;
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&value_format)) {
+ return OTS_FAILURE_MSG("Can't read single adjustment information");
+ }
+
+ if (format == 1) {
+ // Format 1 exactly one value record.
+ if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
+ return OTS_FAILURE_MSG("Failed to parse format 1 single adjustment table");
+ }
+ } else if (format == 2) {
+ uint16_t value_count = 0;
+ if (!subtable.ReadU16(&value_count)) {
+ return OTS_FAILURE_MSG("Failed to parse format 2 single adjustment table");
+ }
+ for (unsigned i = 0; i < value_count; ++i) {
+ if (!ParseValueRecord(file, &subtable, data, length, value_format)) {
+ return OTS_FAILURE_MSG("Failed to parse value record %d in format 2 single adjustment table", i);
+ }
+ }
+ } else {
+ return OTS_FAILURE_MSG("Bad format %d in single adjustment table", format);
+ }
+
+ if (offset_coverage < subtable.offset() || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d in single adjustment table", offset_coverage);
+ }
+
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage,
+ file->maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table in single adjustment table");
+ }
+
+ return true;
+}
+
+bool ParsePairSetTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t value_format1,
+ const uint16_t value_format2,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t value_count = 0;
+ if (!subtable.ReadU16(&value_count)) {
+ return OTS_FAILURE_MSG("Failed to read pair set table structure");
+ }
+ for (unsigned i = 0; i < value_count; ++i) {
+ // Check pair value record.
+ uint16_t glyph_id = 0;
+ if (!subtable.ReadU16(&glyph_id)) {
+ return OTS_FAILURE_MSG("Failed to read glyph in pair value record %d", i);
+ }
+ if (glyph_id >= num_glyphs) {
+ return OTS_FAILURE_MSG("glyph id %d too high >= %d", glyph_id, num_glyphs);
+ }
+ if (!ParseValueRecord(file, &subtable, data, length, value_format1)) {
+ return OTS_FAILURE_MSG("Failed to parse value record in format 1 pair set table");
+ }
+ if (!ParseValueRecord(file, &subtable, data, length, value_format2)) {
+ return OTS_FAILURE_MSG("Failed to parse value record in format 2 pair set table");
+ }
+ }
+ return true;
+}
+
+bool ParsePairPosFormat1(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t value_format1,
+ const uint16_t value_format2,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Skip 8 bytes that are already read before.
+ if (!subtable.Skip(8)) {
+ return OTS_FAILURE_MSG("Failed to read pair pos table structure");
+ }
+
+ uint16_t pair_set_count = 0;
+ if (!subtable.ReadU16(&pair_set_count)) {
+ return OTS_FAILURE_MSG("Failed to read pair pos set count");
+ }
+
+ const unsigned pair_pos_end = 2 * static_cast<unsigned>(pair_set_count) + 10;
+ if (pair_pos_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad pair set length %d", pair_pos_end);
+ }
+ for (unsigned i = 0; i < pair_set_count; ++i) {
+ uint16_t pair_set_offset = 0;
+ if (!subtable.ReadU16(&pair_set_offset)) {
+ return OTS_FAILURE_MSG("Failed to read pair set offset for pair set %d", i);
+ }
+ if (pair_set_offset < pair_pos_end || pair_set_offset >= length) {
+ return OTS_FAILURE_MSG("Bad pair set offset %d for pair set %d", pair_set_offset, i);
+ }
+ // Check pair set tables
+ if (!ParsePairSetTable(file, data + pair_set_offset, length - pair_set_offset,
+ value_format1, value_format2,
+ num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse pair set table %d", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParsePairPosFormat2(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t value_format1,
+ const uint16_t value_format2,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Skip 8 bytes that are already read before.
+ if (!subtable.Skip(8)) {
+ return OTS_FAILURE_MSG("Failed to read pair pos format 2 structure");
+ }
+
+ uint16_t offset_class_def1 = 0;
+ uint16_t offset_class_def2 = 0;
+ uint16_t class1_count = 0;
+ uint16_t class2_count = 0;
+ if (!subtable.ReadU16(&offset_class_def1) ||
+ !subtable.ReadU16(&offset_class_def2) ||
+ !subtable.ReadU16(&class1_count) ||
+ !subtable.ReadU16(&class2_count)) {
+ return OTS_FAILURE_MSG("Failed to read pair pos format 2 data");
+ }
+
+ // Check class 1 records.
+ for (unsigned i = 0; i < class1_count; ++i) {
+ // Check class 2 records.
+ for (unsigned j = 0; j < class2_count; ++j) {
+ if (value_format1 && !ParseValueRecord(file, &subtable, data, length,
+ value_format1)) {
+ return OTS_FAILURE_MSG("Failed to parse value record 1 %d and %d", j, i);
+ }
+ if (value_format2 && !ParseValueRecord(file, &subtable, data, length,
+ value_format2)) {
+ return OTS_FAILURE_MSG("Falied to parse value record 2 %d and %d", j, i);
+ }
+ }
+ }
+
+ // Check class definition tables.
+ if (offset_class_def1 < subtable.offset() || offset_class_def1 >= length ||
+ offset_class_def2 < subtable.offset() || offset_class_def2 >= length) {
+ return OTS_FAILURE_MSG("Bad class definition table offsets %d or %d", offset_class_def1, offset_class_def2);
+ }
+ if (!ots::ParseClassDefTable(file, data + offset_class_def1,
+ length - offset_class_def1,
+ num_glyphs, kMaxClassDefValue)) {
+ return OTS_FAILURE_MSG("Failed to parse class definition table 1");
+ }
+ if (!ots::ParseClassDefTable(file, data + offset_class_def2,
+ length - offset_class_def2,
+ num_glyphs, kMaxClassDefValue)) {
+ return OTS_FAILURE_MSG("Failed to parse class definition table 2");
+ }
+
+ return true;
+}
+
+// Lookup Type 2:
+// Pair Adjustment Positioning Subtable
+bool ParsePairAdjustment(const ots::OpenTypeFile *file, const uint8_t *data,
+ const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+ uint16_t value_format1 = 0;
+ uint16_t value_format2 = 0;
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&value_format1) ||
+ !subtable.ReadU16(&value_format2)) {
+ return OTS_FAILURE_MSG("Failed to read pair adjustment structure");
+ }
+
+ if (format == 1) {
+ if (!ParsePairPosFormat1(file, data, length, value_format1, value_format2,
+ file->maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse pair pos format 1");
+ }
+ } else if (format == 2) {
+ if (!ParsePairPosFormat2(file, data, length, value_format1, value_format2,
+ file->maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse pair format 2");
+ }
+ } else {
+ return OTS_FAILURE_MSG("Bad pos pair format %d", format);
+ }
+
+ if (offset_coverage < subtable.offset() || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad pair pos offset coverage %d", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage,
+ file->maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table");
+ }
+
+ return true;
+}
+
+// Lookup Type 3
+// Cursive Attachment Positioning Subtable
+bool ParseCursiveAttachment(const ots::OpenTypeFile *file, const uint8_t *data,
+ const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+ uint16_t entry_exit_count = 0;
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&entry_exit_count)) {
+ return OTS_FAILURE_MSG("Failed to read cursive attachment structure");
+ }
+
+ if (format != 1) {
+ return OTS_FAILURE_MSG("Bad cursive attachment format %d", format);
+ }
+
+ // Check entry exit records.
+ const unsigned entry_exit_records_end =
+ 2 * static_cast<unsigned>(entry_exit_count) + 6;
+ if (entry_exit_records_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad entry exit record end %d", entry_exit_records_end);
+ }
+ for (unsigned i = 0; i < entry_exit_count; ++i) {
+ uint16_t offset_entry_anchor = 0;
+ uint16_t offset_exit_anchor = 0;
+ if (!subtable.ReadU16(&offset_entry_anchor) ||
+ !subtable.ReadU16(&offset_exit_anchor)) {
+ return OTS_FAILURE_MSG("Can't read entry exit record %d", i);
+ }
+ // These offsets could be NULL.
+ if (offset_entry_anchor) {
+ if (offset_entry_anchor < entry_exit_records_end ||
+ offset_entry_anchor >= length) {
+ return OTS_FAILURE_MSG("Bad entry anchor offset %d in entry exit record %d", offset_entry_anchor, i);
+ }
+ if (!ParseAnchorTable(file, data + offset_entry_anchor,
+ length - offset_entry_anchor)) {
+ return OTS_FAILURE_MSG("Failed to parse entry anchor table in entry exit record %d", i);
+ }
+ }
+ if (offset_exit_anchor) {
+ if (offset_exit_anchor < entry_exit_records_end ||
+ offset_exit_anchor >= length) {
+ return OTS_FAILURE_MSG("Bad exit anchor offset %d in entry exit record %d", offset_exit_anchor, i);
+ }
+ if (!ParseAnchorTable(file, data + offset_exit_anchor,
+ length - offset_exit_anchor)) {
+ return OTS_FAILURE_MSG("Failed to parse exit anchor table in entry exit record %d", i);
+ }
+ }
+ }
+
+ if (offset_coverage < subtable.offset() || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset in cursive attachment %d", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage,
+ file->maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table in cursive attachment");
+ }
+
+ return true;
+}
+
+bool ParseAnchorArrayTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t class_count) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t record_count = 0;
+ if (!subtable.ReadU16(&record_count)) {
+ return OTS_FAILURE_MSG("Can't read anchor array length");
+ }
+
+ const unsigned anchor_array_end = 2 * static_cast<unsigned>(record_count) *
+ static_cast<unsigned>(class_count) + 2;
+ if (anchor_array_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of anchor array %d", anchor_array_end);
+ }
+ for (unsigned i = 0; i < record_count; ++i) {
+ for (unsigned j = 0; j < class_count; ++j) {
+ uint16_t offset_record = 0;
+ if (!subtable.ReadU16(&offset_record)) {
+ return OTS_FAILURE_MSG("Can't read anchor array record offset for class %d and record %d", j, i);
+ }
+ // |offset_record| could be NULL.
+ if (offset_record) {
+ if (offset_record < anchor_array_end || offset_record >= length) {
+ return OTS_FAILURE_MSG("Bad record offset %d in class %d, record %d", offset_record, j, i);
+ }
+ if (!ParseAnchorTable(file, data + offset_record,
+ length - offset_record)) {
+ return OTS_FAILURE_MSG("Failed to parse anchor table for class %d, record %d", j, i);
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool ParseLigatureArrayTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t class_count) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t ligature_count = 0;
+ if (!subtable.ReadU16(&ligature_count)) {
+ return OTS_FAILURE_MSG("Failed to read ligature count");
+ }
+ for (unsigned i = 0; i < ligature_count; ++i) {
+ uint16_t offset_ligature_attach = 0;
+ if (!subtable.ReadU16(&offset_ligature_attach)) {
+ return OTS_FAILURE_MSG("Can't read ligature offset %d", i);
+ }
+ if (offset_ligature_attach < 2 || offset_ligature_attach >= length) {
+ return OTS_FAILURE_MSG("Bad ligature attachment offset %d in ligature %d", offset_ligature_attach, i);
+ }
+ if (!ParseAnchorArrayTable(file, data + offset_ligature_attach,
+ length - offset_ligature_attach, class_count)) {
+ return OTS_FAILURE_MSG("Failed to parse anchor table for ligature %d", i);
+ }
+ }
+ return true;
+}
+
+// Common parser for Lookup Type 4, 5 and 6.
+bool ParseMarkToAttachmentSubtables(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const GPOS_TYPE type) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage1 = 0;
+ uint16_t offset_coverage2 = 0;
+ uint16_t class_count = 0;
+ uint16_t offset_mark_array = 0;
+ uint16_t offset_type_specific_array = 0;
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage1) ||
+ !subtable.ReadU16(&offset_coverage2) ||
+ !subtable.ReadU16(&class_count) ||
+ !subtable.ReadU16(&offset_mark_array) ||
+ !subtable.ReadU16(&offset_type_specific_array)) {
+ return OTS_FAILURE_MSG("Failed to read mark attachment subtable header");
+ }
+
+ if (format != 1) {
+ return OTS_FAILURE_MSG("bad mark attachment subtable format %d", format);
+ }
+
+ const unsigned header_end = static_cast<unsigned>(subtable.offset());
+ if (header_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad mark attachment subtable size ending at %d", header_end);
+ }
+ if (offset_coverage1 < header_end || offset_coverage1 >= length) {
+ return OTS_FAILURE_MSG("Bad coverage 1 offset %d", offset_coverage1);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage1,
+ length - offset_coverage1,
+ file->maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse converge 1 table");
+ }
+ if (offset_coverage2 < header_end || offset_coverage2 >= length) {
+ return OTS_FAILURE_MSG("Bad coverage 2 offset %d", offset_coverage2);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage2,
+ length - offset_coverage2,
+ file->maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table 2");
+ }
+
+ if (offset_mark_array < header_end || offset_mark_array >= length) {
+ return OTS_FAILURE_MSG("Bad mark array offset %d", offset_mark_array);
+ }
+ if (!ParseMarkArrayTable(file, data + offset_mark_array,
+ length - offset_mark_array, class_count)) {
+ return OTS_FAILURE_MSG("Failed to parse mark array");
+ }
+
+ if (offset_type_specific_array < header_end ||
+ offset_type_specific_array >= length) {
+ return OTS_FAILURE_MSG("Bad type specific array offset %d", offset_type_specific_array);
+ }
+ if (type == GPOS_TYPE_MARK_TO_BASE_ATTACHMENT ||
+ type == GPOS_TYPE_MARK_TO_MARK_ATTACHMENT) {
+ if (!ParseAnchorArrayTable(file, data + offset_type_specific_array,
+ length - offset_type_specific_array,
+ class_count)) {
+ return OTS_FAILURE_MSG("Failed to parse anchor array");
+ }
+ } else if (type == GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT) {
+ if (!ParseLigatureArrayTable(file, data + offset_type_specific_array,
+ length - offset_type_specific_array,
+ class_count)) {
+ return OTS_FAILURE_MSG("Failed to parse ligature array");
+ }
+ } else {
+ return OTS_FAILURE_MSG("Bad attachment type %d", type);
+ }
+
+ return true;
+}
+
+// Lookup Type 4:
+// MarkToBase Attachment Positioning Subtable
+bool ParseMarkToBaseAttachment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ParseMarkToAttachmentSubtables(file, data, length,
+ GPOS_TYPE_MARK_TO_BASE_ATTACHMENT);
+}
+
+// Lookup Type 5:
+// MarkToLigature Attachment Positioning Subtable
+bool ParseMarkToLigatureAttachment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ParseMarkToAttachmentSubtables(file, data, length,
+ GPOS_TYPE_MARK_TO_LIGATURE_ATTACHMENT);
+}
+
+// Lookup Type 6:
+// MarkToMark Attachment Positioning Subtable
+bool ParseMarkToMarkAttachment(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ParseMarkToAttachmentSubtables(file, data, length,
+ GPOS_TYPE_MARK_TO_MARK_ATTACHMENT);
+}
+
+// Lookup Type 7:
+// Contextual Positioning Subtables
+bool ParseContextPositioning(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
+ file->gpos->num_lookups);
+}
+
+// Lookup Type 8:
+// Chaining Contexual Positioning Subtable
+bool ParseChainedContextPositioning(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ots::ParseChainingContextSubtable(file, data, length,
+ file->maxp->num_glyphs,
+ file->gpos->num_lookups);
+}
+
+// Lookup Type 9:
+// Extension Positioning
+bool ParseExtensionPositioning(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ots::ParseExtensionSubtable(file, data, length,
+ &kGposLookupSubtableParser);
+}
+
+} // namespace
+
+#define DROP_THIS_TABLE(msg_) \
+ do { \
+ OTS_FAILURE_MSG(msg_ ", table discarded"); \
+ file->gpos->data = 0; \
+ file->gpos->length = 0; \
+ } while (0)
+
+namespace ots {
+
+// As far as I checked, following fonts contain invalid GPOS table and
+// OTS will drop their GPOS table.
+//
+// # invalid delta format in device table
+// samanata.ttf
+//
+// # bad size range in device table
+// Sarai_07.ttf
+//
+// # bad offset to PairSetTable
+// chandas1-2.ttf
+//
+// # bad offset to FeatureTable
+// glrso12.ttf
+// gllr12.ttf
+// glbo12.ttf
+// glb12.ttf
+// glro12.ttf
+// glbso12.ttf
+// glrc12.ttf
+// glrsc12.ttf
+// glbs12.ttf
+// glrs12.ttf
+// glr12.ttf
+//
+// # ScriptRecords aren't sorted by tag
+// Garogier_unhinted.otf
+//
+// # bad start coverage index in CoverageFormat2
+// AndBasR.ttf
+// CharisSILB.ttf
+// CharisSILBI.ttf
+// CharisSILI.ttf
+// CharisSILR.ttf
+// DoulosSILR.ttf
+// GenBasBI.ttf
+// GenBasI.ttf
+// GenBkBasI.ttf
+// GenBkBasB.ttf
+// GenBkBasR.ttf
+// Padauk-Bold.ttf
+// Padauk.ttf
+//
+// # Contour point indexes aren't sorted
+// Arial Unicode.ttf
+
+bool ots_gpos_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ // Parsing GPOS table requires num_glyphs which is contained in maxp table.
+ if (!file->maxp) {
+ return OTS_FAILURE_MSG("missing maxp table needed in GPOS");
+ }
+
+ Buffer table(data, length);
+
+ OpenTypeGPOS *gpos = new OpenTypeGPOS;
+ file->gpos = gpos;
+
+ uint32_t version = 0;
+ uint16_t offset_script_list = 0;
+ uint16_t offset_feature_list = 0;
+ uint16_t offset_lookup_list = 0;
+ if (!table.ReadU32(&version) ||
+ !table.ReadU16(&offset_script_list) ||
+ !table.ReadU16(&offset_feature_list) ||
+ !table.ReadU16(&offset_lookup_list)) {
+ DROP_THIS_TABLE("Incomplete table");
+ return true;
+ }
+
+ if (version != 0x00010000) {
+ DROP_THIS_TABLE("Bad version");
+ return true;
+ }
+
+ if (offset_lookup_list) {
+ if (offset_lookup_list < kGposHeaderSize || offset_lookup_list >= length) {
+ DROP_THIS_TABLE("Bad lookup list offset in table header");
+ return true;
+ }
+
+ if (!ParseLookupListTable(file, data + offset_lookup_list,
+ length - offset_lookup_list,
+ &kGposLookupSubtableParser,
+ &gpos->num_lookups)) {
+ DROP_THIS_TABLE("Failed to parse lookup list table");
+ return true;
+ }
+ }
+
+ uint16_t num_features = 0;
+ if (offset_feature_list) {
+ if (offset_feature_list < kGposHeaderSize || offset_feature_list >= length) {
+ DROP_THIS_TABLE("Bad feature list offset in table header");
+ return true;
+ }
+
+ if (!ParseFeatureListTable(file, data + offset_feature_list,
+ length - offset_feature_list, gpos->num_lookups,
+ &num_features)) {
+ DROP_THIS_TABLE("Failed to parse feature list table");
+ return true;
+ }
+ }
+
+ if (offset_script_list) {
+ if (offset_script_list < kGposHeaderSize || offset_script_list >= length) {
+ DROP_THIS_TABLE("Bad script list offset in table header");
+ return true;
+ }
+
+ if (!ParseScriptListTable(file, data + offset_script_list,
+ length - offset_script_list, num_features)) {
+ DROP_THIS_TABLE("Failed to parse script list table");
+ return true;
+ }
+ }
+
+ gpos->data = data;
+ gpos->length = length;
+ return true;
+}
+
+bool ots_gpos_should_serialise(OpenTypeFile *file) {
+ return file->gpos != NULL && file->gpos->data != NULL;
+}
+
+bool ots_gpos_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!out->Write(file->gpos->data, file->gpos->length)) {
+ return OTS_FAILURE_MSG("Failed to write GPOS table");
+ }
+
+ return true;
+}
+
+void ots_gpos_free(OpenTypeFile *file) {
+ delete file->gpos;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/gpos.h b/third_party/ots/src/gpos.h
new file mode 100644
index 0000000..3a4034f
--- /dev/null
+++ b/third_party/ots/src/gpos.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_GPOS_H_
+#define OTS_GPOS_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeGPOS {
+ OpenTypeGPOS()
+ : num_lookups(0),
+ data(NULL),
+ length(0) {
+ }
+
+ // Number of lookups in GPOS table
+ uint16_t num_lookups;
+
+ const uint8_t *data;
+ size_t length;
+};
+
+} // namespace ots
+
+#endif
+
diff --git a/third_party/ots/src/gsub.cc b/third_party/ots/src/gsub.cc
new file mode 100644
index 0000000..af31144
--- /dev/null
+++ b/third_party/ots/src/gsub.cc
@@ -0,0 +1,685 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "gsub.h"
+
+#include <limits>
+#include <vector>
+
+#include "layout.h"
+#include "maxp.h"
+
+// GSUB - The Glyph Substitution Table
+// http://www.microsoft.com/typography/otspec/gsub.htm
+
+#define TABLE_NAME "GSUB"
+
+namespace {
+
+// The GSUB header size
+const size_t kGsubHeaderSize = 4 + 3 * 2;
+
+enum GSUB_TYPE {
+ GSUB_TYPE_SINGLE = 1,
+ GSUB_TYPE_MULTIPLE = 2,
+ GSUB_TYPE_ALTERNATE = 3,
+ GSUB_TYPE_LIGATURE = 4,
+ GSUB_TYPE_CONTEXT = 5,
+ GSUB_TYPE_CHANGING_CONTEXT = 6,
+ GSUB_TYPE_EXTENSION_SUBSTITUTION = 7,
+ GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE = 8,
+ GSUB_TYPE_RESERVED = 9
+};
+
+// Lookup type parsers.
+bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseContextSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data,
+ const size_t length);
+bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length);
+bool ParseReverseChainingContextSingleSubstitution(
+ const ots::OpenTypeFile *file, const uint8_t *data, const size_t length);
+
+const ots::LookupSubtableParser::TypeParser kGsubTypeParsers[] = {
+ {GSUB_TYPE_SINGLE, ParseSingleSubstitution},
+ {GSUB_TYPE_MULTIPLE, ParseMutipleSubstitution},
+ {GSUB_TYPE_ALTERNATE, ParseAlternateSubstitution},
+ {GSUB_TYPE_LIGATURE, ParseLigatureSubstitution},
+ {GSUB_TYPE_CONTEXT, ParseContextSubstitution},
+ {GSUB_TYPE_CHANGING_CONTEXT, ParseChainingContextSubstitution},
+ {GSUB_TYPE_EXTENSION_SUBSTITUTION, ParseExtensionSubstitution},
+ {GSUB_TYPE_REVERSE_CHAINING_CONTEXT_SINGLE,
+ ParseReverseChainingContextSingleSubstitution}
+};
+
+const ots::LookupSubtableParser kGsubLookupSubtableParser = {
+ arraysize(kGsubTypeParsers),
+ GSUB_TYPE_EXTENSION_SUBSTITUTION, kGsubTypeParsers
+};
+
+// Lookup Type 1:
+// Single Substitution Subtable
+bool ParseSingleSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage)) {
+ return OTS_FAILURE_MSG("Failed to read single subst table header");
+ }
+
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+ if (format == 1) {
+ // Parse SingleSubstFormat1
+ int16_t delta_glyph_id = 0;
+ if (!subtable.ReadS16(&delta_glyph_id)) {
+ return OTS_FAILURE_MSG("Failed to read glyph shift from format 1 single subst table");
+ }
+ if (std::abs(delta_glyph_id) >= num_glyphs) {
+ return OTS_FAILURE_MSG("bad glyph shift of %d in format 1 single subst table", delta_glyph_id);
+ }
+ } else if (format == 2) {
+ // Parse SingleSubstFormat2
+ uint16_t glyph_count = 0;
+ if (!subtable.ReadU16(&glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read glyph cound in format 2 single subst table");
+ }
+ if (glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph count %d > %d in format 2 single subst table", glyph_count, num_glyphs);
+ }
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t substitute = 0;
+ if (!subtable.ReadU16(&substitute)) {
+ return OTS_FAILURE_MSG("Failed to read substitution %d in format 2 single subst table", i);
+ }
+ if (substitute >= num_glyphs) {
+ return OTS_FAILURE_MSG("too large substitute: %u", substitute);
+ }
+ }
+ } else {
+ return OTS_FAILURE_MSG("Bad single subst table format %d", format);
+ }
+
+ if (offset_coverage < subtable.offset() || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %x", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table");
+ }
+
+ return true;
+}
+
+bool ParseSequenceTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t glyph_count = 0;
+ if (!subtable.ReadU16(&glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read glyph count in sequence table");
+ }
+ if (glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("bad glyph count %d > %d", glyph_count, num_glyphs);
+ }
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t substitute = 0;
+ if (!subtable.ReadU16(&substitute)) {
+ return OTS_FAILURE_MSG("Failedt o read substitution %d in sequence table", i);
+ }
+ if (substitute >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad subsitution (%d) %d > %d", i, substitute, num_glyphs);
+ }
+ }
+
+ return true;
+}
+
+// Lookup Type 2:
+// Multiple Substitution Subtable
+bool ParseMutipleSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+ uint16_t sequence_count = 0;
+
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&sequence_count)) {
+ return OTS_FAILURE_MSG("Can't read header of multiple subst table");
+ }
+
+ if (format != 1) {
+ return OTS_FAILURE_MSG("Bad multiple subst table format %d", format);
+ }
+
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+ const unsigned sequence_end = static_cast<unsigned>(6) +
+ sequence_count * 2;
+ if (sequence_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad segence end %d, in multiple subst", sequence_end);
+ }
+ for (unsigned i = 0; i < sequence_count; ++i) {
+ uint16_t offset_sequence = 0;
+ if (!subtable.ReadU16(&offset_sequence)) {
+ return OTS_FAILURE_MSG("Failed to read sequence offset for sequence %d", i);
+ }
+ if (offset_sequence < sequence_end || offset_sequence >= length) {
+ return OTS_FAILURE_MSG("Bad sequence offset %d for sequence %d", offset_sequence, i);
+ }
+ if (!ParseSequenceTable(file, data + offset_sequence, length - offset_sequence,
+ num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse sequence table %d", i);
+ }
+ }
+
+ if (offset_coverage < sequence_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table");
+ }
+
+ return true;
+}
+
+bool ParseAlternateSetTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t glyph_count = 0;
+ if (!subtable.ReadU16(&glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read alternate set header");
+ }
+ if (glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph count %d > %d in alternate set table", glyph_count, num_glyphs);
+ }
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t alternate = 0;
+ if (!subtable.ReadU16(&alternate)) {
+ return OTS_FAILURE_MSG("Can't read alternate %d", i);
+ }
+ if (alternate >= num_glyphs) {
+ return OTS_FAILURE_MSG("Too large alternate: %u", alternate);
+ }
+ }
+ return true;
+}
+
+// Lookup Type 3:
+// Alternate Substitution Subtable
+bool ParseAlternateSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+ uint16_t alternate_set_count = 0;
+
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&alternate_set_count)) {
+ return OTS_FAILURE_MSG("Can't read alternate subst header");
+ }
+
+ if (format != 1) {
+ return OTS_FAILURE_MSG("Bad alternate subst table format %d", format);
+ }
+
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+ const unsigned alternate_set_end = static_cast<unsigned>(6) +
+ alternate_set_count * 2;
+ if (alternate_set_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of alternate set %d", alternate_set_end);
+ }
+ for (unsigned i = 0; i < alternate_set_count; ++i) {
+ uint16_t offset_alternate_set = 0;
+ if (!subtable.ReadU16(&offset_alternate_set)) {
+ return OTS_FAILURE_MSG("Can't read alternate set offset for set %d", i);
+ }
+ if (offset_alternate_set < alternate_set_end ||
+ offset_alternate_set >= length) {
+ return OTS_FAILURE_MSG("Bad alternate set offset %d for set %d", offset_alternate_set, i);
+ }
+ if (!ParseAlternateSetTable(file, data + offset_alternate_set,
+ length - offset_alternate_set,
+ num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse alternate set");
+ }
+ }
+
+ if (offset_coverage < alternate_set_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table");
+ }
+
+ return true;
+}
+
+bool ParseLigatureTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t lig_glyph = 0;
+ uint16_t comp_count = 0;
+
+ if (!subtable.ReadU16(&lig_glyph) ||
+ !subtable.ReadU16(&comp_count)) {
+ return OTS_FAILURE_MSG("Failed to read ligatuer table header");
+ }
+
+ if (lig_glyph >= num_glyphs) {
+ return OTS_FAILURE_MSG("too large lig_glyph: %u", lig_glyph);
+ }
+ if (comp_count == 0 || comp_count > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad component count of %d", comp_count);
+ }
+ for (unsigned i = 0; i < comp_count - static_cast<unsigned>(1); ++i) {
+ uint16_t component = 0;
+ if (!subtable.ReadU16(&component)) {
+ return OTS_FAILURE_MSG("Can't read ligature component %d", i);
+ }
+ if (component >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad ligature component %d of %d", i, component);
+ }
+ }
+
+ return true;
+}
+
+bool ParseLigatureSetTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t ligature_count = 0;
+
+ if (!subtable.ReadU16(&ligature_count)) {
+ return OTS_FAILURE_MSG("Can't read ligature count in ligature set");
+ }
+
+ const unsigned ligature_end = static_cast<unsigned>(2) + ligature_count * 2;
+ if (ligature_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of ligature %d in ligature set", ligature_end);
+ }
+ for (unsigned i = 0; i < ligature_count; ++i) {
+ uint16_t offset_ligature = 0;
+ if (!subtable.ReadU16(&offset_ligature)) {
+ return OTS_FAILURE_MSG("Failed to read ligature offset %d", i);
+ }
+ if (offset_ligature < ligature_end || offset_ligature >= length) {
+ return OTS_FAILURE_MSG("Bad ligature offset %d for ligature %d", offset_ligature, i);
+ }
+ if (!ParseLigatureTable(file, data + offset_ligature, length - offset_ligature,
+ num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse ligature %d", i);
+ }
+ }
+
+ return true;
+}
+
+// Lookup Type 4:
+// Ligature Substitution Subtable
+bool ParseLigatureSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+ uint16_t lig_set_count = 0;
+
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&lig_set_count)) {
+ return OTS_FAILURE_MSG("Failed to read ligature substitution header");
+ }
+
+ if (format != 1) {
+ return OTS_FAILURE_MSG("Bad ligature substitution table format %d", format);
+ }
+
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+ const unsigned ligature_set_end = static_cast<unsigned>(6) +
+ lig_set_count * 2;
+ if (ligature_set_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of ligature set %d in ligature substitution table", ligature_set_end);
+ }
+ for (unsigned i = 0; i < lig_set_count; ++i) {
+ uint16_t offset_ligature_set = 0;
+ if (!subtable.ReadU16(&offset_ligature_set)) {
+ return OTS_FAILURE_MSG("Can't read ligature set offset %d", i);
+ }
+ if (offset_ligature_set < ligature_set_end ||
+ offset_ligature_set >= length) {
+ return OTS_FAILURE_MSG("Bad ligature set offset %d for set %d", offset_ligature_set, i);
+ }
+ if (!ParseLigatureSetTable(file, data + offset_ligature_set,
+ length - offset_ligature_set, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse ligature set %d", i);
+ }
+ }
+
+ if (offset_coverage < ligature_set_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table");
+ }
+
+ return true;
+}
+
+// Lookup Type 5:
+// Contextual Substitution Subtable
+bool ParseContextSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ots::ParseContextSubtable(file, data, length, file->maxp->num_glyphs,
+ file->gsub->num_lookups);
+}
+
+// Lookup Type 6:
+// Chaining Contextual Substitution Subtable
+bool ParseChainingContextSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data,
+ const size_t length) {
+ return ots::ParseChainingContextSubtable(file, data, length,
+ file->maxp->num_glyphs,
+ file->gsub->num_lookups);
+}
+
+// Lookup Type 7:
+// Extension Substition
+bool ParseExtensionSubstitution(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length) {
+ return ots::ParseExtensionSubtable(file, data, length,
+ &kGsubLookupSubtableParser);
+}
+
+// Lookup Type 8:
+// Reverse Chaining Contexual Single Substitution Subtable
+bool ParseReverseChainingContextSingleSubstitution(
+ const ots::OpenTypeFile *file, const uint8_t *data, const size_t length) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t offset_coverage = 0;
+
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&offset_coverage)) {
+ return OTS_FAILURE_MSG("Failed to read reverse chaining header");
+ }
+
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+
+ uint16_t backtrack_glyph_count = 0;
+ if (!subtable.ReadU16(&backtrack_glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read backtrack glyph count in reverse chaining table");
+ }
+ if (backtrack_glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad backtrack glyph count of %d", backtrack_glyph_count);
+ }
+ std::vector<uint16_t> offsets_backtrack;
+ offsets_backtrack.reserve(backtrack_glyph_count);
+ for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
+ uint16_t offset = 0;
+ if (!subtable.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read backtrack offset %d", i);
+ }
+ offsets_backtrack.push_back(offset);
+ }
+
+ uint16_t lookahead_glyph_count = 0;
+ if (!subtable.ReadU16(&lookahead_glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read look ahead glyph count");
+ }
+ if (lookahead_glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad look ahead glyph count %d", lookahead_glyph_count);
+ }
+ std::vector<uint16_t> offsets_lookahead;
+ offsets_lookahead.reserve(lookahead_glyph_count);
+ for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
+ uint16_t offset = 0;
+ if (!subtable.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Can't read look ahead offset %d", i);
+ }
+ offsets_lookahead.push_back(offset);
+ }
+
+ uint16_t glyph_count = 0;
+ if (!subtable.ReadU16(&glyph_count)) {
+ return OTS_FAILURE_MSG("Can't read glyph count in reverse chaining table");
+ }
+ if (glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph count of %d", glyph_count);
+ }
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t substitute = 0;
+ if (!subtable.ReadU16(&substitute)) {
+ return OTS_FAILURE_MSG("Failed to read substitution %d reverse chaining table", i);
+ }
+ if (substitute >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad substitute glyph %d in reverse chaining table substitution %d", substitute, i);
+ }
+ }
+
+ const unsigned substitute_end = static_cast<unsigned>(10) +
+ (backtrack_glyph_count + lookahead_glyph_count + glyph_count) * 2;
+ if (substitute_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad substitute end offset in reverse chaining table");
+ }
+
+ if (offset_coverage < substitute_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d in reverse chaining table", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table in reverse chaining table");
+ }
+
+ for (unsigned i = 0; i < backtrack_glyph_count; ++i) {
+ if (offsets_backtrack[i] < substitute_end ||
+ offsets_backtrack[i] >= length) {
+ return OTS_FAILURE_MSG("Bad backtrack offset %d for backtrack %d in reverse chaining table", offsets_backtrack[i], i);
+ }
+ if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
+ length - offsets_backtrack[i], num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table for backtrack %d in reverse chaining table", i);
+ }
+ }
+
+ for (unsigned i = 0; i < lookahead_glyph_count; ++i) {
+ if (offsets_lookahead[i] < substitute_end ||
+ offsets_lookahead[i] >= length) {
+ return OTS_FAILURE_MSG("Bad lookahead offset %d for lookahead %d in reverse chaining table", offsets_lookahead[i], i);
+ }
+ if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
+ length - offsets_lookahead[i], num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in reverse chaining table", i);
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+#define DROP_THIS_TABLE(msg_) \
+ do { \
+ OTS_FAILURE_MSG(msg_ ", table discarded"); \
+ file->gsub->data = 0; \
+ file->gsub->length = 0; \
+ } while (0)
+
+namespace ots {
+
+// As far as I checked, following fonts contain invalid values in GSUB table.
+// OTS will drop their GSUB table.
+//
+// # too large substitute (value is 0xFFFF)
+// kaiu.ttf
+// mingliub2.ttf
+// mingliub1.ttf
+// mingliub0.ttf
+// GraublauWeb.otf
+// GraublauWebBold.otf
+//
+// # too large alternate (value is 0xFFFF)
+// ManchuFont.ttf
+//
+// # bad offset to lang sys table (NULL offset)
+// DejaVuMonoSansBold.ttf
+// DejaVuMonoSansBoldOblique.ttf
+// DejaVuMonoSansOblique.ttf
+// DejaVuSansMono-BoldOblique.ttf
+// DejaVuSansMono-Oblique.ttf
+// DejaVuSansMono-Bold.ttf
+//
+// # bad start coverage index
+// GenBasBI.ttf
+// GenBasI.ttf
+// AndBasR.ttf
+// GenBkBasI.ttf
+// CharisSILR.ttf
+// CharisSILBI.ttf
+// CharisSILI.ttf
+// CharisSILB.ttf
+// DoulosSILR.ttf
+// CharisSILBI.ttf
+// GenBkBasB.ttf
+// GenBkBasR.ttf
+// GenBkBasBI.ttf
+// GenBasB.ttf
+// GenBasR.ttf
+//
+// # glyph range is overlapping
+// KacstTitleL.ttf
+// KacstDecorative.ttf
+// KacstTitle.ttf
+// KacstArt.ttf
+// KacstPoster.ttf
+// KacstQurn.ttf
+// KacstDigital.ttf
+// KacstBook.ttf
+// KacstFarsi.ttf
+
+bool ots_gsub_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ // Parsing gsub table requires |file->maxp->num_glyphs|
+ if (!file->maxp) {
+ return OTS_FAILURE_MSG("Missing maxp table in font, needed by GSUB");
+ }
+
+ Buffer table(data, length);
+
+ OpenTypeGSUB *gsub = new OpenTypeGSUB;
+ file->gsub = gsub;
+
+ uint32_t version = 0;
+ uint16_t offset_script_list = 0;
+ uint16_t offset_feature_list = 0;
+ uint16_t offset_lookup_list = 0;
+ if (!table.ReadU32(&version) ||
+ !table.ReadU16(&offset_script_list) ||
+ !table.ReadU16(&offset_feature_list) ||
+ !table.ReadU16(&offset_lookup_list)) {
+ DROP_THIS_TABLE("Incomplete table");
+ return true;
+ }
+
+ if (version != 0x00010000) {
+ DROP_THIS_TABLE("Bad version");
+ return true;
+ }
+
+ if (offset_lookup_list) {
+ if (offset_lookup_list < kGsubHeaderSize || offset_lookup_list >= length) {
+ DROP_THIS_TABLE("Bad lookup list offset in table header");
+ return true;
+ }
+
+ if (!ParseLookupListTable(file, data + offset_lookup_list,
+ length - offset_lookup_list,
+ &kGsubLookupSubtableParser,
+ &gsub->num_lookups)) {
+ DROP_THIS_TABLE("Failed to parse lookup list table");
+ return true;
+ }
+ }
+
+ uint16_t num_features = 0;
+ if (offset_feature_list) {
+ if (offset_feature_list < kGsubHeaderSize || offset_feature_list >= length) {
+ DROP_THIS_TABLE("Bad feature list offset in table header");
+ return true;
+ }
+
+ if (!ParseFeatureListTable(file, data + offset_feature_list,
+ length - offset_feature_list, gsub->num_lookups,
+ &num_features)) {
+ DROP_THIS_TABLE("Failed to parse feature list table");
+ return true;
+ }
+ }
+
+ if (offset_script_list) {
+ if (offset_script_list < kGsubHeaderSize || offset_script_list >= length) {
+ DROP_THIS_TABLE("Bad script list offset in table header");
+ return true;
+ }
+
+ if (!ParseScriptListTable(file, data + offset_script_list,
+ length - offset_script_list, num_features)) {
+ DROP_THIS_TABLE("Failed to parse script list table");
+ return true;
+ }
+ }
+
+ gsub->data = data;
+ gsub->length = length;
+ return true;
+}
+
+bool ots_gsub_should_serialise(OpenTypeFile *file) {
+ return file->gsub != NULL && file->gsub->data != NULL;
+}
+
+bool ots_gsub_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!out->Write(file->gsub->data, file->gsub->length)) {
+ return OTS_FAILURE_MSG("Failed to write GSUB table");
+ }
+
+ return true;
+}
+
+void ots_gsub_free(OpenTypeFile *file) {
+ delete file->gsub;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/gsub.h b/third_party/ots/src/gsub.h
new file mode 100644
index 0000000..f6f8cd3
--- /dev/null
+++ b/third_party/ots/src/gsub.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_GSUB_H_
+#define OTS_GSUB_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeGSUB {
+ OpenTypeGSUB()
+ : num_lookups(0),
+ data(NULL),
+ length(0) {
+ }
+
+ // Number of lookups in GPSUB table
+ uint16_t num_lookups;
+
+ const uint8_t *data;
+ size_t length;
+};
+
+} // namespace ots
+
+#endif // OTS_GSUB_H_
+
diff --git a/third_party/ots/src/hdmx.cc b/third_party/ots/src/hdmx.cc
new file mode 100644
index 0000000..098802b
--- /dev/null
+++ b/third_party/ots/src/hdmx.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "hdmx.h"
+#include "head.h"
+#include "maxp.h"
+
+// hdmx - Horizontal Device Metrics
+// http://www.microsoft.com/typography/otspec/hdmx.htm
+
+#define TABLE_NAME "hdmx"
+
+#define DROP_THIS_TABLE(...) \
+ do { \
+ OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+ OTS_FAILURE_MSG("Table discarded"); \
+ delete file->hdmx; \
+ file->hdmx = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_hdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ file->hdmx = new OpenTypeHDMX;
+ OpenTypeHDMX * const hdmx = file->hdmx;
+
+ if (!file->head || !file->maxp) {
+ return OTS_FAILURE_MSG("Missing maxp or head tables in font, needed by hdmx");
+ }
+
+ if ((file->head->flags & 0x14) == 0) {
+ // http://www.microsoft.com/typography/otspec/recom.htm
+ DROP_THIS_TABLE("the table should not be present when bit 2 and 4 of the "
+ "head->flags are not set");
+ return true;
+ }
+
+ int16_t num_recs;
+ if (!table.ReadU16(&hdmx->version) ||
+ !table.ReadS16(&num_recs) ||
+ !table.ReadS32(&hdmx->size_device_record)) {
+ return OTS_FAILURE_MSG("Failed to read hdmx header");
+ }
+ if (hdmx->version != 0) {
+ DROP_THIS_TABLE("bad version: %u", hdmx->version);
+ return true;
+ }
+ if (num_recs <= 0) {
+ DROP_THIS_TABLE("bad num_recs: %d", num_recs);
+ return true;
+ }
+ const int32_t actual_size_device_record = file->maxp->num_glyphs + 2;
+ if (hdmx->size_device_record < actual_size_device_record) {
+ DROP_THIS_TABLE("bad hdmx->size_device_record: %d", hdmx->size_device_record);
+ return true;
+ }
+
+ hdmx->pad_len = hdmx->size_device_record - actual_size_device_record;
+ if (hdmx->pad_len > 3) {
+ return OTS_FAILURE_MSG("Bad padding %d", hdmx->pad_len);
+ }
+
+ uint8_t last_pixel_size = 0;
+ hdmx->records.reserve(num_recs);
+ for (int i = 0; i < num_recs; ++i) {
+ OpenTypeHDMXDeviceRecord rec;
+
+ if (!table.ReadU8(&rec.pixel_size) ||
+ !table.ReadU8(&rec.max_width)) {
+ return OTS_FAILURE_MSG("Failed to read hdmx record %d", i);
+ }
+ if ((i != 0) &&
+ (rec.pixel_size <= last_pixel_size)) {
+ DROP_THIS_TABLE("records are not sorted");
+ return true;
+ }
+ last_pixel_size = rec.pixel_size;
+
+ rec.widths.reserve(file->maxp->num_glyphs);
+ for (unsigned j = 0; j < file->maxp->num_glyphs; ++j) {
+ uint8_t width;
+ if (!table.ReadU8(&width)) {
+ return OTS_FAILURE_MSG("Failed to read glyph width %d in record %d", j, i);
+ }
+ rec.widths.push_back(width);
+ }
+
+ if ((hdmx->pad_len > 0) &&
+ !table.Skip(hdmx->pad_len)) {
+ return OTS_FAILURE_MSG("Failed to skip padding %d", hdmx->pad_len);
+ }
+
+ hdmx->records.push_back(rec);
+ }
+
+ return true;
+}
+
+bool ots_hdmx_should_serialise(OpenTypeFile *file) {
+ if (!file->hdmx) return false;
+ if (!file->glyf) return false; // this table is not for CFF fonts.
+ return true;
+}
+
+bool ots_hdmx_serialise(OTSStream *out, OpenTypeFile *file) {
+ OpenTypeHDMX * const hdmx = file->hdmx;
+
+ const int16_t num_recs = static_cast<int16_t>(hdmx->records.size());
+ if (hdmx->records.size() >
+ static_cast<size_t>(std::numeric_limits<int16_t>::max()) ||
+ !out->WriteU16(hdmx->version) ||
+ !out->WriteS16(num_recs) ||
+ !out->WriteS32(hdmx->size_device_record)) {
+ return OTS_FAILURE_MSG("Failed to write hdmx header");
+ }
+
+ for (int16_t i = 0; i < num_recs; ++i) {
+ const OpenTypeHDMXDeviceRecord& rec = hdmx->records[i];
+ if (!out->Write(&rec.pixel_size, 1) ||
+ !out->Write(&rec.max_width, 1) ||
+ !out->Write(&rec.widths[0], rec.widths.size())) {
+ return OTS_FAILURE_MSG("Failed to write hdmx record %d", i);
+ }
+ if ((hdmx->pad_len > 0) &&
+ !out->Write((const uint8_t *)"\x00\x00\x00", hdmx->pad_len)) {
+ return OTS_FAILURE_MSG("Failed to write hdmx padding of length %d", hdmx->pad_len);
+ }
+ }
+
+ return true;
+}
+
+void ots_hdmx_free(OpenTypeFile *file) {
+ delete file->hdmx;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/hdmx.h b/third_party/ots/src/hdmx.h
new file mode 100644
index 0000000..9ec2124
--- /dev/null
+++ b/third_party/ots/src/hdmx.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HDMX_H_
+#define OTS_HDMX_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHDMXDeviceRecord {
+ uint8_t pixel_size;
+ uint8_t max_width;
+ std::vector<uint8_t> widths;
+};
+
+struct OpenTypeHDMX {
+ uint16_t version;
+ int32_t size_device_record;
+ int32_t pad_len;
+ std::vector<OpenTypeHDMXDeviceRecord> records;
+};
+
+} // namespace ots
+
+#endif
diff --git a/third_party/ots/src/head.cc b/third_party/ots/src/head.cc
new file mode 100644
index 0000000..dcd234d
--- /dev/null
+++ b/third_party/ots/src/head.cc
@@ -0,0 +1,153 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "head.h"
+
+#include <cstring>
+
+// head - Font Header
+// http://www.microsoft.com/typography/otspec/head.htm
+
+#define TABLE_NAME "head"
+
+namespace ots {
+
+bool ots_head_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ file->head = new OpenTypeHEAD;
+
+ uint32_t version = 0;
+ if (!table.ReadU32(&version) ||
+ !table.ReadU32(&file->head->revision)) {
+ return OTS_FAILURE_MSG("Failed to read head header");
+ }
+
+ if (version >> 16 != 1) {
+ return OTS_FAILURE_MSG("Bad head table version of %d", version);
+ }
+
+ // Skip the checksum adjustment
+ if (!table.Skip(4)) {
+ return OTS_FAILURE_MSG("Failed to read checksum");
+ }
+
+ uint32_t magic;
+ if (!table.ReadTag(&magic) ||
+ std::memcmp(&magic, "\x5F\x0F\x3C\xF5", 4)) {
+ return OTS_FAILURE_MSG("Failed to read font magic number");
+ }
+
+ if (!table.ReadU16(&file->head->flags)) {
+ return OTS_FAILURE_MSG("Failed to read head flags");
+ }
+
+ // We allow bits 0..4, 11..13
+ file->head->flags &= 0x381f;
+
+ if (!table.ReadU16(&file->head->ppem)) {
+ return OTS_FAILURE_MSG("Failed to read pixels per em");
+ }
+
+ // ppem must be in range
+ if (file->head->ppem < 16 ||
+ file->head->ppem > 16384) {
+ return OTS_FAILURE_MSG("Bad ppm of %d", file->head->ppem);
+ }
+
+ // ppem must be a power of two
+#if 0
+ // We don't call ots_failure() for now since lots of TrueType fonts are
+ // not following this rule. Putting OTS_WARNING here is too noisy.
+ if ((file->head->ppem - 1) & file->head->ppem) {
+ return OTS_FAILURE_MSG("ppm not a power of two: %d", file->head->ppem);
+ }
+#endif
+
+ if (!table.ReadR64(&file->head->created) ||
+ !table.ReadR64(&file->head->modified)) {
+ return OTS_FAILURE_MSG("Can't read font dates");
+ }
+
+ if (!table.ReadS16(&file->head->xmin) ||
+ !table.ReadS16(&file->head->ymin) ||
+ !table.ReadS16(&file->head->xmax) ||
+ !table.ReadS16(&file->head->ymax)) {
+ return OTS_FAILURE_MSG("Failed to read font bounding box");
+ }
+
+ if (file->head->xmin > file->head->xmax) {
+ return OTS_FAILURE_MSG("Bad x dimension in the font bounding box (%d, %d)", file->head->xmin, file->head->xmax);
+ }
+ if (file->head->ymin > file->head->ymax) {
+ return OTS_FAILURE_MSG("Bad y dimension in the font bounding box (%d, %d)", file->head->ymin, file->head->ymax);
+ }
+
+ if (!table.ReadU16(&file->head->mac_style)) {
+ return OTS_FAILURE_MSG("Failed to read font style");
+ }
+
+ // We allow bits 0..6
+ file->head->mac_style &= 0x7f;
+
+ if (!table.ReadU16(&file->head->min_ppem)) {
+ return OTS_FAILURE_MSG("Failed to read font minimum ppm");
+ }
+
+ // We don't care about the font direction hint
+ if (!table.Skip(2)) {
+ return OTS_FAILURE_MSG("Failed to skip font direction hint");
+ }
+
+ if (!table.ReadS16(&file->head->index_to_loc_format)) {
+ return OTS_FAILURE_MSG("Failed to read index to loc format");
+ }
+ if (file->head->index_to_loc_format < 0 ||
+ file->head->index_to_loc_format > 1) {
+ return OTS_FAILURE_MSG("Bad index to loc format %d", file->head->index_to_loc_format);
+ }
+
+ int16_t glyph_data_format;
+ if (!table.ReadS16(&glyph_data_format) ||
+ glyph_data_format) {
+ return OTS_FAILURE_MSG("Failed to read glyph data format");
+ }
+
+ return true;
+}
+
+bool ots_head_should_serialise(OpenTypeFile *file) {
+ return file->head != NULL;
+}
+
+bool ots_head_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!out->WriteU32(0x00010000) ||
+ !out->WriteU32(file->head->revision) ||
+ !out->WriteU32(0) || // check sum not filled in yet
+ !out->WriteU32(0x5F0F3CF5) ||
+ !out->WriteU16(file->head->flags) ||
+ !out->WriteU16(file->head->ppem) ||
+ !out->WriteR64(file->head->created) ||
+ !out->WriteR64(file->head->modified) ||
+ !out->WriteS16(file->head->xmin) ||
+ !out->WriteS16(file->head->ymin) ||
+ !out->WriteS16(file->head->xmax) ||
+ !out->WriteS16(file->head->ymax) ||
+ !out->WriteU16(file->head->mac_style) ||
+ !out->WriteU16(file->head->min_ppem) ||
+ !out->WriteS16(2) ||
+ !out->WriteS16(file->head->index_to_loc_format) ||
+ !out->WriteS16(0)) {
+ return OTS_FAILURE_MSG("Failed to write head table");
+ }
+
+ return true;
+}
+
+void ots_head_free(OpenTypeFile *file) {
+ delete file->head;
+}
+
+} // namespace
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/head.h b/third_party/ots/src/head.h
new file mode 100644
index 0000000..5967c4b
--- /dev/null
+++ b/third_party/ots/src/head.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HEAD_H_
+#define OTS_HEAD_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHEAD {
+ uint32_t revision;
+ uint16_t flags;
+ uint16_t ppem;
+ uint64_t created;
+ uint64_t modified;
+
+ int16_t xmin, xmax;
+ int16_t ymin, ymax;
+
+ uint16_t mac_style;
+ uint16_t min_ppem;
+ int16_t index_to_loc_format;
+};
+
+} // namespace ots
+
+#endif // OTS_HEAD_H_
diff --git a/third_party/ots/src/hhea.cc b/third_party/ots/src/hhea.cc
new file mode 100644
index 0000000..8430442
--- /dev/null
+++ b/third_party/ots/src/hhea.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "hhea.h"
+
+#include "head.h"
+#include "maxp.h"
+
+// hhea - Horizontal Header
+// http://www.microsoft.com/typography/otspec/hhea.htm
+
+#define TABLE_NAME "hhea"
+
+namespace ots {
+
+bool ots_hhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ OpenTypeHHEA *hhea = new OpenTypeHHEA;
+ file->hhea = hhea;
+
+ if (!table.ReadU32(&hhea->header.version)) {
+ return OTS_FAILURE_MSG("Failed to read hhea version");
+ }
+ if (hhea->header.version >> 16 != 1) {
+ return OTS_FAILURE_MSG("Bad hhea version of %d", hhea->header.version);
+ }
+
+ if (!ParseMetricsHeader(file, &table, &hhea->header)) {
+ return OTS_FAILURE_MSG("Failed to parse horizontal metrics");
+ }
+
+ return true;
+}
+
+bool ots_hhea_should_serialise(OpenTypeFile *file) {
+ return file->hhea != NULL;
+}
+
+bool ots_hhea_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!SerialiseMetricsHeader(file, out, &file->hhea->header)) {
+ return OTS_FAILURE_MSG("Failed to serialise horizontal metrics");
+ }
+ return true;
+}
+
+void ots_hhea_free(OpenTypeFile *file) {
+ delete file->hhea;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/hhea.h b/third_party/ots/src/hhea.h
new file mode 100644
index 0000000..bdea9aa
--- /dev/null
+++ b/third_party/ots/src/hhea.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HHEA_H_
+#define OTS_HHEA_H_
+
+#include "metrics.h"
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHHEA {
+ OpenTypeMetricsHeader header;
+};
+
+} // namespace ots
+
+#endif // OTS_HHEA_H_
diff --git a/third_party/ots/src/hmtx.cc b/third_party/ots/src/hmtx.cc
new file mode 100644
index 0000000..ae86513
--- /dev/null
+++ b/third_party/ots/src/hmtx.cc
@@ -0,0 +1,51 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "hmtx.h"
+
+#include "hhea.h"
+#include "maxp.h"
+
+// hmtx - Horizontal Metrics
+// http://www.microsoft.com/typography/otspec/hmtx.htm
+
+#define TABLE_NAME "hmtx"
+
+namespace ots {
+
+bool ots_hmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ OpenTypeHMTX *hmtx = new OpenTypeHMTX;
+ file->hmtx = hmtx;
+
+ if (!file->hhea || !file->maxp) {
+ return OTS_FAILURE_MSG("Missing hhea or maxp tables in font, needed by hmtx");
+ }
+
+ if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
+ &file->hhea->header, &hmtx->metrics)) {
+ return OTS_FAILURE_MSG("Failed to parse hmtx metrics");
+ }
+
+ return true;
+}
+
+bool ots_hmtx_should_serialise(OpenTypeFile *file) {
+ return file->hmtx != NULL;
+}
+
+bool ots_hmtx_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!SerialiseMetricsTable(file, out, &file->hmtx->metrics)) {
+ return OTS_FAILURE_MSG("Failed to serialise htmx metrics");
+ }
+ return true;
+}
+
+void ots_hmtx_free(OpenTypeFile *file) {
+ delete file->hmtx;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/hmtx.h b/third_party/ots/src/hmtx.h
new file mode 100644
index 0000000..435949c
--- /dev/null
+++ b/third_party/ots/src/hmtx.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_HMTX_H_
+#define OTS_HMTX_H_
+
+#include "metrics.h"
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeHMTX {
+ OpenTypeMetricsTable metrics;
+};
+
+} // namespace ots
+
+#endif // OTS_HMTX_H_
diff --git a/third_party/ots/src/kern.cc b/third_party/ots/src/kern.cc
new file mode 100644
index 0000000..744c057
--- /dev/null
+++ b/third_party/ots/src/kern.cc
@@ -0,0 +1,203 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "kern.h"
+
+// kern - Kerning
+// http://www.microsoft.com/typography/otspec/kern.htm
+
+#define TABLE_NAME "kern"
+
+#define DROP_THIS_TABLE(msg_) \
+ do { \
+ OTS_FAILURE_MSG(msg_ ", table discarded"); \
+ delete file->kern; \
+ file->kern = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_kern_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypeKERN *kern = new OpenTypeKERN;
+ file->kern = kern;
+
+ uint16_t num_tables = 0;
+ if (!table.ReadU16(&kern->version) ||
+ !table.ReadU16(&num_tables)) {
+ return OTS_FAILURE_MSG("Failed to read kern header");
+ }
+
+ if (kern->version > 0) {
+ DROP_THIS_TABLE("bad table version");
+ return true;
+ }
+
+ if (num_tables == 0) {
+ DROP_THIS_TABLE("num_tables is zero");
+ return true;
+ }
+
+ kern->subtables.reserve(num_tables);
+ for (unsigned i = 0; i < num_tables; ++i) {
+ OpenTypeKERNFormat0 subtable;
+ uint16_t sub_length = 0;
+
+ if (!table.ReadU16(&subtable.version) ||
+ !table.ReadU16(&sub_length)) {
+ return OTS_FAILURE_MSG("Failed to read kern subtable %d header", i);
+ }
+
+ if (subtable.version > 0) {
+ OTS_WARNING("Bad subtable version: %d", subtable.version);
+ continue;
+ }
+
+ const size_t current_offset = table.offset();
+ if (current_offset - 4 + sub_length > length) {
+ return OTS_FAILURE_MSG("Bad kern subtable %d offset %ld", i, current_offset);
+ }
+
+ if (!table.ReadU16(&subtable.coverage)) {
+ return OTS_FAILURE_MSG("Cailed to read kern subtable %d coverage", i);
+ }
+
+ if (!(subtable.coverage & 0x1)) {
+ OTS_WARNING(
+ "We don't support vertical data as the renderer doesn't support it.");
+ continue;
+ }
+ if (subtable.coverage & 0xF0) {
+ DROP_THIS_TABLE("Reserved fields should zero-filled.");
+ return true;
+ }
+ const uint32_t format = (subtable.coverage & 0xFF00) >> 8;
+ if (format != 0) {
+ OTS_WARNING("Format %d is not supported.", format);
+ continue;
+ }
+
+ // Parse the format 0 field.
+ uint16_t num_pairs = 0;
+ if (!table.ReadU16(&num_pairs) ||
+ !table.ReadU16(&subtable.search_range) ||
+ !table.ReadU16(&subtable.entry_selector) ||
+ !table.ReadU16(&subtable.range_shift)) {
+ return OTS_FAILURE_MSG("Failed to read kern subtable %d format 0 fields", i);
+ }
+
+ if (!num_pairs) {
+ DROP_THIS_TABLE("Zero length subtable is found.");
+ return true;
+ }
+
+ // Sanity checks for search_range, entry_selector, and range_shift. See the
+ // comment in ots.cc for details.
+ const size_t kFormat0PairSize = 6; // left, right, and value. 2 bytes each.
+ if (num_pairs > (65536 / kFormat0PairSize)) {
+ // Some fonts (e.g. calibri.ttf, pykes_peak_zero.ttf) have pairs >= 10923.
+ DROP_THIS_TABLE("Too large subtable.");
+ return true;
+ }
+ unsigned max_pow2 = 0;
+ while (1u << (max_pow2 + 1) <= num_pairs) {
+ ++max_pow2;
+ }
+ const uint16_t expected_search_range = (1u << max_pow2) * kFormat0PairSize;
+ if (subtable.search_range != expected_search_range) {
+ OTS_WARNING("bad search range");
+ subtable.search_range = expected_search_range;
+ }
+ if (subtable.entry_selector != max_pow2) {
+ return OTS_FAILURE_MSG("Bad subtable %d entry selector %d", i, subtable.entry_selector);
+ }
+ const uint16_t expected_range_shift =
+ kFormat0PairSize * num_pairs - subtable.search_range;
+ if (subtable.range_shift != expected_range_shift) {
+ OTS_WARNING("bad range shift");
+ subtable.range_shift = expected_range_shift;
+ }
+
+ // Read kerning pairs.
+ subtable.pairs.reserve(num_pairs);
+ uint32_t last_pair = 0;
+ for (unsigned j = 0; j < num_pairs; ++j) {
+ OpenTypeKERNFormat0Pair kerning_pair;
+ if (!table.ReadU16(&kerning_pair.left) ||
+ !table.ReadU16(&kerning_pair.right) ||
+ !table.ReadS16(&kerning_pair.value)) {
+ return OTS_FAILURE_MSG("Failed to read subtable %d kerning pair %d", i, j);
+ }
+ const uint32_t current_pair
+ = (kerning_pair.left << 16) + kerning_pair.right;
+ if (j != 0 && current_pair <= last_pair) {
+ // Many free fonts don't follow this rule, so we don't call OTS_FAILURE
+ // in order to support these fonts.
+ DROP_THIS_TABLE("Kerning pairs are not sorted.");
+ return true;
+ }
+ last_pair = current_pair;
+ subtable.pairs.push_back(kerning_pair);
+ }
+
+ kern->subtables.push_back(subtable);
+ }
+
+ if (!kern->subtables.size()) {
+ DROP_THIS_TABLE("All subtables are removed.");
+ return true;
+ }
+
+ return true;
+}
+
+bool ots_kern_should_serialise(OpenTypeFile *file) {
+ if (!file->glyf) return false; // this table is not for CFF fonts.
+ return file->kern != NULL;
+}
+
+bool ots_kern_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeKERN *kern = file->kern;
+
+ const uint16_t num_subtables = static_cast<uint16_t>(kern->subtables.size());
+ if (num_subtables != kern->subtables.size() ||
+ !out->WriteU16(kern->version) ||
+ !out->WriteU16(num_subtables)) {
+ return OTS_FAILURE_MSG("Can't write kern table header");
+ }
+
+ for (uint16_t i = 0; i < num_subtables; ++i) {
+ const size_t length = 14 + (6 * kern->subtables[i].pairs.size());
+ if (length > std::numeric_limits<uint16_t>::max() ||
+ !out->WriteU16(kern->subtables[i].version) ||
+ !out->WriteU16(static_cast<uint16_t>(length)) ||
+ !out->WriteU16(kern->subtables[i].coverage) ||
+ !out->WriteU16(
+ static_cast<uint16_t>(kern->subtables[i].pairs.size())) ||
+ !out->WriteU16(kern->subtables[i].search_range) ||
+ !out->WriteU16(kern->subtables[i].entry_selector) ||
+ !out->WriteU16(kern->subtables[i].range_shift)) {
+ return OTS_FAILURE_MSG("Failed to write kern subtable %d", i);
+ }
+ for (unsigned j = 0; j < kern->subtables[i].pairs.size(); ++j) {
+ if (!out->WriteU16(kern->subtables[i].pairs[j].left) ||
+ !out->WriteU16(kern->subtables[i].pairs[j].right) ||
+ !out->WriteS16(kern->subtables[i].pairs[j].value)) {
+ return OTS_FAILURE_MSG("Failed to write kern pair %d for subtable %d", j, i);
+ }
+ }
+ }
+
+ return true;
+}
+
+void ots_kern_free(OpenTypeFile *file) {
+ delete file->kern;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/kern.h b/third_party/ots/src/kern.h
new file mode 100644
index 0000000..9350ef7
--- /dev/null
+++ b/third_party/ots/src/kern.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_KERN_H_
+#define OTS_KERN_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeKERNFormat0Pair {
+ uint16_t left;
+ uint16_t right;
+ int16_t value;
+};
+
+struct OpenTypeKERNFormat0 {
+ uint16_t version;
+ uint16_t coverage;
+ uint16_t search_range;
+ uint16_t entry_selector;
+ uint16_t range_shift;
+ std::vector<OpenTypeKERNFormat0Pair> pairs;
+};
+
+// Format 2 is not supported. Since the format is not supported by Windows,
+// WebFonts unlikely use it. I've checked thousands of proprietary fonts and
+// free fonts, and found no font uses the format.
+
+struct OpenTypeKERN {
+ uint16_t version;
+ std::vector<OpenTypeKERNFormat0> subtables;
+};
+
+} // namespace ots
+
+#endif // OTS_KERN_H_
diff --git a/third_party/ots/src/layout.cc b/third_party/ots/src/layout.cc
new file mode 100644
index 0000000..856152c
--- /dev/null
+++ b/third_party/ots/src/layout.cc
@@ -0,0 +1,1511 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "layout.h"
+
+#include <limits>
+#include <vector>
+
+#include "gdef.h"
+
+// OpenType Layout Common Table Formats
+// http://www.microsoft.com/typography/otspec/chapter2.htm
+
+#define TABLE_NAME "Layout" // XXX: use individual table names
+
+namespace {
+
+// The 'DFLT' tag of script table.
+const uint32_t kScriptTableTagDflt = 0x44464c54;
+// The value which represents there is no required feature index.
+const uint16_t kNoRequiredFeatureIndexDefined = 0xFFFF;
+// The lookup flag bit which indicates existence of MarkFilteringSet.
+const uint16_t kUseMarkFilteringSetBit = 0x0010;
+// The lookup flags which require GDEF table.
+const uint16_t kGdefRequiredFlags = 0x0002 | 0x0004 | 0x0008;
+// The mask for MarkAttachmentType.
+const uint16_t kMarkAttachmentTypeMask = 0xFF00;
+// The maximum type number of format for device tables.
+const uint16_t kMaxDeltaFormatType = 3;
+// The maximum number of class value.
+const uint16_t kMaxClassDefValue = 0xFFFF;
+
+struct ScriptRecord {
+ uint32_t tag;
+ uint16_t offset;
+};
+
+struct LangSysRecord {
+ uint32_t tag;
+ uint16_t offset;
+};
+
+struct FeatureRecord {
+ uint32_t tag;
+ uint16_t offset;
+};
+
+bool ParseLangSysTable(const ots::OpenTypeFile *file,
+ ots::Buffer *subtable, const uint32_t tag,
+ const uint16_t num_features) {
+ uint16_t offset_lookup_order = 0;
+ uint16_t req_feature_index = 0;
+ uint16_t feature_count = 0;
+ if (!subtable->ReadU16(&offset_lookup_order) ||
+ !subtable->ReadU16(&req_feature_index) ||
+ !subtable->ReadU16(&feature_count)) {
+ return OTS_FAILURE_MSG("Failed to read langsys header for tag %4.4s", (char *)&tag);
+ }
+ // |offset_lookup_order| is reserved and should be NULL.
+ if (offset_lookup_order != 0) {
+ return OTS_FAILURE_MSG("Bad lookup offset order %d for langsys tag %4.4s", offset_lookup_order, (char *)&tag);
+ }
+ if (req_feature_index != kNoRequiredFeatureIndexDefined &&
+ req_feature_index >= num_features) {
+ return OTS_FAILURE_MSG("Bad required features index %d for langsys tag %4.4s", req_feature_index, (char *)&tag);
+ }
+ if (feature_count > num_features) {
+ return OTS_FAILURE_MSG("Bad feature count %d for langsys tag %4.4s", feature_count, (char *)&tag);
+ }
+
+ for (unsigned i = 0; i < feature_count; ++i) {
+ uint16_t feature_index = 0;
+ if (!subtable->ReadU16(&feature_index)) {
+ return OTS_FAILURE_MSG("Failed to read feature index %d for langsys tag %4.4s", i, (char *)&tag);
+ }
+ if (feature_index >= num_features) {
+ return OTS_FAILURE_MSG("Bad feature index %d for feature %d for langsys tag %4.4s", feature_index, i, (char *)&tag);
+ }
+ }
+ return true;
+}
+
+bool ParseScriptTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint32_t tag, const uint16_t num_features) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_default_lang_sys = 0;
+ uint16_t lang_sys_count = 0;
+ if (!subtable.ReadU16(&offset_default_lang_sys) ||
+ !subtable.ReadU16(&lang_sys_count)) {
+ return OTS_FAILURE_MSG("Failed to read script header for script tag %4.4s", (char *)&tag);
+ }
+
+ // The spec requires a script table for 'DFLT' tag must contain non-NULL
+ // |offset_default_lang_sys| and |lang_sys_count| == 0
+ if (tag == kScriptTableTagDflt &&
+ (offset_default_lang_sys == 0 || lang_sys_count != 0)) {
+ return OTS_FAILURE_MSG("DFLT table doesn't satisfy the spec. for script tag %4.4s", (char *)&tag);
+ }
+
+ const unsigned lang_sys_record_end =
+ 6 * static_cast<unsigned>(lang_sys_count) + 4;
+ if (lang_sys_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of langsys record %d for script tag %4.4s", lang_sys_record_end, (char *)&tag);
+ }
+
+ std::vector<LangSysRecord> lang_sys_records;
+ lang_sys_records.resize(lang_sys_count);
+ uint32_t last_tag = 0;
+ for (unsigned i = 0; i < lang_sys_count; ++i) {
+ if (!subtable.ReadU32(&lang_sys_records[i].tag) ||
+ !subtable.ReadU16(&lang_sys_records[i].offset)) {
+ return OTS_FAILURE_MSG("Failed to read langsys record header %d for script tag %4.4s", i, (char *)&tag);
+ }
+ // The record array must store the records alphabetically by tag
+ if (last_tag != 0 && last_tag > lang_sys_records[i].tag) {
+ return OTS_FAILURE_MSG("Bad last tag %d for langsys record %d for script tag %4.4s", last_tag, i, (char *)&tag);
+ }
+ if (lang_sys_records[i].offset < lang_sys_record_end ||
+ lang_sys_records[i].offset >= length) {
+ return OTS_FAILURE_MSG("bad offset to lang sys table: %x",
+ lang_sys_records[i].offset);
+ }
+ last_tag = lang_sys_records[i].tag;
+ }
+
+ // Check lang sys tables
+ for (unsigned i = 0; i < lang_sys_count; ++i) {
+ subtable.set_offset(lang_sys_records[i].offset);
+ if (!ParseLangSysTable(file, &subtable, lang_sys_records[i].tag, num_features)) {
+ return OTS_FAILURE_MSG("Failed to parse langsys table %d (%4.4s) for script tag %4.4s", i, (char *)&lang_sys_records[i].tag, (char *)&tag);
+ }
+ }
+
+ return true;
+}
+
+bool ParseFeatureTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_feature_params = 0;
+ uint16_t lookup_count = 0;
+ if (!subtable.ReadU16(&offset_feature_params) ||
+ !subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE_MSG("Failed to read feature table header");
+ }
+
+ const unsigned feature_table_end =
+ 2 * static_cast<unsigned>(lookup_count) + 4;
+ if (feature_table_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of feature table %d", feature_table_end);
+ }
+ // |offset_feature_params| is generally set to NULL.
+ if (offset_feature_params != 0 &&
+ (offset_feature_params < feature_table_end ||
+ offset_feature_params >= length)) {
+ return OTS_FAILURE_MSG("Bad feature params offset %d", offset_feature_params);
+ }
+
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ uint16_t lookup_index = 0;
+ if (!subtable.ReadU16(&lookup_index)) {
+ return OTS_FAILURE_MSG("Failed to read lookup index for lookup %d", i);
+ }
+ // lookup index starts with 0.
+ if (lookup_index >= num_lookups) {
+ return OTS_FAILURE_MSG("Bad lookup index %d for lookup %d", lookup_index, i);
+ }
+ }
+ return true;
+}
+
+bool ParseLookupTable(ots::OpenTypeFile *file, const uint8_t *data,
+ const size_t length,
+ const ots::LookupSubtableParser* parser) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t lookup_type = 0;
+ uint16_t lookup_flag = 0;
+ uint16_t subtable_count = 0;
+ if (!subtable.ReadU16(&lookup_type) ||
+ !subtable.ReadU16(&lookup_flag) ||
+ !subtable.ReadU16(&subtable_count)) {
+ return OTS_FAILURE_MSG("Failed to read lookup table header");
+ }
+
+ if (lookup_type == 0 || lookup_type > parser->num_types) {
+ return OTS_FAILURE_MSG("Bad lookup type %d", lookup_type);
+ }
+
+ // Check lookup flags.
+ if ((lookup_flag & kGdefRequiredFlags) &&
+ (!file->gdef || !file->gdef->has_glyph_class_def)) {
+ return OTS_FAILURE_MSG("Bad lookup flags %d", lookup_flag);
+ }
+ if ((lookup_flag & kMarkAttachmentTypeMask) &&
+ (!file->gdef || !file->gdef->has_mark_attachment_class_def)) {
+ return OTS_FAILURE_MSG("lookup flag asks for mark attachment that is bad %d", lookup_flag);
+ }
+ bool use_mark_filtering_set = false;
+ if (lookup_flag & kUseMarkFilteringSetBit) {
+ if (!file->gdef || !file->gdef->has_mark_glyph_sets_def) {
+ return OTS_FAILURE_MSG("lookup flag asks for mark filtering that is bad %d", lookup_flag);
+ }
+ use_mark_filtering_set = true;
+ }
+
+ std::vector<uint16_t> subtables;
+ subtables.reserve(subtable_count);
+ // If the |kUseMarkFilteringSetBit| of |lookup_flag| is set,
+ // extra 2 bytes will follow after subtable offset array.
+ const unsigned lookup_table_end = 2 * static_cast<unsigned>(subtable_count) +
+ (use_mark_filtering_set ? 8 : 6);
+ if (lookup_table_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of lookup %d", lookup_table_end);
+ }
+ for (unsigned i = 0; i < subtable_count; ++i) {
+ uint16_t offset_subtable = 0;
+ if (!subtable.ReadU16(&offset_subtable)) {
+ return OTS_FAILURE_MSG("Failed to read subtable offset %d", i);
+ }
+ if (offset_subtable < lookup_table_end ||
+ offset_subtable >= length) {
+ return OTS_FAILURE_MSG("Bad subtable offset %d for subtable %d", offset_subtable, i);
+ }
+ subtables.push_back(offset_subtable);
+ }
+ if (subtables.size() != subtable_count) {
+ return OTS_FAILURE_MSG("Bad subtable size %ld", subtables.size());
+ }
+
+ if (use_mark_filtering_set) {
+ uint16_t mark_filtering_set = 0;
+ if (!subtable.ReadU16(&mark_filtering_set)) {
+ return OTS_FAILURE_MSG("Failed to read mark filtering set");
+ }
+ if (file->gdef->num_mark_glyph_sets == 0 ||
+ mark_filtering_set >= file->gdef->num_mark_glyph_sets) {
+ return OTS_FAILURE_MSG("Bad mark filtering set %d", mark_filtering_set);
+ }
+ }
+
+ // Parse lookup subtables for this lookup type.
+ for (unsigned i = 0; i < subtable_count; ++i) {
+ if (!parser->Parse(file, data + subtables[i], length - subtables[i],
+ lookup_type)) {
+ return OTS_FAILURE_MSG("Failed to parse subtable %d", i);
+ }
+ }
+ return true;
+}
+
+bool ParseClassDefFormat1(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_classes) {
+ ots::Buffer subtable(data, length);
+
+ // Skip format field.
+ if (!subtable.Skip(2)) {
+ return OTS_FAILURE_MSG("Failed to skip class definition header");
+ }
+
+ uint16_t start_glyph = 0;
+ if (!subtable.ReadU16(&start_glyph)) {
+ return OTS_FAILURE_MSG("Failed to read starting glyph of class definition");
+ }
+ if (start_glyph > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad starting glyph %d in class definition", start_glyph);
+ }
+
+ uint16_t glyph_count = 0;
+ if (!subtable.ReadU16(&glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read glyph count in class definition");
+ }
+ if (glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
+ }
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t class_value = 0;
+ if (!subtable.ReadU16(&class_value)) {
+ return OTS_FAILURE_MSG("Failed to read class value for glyph %d in class definition", i);
+ }
+ if (class_value > num_classes) {
+ return OTS_FAILURE_MSG("Bad class value %d for glyph %d in class definition", class_value, i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseClassDefFormat2(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_classes) {
+ ots::Buffer subtable(data, length);
+
+ // Skip format field.
+ if (!subtable.Skip(2)) {
+ return OTS_FAILURE_MSG("Failed to skip format of class defintion header");
+ }
+
+ uint16_t range_count = 0;
+ if (!subtable.ReadU16(&range_count)) {
+ return OTS_FAILURE_MSG("Failed to read range count in class definition");
+ }
+ if (range_count > num_glyphs) {
+ return OTS_FAILURE_MSG("bad range count: %u", range_count);
+ }
+
+ uint16_t last_end = 0;
+ for (unsigned i = 0; i < range_count; ++i) {
+ uint16_t start = 0;
+ uint16_t end = 0;
+ uint16_t class_value = 0;
+ if (!subtable.ReadU16(&start) ||
+ !subtable.ReadU16(&end) ||
+ !subtable.ReadU16(&class_value)) {
+ return OTS_FAILURE_MSG("Failed to read class definition reange %d", i);
+ }
+ if (start > end || (last_end && start <= last_end)) {
+ return OTS_FAILURE_MSG("glyph range is overlapping.in range %d", i);
+ }
+ if (class_value > num_classes) {
+ return OTS_FAILURE_MSG("bad class value: %u", class_value);
+ }
+ last_end = end;
+ }
+
+ return true;
+}
+
+bool ParseCoverageFormat1(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t expected_num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Skip format field.
+ if (!subtable.Skip(2)) {
+ return OTS_FAILURE_MSG("Failed to skip coverage format");
+ }
+
+ uint16_t glyph_count = 0;
+ if (!subtable.ReadU16(&glyph_count)) {
+ return OTS_FAILURE_MSG("Failed to read glyph count in coverage");
+ }
+ if (glyph_count > num_glyphs) {
+ return OTS_FAILURE_MSG("bad glyph count: %u", glyph_count);
+ }
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t glyph = 0;
+ if (!subtable.ReadU16(&glyph)) {
+ return OTS_FAILURE_MSG("Failed to read glyph %d in coverage", i);
+ }
+ if (glyph > num_glyphs) {
+ return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
+ }
+ }
+
+ if (expected_num_glyphs && expected_num_glyphs != glyph_count) {
+ return OTS_FAILURE_MSG("unexpected number of glyphs: %u", glyph_count);
+ }
+
+ return true;
+}
+
+bool ParseCoverageFormat2(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t expected_num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Skip format field.
+ if (!subtable.Skip(2)) {
+ return OTS_FAILURE_MSG("Failed to skip format of coverage type 2");
+ }
+
+ uint16_t range_count = 0;
+ if (!subtable.ReadU16(&range_count)) {
+ return OTS_FAILURE_MSG("Failed to read range count in coverage");
+ }
+ if (range_count > num_glyphs) {
+ return OTS_FAILURE_MSG("bad range count: %u", range_count);
+ }
+ uint16_t last_end = 0;
+ uint16_t last_start_coverage_index = 0;
+ for (unsigned i = 0; i < range_count; ++i) {
+ uint16_t start = 0;
+ uint16_t end = 0;
+ uint16_t start_coverage_index = 0;
+ if (!subtable.ReadU16(&start) ||
+ !subtable.ReadU16(&end) ||
+ !subtable.ReadU16(&start_coverage_index)) {
+ return OTS_FAILURE_MSG("Failed to read range %d in coverage", i);
+ }
+
+ // Some of the Adobe Pro fonts have ranges that overlap by one element: the
+ // start of one range is equal to the end of the previous range. Therefore
+ // the < in the following condition should be <= were it not for this.
+ // See crbug.com/134135.
+ if (start > end || (last_end && start < last_end)) {
+ return OTS_FAILURE_MSG("glyph range is overlapping.");
+ }
+ if (start_coverage_index != last_start_coverage_index) {
+ return OTS_FAILURE_MSG("bad start coverage index.");
+ }
+ last_end = end;
+ last_start_coverage_index += end - start + 1;
+ }
+
+ if (expected_num_glyphs &&
+ expected_num_glyphs != last_start_coverage_index) {
+ return OTS_FAILURE_MSG("unexpected number of glyphs: %u", last_start_coverage_index);
+ }
+
+ return true;
+}
+
+// Parsers for Contextual subtables in GSUB/GPOS tables.
+
+bool ParseLookupRecord(const ots::OpenTypeFile *file,
+ ots::Buffer *subtable, const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ uint16_t sequence_index = 0;
+ uint16_t lookup_list_index = 0;
+ if (!subtable->ReadU16(&sequence_index) ||
+ !subtable->ReadU16(&lookup_list_index)) {
+ return OTS_FAILURE_MSG("Failed to read header for lookup record");
+ }
+ if (sequence_index >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad sequence index %d in lookup record", sequence_index);
+ }
+ if (lookup_list_index >= num_lookups) {
+ return OTS_FAILURE_MSG("Bad lookup list index %d in lookup record", lookup_list_index);
+ }
+ return true;
+}
+
+bool ParseRuleSubtable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t glyph_count = 0;
+ uint16_t lookup_count = 0;
+ if (!subtable.ReadU16(&glyph_count) ||
+ !subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE_MSG("Failed to read rule subtable header");
+ }
+
+ if (glyph_count == 0 || glyph_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph count %d in rule subtable", glyph_count);
+ }
+ for (unsigned i = 0; i < glyph_count - static_cast<unsigned>(1); ++i) {
+ uint16_t glyph_id = 0;
+ if (!subtable.ReadU16(&glyph_id)) {
+ return OTS_FAILURE_MSG("Failed to read glyph %d", i);
+ }
+ if (glyph_id > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph %d for entry %d", glyph_id, i);
+ }
+ }
+
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup record %d", i);
+ }
+ }
+ return true;
+}
+
+bool ParseRuleSetTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t rule_count = 0;
+ if (!subtable.ReadU16(&rule_count)) {
+ return OTS_FAILURE_MSG("Failed to read rule count in rule set");
+ }
+ const unsigned rule_end = 2 * static_cast<unsigned>(rule_count) + 2;
+ if (rule_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of rule %d in rule set", rule_end);
+ }
+
+ for (unsigned i = 0; i < rule_count; ++i) {
+ uint16_t offset_rule = 0;
+ if (!subtable.ReadU16(&offset_rule)) {
+ return OTS_FAILURE_MSG("Failed to read rule offset for rule set %d", i);
+ }
+ if (offset_rule < rule_end || offset_rule >= length) {
+ return OTS_FAILURE_MSG("Bad rule offset %d in set %d", offset_rule, i);
+ }
+ if (!ParseRuleSubtable(file, data + offset_rule, length - offset_rule,
+ num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse rule set %d", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseContextFormat1(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_coverage = 0;
+ uint16_t rule_set_count = 0;
+ // Skip format field.
+ if (!subtable.Skip(2) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&rule_set_count)) {
+ return OTS_FAILURE_MSG("Failed to read header of context format 1");
+ }
+
+ const unsigned rule_set_end = static_cast<unsigned>(6) +
+ rule_set_count * 2;
+ if (rule_set_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of rule set %d of context format 1", rule_set_end);
+ }
+ if (offset_coverage < rule_set_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d in context format 1", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table in context format 1");
+ }
+
+ for (unsigned i = 0; i < rule_set_count; ++i) {
+ uint16_t offset_rule = 0;
+ if (!subtable.ReadU16(&offset_rule)) {
+ return OTS_FAILURE_MSG("Failed to read rule offset %d in context format 1", i);
+ }
+ if (offset_rule < rule_set_end || offset_rule >= length) {
+ return OTS_FAILURE_MSG("Bad rule offset %d in rule %d in context format 1", offset_rule, i);
+ }
+ if (!ParseRuleSetTable(file, data + offset_rule, length - offset_rule,
+ num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse rule set %d in context format 1", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseClassRuleTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t glyph_count = 0;
+ uint16_t lookup_count = 0;
+ if (!subtable.ReadU16(&glyph_count) ||
+ !subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE_MSG("Failed to read header of class rule table");
+ }
+
+ if (glyph_count == 0 || glyph_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph count %d in class rule table", glyph_count);
+ }
+
+ // ClassRule table contains an array of classes. Each value of classes
+ // could take arbitrary values including zero so we don't check these value.
+ const unsigned num_classes = glyph_count - static_cast<unsigned>(1);
+ if (!subtable.Skip(2 * num_classes)) {
+ return OTS_FAILURE_MSG("Failed to skip classes in class rule table");
+ }
+
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup record %d in class rule table", i);
+ }
+ }
+ return true;
+}
+
+bool ParseClassSetTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t class_rule_count = 0;
+ if (!subtable.ReadU16(&class_rule_count)) {
+ return OTS_FAILURE_MSG("Failed to read class rule count in class set table");
+ }
+ const unsigned class_rule_end =
+ 2 * static_cast<unsigned>(class_rule_count) + 2;
+ if (class_rule_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("bad class rule end %d in class set table", class_rule_end);
+ }
+ for (unsigned i = 0; i < class_rule_count; ++i) {
+ uint16_t offset_class_rule = 0;
+ if (!subtable.ReadU16(&offset_class_rule)) {
+ return OTS_FAILURE_MSG("Failed to read class rule offset %d in class set table", i);
+ }
+ if (offset_class_rule < class_rule_end || offset_class_rule >= length) {
+ return OTS_FAILURE_MSG("Bad class rule offset %d in class %d", offset_class_rule, i);
+ }
+ if (!ParseClassRuleTable(file, data + offset_class_rule,
+ length - offset_class_rule, num_glyphs,
+ num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse class rule table %d", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseContextFormat2(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_coverage = 0;
+ uint16_t offset_class_def = 0;
+ uint16_t class_set_cnt = 0;
+ // Skip format field.
+ if (!subtable.Skip(2) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&offset_class_def) ||
+ !subtable.ReadU16(&class_set_cnt)) {
+ return OTS_FAILURE_MSG("Failed to read header for context format 2");
+ }
+
+ const unsigned class_set_end = 2 * static_cast<unsigned>(class_set_cnt) + 8;
+ if (class_set_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of class set %d for context format 2", class_set_end);
+ }
+ if (offset_coverage < class_set_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d in context format 2", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table in context format 2");
+ }
+
+ if (offset_class_def < class_set_end || offset_class_def >= length) {
+ return OTS_FAILURE_MSG("bad class definition offset %d in context format 2", offset_class_def);
+ }
+ if (!ots::ParseClassDefTable(file, data + offset_class_def,
+ length - offset_class_def,
+ num_glyphs, kMaxClassDefValue)) {
+ return OTS_FAILURE_MSG("Failed to parse class definition table in context format 2");
+ }
+
+ for (unsigned i = 0; i < class_set_cnt; ++i) {
+ uint16_t offset_class_rule = 0;
+ if (!subtable.ReadU16(&offset_class_rule)) {
+ return OTS_FAILURE_MSG("Failed to read class rule offset %d in context format 2", i);
+ }
+ if (offset_class_rule) {
+ if (offset_class_rule < class_set_end || offset_class_rule >= length) {
+ return OTS_FAILURE_MSG("Bad class rule offset %d for rule %d in context format 2", offset_class_rule, i);
+ }
+ if (!ParseClassSetTable(file, data + offset_class_rule,
+ length - offset_class_rule, num_glyphs,
+ num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse class set %d in context format 2", i);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ParseContextFormat3(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t glyph_count = 0;
+ uint16_t lookup_count = 0;
+ // Skip format field.
+ if (!subtable.Skip(2) ||
+ !subtable.ReadU16(&glyph_count) ||
+ !subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE_MSG("Failed to read header in context format 3");
+ }
+
+ if (glyph_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph count %d in context format 3", glyph_count);
+ }
+ const unsigned lookup_record_end = 2 * static_cast<unsigned>(glyph_count) +
+ 4 * static_cast<unsigned>(lookup_count) + 6;
+ if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of lookup %d in context format 3", lookup_record_end);
+ }
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t offset_coverage = 0;
+ if (!subtable.ReadU16(&offset_coverage)) {
+ return OTS_FAILURE_MSG("Failed to read coverage offset %d in conxtext format 3", i);
+ }
+ if (offset_coverage < lookup_record_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d for glyph %d in context format 3", offset_coverage, i);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table for glyph %d in context format 3", i);
+ }
+ }
+
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup record %d in context format 3", i);
+ }
+ }
+
+ return true;
+}
+
+// Parsers for Chaning Contextual subtables in GSUB/GPOS tables.
+
+bool ParseChainRuleSubtable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t backtrack_count = 0;
+ if (!subtable.ReadU16(&backtrack_count)) {
+ return OTS_FAILURE_MSG("Failed to read backtrack count in chain rule subtable");
+ }
+ if (backtrack_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad backtrack count %d in chain rule subtable", backtrack_count);
+ }
+ for (unsigned i = 0; i < backtrack_count; ++i) {
+ uint16_t glyph_id = 0;
+ if (!subtable.ReadU16(&glyph_id)) {
+ return OTS_FAILURE_MSG("Failed to read backtrack glyph %d in chain rule subtable", i);
+ }
+ if (glyph_id > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph id %d for bactrack glyph %d in chain rule subtable", glyph_id, i);
+ }
+ }
+
+ uint16_t input_count = 0;
+ if (!subtable.ReadU16(&input_count)) {
+ return OTS_FAILURE_MSG("Failed to read input count in chain rule subtable");
+ }
+ if (input_count == 0 || input_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad input count %d in chain rule subtable", input_count);
+ }
+ for (unsigned i = 0; i < input_count - static_cast<unsigned>(1); ++i) {
+ uint16_t glyph_id = 0;
+ if (!subtable.ReadU16(&glyph_id)) {
+ return OTS_FAILURE_MSG("Failed to read input glyph %d in chain rule subtable", i);
+ }
+ if (glyph_id > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph id %d for input glyph %d in chain rule subtable", glyph_id, i);
+ }
+ }
+
+ uint16_t lookahead_count = 0;
+ if (!subtable.ReadU16(&lookahead_count)) {
+ return OTS_FAILURE_MSG("Failed to read lookahead count in chain rule subtable");
+ }
+ if (lookahead_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad lookahead count %d in chain rule subtable", lookahead_count);
+ }
+ for (unsigned i = 0; i < lookahead_count; ++i) {
+ uint16_t glyph_id = 0;
+ if (!subtable.ReadU16(&glyph_id)) {
+ return OTS_FAILURE_MSG("Failed to read lookahead glyph %d in chain rule subtable", i);
+ }
+ if (glyph_id > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad glyph id %d for lookadhead glyph %d in chain rule subtable", glyph_id, i);
+ }
+ }
+
+ uint16_t lookup_count = 0;
+ if (!subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE_MSG("Failed to read lookup count in chain rule subtable");
+ }
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain rule subtable", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseChainRuleSetTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t chain_rule_count = 0;
+ if (!subtable.ReadU16(&chain_rule_count)) {
+ return OTS_FAILURE_MSG("Failed to read rule count in chain rule set");
+ }
+ const unsigned chain_rule_end =
+ 2 * static_cast<unsigned>(chain_rule_count) + 2;
+ if (chain_rule_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of chain rule %d in chain rule set", chain_rule_end);
+ }
+ for (unsigned i = 0; i < chain_rule_count; ++i) {
+ uint16_t offset_chain_rule = 0;
+ if (!subtable.ReadU16(&offset_chain_rule)) {
+ return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain rule set", i);
+ }
+ if (offset_chain_rule < chain_rule_end || offset_chain_rule >= length) {
+ return OTS_FAILURE_MSG("Bad chain rule offset %d for chain rule %d in chain rule set", offset_chain_rule, i);
+ }
+ if (!ParseChainRuleSubtable(file, data + offset_chain_rule,
+ length - offset_chain_rule,
+ num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse chain rule %d in chain rule set", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseChainContextFormat1(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_coverage = 0;
+ uint16_t chain_rule_set_count = 0;
+ // Skip format field.
+ if (!subtable.Skip(2) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&chain_rule_set_count)) {
+ return OTS_FAILURE_MSG("Failed to read header of chain context format 1");
+ }
+
+ const unsigned chain_rule_set_end =
+ 2 * static_cast<unsigned>(chain_rule_set_count) + 6;
+ if (chain_rule_set_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad chain rule end %d in chain context format 1", chain_rule_set_end);
+ }
+ if (offset_coverage < chain_rule_set_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 1", chain_rule_set_end);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table for chain context format 1");
+ }
+
+ for (unsigned i = 0; i < chain_rule_set_count; ++i) {
+ uint16_t offset_chain_rule_set = 0;
+ if (!subtable.ReadU16(&offset_chain_rule_set)) {
+ return OTS_FAILURE_MSG("Failed to read chain rule offset %d in chain context format 1", i);
+ }
+ if (offset_chain_rule_set < chain_rule_set_end ||
+ offset_chain_rule_set >= length) {
+ return OTS_FAILURE_MSG("Bad chain rule set offset %d for chain rule set %d in chain context format 1", offset_chain_rule_set, i);
+ }
+ if (!ParseChainRuleSetTable(file, data + offset_chain_rule_set,
+ length - offset_chain_rule_set,
+ num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse chain rule set %d in chain context format 1", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseChainClassRuleSubtable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ // In this subtable, we don't check the value of classes for now since
+ // these could take arbitrary values.
+
+ uint16_t backtrack_count = 0;
+ if (!subtable.ReadU16(&backtrack_count)) {
+ return OTS_FAILURE_MSG("Failed to read backtrack count in chain class rule subtable");
+ }
+ if (backtrack_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad backtrack count %d in chain class rule subtable", backtrack_count);
+ }
+ if (!subtable.Skip(2 * backtrack_count)) {
+ return OTS_FAILURE_MSG("Failed to skip backtrack offsets in chain class rule subtable");
+ }
+
+ uint16_t input_count = 0;
+ if (!subtable.ReadU16(&input_count)) {
+ return OTS_FAILURE_MSG("Failed to read input count in chain class rule subtable");
+ }
+ if (input_count == 0 || input_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad input count %d in chain class rule subtable", input_count);
+ }
+ if (!subtable.Skip(2 * (input_count - 1))) {
+ return OTS_FAILURE_MSG("Failed to skip input offsets in chain class rule subtable");
+ }
+
+ uint16_t lookahead_count = 0;
+ if (!subtable.ReadU16(&lookahead_count)) {
+ return OTS_FAILURE_MSG("Failed to read lookahead count in chain class rule subtable");
+ }
+ if (lookahead_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad lookahead count %d in chain class rule subtable", lookahead_count);
+ }
+ if (!subtable.Skip(2 * lookahead_count)) {
+ return OTS_FAILURE_MSG("Failed to skip lookahead offsets in chain class rule subtable");
+ }
+
+ uint16_t lookup_count = 0;
+ if (!subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE_MSG("Failed to read lookup count in chain class rule subtable");
+ }
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup record %d in chain class rule subtable", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseChainClassSetTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t chain_class_rule_count = 0;
+ if (!subtable.ReadU16(&chain_class_rule_count)) {
+ return OTS_FAILURE_MSG("Failed to read rule count in chain class set");
+ }
+ const unsigned chain_class_rule_end =
+ 2 * static_cast<unsigned>(chain_class_rule_count) + 2;
+ if (chain_class_rule_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of chain class set %d in chain class set", chain_class_rule_end);
+ }
+ for (unsigned i = 0; i < chain_class_rule_count; ++i) {
+ uint16_t offset_chain_class_rule = 0;
+ if (!subtable.ReadU16(&offset_chain_class_rule)) {
+ return OTS_FAILURE_MSG("Failed to read chain class rule offset %d in chain class set", i);
+ }
+ if (offset_chain_class_rule < chain_class_rule_end ||
+ offset_chain_class_rule >= length) {
+ return OTS_FAILURE_MSG("Bad chain class rule offset %d for chain class %d in chain class set", offset_chain_class_rule, i);
+ }
+ if (!ParseChainClassRuleSubtable(file, data + offset_chain_class_rule,
+ length - offset_chain_class_rule,
+ num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse chain class rule %d in chain class set", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseChainContextFormat2(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t offset_coverage = 0;
+ uint16_t offset_backtrack_class_def = 0;
+ uint16_t offset_input_class_def = 0;
+ uint16_t offset_lookahead_class_def = 0;
+ uint16_t chain_class_set_count = 0;
+ // Skip format field.
+ if (!subtable.Skip(2) ||
+ !subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&offset_backtrack_class_def) ||
+ !subtable.ReadU16(&offset_input_class_def) ||
+ !subtable.ReadU16(&offset_lookahead_class_def) ||
+ !subtable.ReadU16(&chain_class_set_count)) {
+ return OTS_FAILURE_MSG("Failed to read header of chain context format 2");
+ }
+
+ const unsigned chain_class_set_end =
+ 2 * static_cast<unsigned>(chain_class_set_count) + 12;
+ if (chain_class_set_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad chain class set end %d in chain context format 2", chain_class_set_end);
+ }
+ if (offset_coverage < chain_class_set_end || offset_coverage >= length) {
+ return OTS_FAILURE_MSG("Bad coverage offset %d in chain context format 2", offset_coverage);
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage, num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse coverage table in chain context format 2");
+ }
+
+ // Classes for backtrack/lookahead sequences might not be defined.
+ if (offset_backtrack_class_def) {
+ if (offset_backtrack_class_def < chain_class_set_end ||
+ offset_backtrack_class_def >= length) {
+ return OTS_FAILURE_MSG("Bad backtrack class offset %d in chain context format 2", offset_backtrack_class_def);
+ }
+ if (!ots::ParseClassDefTable(file, data + offset_backtrack_class_def,
+ length - offset_backtrack_class_def,
+ num_glyphs, kMaxClassDefValue)) {
+ return OTS_FAILURE_MSG("Failed to parse backtrack class defn table in chain context format 2");
+ }
+ }
+
+ if (offset_input_class_def < chain_class_set_end ||
+ offset_input_class_def >= length) {
+ return OTS_FAILURE_MSG("Bad input class defn offset %d in chain context format 2", offset_input_class_def);
+ }
+ if (!ots::ParseClassDefTable(file, data + offset_input_class_def,
+ length - offset_input_class_def,
+ num_glyphs, kMaxClassDefValue)) {
+ return OTS_FAILURE_MSG("Failed to parse input class defn in chain context format 2");
+ }
+
+ if (offset_lookahead_class_def) {
+ if (offset_lookahead_class_def < chain_class_set_end ||
+ offset_lookahead_class_def >= length) {
+ return OTS_FAILURE_MSG("Bad lookahead class defn offset %d in chain context format 2", offset_lookahead_class_def);
+ }
+ if (!ots::ParseClassDefTable(file, data + offset_lookahead_class_def,
+ length - offset_lookahead_class_def,
+ num_glyphs, kMaxClassDefValue)) {
+ return OTS_FAILURE_MSG("Failed to parse lookahead class defn in chain context format 2");
+ }
+ }
+
+ for (unsigned i = 0; i < chain_class_set_count; ++i) {
+ uint16_t offset_chain_class_set = 0;
+ if (!subtable.ReadU16(&offset_chain_class_set)) {
+ return OTS_FAILURE_MSG("Failed to read chain class set offset %d", i);
+ }
+ // |offset_chain_class_set| could be NULL.
+ if (offset_chain_class_set) {
+ if (offset_chain_class_set < chain_class_set_end ||
+ offset_chain_class_set >= length) {
+ return OTS_FAILURE_MSG("Bad chain set class offset %d for chain set %d in chain context format 2", offset_chain_class_set, i);
+ }
+ if (!ParseChainClassSetTable(file, data + offset_chain_class_set,
+ length - offset_chain_class_set,
+ num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse chain class set table %d in chain context format 2", i);
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ParseChainContextFormat3(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ ots::Buffer subtable(data, length);
+
+ uint16_t backtrack_count = 0;
+ // Skip format field.
+ if (!subtable.Skip(2) ||
+ !subtable.ReadU16(&backtrack_count)) {
+ return OTS_FAILURE_MSG("Failed to read backtrack count in chain context format 3");
+ }
+
+ if (backtrack_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad backtrack count %d in chain context format 3", backtrack_count);
+ }
+ std::vector<uint16_t> offsets_backtrack;
+ offsets_backtrack.reserve(backtrack_count);
+ for (unsigned i = 0; i < backtrack_count; ++i) {
+ uint16_t offset = 0;
+ if (!subtable.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read backtrack offset %d in chain context format 3", i);
+ }
+ offsets_backtrack.push_back(offset);
+ }
+ if (offsets_backtrack.size() != backtrack_count) {
+ return OTS_FAILURE_MSG("Bad backtrack offsets size %ld in chain context format 3", offsets_backtrack.size());
+ }
+
+ uint16_t input_count = 0;
+ if (!subtable.ReadU16(&input_count)) {
+ return OTS_FAILURE_MSG("Failed to read input count in chain context format 3");
+ }
+ if (input_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad input count %d in chain context format 3", input_count);
+ }
+ std::vector<uint16_t> offsets_input;
+ offsets_input.reserve(input_count);
+ for (unsigned i = 0; i < input_count; ++i) {
+ uint16_t offset = 0;
+ if (!subtable.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read input offset %d in chain context format 3", i);
+ }
+ offsets_input.push_back(offset);
+ }
+ if (offsets_input.size() != input_count) {
+ return OTS_FAILURE_MSG("Bad input offsets size %ld in chain context format 3", offsets_input.size());
+ }
+
+ uint16_t lookahead_count = 0;
+ if (!subtable.ReadU16(&lookahead_count)) {
+ return OTS_FAILURE_MSG("Failed ot read lookahead count in chain context format 3");
+ }
+ if (lookahead_count >= num_glyphs) {
+ return OTS_FAILURE_MSG("Bad lookahead count %d in chain context format 3", lookahead_count);
+ }
+ std::vector<uint16_t> offsets_lookahead;
+ offsets_lookahead.reserve(lookahead_count);
+ for (unsigned i = 0; i < lookahead_count; ++i) {
+ uint16_t offset = 0;
+ if (!subtable.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read lookahead offset %d in chain context format 3", i);
+ }
+ offsets_lookahead.push_back(offset);
+ }
+ if (offsets_lookahead.size() != lookahead_count) {
+ return OTS_FAILURE_MSG("Bad lookahead offsets size %ld in chain context format 3", offsets_lookahead.size());
+ }
+
+ uint16_t lookup_count = 0;
+ if (!subtable.ReadU16(&lookup_count)) {
+ return OTS_FAILURE_MSG("Failed to read lookup count in chain context format 3");
+ }
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!ParseLookupRecord(file, &subtable, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup %d in chain context format 3", i);
+ }
+ }
+
+ const unsigned lookup_record_end =
+ 2 * (static_cast<unsigned>(backtrack_count) +
+ static_cast<unsigned>(input_count) +
+ static_cast<unsigned>(lookahead_count)) +
+ 4 * static_cast<unsigned>(lookup_count) + 10;
+ if (lookup_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of lookup record %d in chain context format 3", lookup_record_end);
+ }
+ for (unsigned i = 0; i < backtrack_count; ++i) {
+ if (offsets_backtrack[i] < lookup_record_end ||
+ offsets_backtrack[i] >= length) {
+ return OTS_FAILURE_MSG("Bad backtrack offset of %d for backtrack %d in chain context format 3", offsets_backtrack[i], i);
+ }
+ if (!ots::ParseCoverageTable(file, data + offsets_backtrack[i],
+ length - offsets_backtrack[i], num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse backtrack coverage %d in chain context format 3", i);
+ }
+ }
+ for (unsigned i = 0; i < input_count; ++i) {
+ if (offsets_input[i] < lookup_record_end || offsets_input[i] >= length) {
+ return OTS_FAILURE_MSG("Bad input offset %d for input %d in chain context format 3", offsets_input[i], i);
+ }
+ if (!ots::ParseCoverageTable(file, data + offsets_input[i],
+ length - offsets_input[i], num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse input coverage table %d in chain context format 3", i);
+ }
+ }
+ for (unsigned i = 0; i < lookahead_count; ++i) {
+ if (offsets_lookahead[i] < lookup_record_end ||
+ offsets_lookahead[i] >= length) {
+ return OTS_FAILURE_MSG("Bad lookadhead offset %d for lookahead %d in chain context format 3", offsets_lookahead[i], i);
+ }
+ if (!ots::ParseCoverageTable(file, data + offsets_lookahead[i],
+ length - offsets_lookahead[i], num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to parse lookahead coverage table %d in chain context format 3", i);
+ }
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace ots {
+
+bool LookupSubtableParser::Parse(const OpenTypeFile *file, const uint8_t *data,
+ const size_t length,
+ const uint16_t lookup_type) const {
+ for (unsigned i = 0; i < num_types; ++i) {
+ if (parsers[i].type == lookup_type && parsers[i].parse) {
+ if (!parsers[i].parse(file, data, length)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup subtable %d", i);
+ }
+ return true;
+ }
+ }
+ return OTS_FAILURE_MSG("No lookup subtables to parse");
+}
+
+// Parsing ScriptListTable requires number of features so we need to
+// parse FeatureListTable before calling this function.
+bool ParseScriptListTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_features) {
+ Buffer subtable(data, length);
+
+ uint16_t script_count = 0;
+ if (!subtable.ReadU16(&script_count)) {
+ return OTS_FAILURE_MSG("Failed to read script count in script list table");
+ }
+
+ const unsigned script_record_end =
+ 6 * static_cast<unsigned>(script_count) + 2;
+ if (script_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of script record %d in script list table", script_record_end);
+ }
+ std::vector<ScriptRecord> script_list;
+ script_list.reserve(script_count);
+ uint32_t last_tag = 0;
+ for (unsigned i = 0; i < script_count; ++i) {
+ ScriptRecord record;
+ if (!subtable.ReadU32(&record.tag) ||
+ !subtable.ReadU16(&record.offset)) {
+ return OTS_FAILURE_MSG("Failed to read script record %d in script list table", i);
+ }
+ // Script tags should be arranged alphabetically by tag
+ if (last_tag != 0 && last_tag > record.tag) {
+ // Several fonts don't arrange tags alphabetically.
+ // It seems that the order of tags might not be a security issue
+ // so we just warn it.
+ OTS_WARNING("tags aren't arranged alphabetically.");
+ }
+ last_tag = record.tag;
+ if (record.offset < script_record_end || record.offset >= length) {
+ return OTS_FAILURE_MSG("Bad record offset %d for script %4.4s entry %d in script list table", record.offset, (char *)&record.tag, i);
+ }
+ script_list.push_back(record);
+ }
+ if (script_list.size() != script_count) {
+ return OTS_FAILURE_MSG("Bad script list size %ld in script list table", script_list.size());
+ }
+
+ // Check script records.
+ for (unsigned i = 0; i < script_count; ++i) {
+ if (!ParseScriptTable(file, data + script_list[i].offset,
+ length - script_list[i].offset,
+ script_list[i].tag, num_features)) {
+ return OTS_FAILURE_MSG("Failed to parse script table %d", i);
+ }
+ }
+
+ return true;
+}
+
+// Parsing FeatureListTable requires number of lookups so we need to parse
+// LookupListTable before calling this function.
+bool ParseFeatureListTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_lookups,
+ uint16_t* num_features) {
+ Buffer subtable(data, length);
+
+ uint16_t feature_count = 0;
+ if (!subtable.ReadU16(&feature_count)) {
+ return OTS_FAILURE_MSG("Failed to read feature count");
+ }
+
+ std::vector<FeatureRecord> feature_records;
+ feature_records.resize(feature_count);
+ const unsigned feature_record_end =
+ 6 * static_cast<unsigned>(feature_count) + 2;
+ if (feature_record_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of feature record %d", feature_record_end);
+ }
+ uint32_t last_tag = 0;
+ for (unsigned i = 0; i < feature_count; ++i) {
+ if (!subtable.ReadU32(&feature_records[i].tag) ||
+ !subtable.ReadU16(&feature_records[i].offset)) {
+ return OTS_FAILURE_MSG("Failed to read feature header %d", i);
+ }
+ // Feature record array should be arranged alphabetically by tag
+ if (last_tag != 0 && last_tag > feature_records[i].tag) {
+ // Several fonts don't arrange tags alphabetically.
+ // It seems that the order of tags might not be a security issue
+ // so we just warn it.
+ OTS_WARNING("tags aren't arranged alphabetically.");
+ }
+ last_tag = feature_records[i].tag;
+ if (feature_records[i].offset < feature_record_end ||
+ feature_records[i].offset >= length) {
+ return OTS_FAILURE_MSG("Bad feature offset %d for feature %d %4.4s", feature_records[i].offset, i, (char *)&feature_records[i].tag);
+ }
+ }
+
+ for (unsigned i = 0; i < feature_count; ++i) {
+ if (!ParseFeatureTable(file, data + feature_records[i].offset,
+ length - feature_records[i].offset, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse feature table %d", i);
+ }
+ }
+ *num_features = feature_count;
+ return true;
+}
+
+// For parsing GPOS/GSUB tables, this function should be called at first to
+// obtain the number of lookups because parsing FeatureTableList requires
+// the number.
+bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
+ const size_t length,
+ const LookupSubtableParser* parser,
+ uint16_t *num_lookups) {
+ Buffer subtable(data, length);
+
+ if (!subtable.ReadU16(num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to read number of lookups");
+ }
+
+ std::vector<uint16_t> lookups;
+ lookups.reserve(*num_lookups);
+ const unsigned lookup_end =
+ 2 * static_cast<unsigned>(*num_lookups) + 2;
+ if (lookup_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE_MSG("Bad end of lookups %d", lookup_end);
+ }
+ for (unsigned i = 0; i < *num_lookups; ++i) {
+ uint16_t offset = 0;
+ if (!subtable.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read lookup offset %d", i);
+ }
+ if (offset < lookup_end || offset >= length) {
+ return OTS_FAILURE_MSG("Bad lookup offset %d for lookup %d", offset, i);
+ }
+ lookups.push_back(offset);
+ }
+ if (lookups.size() != *num_lookups) {
+ return OTS_FAILURE_MSG("Bad lookup offsets list size %ld", lookups.size());
+ }
+
+ for (unsigned i = 0; i < *num_lookups; ++i) {
+ if (!ParseLookupTable(file, data + lookups[i], length - lookups[i],
+ parser)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup %d", i);
+ }
+ }
+
+ return true;
+}
+
+bool ParseClassDefTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_classes) {
+ Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ if (!subtable.ReadU16(&format)) {
+ return OTS_FAILURE_MSG("Failed to read class defn format");
+ }
+ if (format == 1) {
+ return ParseClassDefFormat1(file, data, length, num_glyphs, num_classes);
+ } else if (format == 2) {
+ return ParseClassDefFormat2(file, data, length, num_glyphs, num_classes);
+ }
+
+ return OTS_FAILURE_MSG("Bad class defn format %d", format);
+}
+
+bool ParseCoverageTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t expected_num_glyphs) {
+ Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ if (!subtable.ReadU16(&format)) {
+ return OTS_FAILURE_MSG("Failed to read coverage table format");
+ }
+ if (format == 1) {
+ return ParseCoverageFormat1(file, data, length, num_glyphs, expected_num_glyphs);
+ } else if (format == 2) {
+ return ParseCoverageFormat2(file, data, length, num_glyphs, expected_num_glyphs);
+ }
+
+ return OTS_FAILURE_MSG("Bad coverage table format %d", format);
+}
+
+bool ParseDeviceTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length) {
+ Buffer subtable(data, length);
+
+ uint16_t start_size = 0;
+ uint16_t end_size = 0;
+ uint16_t delta_format = 0;
+ if (!subtable.ReadU16(&start_size) ||
+ !subtable.ReadU16(&end_size) ||
+ !subtable.ReadU16(&delta_format)) {
+ return OTS_FAILURE_MSG("Failed to read device table header");
+ }
+ if (start_size > end_size) {
+ return OTS_FAILURE_MSG("bad size range: %u > %u", start_size, end_size);
+ }
+ if (delta_format == 0 || delta_format > kMaxDeltaFormatType) {
+ return OTS_FAILURE_MSG("bad delta format: %u", delta_format);
+ }
+ // The number of delta values per uint16. The device table should contain
+ // at least |num_units| * 2 bytes compressed data.
+ const unsigned num_units = (end_size - start_size) /
+ (1 << (4 - delta_format)) + 1;
+ // Just skip |num_units| * 2 bytes since the compressed data could take
+ // arbitrary values.
+ if (!subtable.Skip(num_units * 2)) {
+ return OTS_FAILURE_MSG("Failed to skip data in device table");
+ }
+ return true;
+}
+
+bool ParseContextSubtable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ if (!subtable.ReadU16(&format)) {
+ return OTS_FAILURE_MSG("Failed to read context subtable format");
+ }
+
+ if (format == 1) {
+ if (!ParseContextFormat1(file, data, length, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse context format 1 subtable");
+ }
+ } else if (format == 2) {
+ if (!ParseContextFormat2(file, data, length, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse context format 2 subtable");
+ }
+ } else if (format == 3) {
+ if (!ParseContextFormat3(file, data, length, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse context format 3 subtable");
+ }
+ } else {
+ return OTS_FAILURE_MSG("Bad context subtable format %d", format);
+ }
+
+ return true;
+}
+
+bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups) {
+ Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ if (!subtable.ReadU16(&format)) {
+ return OTS_FAILURE_MSG("Failed to read chaining context subtable format");
+ }
+
+ if (format == 1) {
+ if (!ParseChainContextFormat1(file, data, length, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse chaining context format 1 subtable");
+ }
+ } else if (format == 2) {
+ if (!ParseChainContextFormat2(file, data, length, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse chaining context format 2 subtable");
+ }
+ } else if (format == 3) {
+ if (!ParseChainContextFormat3(file, data, length, num_glyphs, num_lookups)) {
+ return OTS_FAILURE_MSG("Failed to parse chaining context format 3 subtable");
+ }
+ } else {
+ return OTS_FAILURE_MSG("Bad chaining context subtable format %d", format);
+ }
+
+ return true;
+}
+
+bool ParseExtensionSubtable(const OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const LookupSubtableParser* parser) {
+ Buffer subtable(data, length);
+
+ uint16_t format = 0;
+ uint16_t lookup_type = 0;
+ uint32_t offset_extension = 0;
+ if (!subtable.ReadU16(&format) ||
+ !subtable.ReadU16(&lookup_type) ||
+ !subtable.ReadU32(&offset_extension)) {
+ return OTS_FAILURE_MSG("Failed to read extension table header");
+ }
+
+ if (format != 1) {
+ return OTS_FAILURE_MSG("Bad extension table format %d", format);
+ }
+ // |lookup_type| should be other than |parser->extension_type|.
+ if (lookup_type < 1 || lookup_type > parser->num_types ||
+ lookup_type == parser->extension_type) {
+ return OTS_FAILURE_MSG("Bad lookup type %d in extension table", lookup_type);
+ }
+
+ const unsigned format_end = static_cast<unsigned>(8);
+ if (offset_extension < format_end ||
+ offset_extension >= length) {
+ return OTS_FAILURE_MSG("Bad extension offset %d", offset_extension);
+ }
+
+ // Parse the extension subtable of |lookup_type|.
+ if (!parser->Parse(file, data + offset_extension, length - offset_extension,
+ lookup_type)) {
+ return OTS_FAILURE_MSG("Failed to parse lookup from extension lookup");
+ }
+
+ return true;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/layout.h b/third_party/ots/src/layout.h
new file mode 100644
index 0000000..3b94589
--- /dev/null
+++ b/third_party/ots/src/layout.h
@@ -0,0 +1,76 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_LAYOUT_H_
+#define OTS_LAYOUT_H_
+
+#include "ots.h"
+
+// Utility functions for OpenType layout common table formats.
+// http://www.microsoft.com/typography/otspec/chapter2.htm
+
+namespace ots {
+
+
+struct LookupSubtableParser {
+ struct TypeParser {
+ uint16_t type;
+ bool (*parse)(const OpenTypeFile *file, const uint8_t *data,
+ const size_t length);
+ };
+ size_t num_types;
+ uint16_t extension_type;
+ const TypeParser *parsers;
+
+ bool Parse(const OpenTypeFile *file, const uint8_t *data,
+ const size_t length, const uint16_t lookup_type) const;
+};
+
+bool ParseScriptListTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_features);
+
+bool ParseFeatureListTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_lookups,
+ uint16_t *num_features);
+
+bool ParseLookupListTable(OpenTypeFile *file, const uint8_t *data,
+ const size_t length,
+ const LookupSubtableParser* parser,
+ uint16_t* num_lookups);
+
+bool ParseClassDefTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_classes);
+
+bool ParseCoverageTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t expected_num_glyphs = 0);
+
+bool ParseDeviceTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length);
+
+// Parser for 'Contextual' subtable shared by GSUB/GPOS tables.
+bool ParseContextSubtable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups);
+
+// Parser for 'Chaining Contextual' subtable shared by GSUB/GPOS tables.
+bool ParseChainingContextSubtable(const ots::OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const uint16_t num_glyphs,
+ const uint16_t num_lookups);
+
+bool ParseExtensionSubtable(const OpenTypeFile *file,
+ const uint8_t *data, const size_t length,
+ const LookupSubtableParser* parser);
+
+} // namespace ots
+
+#endif // OTS_LAYOUT_H_
+
diff --git a/third_party/ots/src/loca.cc b/third_party/ots/src/loca.cc
new file mode 100644
index 0000000..4b291f0
--- /dev/null
+++ b/third_party/ots/src/loca.cc
@@ -0,0 +1,104 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "loca.h"
+
+#include "head.h"
+#include "maxp.h"
+
+// loca - Index to Location
+// http://www.microsoft.com/typography/otspec/loca.htm
+
+#define TABLE_NAME "loca"
+
+namespace ots {
+
+bool ots_loca_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ // We can't do anything useful in validating this data except to ensure that
+ // the values are monotonically increasing.
+
+ OpenTypeLOCA *loca = new OpenTypeLOCA;
+ file->loca = loca;
+
+ if (!file->maxp || !file->head) {
+ return OTS_FAILURE_MSG("maxp or head tables missing from font, needed by loca");
+ }
+
+ const unsigned num_glyphs = file->maxp->num_glyphs;
+ unsigned last_offset = 0;
+ loca->offsets.resize(num_glyphs + 1);
+ // maxp->num_glyphs is uint16_t, thus the addition never overflows.
+
+ if (file->head->index_to_loc_format == 0) {
+ // Note that the <= here (and below) is correct. There is one more offset
+ // than the number of glyphs in order to give the length of the final
+ // glyph.
+ for (unsigned i = 0; i <= num_glyphs; ++i) {
+ uint16_t offset = 0;
+ if (!table.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read offset for glyph %d", i);
+ }
+ if (offset < last_offset) {
+ return OTS_FAILURE_MSG("Out of order offset %d < %d for glyph %d", offset, last_offset, i);
+ }
+ last_offset = offset;
+ loca->offsets[i] = offset * 2;
+ }
+ } else {
+ for (unsigned i = 0; i <= num_glyphs; ++i) {
+ uint32_t offset = 0;
+ if (!table.ReadU32(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read offset for glyph %d", i);
+ }
+ if (offset < last_offset) {
+ return OTS_FAILURE_MSG("Out of order offset %d < %d for glyph %d", offset, last_offset, i);
+ }
+ last_offset = offset;
+ loca->offsets[i] = offset;
+ }
+ }
+
+ return true;
+}
+
+bool ots_loca_should_serialise(OpenTypeFile *file) {
+ return file->loca != NULL;
+}
+
+bool ots_loca_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeLOCA *loca = file->loca;
+ const OpenTypeHEAD *head = file->head;
+
+ if (!head) {
+ return OTS_FAILURE_MSG("Missing head table in font needed by loca");
+ }
+
+ if (head->index_to_loc_format == 0) {
+ for (unsigned i = 0; i < loca->offsets.size(); ++i) {
+ const uint16_t offset = static_cast<uint16_t>(loca->offsets[i] >> 1);
+ if ((offset != (loca->offsets[i] >> 1)) ||
+ !out->WriteU16(offset)) {
+ return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
+ }
+ }
+ } else {
+ for (unsigned i = 0; i < loca->offsets.size(); ++i) {
+ if (!out->WriteU32(loca->offsets[i])) {
+ return OTS_FAILURE_MSG("Failed to write glyph offset for glyph %d", i);
+ }
+ }
+ }
+
+ return true;
+}
+
+void ots_loca_free(OpenTypeFile *file) {
+ delete file->loca;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/loca.h b/third_party/ots/src/loca.h
new file mode 100644
index 0000000..255ef06
--- /dev/null
+++ b/third_party/ots/src/loca.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_LOCA_H_
+#define OTS_LOCA_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeLOCA {
+ std::vector<uint32_t> offsets;
+};
+
+} // namespace ots
+
+#endif // OTS_LOCA_H_
diff --git a/third_party/ots/src/ltsh.cc b/third_party/ots/src/ltsh.cc
new file mode 100644
index 0000000..418c159
--- /dev/null
+++ b/third_party/ots/src/ltsh.cc
@@ -0,0 +1,92 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ltsh.h"
+
+#include "maxp.h"
+
+// LTSH - Linear Threshold
+// http://www.microsoft.com/typography/otspec/ltsh.htm
+
+#define TABLE_NAME "LTSH"
+
+#define DROP_THIS_TABLE(...) \
+ do { \
+ OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+ OTS_FAILURE_MSG("Table discarded"); \
+ delete file->ltsh; \
+ file->ltsh = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_ltsh_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ if (!file->maxp) {
+ return OTS_FAILURE_MSG("Missing maxp table from font needed by ltsh");
+ }
+
+ OpenTypeLTSH *ltsh = new OpenTypeLTSH;
+ file->ltsh = ltsh;
+
+ uint16_t num_glyphs = 0;
+ if (!table.ReadU16(<sh->version) ||
+ !table.ReadU16(&num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to read ltsh header");
+ }
+
+ if (ltsh->version != 0) {
+ DROP_THIS_TABLE("bad version: %u", ltsh->version);
+ return true;
+ }
+
+ if (num_glyphs != file->maxp->num_glyphs) {
+ DROP_THIS_TABLE("bad num_glyphs: %u", num_glyphs);
+ return true;
+ }
+
+ ltsh->ypels.reserve(num_glyphs);
+ for (unsigned i = 0; i < num_glyphs; ++i) {
+ uint8_t pel = 0;
+ if (!table.ReadU8(&pel)) {
+ return OTS_FAILURE_MSG("Failed to read pixels for glyph %d", i);
+ }
+ ltsh->ypels.push_back(pel);
+ }
+
+ return true;
+}
+
+bool ots_ltsh_should_serialise(OpenTypeFile *file) {
+ if (!file->glyf) return false; // this table is not for CFF fonts.
+ return file->ltsh != NULL;
+}
+
+bool ots_ltsh_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeLTSH *ltsh = file->ltsh;
+
+ const uint16_t num_ypels = static_cast<uint16_t>(ltsh->ypels.size());
+ if (num_ypels != ltsh->ypels.size() ||
+ !out->WriteU16(ltsh->version) ||
+ !out->WriteU16(num_ypels)) {
+ return OTS_FAILURE_MSG("Failed to write pels size");
+ }
+ for (uint16_t i = 0; i < num_ypels; ++i) {
+ if (!out->Write(&(ltsh->ypels[i]), 1)) {
+ return OTS_FAILURE_MSG("Failed to write pixel size for glyph %d", i);
+ }
+ }
+
+ return true;
+}
+
+void ots_ltsh_free(OpenTypeFile *file) {
+ delete file->ltsh;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/ltsh.h b/third_party/ots/src/ltsh.h
new file mode 100644
index 0000000..23d97d7
--- /dev/null
+++ b/third_party/ots/src/ltsh.h
@@ -0,0 +1,21 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_LTSH_H_
+#define OTS_LTSH_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeLTSH {
+ uint16_t version;
+ std::vector<uint8_t> ypels;
+};
+
+} // namespace ots
+
+#endif // OTS_LTSH_H_
diff --git a/third_party/ots/src/math.cc b/third_party/ots/src/math.cc
new file mode 100644
index 0000000..9124a88
--- /dev/null
+++ b/third_party/ots/src/math.cc
@@ -0,0 +1,609 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// We use an underscore to avoid confusion with the standard math.h library.
+#include "math_.h"
+
+#include <limits>
+#include <vector>
+
+#include "layout.h"
+#include "maxp.h"
+
+// MATH - The MATH Table
+// The specification is not yet public but has been submitted to the MPEG group
+// in response to the 'Call for Proposals for ISO/IEC 14496-22 "Open Font
+// Format" Color Font Technology and MATH layout support'. Meanwhile, you can
+// contact Microsoft's engineer Murray Sargent to obtain a copy.
+
+#define TABLE_NAME "MATH"
+
+namespace {
+
+// The size of MATH header.
+// Version
+// MathConstants
+// MathGlyphInfo
+// MathVariants
+const unsigned kMathHeaderSize = 4 + 3 * 2;
+
+// The size of the MathGlyphInfo header.
+// MathItalicsCorrectionInfo
+// MathTopAccentAttachment
+// ExtendedShapeCoverage
+// MathKernInfo
+const unsigned kMathGlyphInfoHeaderSize = 4 * 2;
+
+// The size of the MathValueRecord.
+// Value
+// DeviceTable
+const unsigned kMathValueRecordSize = 2 * 2;
+
+// The size of the GlyphPartRecord.
+// glyph
+// StartConnectorLength
+// EndConnectorLength
+// FullAdvance
+// PartFlags
+const unsigned kGlyphPartRecordSize = 5 * 2;
+
+// Shared Table: MathValueRecord
+
+bool ParseMathValueRecord(const ots::OpenTypeFile *file,
+ ots::Buffer* subtable, const uint8_t *data,
+ const size_t length) {
+ // Check the Value field.
+ if (!subtable->Skip(2)) {
+ return OTS_FAILURE();
+ }
+
+ // Check the offset to device table.
+ uint16_t offset = 0;
+ if (!subtable->ReadU16(&offset)) {
+ return OTS_FAILURE();
+ }
+ if (offset) {
+ if (offset >= length) {
+ return OTS_FAILURE();
+ }
+ if (!ots::ParseDeviceTable(file, data + offset, length - offset)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
+bool ParseMathConstantsTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length) {
+ ots::Buffer subtable(data, length);
+
+ // Part 1: int16 or uint16 constants.
+ // ScriptPercentScaleDown
+ // ScriptScriptPercentScaleDown
+ // DelimitedSubFormulaMinHeight
+ // DisplayOperatorMinHeight
+ if (!subtable.Skip(4 * 2)) {
+ return OTS_FAILURE();
+ }
+
+ // Part 2: MathValueRecord constants.
+ // MathLeading
+ // AxisHeight
+ // AccentBaseHeight
+ // FlattenedAccentBaseHeight
+ // SubscriptShiftDown
+ // SubscriptTopMax
+ // SubscriptBaselineDropMin
+ // SuperscriptShiftUp
+ // SuperscriptShiftUpCramped
+ // SuperscriptBottomMin
+ //
+ // SuperscriptBaselineDropMax
+ // SubSuperscriptGapMin
+ // SuperscriptBottomMaxWithSubscript
+ // SpaceAfterScript
+ // UpperLimitGapMin
+ // UpperLimitBaselineRiseMin
+ // LowerLimitGapMin
+ // LowerLimitBaselineDropMin
+ // StackTopShiftUp
+ // StackTopDisplayStyleShiftUp
+ //
+ // StackBottomShiftDown
+ // StackBottomDisplayStyleShiftDown
+ // StackGapMin
+ // StackDisplayStyleGapMin
+ // StretchStackTopShiftUp
+ // StretchStackBottomShiftDown
+ // StretchStackGapAboveMin
+ // StretchStackGapBelowMin
+ // FractionNumeratorShiftUp
+ // FractionNumeratorDisplayStyleShiftUp
+ //
+ // FractionDenominatorShiftDown
+ // FractionDenominatorDisplayStyleShiftDown
+ // FractionNumeratorGapMin
+ // FractionNumDisplayStyleGapMin
+ // FractionRuleThickness
+ // FractionDenominatorGapMin
+ // FractionDenomDisplayStyleGapMin
+ // SkewedFractionHorizontalGap
+ // SkewedFractionVerticalGap
+ // OverbarVerticalGap
+ //
+ // OverbarRuleThickness
+ // OverbarExtraAscender
+ // UnderbarVerticalGap
+ // UnderbarRuleThickness
+ // UnderbarExtraDescender
+ // RadicalVerticalGap
+ // RadicalDisplayStyleVerticalGap
+ // RadicalRuleThickness
+ // RadicalExtraAscender
+ // RadicalKernBeforeDegree
+ //
+ // RadicalKernAfterDegree
+ for (unsigned i = 0; i < static_cast<unsigned>(51); ++i) {
+ if (!ParseMathValueRecord(file, &subtable, data, length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ // Part 3: uint16 constant
+ // RadicalDegreeBottomRaisePercent
+ if (!subtable.Skip(2)) {
+ return OTS_FAILURE();
+ }
+
+ return true;
+}
+
+bool ParseMathValueRecordSequenceForGlyphs(const ots::OpenTypeFile *file,
+ ots::Buffer* subtable,
+ const uint8_t *data,
+ const size_t length,
+ const uint16_t num_glyphs) {
+ // Check the header.
+ uint16_t offset_coverage = 0;
+ uint16_t sequence_count = 0;
+ if (!subtable->ReadU16(&offset_coverage) ||
+ !subtable->ReadU16(&sequence_count)) {
+ return OTS_FAILURE();
+ }
+
+ const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
+ sequence_count * kMathValueRecordSize;
+ if (sequence_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+
+ // Check coverage table.
+ if (offset_coverage < sequence_end || offset_coverage >= length) {
+ return OTS_FAILURE();
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage,
+ num_glyphs, sequence_count)) {
+ return OTS_FAILURE();
+ }
+
+ // Check sequence.
+ for (unsigned i = 0; i < sequence_count; ++i) {
+ if (!ParseMathValueRecord(file, subtable, data, length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
+bool ParseMathItalicsCorrectionInfoTable(const ots::OpenTypeFile *file,
+ const uint8_t *data,
+ size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+ return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
+ num_glyphs);
+}
+
+bool ParseMathTopAccentAttachmentTable(const ots::OpenTypeFile *file,
+ const uint8_t *data,
+ size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+ return ParseMathValueRecordSequenceForGlyphs(file, &subtable, data, length,
+ num_glyphs);
+}
+
+bool ParseMathKernTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length) {
+ ots::Buffer subtable(data, length);
+
+ // Check the Height count.
+ uint16_t height_count = 0;
+ if (!subtable.ReadU16(&height_count)) {
+ return OTS_FAILURE();
+ }
+
+ // Check the Correction Heights.
+ for (unsigned i = 0; i < height_count; ++i) {
+ if (!ParseMathValueRecord(file, &subtable, data, length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ // Check the Kern Values.
+ for (unsigned i = 0; i <= height_count; ++i) {
+ if (!ParseMathValueRecord(file, &subtable, data, length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
+bool ParseMathKernInfoTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Check the header.
+ uint16_t offset_coverage = 0;
+ uint16_t sequence_count = 0;
+ if (!subtable.ReadU16(&offset_coverage) ||
+ !subtable.ReadU16(&sequence_count)) {
+ return OTS_FAILURE();
+ }
+
+ const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
+ sequence_count * 4 * 2;
+ if (sequence_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+
+ // Check coverage table.
+ if (offset_coverage < sequence_end || offset_coverage >= length) {
+ return OTS_FAILURE();
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage, length - offset_coverage,
+ num_glyphs, sequence_count)) {
+ return OTS_FAILURE();
+ }
+
+ // Check sequence of MathKernInfoRecord
+ for (unsigned i = 0; i < sequence_count; ++i) {
+ // Check TopRight, TopLeft, BottomRight and BottomLeft Math Kern.
+ for (unsigned j = 0; j < 4; ++j) {
+ uint16_t offset_math_kern = 0;
+ if (!subtable.ReadU16(&offset_math_kern)) {
+ return OTS_FAILURE();
+ }
+ if (offset_math_kern) {
+ if (offset_math_kern < sequence_end || offset_math_kern >= length ||
+ !ParseMathKernTable(file, data + offset_math_kern,
+ length - offset_math_kern)) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+bool ParseMathGlyphInfoTable(const ots::OpenTypeFile *file,
+ const uint8_t *data, size_t length,
+ const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Check Header.
+ uint16_t offset_math_italics_correction_info = 0;
+ uint16_t offset_math_top_accent_attachment = 0;
+ uint16_t offset_extended_shaped_coverage = 0;
+ uint16_t offset_math_kern_info = 0;
+ if (!subtable.ReadU16(&offset_math_italics_correction_info) ||
+ !subtable.ReadU16(&offset_math_top_accent_attachment) ||
+ !subtable.ReadU16(&offset_extended_shaped_coverage) ||
+ !subtable.ReadU16(&offset_math_kern_info)) {
+ return OTS_FAILURE();
+ }
+
+ // Check subtables.
+ // The specification does not say whether the offsets for
+ // MathItalicsCorrectionInfo, MathTopAccentAttachment and MathKernInfo may
+ // be NULL, but that's the case in some fonts (e.g STIX) so we accept that.
+ if (offset_math_italics_correction_info) {
+ if (offset_math_italics_correction_info >= length ||
+ offset_math_italics_correction_info < kMathGlyphInfoHeaderSize ||
+ !ParseMathItalicsCorrectionInfoTable(
+ file, data + offset_math_italics_correction_info,
+ length - offset_math_italics_correction_info,
+ num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+ if (offset_math_top_accent_attachment) {
+ if (offset_math_top_accent_attachment >= length ||
+ offset_math_top_accent_attachment < kMathGlyphInfoHeaderSize ||
+ !ParseMathTopAccentAttachmentTable(file, data +
+ offset_math_top_accent_attachment,
+ length -
+ offset_math_top_accent_attachment,
+ num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+ if (offset_extended_shaped_coverage) {
+ if (offset_extended_shaped_coverage >= length ||
+ offset_extended_shaped_coverage < kMathGlyphInfoHeaderSize ||
+ !ots::ParseCoverageTable(file, data + offset_extended_shaped_coverage,
+ length - offset_extended_shaped_coverage,
+ num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+ if (offset_math_kern_info) {
+ if (offset_math_kern_info >= length ||
+ offset_math_kern_info < kMathGlyphInfoHeaderSize ||
+ !ParseMathKernInfoTable(file, data + offset_math_kern_info,
+ length - offset_math_kern_info, num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
+bool ParseGlyphAssemblyTable(const ots::OpenTypeFile *file,
+ const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Check the header.
+ uint16_t part_count = 0;
+ if (!ParseMathValueRecord(file, &subtable, data, length) ||
+ !subtable.ReadU16(&part_count)) {
+ return OTS_FAILURE();
+ }
+
+ const unsigned sequence_end = kMathValueRecordSize +
+ static_cast<unsigned>(2) + part_count * kGlyphPartRecordSize;
+ if (sequence_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+
+ // Check the sequence of GlyphPartRecord.
+ for (unsigned i = 0; i < part_count; ++i) {
+ uint16_t glyph = 0;
+ uint16_t part_flags = 0;
+ if (!subtable.ReadU16(&glyph) ||
+ !subtable.Skip(2 * 3) ||
+ !subtable.ReadU16(&part_flags)) {
+ return OTS_FAILURE();
+ }
+ if (glyph >= num_glyphs) {
+ return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
+ }
+ if (part_flags & ~0x00000001) {
+ return OTS_FAILURE_MSG("unknown part flag: %u", part_flags);
+ }
+ }
+
+ return true;
+}
+
+bool ParseMathGlyphConstructionTable(const ots::OpenTypeFile *file,
+ const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Check the header.
+ uint16_t offset_glyph_assembly = 0;
+ uint16_t variant_count = 0;
+ if (!subtable.ReadU16(&offset_glyph_assembly) ||
+ !subtable.ReadU16(&variant_count)) {
+ return OTS_FAILURE();
+ }
+
+ const unsigned sequence_end = static_cast<unsigned>(2 * 2) +
+ variant_count * 2 * 2;
+ if (sequence_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+
+ // Check the GlyphAssembly offset.
+ if (offset_glyph_assembly) {
+ if (offset_glyph_assembly >= length ||
+ offset_glyph_assembly < sequence_end) {
+ return OTS_FAILURE();
+ }
+ if (!ParseGlyphAssemblyTable(file, data + offset_glyph_assembly,
+ length - offset_glyph_assembly, num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ // Check the sequence of MathGlyphVariantRecord.
+ for (unsigned i = 0; i < variant_count; ++i) {
+ uint16_t glyph = 0;
+ if (!subtable.ReadU16(&glyph) ||
+ !subtable.Skip(2)) {
+ return OTS_FAILURE();
+ }
+ if (glyph >= num_glyphs) {
+ return OTS_FAILURE_MSG("bad glyph ID: %u", glyph);
+ }
+ }
+
+ return true;
+}
+
+bool ParseMathGlyphConstructionSequence(const ots::OpenTypeFile *file,
+ ots::Buffer* subtable,
+ const uint8_t *data,
+ size_t length,
+ const uint16_t num_glyphs,
+ uint16_t offset_coverage,
+ uint16_t glyph_count,
+ const unsigned sequence_end) {
+ // Check coverage table.
+ if (offset_coverage < sequence_end || offset_coverage >= length) {
+ return OTS_FAILURE();
+ }
+ if (!ots::ParseCoverageTable(file, data + offset_coverage,
+ length - offset_coverage,
+ num_glyphs, glyph_count)) {
+ return OTS_FAILURE();
+ }
+
+ // Check sequence of MathGlyphConstruction.
+ for (unsigned i = 0; i < glyph_count; ++i) {
+ uint16_t offset_glyph_construction = 0;
+ if (!subtable->ReadU16(&offset_glyph_construction)) {
+ return OTS_FAILURE();
+ }
+ if (offset_glyph_construction < sequence_end ||
+ offset_glyph_construction >= length ||
+ !ParseMathGlyphConstructionTable(file, data + offset_glyph_construction,
+ length - offset_glyph_construction,
+ num_glyphs)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return true;
+}
+
+bool ParseMathVariantsTable(const ots::OpenTypeFile *file,
+ const uint8_t *data,
+ size_t length, const uint16_t num_glyphs) {
+ ots::Buffer subtable(data, length);
+
+ // Check the header.
+ uint16_t offset_vert_glyph_coverage = 0;
+ uint16_t offset_horiz_glyph_coverage = 0;
+ uint16_t vert_glyph_count = 0;
+ uint16_t horiz_glyph_count = 0;
+ if (!subtable.Skip(2) || // MinConnectorOverlap
+ !subtable.ReadU16(&offset_vert_glyph_coverage) ||
+ !subtable.ReadU16(&offset_horiz_glyph_coverage) ||
+ !subtable.ReadU16(&vert_glyph_count) ||
+ !subtable.ReadU16(&horiz_glyph_count)) {
+ return OTS_FAILURE();
+ }
+
+ const unsigned sequence_end = 5 * 2 + vert_glyph_count * 2 +
+ horiz_glyph_count * 2;
+ if (sequence_end > std::numeric_limits<uint16_t>::max()) {
+ return OTS_FAILURE();
+ }
+
+ if (!ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
+ offset_vert_glyph_coverage,
+ vert_glyph_count,
+ sequence_end) ||
+ !ParseMathGlyphConstructionSequence(file, &subtable, data, length, num_glyphs,
+ offset_horiz_glyph_coverage,
+ horiz_glyph_count,
+ sequence_end)) {
+ return OTS_FAILURE();
+ }
+
+ return true;
+}
+
+} // namespace
+
+#define DROP_THIS_TABLE(msg_) \
+ do { \
+ OTS_FAILURE_MSG(msg_ ", table discarded"); \
+ file->math->data = 0; \
+ file->math->length = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_math_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ // Grab the number of glyphs in the file from the maxp table to check
+ // GlyphIDs in MATH table.
+ if (!file->maxp) {
+ return OTS_FAILURE();
+ }
+ const uint16_t num_glyphs = file->maxp->num_glyphs;
+
+ Buffer table(data, length);
+
+ OpenTypeMATH* math = new OpenTypeMATH;
+ file->math = math;
+
+ uint32_t version = 0;
+ if (!table.ReadU32(&version)) {
+ return OTS_FAILURE();
+ }
+ if (version != 0x00010000) {
+ DROP_THIS_TABLE("bad MATH version");
+ return true;
+ }
+
+ uint16_t offset_math_constants = 0;
+ uint16_t offset_math_glyph_info = 0;
+ uint16_t offset_math_variants = 0;
+ if (!table.ReadU16(&offset_math_constants) ||
+ !table.ReadU16(&offset_math_glyph_info) ||
+ !table.ReadU16(&offset_math_variants)) {
+ return OTS_FAILURE();
+ }
+
+ if (offset_math_constants >= length ||
+ offset_math_constants < kMathHeaderSize ||
+ offset_math_glyph_info >= length ||
+ offset_math_glyph_info < kMathHeaderSize ||
+ offset_math_variants >= length ||
+ offset_math_variants < kMathHeaderSize) {
+ DROP_THIS_TABLE("bad offset in MATH header");
+ return true;
+ }
+
+ if (!ParseMathConstantsTable(file, data + offset_math_constants,
+ length - offset_math_constants)) {
+ DROP_THIS_TABLE("failed to parse MathConstants table");
+ return true;
+ }
+ if (!ParseMathGlyphInfoTable(file, data + offset_math_glyph_info,
+ length - offset_math_glyph_info, num_glyphs)) {
+ DROP_THIS_TABLE("failed to parse MathGlyphInfo table");
+ return true;
+ }
+ if (!ParseMathVariantsTable(file, data + offset_math_variants,
+ length - offset_math_variants, num_glyphs)) {
+ DROP_THIS_TABLE("failed to parse MathVariants table");
+ return true;
+ }
+
+ math->data = data;
+ math->length = length;
+ return true;
+}
+
+bool ots_math_should_serialise(OpenTypeFile *file) {
+ return file->math != NULL && file->math->data != NULL;
+}
+
+bool ots_math_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!out->Write(file->math->data, file->math->length)) {
+ return OTS_FAILURE();
+ }
+
+ return true;
+}
+
+void ots_math_free(OpenTypeFile *file) {
+ delete file->math;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/math_.h b/third_party/ots/src/math_.h
new file mode 100644
index 0000000..91c54db
--- /dev/null
+++ b/third_party/ots/src/math_.h
@@ -0,0 +1,25 @@
+// Copyright (c) 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_MATH_H_
+#define OTS_MATH_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeMATH {
+ OpenTypeMATH()
+ : data(NULL),
+ length(0) {
+ }
+
+ const uint8_t *data;
+ size_t length;
+};
+
+} // namespace ots
+
+#endif
+
diff --git a/third_party/ots/src/maxp.cc b/third_party/ots/src/maxp.cc
new file mode 100644
index 0000000..aaf0076
--- /dev/null
+++ b/third_party/ots/src/maxp.cc
@@ -0,0 +1,120 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "maxp.h"
+
+// maxp - Maximum Profile
+// http://www.microsoft.com/typography/otspec/maxp.htm
+
+#define TABLE_NAME "maxp"
+
+namespace ots {
+
+bool ots_maxp_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypeMAXP *maxp = new OpenTypeMAXP;
+ file->maxp = maxp;
+
+ uint32_t version = 0;
+ if (!table.ReadU32(&version)) {
+ return OTS_FAILURE_MSG("Failed to read version of maxp table");
+ }
+
+ if (version >> 16 > 1) {
+ return OTS_FAILURE_MSG("Bad maxp version %d", version);
+ }
+
+ if (!table.ReadU16(&maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to read number of glyphs from maxp table");
+ }
+
+ if (!maxp->num_glyphs) {
+ return OTS_FAILURE_MSG("Bad number of glyphs 0 in maxp table");
+ }
+
+ if (version >> 16 == 1) {
+ maxp->version_1 = true;
+ if (!table.ReadU16(&maxp->max_points) ||
+ !table.ReadU16(&maxp->max_contours) ||
+ !table.ReadU16(&maxp->max_c_points) ||
+ !table.ReadU16(&maxp->max_c_contours) ||
+ !table.ReadU16(&maxp->max_zones) ||
+ !table.ReadU16(&maxp->max_t_points) ||
+ !table.ReadU16(&maxp->max_storage) ||
+ !table.ReadU16(&maxp->max_fdefs) ||
+ !table.ReadU16(&maxp->max_idefs) ||
+ !table.ReadU16(&maxp->max_stack) ||
+ !table.ReadU16(&maxp->max_size_glyf_instructions) ||
+ !table.ReadU16(&maxp->max_c_components) ||
+ !table.ReadU16(&maxp->max_c_depth)) {
+ return OTS_FAILURE_MSG("Failed to read maxp table");
+ }
+
+ if (maxp->max_zones == 0) {
+ // workaround for ipa*.ttf Japanese fonts.
+ OTS_WARNING("bad max_zones: %u", maxp->max_zones);
+ maxp->max_zones = 1;
+ } else if (maxp->max_zones == 3) {
+ // workaround for Ecolier-*.ttf fonts.
+ OTS_WARNING("bad max_zones: %u", maxp->max_zones);
+ maxp->max_zones = 2;
+ }
+
+ if ((maxp->max_zones != 1) && (maxp->max_zones != 2)) {
+ return OTS_FAILURE_MSG("Bad max zones %d in maxp", maxp->max_zones);
+ }
+ } else {
+ maxp->version_1 = false;
+ }
+
+ return true;
+}
+
+bool ots_maxp_should_serialise(OpenTypeFile *file) {
+ return file->maxp != NULL;
+}
+
+bool ots_maxp_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeMAXP *maxp = file->maxp;
+
+ if (!out->WriteU32(maxp->version_1 ? 0x00010000 : 0x00005000) ||
+ !out->WriteU16(maxp->num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to write maxp version or number of glyphs");
+ }
+
+ if (!maxp->version_1) return true;
+
+ if (!out->WriteU16(maxp->max_points) ||
+ !out->WriteU16(maxp->max_contours) ||
+ !out->WriteU16(maxp->max_c_points) ||
+ !out->WriteU16(maxp->max_c_contours)) {
+ return OTS_FAILURE_MSG("Failed to write maxp");
+ }
+
+ if (!out->WriteU16(maxp->max_zones) ||
+ !out->WriteU16(maxp->max_t_points) ||
+ !out->WriteU16(maxp->max_storage) ||
+ !out->WriteU16(maxp->max_fdefs) ||
+ !out->WriteU16(maxp->max_idefs) ||
+ !out->WriteU16(maxp->max_stack) ||
+ !out->WriteU16(maxp->max_size_glyf_instructions)) {
+ return OTS_FAILURE_MSG("Failed to write more maxp");
+ }
+
+ if (!out->WriteU16(maxp->max_c_components) ||
+ !out->WriteU16(maxp->max_c_depth)) {
+ return OTS_FAILURE_MSG("Failed to write yet more maxp");
+ }
+
+ return true;
+}
+
+void ots_maxp_free(OpenTypeFile *file) {
+ delete file->maxp;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/maxp.h b/third_party/ots/src/maxp.h
new file mode 100644
index 0000000..efca0c9
--- /dev/null
+++ b/third_party/ots/src/maxp.h
@@ -0,0 +1,35 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_MAXP_H_
+#define OTS_MAXP_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeMAXP {
+ uint16_t num_glyphs;
+ bool version_1;
+
+ uint16_t max_points;
+ uint16_t max_contours;
+ uint16_t max_c_points;
+ uint16_t max_c_contours;
+
+ uint16_t max_zones;
+ uint16_t max_t_points;
+ uint16_t max_storage;
+ uint16_t max_fdefs;
+ uint16_t max_idefs;
+ uint16_t max_stack;
+ uint16_t max_size_glyf_instructions;
+
+ uint16_t max_c_components;
+ uint16_t max_c_depth;
+};
+
+} // namespace ots
+
+#endif // OTS_MAXP_H_
diff --git a/third_party/ots/src/metrics.cc b/third_party/ots/src/metrics.cc
new file mode 100644
index 0000000..8d59b95
--- /dev/null
+++ b/third_party/ots/src/metrics.cc
@@ -0,0 +1,193 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "metrics.h"
+
+#include "head.h"
+#include "maxp.h"
+
+// OpenType horizontal and vertical common header format
+// http://www.microsoft.com/typography/otspec/hhea.htm
+// http://www.microsoft.com/typography/otspec/vhea.htm
+
+#define TABLE_NAME "metrics" // XXX: use individual table names
+
+namespace ots {
+
+bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
+ OpenTypeMetricsHeader *header) {
+ if (!table->ReadS16(&header->ascent) ||
+ !table->ReadS16(&header->descent) ||
+ !table->ReadS16(&header->linegap) ||
+ !table->ReadU16(&header->adv_width_max) ||
+ !table->ReadS16(&header->min_sb1) ||
+ !table->ReadS16(&header->min_sb2) ||
+ !table->ReadS16(&header->max_extent) ||
+ !table->ReadS16(&header->caret_slope_rise) ||
+ !table->ReadS16(&header->caret_slope_run) ||
+ !table->ReadS16(&header->caret_offset)) {
+ return OTS_FAILURE_MSG("Failed to read metrics header");
+ }
+
+ if (header->ascent < 0) {
+ OTS_WARNING("bad ascent: %d", header->ascent);
+ header->ascent = 0;
+ }
+ if (header->linegap < 0) {
+ OTS_WARNING("bad linegap: %d", header->linegap);
+ header->linegap = 0;
+ }
+
+ if (!file->head) {
+ return OTS_FAILURE_MSG("Missing head font table");
+ }
+
+ // if the font is non-slanted, caret_offset should be zero.
+ if (!(file->head->mac_style & 2) &&
+ (header->caret_offset != 0)) {
+ OTS_WARNING("bad caret offset: %d", header->caret_offset);
+ header->caret_offset = 0;
+ }
+
+ // skip the reserved bytes
+ if (!table->Skip(8)) {
+ return OTS_FAILURE_MSG("Failed to skip reserverd bytes");
+ }
+
+ int16_t data_format;
+ if (!table->ReadS16(&data_format)) {
+ return OTS_FAILURE_MSG("Failed to read data format");
+ }
+ if (data_format) {
+ return OTS_FAILURE_MSG("Bad data format %d", data_format);
+ }
+
+ if (!table->ReadU16(&header->num_metrics)) {
+ return OTS_FAILURE_MSG("Failed to read number of metrics");
+ }
+
+ if (!file->maxp) {
+ return OTS_FAILURE_MSG("Missing maxp font table");
+ }
+
+ if (header->num_metrics > file->maxp->num_glyphs) {
+ return OTS_FAILURE_MSG("Bad number of metrics %d", header->num_metrics);
+ }
+
+ return true;
+}
+
+bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
+ OTSStream *out,
+ const OpenTypeMetricsHeader *header) {
+ if (!out->WriteU32(header->version) ||
+ !out->WriteS16(header->ascent) ||
+ !out->WriteS16(header->descent) ||
+ !out->WriteS16(header->linegap) ||
+ !out->WriteU16(header->adv_width_max) ||
+ !out->WriteS16(header->min_sb1) ||
+ !out->WriteS16(header->min_sb2) ||
+ !out->WriteS16(header->max_extent) ||
+ !out->WriteS16(header->caret_slope_rise) ||
+ !out->WriteS16(header->caret_slope_run) ||
+ !out->WriteS16(header->caret_offset) ||
+ !out->WriteR64(0) || // reserved
+ !out->WriteS16(0) || // metric data format
+ !out->WriteU16(header->num_metrics)) {
+ return OTS_FAILURE_MSG("Failed to write metrics");
+ }
+
+ return true;
+}
+
+bool ParseMetricsTable(const ots::OpenTypeFile *file,
+ Buffer *table,
+ const uint16_t num_glyphs,
+ const OpenTypeMetricsHeader *header,
+ OpenTypeMetricsTable *metrics) {
+ // |num_metrics| is a uint16_t, so it's bounded < 65536. This limits that
+ // amount of memory that we'll allocate for this to a sane amount.
+ const unsigned num_metrics = header->num_metrics;
+
+ if (num_metrics > num_glyphs) {
+ return OTS_FAILURE_MSG("Bad number of metrics %d", num_metrics);
+ }
+ if (!num_metrics) {
+ return OTS_FAILURE_MSG("No metrics!");
+ }
+ const unsigned num_sbs = num_glyphs - num_metrics;
+
+ metrics->entries.reserve(num_metrics);
+ for (unsigned i = 0; i < num_metrics; ++i) {
+ uint16_t adv = 0;
+ int16_t sb = 0;
+ if (!table->ReadU16(&adv) || !table->ReadS16(&sb)) {
+ return OTS_FAILURE_MSG("Failed to read metric %d", i);
+ }
+
+ // This check is bogus, see https://github.com/khaledhosny/ots/issues/36
+#if 0
+ // Since so many fonts don't have proper value on |adv| and |sb|,
+ // we should not call ots_failure() here. For example, about 20% of fonts
+ // in http://www.princexml.com/fonts/ (200+ fonts) fails these tests.
+ if (adv > header->adv_width_max) {
+ OTS_WARNING("bad adv: %u > %u", adv, header->adv_width_max);
+ adv = header->adv_width_max;
+ }
+
+ if (sb < header->min_sb1) {
+ OTS_WARNING("bad sb: %d < %d", sb, header->min_sb1);
+ sb = header->min_sb1;
+ }
+#endif
+
+ metrics->entries.push_back(std::make_pair(adv, sb));
+ }
+
+ metrics->sbs.reserve(num_sbs);
+ for (unsigned i = 0; i < num_sbs; ++i) {
+ int16_t sb;
+ if (!table->ReadS16(&sb)) {
+ // Some Japanese fonts (e.g., mona.ttf) fail this test.
+ return OTS_FAILURE_MSG("Failed to read side bearing %d", i + num_metrics);
+ }
+
+ // This check is bogus, see https://github.com/khaledhosny/ots/issues/36
+#if 0
+ if (sb < header->min_sb1) {
+ // The same as above. Three fonts in http://www.fontsquirrel.com/fontface
+ // (e.g., Notice2Std.otf) have weird lsb values.
+ OTS_WARNING("bad lsb: %d < %d", sb, header->min_sb1);
+ sb = header->min_sb1;
+ }
+#endif
+
+ metrics->sbs.push_back(sb);
+ }
+
+ return true;
+}
+
+bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
+ OTSStream *out,
+ const OpenTypeMetricsTable *metrics) {
+ for (unsigned i = 0; i < metrics->entries.size(); ++i) {
+ if (!out->WriteU16(metrics->entries[i].first) ||
+ !out->WriteS16(metrics->entries[i].second)) {
+ return OTS_FAILURE_MSG("Failed to write metric %d", i);
+ }
+ }
+
+ for (unsigned i = 0; i < metrics->sbs.size(); ++i) {
+ if (!out->WriteS16(metrics->sbs[i])) {
+ return OTS_FAILURE_MSG("Failed to write side bearing %ld", i + metrics->entries.size());
+ }
+ }
+
+ return true;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/metrics.h b/third_party/ots/src/metrics.h
new file mode 100644
index 0000000..f0b4ee8
--- /dev/null
+++ b/third_party/ots/src/metrics.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_METRICS_H_
+#define OTS_METRICS_H_
+
+#include <new>
+#include <utility>
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeMetricsHeader {
+ uint32_t version;
+ int16_t ascent;
+ int16_t descent;
+ int16_t linegap;
+ uint16_t adv_width_max;
+ int16_t min_sb1;
+ int16_t min_sb2;
+ int16_t max_extent;
+ int16_t caret_slope_rise;
+ int16_t caret_slope_run;
+ int16_t caret_offset;
+ uint16_t num_metrics;
+};
+
+struct OpenTypeMetricsTable {
+ std::vector<std::pair<uint16_t, int16_t> > entries;
+ std::vector<int16_t> sbs;
+};
+
+bool ParseMetricsHeader(OpenTypeFile *file, Buffer *table,
+ OpenTypeMetricsHeader *header);
+bool SerialiseMetricsHeader(const ots::OpenTypeFile *file,
+ OTSStream *out,
+ const OpenTypeMetricsHeader *header);
+
+bool ParseMetricsTable(const ots::OpenTypeFile *file,
+ Buffer *table,
+ const uint16_t num_glyphs,
+ const OpenTypeMetricsHeader *header,
+ OpenTypeMetricsTable *metrics);
+bool SerialiseMetricsTable(const ots::OpenTypeFile *file,
+ OTSStream *out,
+ const OpenTypeMetricsTable *metrics);
+
+} // namespace ots
+
+#endif // OTS_METRICS_H_
+
diff --git a/third_party/ots/src/name.cc b/third_party/ots/src/name.cc
new file mode 100644
index 0000000..2ea10dc
--- /dev/null
+++ b/third_party/ots/src/name.cc
@@ -0,0 +1,340 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "name.h"
+
+#include <algorithm>
+#include <cstring>
+
+#include "cff.h"
+
+// name - Naming Table
+// http://www.microsoft.com/typography/otspec/name.htm
+
+#define TABLE_NAME "name"
+
+namespace {
+
+bool ValidInPsName(char c) {
+ return (c > 0x20 && c < 0x7f && !std::strchr("[](){}<>/%", c));
+}
+
+bool CheckPsNameAscii(const std::string& name) {
+ for (unsigned i = 0; i < name.size(); ++i) {
+ if (!ValidInPsName(name[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool CheckPsNameUtf16Be(const std::string& name) {
+ if ((name.size() & 1) != 0)
+ return false;
+
+ for (unsigned i = 0; i < name.size(); i += 2) {
+ if (name[i] != 0) {
+ return false;
+ }
+ if (!ValidInPsName(name[i+1])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void AssignToUtf16BeFromAscii(std::string* target,
+ const std::string& source) {
+ target->resize(source.size() * 2);
+ for (unsigned i = 0, j = 0; i < source.size(); i++) {
+ (*target)[j++] = '\0';
+ (*target)[j++] = source[i];
+ }
+}
+
+} // namespace
+
+
+namespace ots {
+
+bool ots_name_parse(OpenTypeFile* file, const uint8_t* data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypeNAME* name = new OpenTypeNAME;
+ file->name = name;
+
+ uint16_t format = 0;
+ if (!table.ReadU16(&format) || format > 1) {
+ return OTS_FAILURE_MSG("Failed to read name table format or bad format %d", format);
+ }
+
+ uint16_t count = 0;
+ if (!table.ReadU16(&count)) {
+ return OTS_FAILURE_MSG("Failed to read name count");
+ }
+
+ uint16_t string_offset = 0;
+ if (!table.ReadU16(&string_offset) || string_offset > length) {
+ return OTS_FAILURE_MSG("Failed to read strings offset");
+ }
+ const char* string_base = reinterpret_cast<const char*>(data) +
+ string_offset;
+
+ NameRecord prev_record;
+ bool sort_required = false;
+
+ // Read all the names, discarding any with invalid IDs,
+ // and any where the offset/length would be outside the table.
+ // A stricter alternative would be to reject the font if there
+ // are invalid name records, but it's not clear that is necessary.
+ for (unsigned i = 0; i < count; ++i) {
+ NameRecord rec;
+ uint16_t name_length, name_offset = 0;
+ if (!table.ReadU16(&rec.platform_id) ||
+ !table.ReadU16(&rec.encoding_id) ||
+ !table.ReadU16(&rec.language_id) ||
+ !table.ReadU16(&rec.name_id) ||
+ !table.ReadU16(&name_length) ||
+ !table.ReadU16(&name_offset)) {
+ return OTS_FAILURE_MSG("Failed to read name entry %d", i);
+ }
+ // check platform & encoding, discard names with unknown values
+ switch (rec.platform_id) {
+ case 0: // Unicode
+ if (rec.encoding_id > 6) {
+ continue;
+ }
+ break;
+ case 1: // Macintosh
+ if (rec.encoding_id > 32) {
+ continue;
+ }
+ break;
+ case 2: // ISO
+ if (rec.encoding_id > 2) {
+ continue;
+ }
+ break;
+ case 3: // Windows: IDs 7 to 9 are "reserved"
+ if (rec.encoding_id > 6 && rec.encoding_id != 10) {
+ continue;
+ }
+ break;
+ case 4: // Custom (OTF Windows NT compatibility)
+ if (rec.encoding_id > 255) {
+ continue;
+ }
+ break;
+ default: // unknown platform
+ continue;
+ }
+
+ const unsigned name_end = static_cast<unsigned>(string_offset) +
+ name_offset + name_length;
+ if (name_end > length) {
+ continue;
+ }
+ rec.text.resize(name_length);
+ rec.text.assign(string_base + name_offset, name_length);
+
+ if (rec.name_id == 6) {
+ // PostScript name: check that it is valid, if not then discard it
+ if (rec.platform_id == 1) {
+ if (file->cff && !file->cff->name.empty()) {
+ rec.text = file->cff->name;
+ } else if (!CheckPsNameAscii(rec.text)) {
+ continue;
+ }
+ } else if (rec.platform_id == 0 || rec.platform_id == 3) {
+ if (file->cff && !file->cff->name.empty()) {
+ AssignToUtf16BeFromAscii(&rec.text, file->cff->name);
+ } else if (!CheckPsNameUtf16Be(rec.text)) {
+ continue;
+ }
+ }
+ }
+
+ if ((i > 0) && !(prev_record < rec)) {
+ OTS_WARNING("name records are not sorted.");
+ sort_required = true;
+ }
+
+ name->names.push_back(rec);
+ prev_record = rec;
+ }
+
+ if (format == 1) {
+ // extended name table format with language tags
+ uint16_t lang_tag_count;
+ if (!table.ReadU16(&lang_tag_count)) {
+ return OTS_FAILURE_MSG("Failed to read language tag count");
+ }
+ for (unsigned i = 0; i < lang_tag_count; ++i) {
+ uint16_t tag_length = 0;
+ uint16_t tag_offset = 0;
+ if (!table.ReadU16(&tag_length) || !table.ReadU16(&tag_offset)) {
+ return OTS_FAILURE_MSG("Faile to read tag length or offset");
+ }
+ const unsigned tag_end = static_cast<unsigned>(string_offset) +
+ tag_offset + tag_length;
+ if (tag_end > length) {
+ return OTS_FAILURE_MSG("bad end of tag %d > %ld for name entry %d", tag_end, length, i);
+ }
+ std::string tag(string_base + tag_offset, tag_length);
+ name->lang_tags.push_back(tag);
+ }
+ }
+
+ if (table.offset() > string_offset) {
+ // the string storage apparently overlapped the name/tag records;
+ // consider this font to be badly broken
+ return OTS_FAILURE_MSG("Bad table offset %ld > %d", table.offset(), string_offset);
+ }
+
+ // check existence of required name strings (synthesize if necessary)
+ // [0 - copyright - skip]
+ // 1 - family
+ // 2 - subfamily
+ // [3 - unique ID - skip]
+ // 4 - full name
+ // 5 - version
+ // 6 - postscript name
+ static const uint16_t kStdNameCount = 7;
+ static const char* kStdNames[kStdNameCount] = {
+ NULL,
+ "OTS derived font",
+ "Unspecified",
+ NULL,
+ "OTS derived font",
+ "1.000",
+ "OTS-derived-font"
+ };
+ // The spec says that "In CFF OpenType fonts, these two name strings, when
+ // translated to ASCII, must also be identical to the font name as stored in
+ // the CFF's Name INDEX." And actually, Mac OS X's font parser requires that.
+ if (file->cff && !file->cff->name.empty()) {
+ kStdNames[6] = file->cff->name.c_str();
+ }
+
+ // scan the names to check whether the required "standard" ones are present;
+ // if not, we'll add our fixed versions here
+ bool mac_name[kStdNameCount] = { 0 };
+ bool win_name[kStdNameCount] = { 0 };
+ for (std::vector<NameRecord>::iterator name_iter = name->names.begin();
+ name_iter != name->names.end(); name_iter++) {
+ const uint16_t id = name_iter->name_id;
+ if (id >= kStdNameCount || kStdNames[id] == NULL) {
+ continue;
+ }
+ if (name_iter->platform_id == 1) {
+ mac_name[id] = true;
+ continue;
+ }
+ if (name_iter->platform_id == 3) {
+ win_name[id] = true;
+ continue;
+ }
+ }
+
+ for (uint16_t i = 0; i < kStdNameCount; ++i) {
+ if (kStdNames[i] == NULL) {
+ continue;
+ }
+ if (!mac_name[i]) {
+ NameRecord rec(1 /* platform_id */, 0 /* encoding_id */,
+ 0 /* language_id */ , i /* name_id */);
+ rec.text.assign(kStdNames[i]);
+ name->names.push_back(rec);
+ sort_required = true;
+ }
+ if (!win_name[i]) {
+ NameRecord rec(3 /* platform_id */, 1 /* encoding_id */,
+ 1033 /* language_id */ , i /* name_id */);
+ AssignToUtf16BeFromAscii(&rec.text, std::string(kStdNames[i]));
+ name->names.push_back(rec);
+ sort_required = true;
+ }
+ }
+
+ if (sort_required) {
+ std::sort(name->names.begin(), name->names.end());
+ }
+
+ return true;
+}
+
+bool ots_name_should_serialise(OpenTypeFile* file) {
+ return file->name != NULL;
+}
+
+bool ots_name_serialise(OTSStream* out, OpenTypeFile* file) {
+ const OpenTypeNAME* name = file->name;
+
+ uint16_t name_count = static_cast<uint16_t>(name->names.size());
+ uint16_t lang_tag_count = static_cast<uint16_t>(name->lang_tags.size());
+ uint16_t format = 0;
+ size_t string_offset = 6 + name_count * 12;
+
+ if (name->lang_tags.size() > 0) {
+ // lang tags require a format-1 name table
+ format = 1;
+ string_offset += 2 + lang_tag_count * 4;
+ }
+ if (string_offset > 0xffff) {
+ return OTS_FAILURE_MSG("Bad string offset %ld", string_offset);
+ }
+ if (!out->WriteU16(format) ||
+ !out->WriteU16(name_count) ||
+ !out->WriteU16(static_cast<uint16_t>(string_offset))) {
+ return OTS_FAILURE_MSG("Failed to write name header");
+ }
+
+ std::string string_data;
+ for (std::vector<NameRecord>::const_iterator name_iter = name->names.begin();
+ name_iter != name->names.end(); name_iter++) {
+ const NameRecord& rec = *name_iter;
+ if (string_data.size() + rec.text.size() >
+ std::numeric_limits<uint16_t>::max() ||
+ !out->WriteU16(rec.platform_id) ||
+ !out->WriteU16(rec.encoding_id) ||
+ !out->WriteU16(rec.language_id) ||
+ !out->WriteU16(rec.name_id) ||
+ !out->WriteU16(static_cast<uint16_t>(rec.text.size())) ||
+ !out->WriteU16(static_cast<uint16_t>(string_data.size())) ) {
+ return OTS_FAILURE_MSG("Faile to write name entry");
+ }
+ string_data.append(rec.text);
+ }
+
+ if (format == 1) {
+ if (!out->WriteU16(lang_tag_count)) {
+ return OTS_FAILURE_MSG("Faile to write language tag count");
+ }
+ for (std::vector<std::string>::const_iterator tag_iter =
+ name->lang_tags.begin();
+ tag_iter != name->lang_tags.end(); tag_iter++) {
+ if (string_data.size() + tag_iter->size() >
+ std::numeric_limits<uint16_t>::max() ||
+ !out->WriteU16(static_cast<uint16_t>(tag_iter->size())) ||
+ !out->WriteU16(static_cast<uint16_t>(string_data.size()))) {
+ return OTS_FAILURE_MSG("Failed to write string");
+ }
+ string_data.append(*tag_iter);
+ }
+ }
+
+ if (!out->Write(string_data.data(), string_data.size())) {
+ return OTS_FAILURE_MSG("Faile to write string data");
+ }
+
+ return true;
+}
+
+void ots_name_free(OpenTypeFile* file) {
+ delete file->name;
+}
+
+} // namespace
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/name.h b/third_party/ots/src/name.h
new file mode 100644
index 0000000..a11965f
--- /dev/null
+++ b/third_party/ots/src/name.h
@@ -0,0 +1,53 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_NAME_H_
+#define OTS_NAME_H_
+
+#include <new>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct NameRecord {
+ NameRecord() {
+ }
+
+ NameRecord(uint16_t platformID, uint16_t encodingID,
+ uint16_t languageID, uint16_t nameID)
+ : platform_id(platformID),
+ encoding_id(encodingID),
+ language_id(languageID),
+ name_id(nameID) {
+ }
+
+ uint16_t platform_id;
+ uint16_t encoding_id;
+ uint16_t language_id;
+ uint16_t name_id;
+ std::string text;
+
+ bool operator<(const NameRecord& rhs) const {
+ if (platform_id < rhs.platform_id) return true;
+ if (platform_id > rhs.platform_id) return false;
+ if (encoding_id < rhs.encoding_id) return true;
+ if (encoding_id > rhs.encoding_id) return false;
+ if (language_id < rhs.language_id) return true;
+ if (language_id > rhs.language_id) return false;
+ return name_id < rhs.name_id;
+ }
+};
+
+struct OpenTypeNAME {
+ std::vector<NameRecord> names;
+ std::vector<std::string> lang_tags;
+};
+
+} // namespace ots
+
+#endif // OTS_NAME_H_
diff --git a/third_party/ots/src/os2.cc b/third_party/ots/src/os2.cc
new file mode 100644
index 0000000..915877e
--- /dev/null
+++ b/third_party/ots/src/os2.cc
@@ -0,0 +1,294 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "os2.h"
+
+#include "head.h"
+
+// OS/2 - OS/2 and Windows Metrics
+// http://www.microsoft.com/typography/otspec/os2.htm
+
+#define TABLE_NAME "OS/2"
+
+namespace ots {
+
+bool ots_os2_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypeOS2 *os2 = new OpenTypeOS2;
+ file->os2 = os2;
+
+ if (!table.ReadU16(&os2->version) ||
+ !table.ReadS16(&os2->avg_char_width) ||
+ !table.ReadU16(&os2->weight_class) ||
+ !table.ReadU16(&os2->width_class) ||
+ !table.ReadU16(&os2->type) ||
+ !table.ReadS16(&os2->subscript_x_size) ||
+ !table.ReadS16(&os2->subscript_y_size) ||
+ !table.ReadS16(&os2->subscript_x_offset) ||
+ !table.ReadS16(&os2->subscript_y_offset) ||
+ !table.ReadS16(&os2->superscript_x_size) ||
+ !table.ReadS16(&os2->superscript_y_size) ||
+ !table.ReadS16(&os2->superscript_x_offset) ||
+ !table.ReadS16(&os2->superscript_y_offset) ||
+ !table.ReadS16(&os2->strikeout_size) ||
+ !table.ReadS16(&os2->strikeout_position) ||
+ !table.ReadS16(&os2->family_class)) {
+ return OTS_FAILURE_MSG("Failed toi read basic os2 elements");
+ }
+
+ if (os2->version > 4) {
+ return OTS_FAILURE_MSG("os2 version too high %d", os2->version);
+ }
+
+ // Some linux fonts (e.g., Kedage-t.ttf and LucidaSansDemiOblique.ttf) have
+ // weird weight/width classes. Overwrite them with FW_NORMAL/1/9.
+ if (os2->weight_class < 100 ||
+ os2->weight_class > 900 ||
+ os2->weight_class % 100) {
+ OTS_WARNING("bad weight: %u", os2->weight_class);
+ os2->weight_class = 400; // FW_NORMAL
+ }
+ if (os2->width_class < 1) {
+ OTS_WARNING("bad width: %u", os2->width_class);
+ os2->width_class = 1;
+ } else if (os2->width_class > 9) {
+ OTS_WARNING("bad width: %u", os2->width_class);
+ os2->width_class = 9;
+ }
+
+ // lowest 3 bits of fsType are exclusive.
+ if (os2->type & 0x2) {
+ // mask bits 2 & 3.
+ os2->type &= 0xfff3u;
+ } else if (os2->type & 0x4) {
+ // mask bits 1 & 3.
+ os2->type &= 0xfff4u;
+ } else if (os2->type & 0x8) {
+ // mask bits 1 & 2.
+ os2->type &= 0xfff9u;
+ }
+
+ // mask reserved bits. use only 0..3, 8, 9 bits.
+ os2->type &= 0x30f;
+
+ if (os2->subscript_x_size < 0) {
+ OTS_WARNING("bad subscript_x_size: %d", os2->subscript_x_size);
+ os2->subscript_x_size = 0;
+ }
+ if (os2->subscript_y_size < 0) {
+ OTS_WARNING("bad subscript_y_size: %d", os2->subscript_y_size);
+ os2->subscript_y_size = 0;
+ }
+ if (os2->superscript_x_size < 0) {
+ OTS_WARNING("bad superscript_x_size: %d", os2->superscript_x_size);
+ os2->superscript_x_size = 0;
+ }
+ if (os2->superscript_y_size < 0) {
+ OTS_WARNING("bad superscript_y_size: %d", os2->superscript_y_size);
+ os2->superscript_y_size = 0;
+ }
+ if (os2->strikeout_size < 0) {
+ OTS_WARNING("bad strikeout_size: %d", os2->strikeout_size);
+ os2->strikeout_size = 0;
+ }
+
+ for (unsigned i = 0; i < 10; ++i) {
+ if (!table.ReadU8(&os2->panose[i])) {
+ return OTS_FAILURE_MSG("Failed to read panose in os2 table");
+ }
+ }
+
+ if (!table.ReadU32(&os2->unicode_range_1) ||
+ !table.ReadU32(&os2->unicode_range_2) ||
+ !table.ReadU32(&os2->unicode_range_3) ||
+ !table.ReadU32(&os2->unicode_range_4) ||
+ !table.ReadU32(&os2->vendor_id) ||
+ !table.ReadU16(&os2->selection) ||
+ !table.ReadU16(&os2->first_char_index) ||
+ !table.ReadU16(&os2->last_char_index) ||
+ !table.ReadS16(&os2->typo_ascender) ||
+ !table.ReadS16(&os2->typo_descender) ||
+ !table.ReadS16(&os2->typo_linegap) ||
+ !table.ReadU16(&os2->win_ascent) ||
+ !table.ReadU16(&os2->win_descent)) {
+ return OTS_FAILURE_MSG("Failed to read more basic os2 fields");
+ }
+
+ // If bit 6 is set, then bits 0 and 5 must be clear.
+ if (os2->selection & 0x40) {
+ os2->selection &= 0xffdeu;
+ }
+
+ // the settings of bits 0 and 1 must be reflected in the macStyle bits
+ // in the 'head' table.
+ if (!file->head) {
+ return OTS_FAILURE_MSG("Head table missing from font as needed by os2 table");
+ }
+ if ((os2->selection & 0x1) &&
+ !(file->head->mac_style & 0x2)) {
+ OTS_WARNING("adjusting Mac style (italic)");
+ file->head->mac_style |= 0x2;
+ }
+ if ((os2->selection & 0x2) &&
+ !(file->head->mac_style & 0x4)) {
+ OTS_WARNING("adjusting Mac style (underscore)");
+ file->head->mac_style |= 0x4;
+ }
+
+ // While bit 6 on implies that bits 0 and 1 of macStyle are clear,
+ // the reverse is not true.
+ if ((os2->selection & 0x40) &&
+ (file->head->mac_style & 0x3)) {
+ OTS_WARNING("adjusting Mac style (regular)");
+ file->head->mac_style &= 0xfffcu;
+ }
+
+ if ((os2->version < 4) &&
+ (os2->selection & 0x300)) {
+ // bit 8 and 9 must be unset in OS/2 table versions less than 4.
+ return OTS_FAILURE_MSG("OS2 version %d incompatible with selection %d", os2->version, os2->selection);
+ }
+
+ // mask reserved bits. use only 0..9 bits.
+ os2->selection &= 0x3ff;
+
+ if (os2->first_char_index > os2->last_char_index) {
+ return OTS_FAILURE_MSG("first char index %d > last char index %d in os2", os2->first_char_index, os2->last_char_index);
+ }
+ if (os2->typo_linegap < 0) {
+ OTS_WARNING("bad linegap: %d", os2->typo_linegap);
+ os2->typo_linegap = 0;
+ }
+
+ if (os2->version < 1) {
+ // http://www.microsoft.com/typography/otspec/os2ver0.htm
+ return true;
+ }
+
+ if (length < offsetof(OpenTypeOS2, code_page_range_2)) {
+ OTS_WARNING("bad version number: %u", os2->version);
+ // Some fonts (e.g., kredit1.ttf and quinquef.ttf) have weird version
+ // numbers. Fix them.
+ os2->version = 0;
+ return true;
+ }
+
+ if (!table.ReadU32(&os2->code_page_range_1) ||
+ !table.ReadU32(&os2->code_page_range_2)) {
+ return OTS_FAILURE_MSG("Failed to read codepage ranges");
+ }
+
+ if (os2->version < 2) {
+ // http://www.microsoft.com/typography/otspec/os2ver1.htm
+ return true;
+ }
+
+ if (length < offsetof(OpenTypeOS2, max_context)) {
+ OTS_WARNING("bad version number: %u", os2->version);
+ // some Japanese fonts (e.g., mona.ttf) have weird version number.
+ // fix them.
+ os2->version = 1;
+ return true;
+ }
+
+ if (!table.ReadS16(&os2->x_height) ||
+ !table.ReadS16(&os2->cap_height) ||
+ !table.ReadU16(&os2->default_char) ||
+ !table.ReadU16(&os2->break_char) ||
+ !table.ReadU16(&os2->max_context)) {
+ return OTS_FAILURE_MSG("Failed to read os2 version 2 information");
+ }
+
+ if (os2->x_height < 0) {
+ OTS_WARNING("bad x_height: %d", os2->x_height);
+ os2->x_height = 0;
+ }
+ if (os2->cap_height < 0) {
+ OTS_WARNING("bad cap_height: %d", os2->cap_height);
+ os2->cap_height = 0;
+ }
+
+ return true;
+}
+
+bool ots_os2_should_serialise(OpenTypeFile *file) {
+ return file->os2 != NULL;
+}
+
+bool ots_os2_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypeOS2 *os2 = file->os2;
+
+ if (!out->WriteU16(os2->version) ||
+ !out->WriteS16(os2->avg_char_width) ||
+ !out->WriteU16(os2->weight_class) ||
+ !out->WriteU16(os2->width_class) ||
+ !out->WriteU16(os2->type) ||
+ !out->WriteS16(os2->subscript_x_size) ||
+ !out->WriteS16(os2->subscript_y_size) ||
+ !out->WriteS16(os2->subscript_x_offset) ||
+ !out->WriteS16(os2->subscript_y_offset) ||
+ !out->WriteS16(os2->superscript_x_size) ||
+ !out->WriteS16(os2->superscript_y_size) ||
+ !out->WriteS16(os2->superscript_x_offset) ||
+ !out->WriteS16(os2->superscript_y_offset) ||
+ !out->WriteS16(os2->strikeout_size) ||
+ !out->WriteS16(os2->strikeout_position) ||
+ !out->WriteS16(os2->family_class)) {
+ return OTS_FAILURE_MSG("Failed to write basic OS2 information");
+ }
+
+ for (unsigned i = 0; i < 10; ++i) {
+ if (!out->Write(&os2->panose[i], 1)) {
+ return OTS_FAILURE_MSG("Failed to write os2 panose information");
+ }
+ }
+
+ if (!out->WriteU32(os2->unicode_range_1) ||
+ !out->WriteU32(os2->unicode_range_2) ||
+ !out->WriteU32(os2->unicode_range_3) ||
+ !out->WriteU32(os2->unicode_range_4) ||
+ !out->WriteU32(os2->vendor_id) ||
+ !out->WriteU16(os2->selection) ||
+ !out->WriteU16(os2->first_char_index) ||
+ !out->WriteU16(os2->last_char_index) ||
+ !out->WriteS16(os2->typo_ascender) ||
+ !out->WriteS16(os2->typo_descender) ||
+ !out->WriteS16(os2->typo_linegap) ||
+ !out->WriteU16(os2->win_ascent) ||
+ !out->WriteU16(os2->win_descent)) {
+ return OTS_FAILURE_MSG("Failed to write os2 version 1 information");
+ }
+
+ if (os2->version < 1) {
+ return true;
+ }
+
+ if (!out->WriteU32(os2->code_page_range_1) ||
+ !out->WriteU32(os2->code_page_range_2)) {
+ return OTS_FAILURE_MSG("Failed to write codepage ranges");
+ }
+
+ if (os2->version < 2) {
+ return true;
+ }
+
+ if (!out->WriteS16(os2->x_height) ||
+ !out->WriteS16(os2->cap_height) ||
+ !out->WriteU16(os2->default_char) ||
+ !out->WriteU16(os2->break_char) ||
+ !out->WriteU16(os2->max_context)) {
+ return OTS_FAILURE_MSG("Failed to write os2 version 2 information");
+ }
+
+ return true;
+}
+
+void ots_os2_free(OpenTypeFile *file) {
+ delete file->os2;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/os2.h b/third_party/ots/src/os2.h
new file mode 100644
index 0000000..9e0fc34
--- /dev/null
+++ b/third_party/ots/src/os2.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_OS2_H_
+#define OTS_OS2_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeOS2 {
+ uint16_t version;
+ int16_t avg_char_width;
+ uint16_t weight_class;
+ uint16_t width_class;
+ uint16_t type;
+ int16_t subscript_x_size;
+ int16_t subscript_y_size;
+ int16_t subscript_x_offset;
+ int16_t subscript_y_offset;
+ int16_t superscript_x_size;
+ int16_t superscript_y_size;
+ int16_t superscript_x_offset;
+ int16_t superscript_y_offset;
+ int16_t strikeout_size;
+ int16_t strikeout_position;
+ int16_t family_class;
+ uint8_t panose[10];
+ uint32_t unicode_range_1;
+ uint32_t unicode_range_2;
+ uint32_t unicode_range_3;
+ uint32_t unicode_range_4;
+ uint32_t vendor_id;
+ uint16_t selection;
+ uint16_t first_char_index;
+ uint16_t last_char_index;
+ int16_t typo_ascender;
+ int16_t typo_descender;
+ int16_t typo_linegap;
+ uint16_t win_ascent;
+ uint16_t win_descent;
+ uint32_t code_page_range_1;
+ uint32_t code_page_range_2;
+ int16_t x_height;
+ int16_t cap_height;
+ uint16_t default_char;
+ uint16_t break_char;
+ uint16_t max_context;
+};
+
+} // namespace ots
+
+#endif // OTS_OS2_H_
diff --git a/third_party/ots/src/ots.cc b/third_party/ots/src/ots.cc
new file mode 100644
index 0000000..197c649
--- /dev/null
+++ b/third_party/ots/src/ots.cc
@@ -0,0 +1,824 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ots.h"
+
+#include <sys/types.h>
+#include <zlib.h>
+
+#include <algorithm>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+#include <map>
+#include <vector>
+
+#include "woff2.h"
+
+// The OpenType Font File
+// http://www.microsoft.com/typography/otspec/cmap.htm
+
+namespace {
+
+// Generate a message with or without a table tag, when 'header' is the OpenTypeFile pointer
+#define OTS_FAILURE_MSG_TAG(msg_,tag_) OTS_FAILURE_MSG_TAG_(header, msg_, tag_)
+#define OTS_FAILURE_MSG_HDR(msg_) OTS_FAILURE_MSG_(header, msg_)
+
+
+struct OpenTypeTable {
+ uint32_t tag;
+ uint32_t chksum;
+ uint32_t offset;
+ uint32_t length;
+ uint32_t uncompressed_length;
+};
+
+bool CheckTag(uint32_t tag_value) {
+ for (unsigned i = 0; i < 4; ++i) {
+ const uint32_t check = tag_value & 0xff;
+ if (check < 32 || check > 126) {
+ return false; // non-ASCII character found.
+ }
+ tag_value >>= 8;
+ }
+ return true;
+}
+
+uint32_t Tag(const char *tag_str) {
+ uint32_t ret;
+ std::memcpy(&ret, tag_str, 4);
+ return ret;
+}
+
+struct OutputTable {
+ uint32_t tag;
+ size_t offset;
+ size_t length;
+ uint32_t chksum;
+
+ static bool SortByTag(const OutputTable& a, const OutputTable& b) {
+ const uint32_t atag = ntohl(a.tag);
+ const uint32_t btag = ntohl(b.tag);
+ return atag < btag;
+ }
+};
+
+struct Arena {
+ public:
+ ~Arena() {
+ for (std::vector<uint8_t*>::iterator
+ i = hunks_.begin(); i != hunks_.end(); ++i) {
+ delete[] *i;
+ }
+ }
+
+ uint8_t* Allocate(size_t length) {
+ uint8_t* p = new uint8_t[length];
+ hunks_.push_back(p);
+ return p;
+ }
+
+ private:
+ std::vector<uint8_t*> hunks_;
+};
+
+const struct {
+ const char* tag;
+ bool (*parse)(ots::OpenTypeFile *otf, const uint8_t *data, size_t length);
+ bool (*serialise)(ots::OTSStream *out, ots::OpenTypeFile *file);
+ bool (*should_serialise)(ots::OpenTypeFile *file);
+ void (*free)(ots::OpenTypeFile *file);
+ bool required;
+} table_parsers[] = {
+ { "maxp", ots::ots_maxp_parse, ots::ots_maxp_serialise,
+ ots::ots_maxp_should_serialise, ots::ots_maxp_free, true },
+ { "head", ots::ots_head_parse, ots::ots_head_serialise,
+ ots::ots_head_should_serialise, ots::ots_head_free, true },
+ { "OS/2", ots::ots_os2_parse, ots::ots_os2_serialise,
+ ots::ots_os2_should_serialise, ots::ots_os2_free, true },
+ { "cmap", ots::ots_cmap_parse, ots::ots_cmap_serialise,
+ ots::ots_cmap_should_serialise, ots::ots_cmap_free, true },
+ { "hhea", ots::ots_hhea_parse, ots::ots_hhea_serialise,
+ ots::ots_hhea_should_serialise, ots::ots_hhea_free, true },
+ { "hmtx", ots::ots_hmtx_parse, ots::ots_hmtx_serialise,
+ ots::ots_hmtx_should_serialise, ots::ots_hmtx_free, true },
+ { "name", ots::ots_name_parse, ots::ots_name_serialise,
+ ots::ots_name_should_serialise, ots::ots_name_free, true },
+ { "post", ots::ots_post_parse, ots::ots_post_serialise,
+ ots::ots_post_should_serialise, ots::ots_post_free, true },
+ { "loca", ots::ots_loca_parse, ots::ots_loca_serialise,
+ ots::ots_loca_should_serialise, ots::ots_loca_free, false },
+ { "glyf", ots::ots_glyf_parse, ots::ots_glyf_serialise,
+ ots::ots_glyf_should_serialise, ots::ots_glyf_free, false },
+ { "CFF ", ots::ots_cff_parse, ots::ots_cff_serialise,
+ ots::ots_cff_should_serialise, ots::ots_cff_free, false },
+ { "VDMX", ots::ots_vdmx_parse, ots::ots_vdmx_serialise,
+ ots::ots_vdmx_should_serialise, ots::ots_vdmx_free, false },
+ { "hdmx", ots::ots_hdmx_parse, ots::ots_hdmx_serialise,
+ ots::ots_hdmx_should_serialise, ots::ots_hdmx_free, false },
+ { "gasp", ots::ots_gasp_parse, ots::ots_gasp_serialise,
+ ots::ots_gasp_should_serialise, ots::ots_gasp_free, false },
+ { "cvt ", ots::ots_cvt_parse, ots::ots_cvt_serialise,
+ ots::ots_cvt_should_serialise, ots::ots_cvt_free, false },
+ { "fpgm", ots::ots_fpgm_parse, ots::ots_fpgm_serialise,
+ ots::ots_fpgm_should_serialise, ots::ots_fpgm_free, false },
+ { "prep", ots::ots_prep_parse, ots::ots_prep_serialise,
+ ots::ots_prep_should_serialise, ots::ots_prep_free, false },
+ { "LTSH", ots::ots_ltsh_parse, ots::ots_ltsh_serialise,
+ ots::ots_ltsh_should_serialise, ots::ots_ltsh_free, false },
+ { "VORG", ots::ots_vorg_parse, ots::ots_vorg_serialise,
+ ots::ots_vorg_should_serialise, ots::ots_vorg_free, false },
+ { "kern", ots::ots_kern_parse, ots::ots_kern_serialise,
+ ots::ots_kern_should_serialise, ots::ots_kern_free, false },
+ // We need to parse GDEF table in advance of parsing GSUB/GPOS tables
+ // because they could refer GDEF table.
+ { "GDEF", ots::ots_gdef_parse, ots::ots_gdef_serialise,
+ ots::ots_gdef_should_serialise, ots::ots_gdef_free, false },
+ { "GPOS", ots::ots_gpos_parse, ots::ots_gpos_serialise,
+ ots::ots_gpos_should_serialise, ots::ots_gpos_free, false },
+ { "GSUB", ots::ots_gsub_parse, ots::ots_gsub_serialise,
+ ots::ots_gsub_should_serialise, ots::ots_gsub_free, false },
+ { "vhea", ots::ots_vhea_parse, ots::ots_vhea_serialise,
+ ots::ots_vhea_should_serialise, ots::ots_vhea_free, false },
+ { "vmtx", ots::ots_vmtx_parse, ots::ots_vmtx_serialise,
+ ots::ots_vmtx_should_serialise, ots::ots_vmtx_free, false },
+ { "MATH", ots::ots_math_parse, ots::ots_math_serialise,
+ ots::ots_math_should_serialise, ots::ots_math_free, false },
+ // TODO(bashi): Support mort, base, and jstf tables.
+ { 0, NULL, NULL, NULL, NULL, false },
+};
+
+bool ProcessGeneric(ots::OpenTypeFile *header,
+ uint32_t signature,
+ ots::OTSStream *output,
+ const uint8_t *data, size_t length,
+ const std::vector<OpenTypeTable>& tables,
+ ots::Buffer& file);
+
+bool ProcessTTF(ots::OpenTypeFile *header,
+ ots::OTSStream *output, const uint8_t *data, size_t length) {
+ ots::Buffer file(data, length);
+
+ // we disallow all files > 1GB in size for sanity.
+ if (length > 1024 * 1024 * 1024) {
+ return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
+ }
+
+ if (!file.ReadTag(&header->version)) {
+ return OTS_FAILURE_MSG_HDR("error reading version tag");
+ }
+ if (!ots::IsValidVersionTag(header->version)) {
+ return OTS_FAILURE_MSG_HDR("invalid version tag");
+ }
+
+ if (!file.ReadU16(&header->num_tables) ||
+ !file.ReadU16(&header->search_range) ||
+ !file.ReadU16(&header->entry_selector) ||
+ !file.ReadU16(&header->range_shift)) {
+ return OTS_FAILURE_MSG_HDR("error reading table directory search header");
+ }
+
+ // search_range is (Maximum power of 2 <= numTables) x 16. Thus, to avoid
+ // overflow num_tables is, at most, 2^16 / 16 = 2^12
+ if (header->num_tables >= 4096 || header->num_tables < 1) {
+ return OTS_FAILURE_MSG_HDR("excessive (or zero) number of tables");
+ }
+
+ unsigned max_pow2 = 0;
+ while (1u << (max_pow2 + 1) <= header->num_tables) {
+ max_pow2++;
+ }
+ const uint16_t expected_search_range = (1u << max_pow2) << 4;
+
+ // Don't call ots_failure() here since ~25% of fonts (250+ fonts) in
+ // http://www.princexml.com/fonts/ have unexpected search_range value.
+ if (header->search_range != expected_search_range) {
+ OTS_FAILURE_MSG_HDR("bad search range");
+ header->search_range = expected_search_range; // Fix the value.
+ }
+
+ // entry_selector is Log2(maximum power of 2 <= numTables)
+ if (header->entry_selector != max_pow2) {
+ return OTS_FAILURE_MSG_HDR("incorrect entrySelector for table directory");
+ }
+
+ // range_shift is NumTables x 16-searchRange. We know that 16*num_tables
+ // doesn't over flow because we range checked it above. Also, we know that
+ // it's > header->search_range by construction of search_range.
+ const uint16_t expected_range_shift =
+ 16 * header->num_tables - header->search_range;
+ if (header->range_shift != expected_range_shift) {
+ OTS_FAILURE_MSG_HDR("bad range shift");
+ header->range_shift = expected_range_shift; // the same as above.
+ }
+
+ // Next up is the list of tables.
+ std::vector<OpenTypeTable> tables;
+
+ for (unsigned i = 0; i < header->num_tables; ++i) {
+ OpenTypeTable table;
+ if (!file.ReadTag(&table.tag) ||
+ !file.ReadU32(&table.chksum) ||
+ !file.ReadU32(&table.offset) ||
+ !file.ReadU32(&table.length)) {
+ return OTS_FAILURE_MSG_HDR("error reading table directory");
+ }
+
+ table.uncompressed_length = table.length;
+ tables.push_back(table);
+ }
+
+ return ProcessGeneric(header, header->version, output, data, length,
+ tables, file);
+}
+
+bool ProcessWOFF(ots::OpenTypeFile *header,
+ ots::OTSStream *output, const uint8_t *data, size_t length) {
+ ots::Buffer file(data, length);
+
+ // we disallow all files > 1GB in size for sanity.
+ if (length > 1024 * 1024 * 1024) {
+ return OTS_FAILURE_MSG_HDR("file exceeds 1GB");
+ }
+
+ uint32_t woff_tag;
+ if (!file.ReadTag(&woff_tag)) {
+ return OTS_FAILURE_MSG_HDR("error reading WOFF marker");
+ }
+
+ if (woff_tag != Tag("wOFF")) {
+ return OTS_FAILURE_MSG_HDR("invalid WOFF marker");
+ }
+
+ if (!file.ReadTag(&header->version)) {
+ return OTS_FAILURE_MSG_HDR("error reading version tag");
+ }
+ if (!ots::IsValidVersionTag(header->version)) {
+ return OTS_FAILURE_MSG_HDR("invalid version tag");
+ }
+
+ header->search_range = 0;
+ header->entry_selector = 0;
+ header->range_shift = 0;
+
+ uint32_t reported_length;
+ if (!file.ReadU32(&reported_length) || length != reported_length) {
+ return OTS_FAILURE_MSG_HDR("incorrect file size in WOFF header");
+ }
+
+ if (!file.ReadU16(&header->num_tables) || !header->num_tables) {
+ return OTS_FAILURE_MSG_HDR("error reading number of tables");
+ }
+
+ uint16_t reserved_value;
+ if (!file.ReadU16(&reserved_value) || reserved_value) {
+ return OTS_FAILURE_MSG_HDR("error in reserved field of WOFF header");
+ }
+
+ uint32_t reported_total_sfnt_size;
+ if (!file.ReadU32(&reported_total_sfnt_size)) {
+ return OTS_FAILURE_MSG_HDR("error reading total sfnt size");
+ }
+
+ // We don't care about these fields of the header:
+ // uint16_t major_version, minor_version
+ if (!file.Skip(2 * 2)) {
+ return OTS_FAILURE_MSG_HDR("error skipping WOFF header fields");
+ }
+
+ // Checks metadata block size.
+ uint32_t meta_offset;
+ uint32_t meta_length;
+ uint32_t meta_length_orig;
+ if (!file.ReadU32(&meta_offset) ||
+ !file.ReadU32(&meta_length) ||
+ !file.ReadU32(&meta_length_orig)) {
+ return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
+ }
+ if (meta_offset) {
+ if (meta_offset >= length || length - meta_offset < meta_length) {
+ return OTS_FAILURE_MSG_HDR("invalid metadata block location/size");
+ }
+ }
+
+ // Checks private data block size.
+ uint32_t priv_offset;
+ uint32_t priv_length;
+ if (!file.ReadU32(&priv_offset) ||
+ !file.ReadU32(&priv_length)) {
+ return OTS_FAILURE_MSG_HDR("error reading WOFF header fields");
+ }
+ if (priv_offset) {
+ if (priv_offset >= length || length - priv_offset < priv_length) {
+ return OTS_FAILURE_MSG_HDR("invalid private block location/size");
+ }
+ }
+
+ // Next up is the list of tables.
+ std::vector<OpenTypeTable> tables;
+
+ uint32_t first_index = 0;
+ uint32_t last_index = 0;
+ // Size of sfnt header plus size of table records.
+ uint64_t total_sfnt_size = 12 + 16 * header->num_tables;
+ for (unsigned i = 0; i < header->num_tables; ++i) {
+ OpenTypeTable table;
+ if (!file.ReadTag(&table.tag) ||
+ !file.ReadU32(&table.offset) ||
+ !file.ReadU32(&table.length) ||
+ !file.ReadU32(&table.uncompressed_length) ||
+ !file.ReadU32(&table.chksum)) {
+ return OTS_FAILURE_MSG_HDR("error reading table directory");
+ }
+
+ total_sfnt_size += ots::Round4(table.uncompressed_length);
+ if (total_sfnt_size > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG_HDR("sfnt size overflow");
+ }
+ tables.push_back(table);
+ if (i == 0 || tables[first_index].offset > table.offset)
+ first_index = i;
+ if (i == 0 || tables[last_index].offset < table.offset)
+ last_index = i;
+ }
+
+ if (reported_total_sfnt_size != total_sfnt_size) {
+ return OTS_FAILURE_MSG_HDR("uncompressed sfnt size mismatch");
+ }
+
+ // Table data must follow immediately after the header.
+ if (tables[first_index].offset != ots::Round4(file.offset())) {
+ return OTS_FAILURE_MSG_HDR("junk before tables in WOFF file");
+ }
+
+ if (tables[last_index].offset >= length ||
+ length - tables[last_index].offset < tables[last_index].length) {
+ return OTS_FAILURE_MSG_HDR("invalid table location/size");
+ }
+ // Blocks must follow immediately after the previous block.
+ // (Except for padding with a maximum of three null bytes)
+ uint64_t block_end = ots::Round4(
+ static_cast<uint64_t>(tables[last_index].offset) +
+ static_cast<uint64_t>(tables[last_index].length));
+ if (block_end > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG_HDR("invalid table location/size");
+ }
+ if (meta_offset) {
+ if (block_end != meta_offset) {
+ return OTS_FAILURE_MSG_HDR("invalid metadata block location");
+ }
+ block_end = ots::Round4(static_cast<uint64_t>(meta_offset) +
+ static_cast<uint64_t>(meta_length));
+ if (block_end > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG_HDR("invalid metadata block size");
+ }
+ }
+ if (priv_offset) {
+ if (block_end != priv_offset) {
+ return OTS_FAILURE_MSG_HDR("invalid private block location");
+ }
+ block_end = ots::Round4(static_cast<uint64_t>(priv_offset) +
+ static_cast<uint64_t>(priv_length));
+ if (block_end > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE_MSG_HDR("invalid private block size");
+ }
+ }
+ if (block_end != ots::Round4(length)) {
+ return OTS_FAILURE_MSG_HDR("file length mismatch (trailing junk?)");
+ }
+
+ return ProcessGeneric(header, woff_tag, output, data, length, tables, file);
+}
+
+bool ProcessWOFF2(ots::OpenTypeFile *header,
+ ots::OTSStream *output, const uint8_t *data, size_t length) {
+ size_t decompressed_size = ots::ComputeWOFF2FinalSize(data, length);
+ if (decompressed_size == 0) {
+ return OTS_FAILURE();
+ }
+ // decompressed font must be <= 30MB
+ if (decompressed_size > 30 * 1024 * 1024) {
+ return OTS_FAILURE();
+ }
+
+ std::vector<uint8_t> decompressed_buffer(decompressed_size);
+ if (!ots::ConvertWOFF2ToTTF(header, &decompressed_buffer[0], decompressed_size,
+ data, length)) {
+ return OTS_FAILURE();
+ }
+ return ProcessTTF(header, output, &decompressed_buffer[0], decompressed_size);
+}
+
+ots::TableAction GetTableAction(ots::OpenTypeFile *header, uint32_t tag) {
+ ots::TableAction action = ots::TABLE_ACTION_DEFAULT;
+
+ action = header->context->GetTableAction(htonl(tag));
+
+ if (action == ots::TABLE_ACTION_DEFAULT) {
+ action = ots::TABLE_ACTION_DROP;
+
+ for (unsigned i = 0; ; ++i) {
+ if (table_parsers[i].parse == NULL) break;
+
+ if (Tag(table_parsers[i].tag) == tag) {
+ action = ots::TABLE_ACTION_SANITIZE;
+ break;
+ }
+ }
+ }
+
+ assert(action != ots::TABLE_ACTION_DEFAULT); // Should never return this.
+ return action;
+}
+
+bool GetTableData(const uint8_t *data,
+ const OpenTypeTable table,
+ Arena *arena,
+ size_t *table_length,
+ const uint8_t **table_data) {
+ if (table.uncompressed_length != table.length) {
+ // Compressed table. Need to uncompress into memory first.
+ *table_length = table.uncompressed_length;
+ *table_data = (*arena).Allocate(*table_length);
+ uLongf dest_len = *table_length;
+ int r = uncompress((Bytef*) *table_data, &dest_len,
+ data + table.offset, table.length);
+ if (r != Z_OK || dest_len != *table_length) {
+ return false;
+ }
+ } else {
+ // Uncompressed table. We can process directly from memory.
+ *table_data = data + table.offset;
+ *table_length = table.length;
+ }
+
+ return true;
+}
+
+bool ProcessGeneric(ots::OpenTypeFile *header, uint32_t signature,
+ ots::OTSStream *output,
+ const uint8_t *data, size_t length,
+ const std::vector<OpenTypeTable>& tables,
+ ots::Buffer& file) {
+ const size_t data_offset = file.offset();
+
+ uint32_t uncompressed_sum = 0;
+
+ for (unsigned i = 0; i < header->num_tables; ++i) {
+ // the tables must be sorted by tag (when taken as big-endian numbers).
+ // This also remove the possibility of duplicate tables.
+ if (i) {
+ const uint32_t this_tag = ntohl(tables[i].tag);
+ const uint32_t prev_tag = ntohl(tables[i - 1].tag);
+ if (this_tag <= prev_tag) {
+ return OTS_FAILURE_MSG_HDR("table directory not correctly ordered");
+ }
+ }
+
+ // all tag names must be built from printable ASCII characters
+ if (!CheckTag(tables[i].tag)) {
+ return OTS_FAILURE_MSG_TAG("invalid table tag", &tables[i].tag);
+ }
+
+ // tables must be 4-byte aligned
+ if (tables[i].offset & 3) {
+ return OTS_FAILURE_MSG_TAG("misaligned table", &tables[i].tag);
+ }
+
+ // and must be within the file
+ if (tables[i].offset < data_offset || tables[i].offset >= length) {
+ return OTS_FAILURE_MSG_TAG("invalid table offset", &tables[i].tag);
+ }
+ // disallow all tables with a zero length
+ if (tables[i].length < 1) {
+ // Note: malayalam.ttf has zero length CVT table...
+ return OTS_FAILURE_MSG_TAG("zero-length table", &tables[i].tag);
+ }
+ // disallow all tables with a length > 1GB
+ if (tables[i].length > 1024 * 1024 * 1024) {
+ return OTS_FAILURE_MSG_TAG("table length exceeds 1GB", &tables[i].tag);
+ }
+ // disallow tables where the uncompressed size is < the compressed size.
+ if (tables[i].uncompressed_length < tables[i].length) {
+ return OTS_FAILURE_MSG_TAG("invalid compressed table", &tables[i].tag);
+ }
+ if (tables[i].uncompressed_length > tables[i].length) {
+ // We'll probably be decompressing this table.
+
+ // disallow all tables which uncompress to > 30 MB
+ if (tables[i].uncompressed_length > 30 * 1024 * 1024) {
+ return OTS_FAILURE_MSG_TAG("uncompressed length exceeds 30MB", &tables[i].tag);
+ }
+ if (uncompressed_sum + tables[i].uncompressed_length < uncompressed_sum) {
+ return OTS_FAILURE_MSG_TAG("overflow of uncompressed sum", &tables[i].tag);
+ }
+
+ uncompressed_sum += tables[i].uncompressed_length;
+ }
+ // since we required that the file be < 1GB in length, and that the table
+ // length is < 1GB, the following addtion doesn't overflow
+ uint32_t end_byte = tables[i].offset + tables[i].length;
+ // Tables in the WOFF file must be aligned 4-byte boundary.
+ if (signature == Tag("wOFF")) {
+ end_byte = ots::Round4(end_byte);
+ }
+ if (!end_byte || end_byte > length) {
+ return OTS_FAILURE_MSG_TAG("table overruns end of file", &tables[i].tag);
+ }
+ }
+
+ // All decompressed tables uncompressed must be <= 30MB.
+ if (uncompressed_sum > 30 * 1024 * 1024) {
+ return OTS_FAILURE_MSG_HDR("uncompressed sum exceeds 30MB");
+ }
+
+ std::map<uint32_t, OpenTypeTable> table_map;
+ for (unsigned i = 0; i < header->num_tables; ++i) {
+ table_map[tables[i].tag] = tables[i];
+ }
+
+ // check that the tables are not overlapping.
+ std::vector<std::pair<uint32_t, uint8_t> > overlap_checker;
+ for (unsigned i = 0; i < header->num_tables; ++i) {
+ overlap_checker.push_back(
+ std::make_pair(tables[i].offset, static_cast<uint8_t>(1) /* start */));
+ overlap_checker.push_back(
+ std::make_pair(tables[i].offset + tables[i].length,
+ static_cast<uint8_t>(0) /* end */));
+ }
+ std::sort(overlap_checker.begin(), overlap_checker.end());
+ int overlap_count = 0;
+ for (unsigned i = 0; i < overlap_checker.size(); ++i) {
+ overlap_count += (overlap_checker[i].second ? 1 : -1);
+ if (overlap_count > 1) {
+ return OTS_FAILURE_MSG_HDR("overlapping tables");
+ }
+ }
+
+ Arena arena;
+
+ for (unsigned i = 0; ; ++i) {
+ if (table_parsers[i].parse == NULL) break;
+
+ uint32_t tag = Tag(table_parsers[i].tag);
+ const std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.find(tag);
+
+ ots::TableAction action = GetTableAction(header, tag);
+ if (it == table_map.end()) {
+ if (table_parsers[i].required && action == ots::TABLE_ACTION_SANITIZE) {
+ return OTS_FAILURE_MSG_TAG("missing required table", table_parsers[i].tag);
+ }
+ continue;
+ }
+
+ const uint8_t* table_data;
+ size_t table_length;
+
+ if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
+ return OTS_FAILURE_MSG_TAG("uncompress failed", table_parsers[i].tag);
+ }
+
+ if (action == ots::TABLE_ACTION_SANITIZE &&
+ !table_parsers[i].parse(header, table_data, table_length)) {
+ // TODO: parsers should generate specific messages detailing the failure;
+ // once those are all added, we won't need a generic failure message here
+ return OTS_FAILURE_MSG_TAG("failed to parse table", table_parsers[i].tag);
+ }
+ }
+
+ if (header->cff) {
+ // font with PostScript glyph
+ if (header->version != Tag("OTTO")) {
+ return OTS_FAILURE_MSG_HDR("wrong font version for PostScript glyph data");
+ }
+ if (header->glyf || header->loca) {
+ // mixing outline formats is not recommended
+ return OTS_FAILURE_MSG_HDR("font contains both PS and TT glyphs");
+ }
+ } else {
+ if (!header->glyf || !header->loca) {
+ // No TrueType glyph found.
+ // Note: bitmap-only fonts are not supported.
+ return OTS_FAILURE_MSG_HDR("neither PS nor TT glyphs present");
+ }
+ }
+
+ uint16_t num_output_tables = 0;
+ for (unsigned i = 0; ; ++i) {
+ if (table_parsers[i].parse == NULL) {
+ break;
+ }
+
+ if (table_parsers[i].should_serialise(header)) {
+ num_output_tables++;
+ }
+ }
+
+ for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
+ it != table_map.end(); ++it) {
+ ots::TableAction action = GetTableAction(header, it->first);
+ if (action == ots::TABLE_ACTION_PASSTHRU) {
+ num_output_tables++;
+ }
+ }
+
+ uint16_t max_pow2 = 0;
+ while (1u << (max_pow2 + 1) <= num_output_tables) {
+ max_pow2++;
+ }
+ const uint16_t output_search_range = (1u << max_pow2) << 4;
+
+ // most of the errors here are highly unlikely - they'd only occur if the
+ // output stream returns a failure, e.g. lack of space to write
+ output->ResetChecksum();
+ if (!output->WriteTag(header->version) ||
+ !output->WriteU16(num_output_tables) ||
+ !output->WriteU16(output_search_range) ||
+ !output->WriteU16(max_pow2) ||
+ !output->WriteU16((num_output_tables << 4) - output_search_range)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+ const uint32_t offset_table_chksum = output->chksum();
+
+ const size_t table_record_offset = output->Tell();
+ if (!output->Pad(16 * num_output_tables)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+
+ std::vector<OutputTable> out_tables;
+
+ size_t head_table_offset = 0;
+ for (unsigned i = 0; ; ++i) {
+ if (table_parsers[i].parse == NULL) {
+ break;
+ }
+
+ if (!table_parsers[i].should_serialise(header)) {
+ continue;
+ }
+
+ OutputTable out;
+ uint32_t tag = Tag(table_parsers[i].tag);
+ out.tag = tag;
+ out.offset = output->Tell();
+
+ output->ResetChecksum();
+ if (tag == Tag("head")) {
+ head_table_offset = out.offset;
+ }
+ if (!table_parsers[i].serialise(output, header)) {
+ return OTS_FAILURE_MSG_TAG("failed to serialize table", table_parsers[i].tag);
+ }
+
+ const size_t end_offset = output->Tell();
+ if (end_offset <= out.offset) {
+ // paranoid check. |end_offset| is supposed to be greater than the offset,
+ // as long as the Tell() interface is implemented correctly.
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+ out.length = end_offset - out.offset;
+
+ // align tables to four bytes
+ if (!output->Pad((4 - (end_offset & 3)) % 4)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+ out.chksum = output->chksum();
+ out_tables.push_back(out);
+ }
+
+ for (std::map<uint32_t, OpenTypeTable>::const_iterator it = table_map.begin();
+ it != table_map.end(); ++it) {
+ ots::TableAction action = GetTableAction(header, it->first);
+ if (action == ots::TABLE_ACTION_PASSTHRU) {
+ OutputTable out;
+ out.tag = it->second.tag;
+ out.offset = output->Tell();
+
+ output->ResetChecksum();
+ if (it->second.tag == Tag("head")) {
+ head_table_offset = out.offset;
+ }
+
+ const uint8_t* table_data;
+ size_t table_length;
+
+ if (!GetTableData(data, it->second, &arena, &table_length, &table_data)) {
+ return OTS_FAILURE_MSG_HDR("Failed to uncompress table");
+ }
+
+ if (!output->Write(table_data, table_length)) {
+ return OTS_FAILURE_MSG_HDR("Failed to serialize table");
+ }
+
+ const size_t end_offset = output->Tell();
+ if (end_offset <= out.offset) {
+ // paranoid check. |end_offset| is supposed to be greater than the offset,
+ // as long as the Tell() interface is implemented correctly.
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+ out.length = end_offset - out.offset;
+
+ // align tables to four bytes
+ if (!output->Pad((4 - (end_offset & 3)) % 4)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+ out.chksum = output->chksum();
+ out_tables.push_back(out);
+ }
+ }
+
+ const size_t end_of_file = output->Tell();
+
+ // Need to sort the output tables for inclusion in the file
+ std::sort(out_tables.begin(), out_tables.end(), OutputTable::SortByTag);
+ if (!output->Seek(table_record_offset)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+
+ output->ResetChecksum();
+ uint32_t tables_chksum = 0;
+ for (unsigned i = 0; i < out_tables.size(); ++i) {
+ if (!output->WriteTag(out_tables[i].tag) ||
+ !output->WriteU32(out_tables[i].chksum) ||
+ !output->WriteU32(out_tables[i].offset) ||
+ !output->WriteU32(out_tables[i].length)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+ tables_chksum += out_tables[i].chksum;
+ }
+ const uint32_t table_record_chksum = output->chksum();
+
+ // http://www.microsoft.com/typography/otspec/otff.htm
+ const uint32_t file_chksum
+ = offset_table_chksum + tables_chksum + table_record_chksum;
+ const uint32_t chksum_magic = static_cast<uint32_t>(0xb1b0afba) - file_chksum;
+
+ // seek into the 'head' table and write in the checksum magic value
+ if (!head_table_offset) {
+ return OTS_FAILURE_MSG_HDR("internal error!");
+ }
+ if (!output->Seek(head_table_offset + 8)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+ if (!output->WriteU32(chksum_magic)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+
+ if (!output->Seek(end_of_file)) {
+ return OTS_FAILURE_MSG_HDR("error writing output");
+ }
+
+ return true;
+}
+
+} // namespace
+
+namespace ots {
+
+void EnableWOFF2() {
+}
+
+bool IsValidVersionTag(uint32_t tag) {
+ return tag == Tag("\x00\x01\x00\x00") ||
+ // OpenType fonts with CFF data have 'OTTO' tag.
+ tag == Tag("OTTO") ||
+ // Older Mac fonts might have 'true' or 'typ1' tag.
+ tag == Tag("true") ||
+ tag == Tag("typ1");
+}
+
+bool OTSContext::Process(OTSStream *output,
+ const uint8_t *data,
+ size_t length) {
+ OpenTypeFile header;
+
+ header.context = this;
+
+ if (length < 4) {
+ return OTS_FAILURE_MSG_(&header, "file less than 4 bytes");
+ }
+
+ bool result;
+ if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == 'F') {
+ result = ProcessWOFF(&header, output, data, length);
+ } else if (data[0] == 'w' && data[1] == 'O' && data[2] == 'F' && data[3] == '2') {
+ result = ProcessWOFF2(&header, output, data, length);
+ } else {
+ result = ProcessTTF(&header, output, data, length);
+ }
+
+ for (unsigned i = 0; ; ++i) {
+ if (table_parsers[i].parse == NULL) break;
+ table_parsers[i].free(&header);
+ }
+ return result;
+}
+
+// For backward compatibility
+bool Process(OTSStream *output, const uint8_t *data, size_t length) {
+ static OTSContext context;
+ return context.Process(output, data, length);
+}
+
+} // namespace ots
diff --git a/third_party/ots/src/ots.h b/third_party/ots/src/ots.h
new file mode 100644
index 0000000..ba3ba77
--- /dev/null
+++ b/third_party/ots/src/ots.h
@@ -0,0 +1,259 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_H_
+#define OTS_H_
+
+#include <stddef.h>
+#include <cstdarg>
+#include <cstddef>
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <limits>
+
+#include "opentype-sanitiser.h"
+
+// arraysize borrowed from base/basictypes.h
+template <typename T, size_t N>
+char (&ArraySizeHelper(T (&array)[N]))[N];
+#define arraysize(array) (sizeof(ArraySizeHelper(array)))
+
+namespace ots {
+
+#if !defined(OTS_DEBUG)
+#define OTS_FAILURE() false
+#else
+#define OTS_FAILURE() \
+ (\
+ std::fprintf(stderr, "ERROR at %s:%d (%s)\n", \
+ __FILE__, __LINE__, __FUNCTION__) \
+ && false\
+ )
+#endif
+
+// All OTS_FAILURE_* macros ultimately evaluate to 'false', just like the original
+// message-less OTS_FAILURE(), so that the current parser will return 'false' as
+// its result (indicating a failure).
+
+#if !defined(OTS_DEBUG)
+#define OTS_MESSAGE_(level,otf_,...) \
+ (otf_)->context->Message(level,__VA_ARGS__)
+#else
+#define OTS_MESSAGE_(level,otf_,...) \
+ OTS_FAILURE(), \
+ (otf_)->context->Message(level,__VA_ARGS__)
+#endif
+
+// Generate a simple message
+#define OTS_FAILURE_MSG_(otf_,...) \
+ (OTS_MESSAGE_(0,otf_,__VA_ARGS__), false)
+
+#define OTS_WARNING_MSG_(otf_,...) \
+ OTS_MESSAGE_(1,otf_,__VA_ARGS__)
+
+// Generate a message with an associated table tag
+#define OTS_FAILURE_MSG_TAG_(otf_,msg_,tag_) \
+ (OTS_MESSAGE_(0,otf_,"%4.4s: %s", tag_, msg_), false)
+
+// Convenience macros for use in files that only handle a single table tag,
+// defined as TABLE_NAME at the top of the file; the 'file' variable is
+// expected to be the current OpenTypeFile pointer.
+#define OTS_FAILURE_MSG(...) OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
+
+#define OTS_WARNING(...) OTS_WARNING_MSG_(file, TABLE_NAME ": " __VA_ARGS__)
+
+// -----------------------------------------------------------------------------
+// Buffer helper class
+//
+// This class perform some trival buffer operations while checking for
+// out-of-bounds errors. As a family they return false if anything is amiss,
+// updating the current offset otherwise.
+// -----------------------------------------------------------------------------
+class Buffer {
+ public:
+ Buffer(const uint8_t *buf, size_t len)
+ : buffer_(buf),
+ length_(len),
+ offset_(0) { }
+
+ bool Skip(size_t n_bytes) {
+ return Read(NULL, n_bytes);
+ }
+
+ bool Read(uint8_t *buf, size_t n_bytes) {
+ if (n_bytes > 1024 * 1024 * 1024) {
+ return OTS_FAILURE();
+ }
+ if ((offset_ + n_bytes > length_) ||
+ (offset_ > length_ - n_bytes)) {
+ return OTS_FAILURE();
+ }
+ if (buf) {
+ std::memcpy(buf, buffer_ + offset_, n_bytes);
+ }
+ offset_ += n_bytes;
+ return true;
+ }
+
+ inline bool ReadU8(uint8_t *value) {
+ if (offset_ + 1 > length_) {
+ return OTS_FAILURE();
+ }
+ *value = buffer_[offset_];
+ ++offset_;
+ return true;
+ }
+
+ bool ReadU16(uint16_t *value) {
+ if (offset_ + 2 > length_) {
+ return OTS_FAILURE();
+ }
+ std::memcpy(value, buffer_ + offset_, sizeof(uint16_t));
+ *value = ntohs(*value);
+ offset_ += 2;
+ return true;
+ }
+
+ bool ReadS16(int16_t *value) {
+ return ReadU16(reinterpret_cast<uint16_t*>(value));
+ }
+
+ bool ReadU24(uint32_t *value) {
+ if (offset_ + 3 > length_) {
+ return OTS_FAILURE();
+ }
+ *value = static_cast<uint32_t>(buffer_[offset_]) << 16 |
+ static_cast<uint32_t>(buffer_[offset_ + 1]) << 8 |
+ static_cast<uint32_t>(buffer_[offset_ + 2]);
+ offset_ += 3;
+ return true;
+ }
+
+ bool ReadU32(uint32_t *value) {
+ if (offset_ + 4 > length_) {
+ return OTS_FAILURE();
+ }
+ std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
+ *value = ntohl(*value);
+ offset_ += 4;
+ return true;
+ }
+
+ bool ReadS32(int32_t *value) {
+ return ReadU32(reinterpret_cast<uint32_t*>(value));
+ }
+
+ bool ReadTag(uint32_t *value) {
+ if (offset_ + 4 > length_) {
+ return OTS_FAILURE();
+ }
+ std::memcpy(value, buffer_ + offset_, sizeof(uint32_t));
+ offset_ += 4;
+ return true;
+ }
+
+ bool ReadR64(uint64_t *value) {
+ if (offset_ + 8 > length_) {
+ return OTS_FAILURE();
+ }
+ std::memcpy(value, buffer_ + offset_, sizeof(uint64_t));
+ offset_ += 8;
+ return true;
+ }
+
+ const uint8_t *buffer() const { return buffer_; }
+ size_t offset() const { return offset_; }
+ size_t length() const { return length_; }
+
+ void set_offset(size_t newoffset) { offset_ = newoffset; }
+
+ private:
+ const uint8_t * const buffer_;
+ const size_t length_;
+ size_t offset_;
+};
+
+// Round a value up to the nearest multiple of 4. Don't round the value in the
+// case that rounding up overflows.
+template<typename T> T Round4(T value) {
+ if (std::numeric_limits<T>::max() - value < 3) {
+ return value;
+ }
+ return (value + 3) & ~3;
+}
+
+template<typename T> T Round2(T value) {
+ if (value == std::numeric_limits<T>::max()) {
+ return value;
+ }
+ return (value + 1) & ~1;
+}
+
+bool IsValidVersionTag(uint32_t tag);
+
+#define FOR_EACH_TABLE_TYPE \
+ F(cff, CFF) \
+ F(cmap, CMAP) \
+ F(cvt, CVT) \
+ F(fpgm, FPGM) \
+ F(gasp, GASP) \
+ F(gdef, GDEF) \
+ F(glyf, GLYF) \
+ F(gpos, GPOS) \
+ F(gsub, GSUB) \
+ F(hdmx, HDMX) \
+ F(head, HEAD) \
+ F(hhea, HHEA) \
+ F(hmtx, HMTX) \
+ F(kern, KERN) \
+ F(loca, LOCA) \
+ F(ltsh, LTSH) \
+ F(math, MATH) \
+ F(maxp, MAXP) \
+ F(name, NAME) \
+ F(os2, OS2) \
+ F(post, POST) \
+ F(prep, PREP) \
+ F(vdmx, VDMX) \
+ F(vorg, VORG) \
+ F(vhea, VHEA) \
+ F(vmtx, VMTX)
+
+#define F(name, capname) struct OpenType##capname;
+FOR_EACH_TABLE_TYPE
+#undef F
+
+struct OpenTypeFile {
+ OpenTypeFile() {
+#define F(name, capname) name = NULL;
+ FOR_EACH_TABLE_TYPE
+#undef F
+ }
+
+ uint32_t version;
+ uint16_t num_tables;
+ uint16_t search_range;
+ uint16_t entry_selector;
+ uint16_t range_shift;
+
+ OTSContext *context;
+
+#define F(name, capname) OpenType##capname *name;
+FOR_EACH_TABLE_TYPE
+#undef F
+};
+
+#define F(name, capname) \
+bool ots_##name##_parse(OpenTypeFile *f, const uint8_t *d, size_t l); \
+bool ots_##name##_should_serialise(OpenTypeFile *f); \
+bool ots_##name##_serialise(OTSStream *s, OpenTypeFile *f); \
+void ots_##name##_free(OpenTypeFile *f);
+// TODO(yusukes): change these function names to follow Chromium coding rule.
+FOR_EACH_TABLE_TYPE
+#undef F
+
+} // namespace ots
+
+#endif // OTS_H_
diff --git a/third_party/ots/src/post.cc b/third_party/ots/src/post.cc
new file mode 100644
index 0000000..338d869
--- /dev/null
+++ b/third_party/ots/src/post.cc
@@ -0,0 +1,188 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "post.h"
+
+#include "maxp.h"
+
+// post - PostScript
+// http://www.microsoft.com/typography/otspec/post.htm
+
+#define TABLE_NAME "post"
+
+namespace ots {
+
+bool ots_post_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypePOST *post = new OpenTypePOST;
+ file->post = post;
+
+ if (!table.ReadU32(&post->version) ||
+ !table.ReadU32(&post->italic_angle) ||
+ !table.ReadS16(&post->underline) ||
+ !table.ReadS16(&post->underline_thickness) ||
+ !table.ReadU32(&post->is_fixed_pitch)) {
+ return OTS_FAILURE_MSG("Failed to read post header");
+ }
+
+ if (post->underline_thickness < 0) {
+ post->underline_thickness = 1;
+ }
+
+ if (post->version == 0x00010000) {
+ return true;
+ } else if (post->version == 0x00030000) {
+ return true;
+ } else if (post->version != 0x00020000) {
+ // 0x00025000 is deprecated. We don't accept it.
+ return OTS_FAILURE_MSG("Bad post version %x", post->version);
+ }
+
+ // We have a version 2 table with a list of Pascal strings at the end
+
+ // We don't care about the memory usage fields. We'll set all these to zero
+ // when serialising
+ if (!table.Skip(16)) {
+ return OTS_FAILURE_MSG("Failed to skip memory usage in post table");
+ }
+
+ uint16_t num_glyphs = 0;
+ if (!table.ReadU16(&num_glyphs)) {
+ return OTS_FAILURE_MSG("Failed to read number of glyphs");
+ }
+
+ if (!file->maxp) {
+ return OTS_FAILURE_MSG("No maxp table required by post table");
+ }
+
+ if (num_glyphs == 0) {
+ if (file->maxp->num_glyphs > 258) {
+ return OTS_FAILURE_MSG("Can't have no glyphs in the post table if there are more than 256 glyphs in the font");
+ }
+ OTS_WARNING("table version is 1, but no glyf names are found");
+ // workaround for fonts in http://www.fontsquirrel.com/fontface
+ // (e.g., yataghan.ttf).
+ post->version = 0x00010000;
+ return true;
+ }
+
+ if (num_glyphs != file->maxp->num_glyphs) {
+ // Note: Fixedsys500c.ttf seems to have inconsistent num_glyphs values.
+ return OTS_FAILURE_MSG("Bad number of glyphs in post table %d", num_glyphs);
+ }
+
+ post->glyph_name_index.resize(num_glyphs);
+ for (unsigned i = 0; i < num_glyphs; ++i) {
+ if (!table.ReadU16(&post->glyph_name_index[i])) {
+ return OTS_FAILURE_MSG("Failed to read post information for glyph %d", i);
+ }
+ // Note: A strict interpretation of the specification requires name indexes
+ // are less than 32768. This, however, excludes fonts like unifont.ttf
+ // which cover all of unicode.
+ }
+
+ // Now we have an array of Pascal strings. We have to check that they are all
+ // valid and read them in.
+ const size_t strings_offset = table.offset();
+ const uint8_t *strings = data + strings_offset;
+ const uint8_t *strings_end = data + length;
+
+ for (;;) {
+ if (strings == strings_end) break;
+ const unsigned string_length = *strings;
+ if (strings + 1 + string_length > strings_end) {
+ return OTS_FAILURE_MSG("Bad string length %d", string_length);
+ }
+ if (std::memchr(strings + 1, '\0', string_length)) {
+ return OTS_FAILURE_MSG("Bad string of length %d", string_length);
+ }
+ post->names.push_back(
+ std::string(reinterpret_cast<const char*>(strings + 1), string_length));
+ strings += 1 + string_length;
+ }
+ const unsigned num_strings = post->names.size();
+
+ // check that all the references are within bounds
+ for (unsigned i = 0; i < num_glyphs; ++i) {
+ unsigned offset = post->glyph_name_index[i];
+ if (offset < 258) {
+ continue;
+ }
+
+ offset -= 258;
+ if (offset >= num_strings) {
+ return OTS_FAILURE_MSG("Bad string index %d", offset);
+ }
+ }
+
+ return true;
+}
+
+bool ots_post_should_serialise(OpenTypeFile *file) {
+ return file->post != NULL;
+}
+
+bool ots_post_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypePOST *post = file->post;
+
+ // OpenType with CFF glyphs must have v3 post table.
+ if (file->post && file->cff && file->post->version != 0x00030000) {
+ return OTS_FAILURE_MSG("Bad post version %x", post->version);
+ }
+
+ if (!out->WriteU32(post->version) ||
+ !out->WriteU32(post->italic_angle) ||
+ !out->WriteS16(post->underline) ||
+ !out->WriteS16(post->underline_thickness) ||
+ !out->WriteU32(post->is_fixed_pitch) ||
+ !out->WriteU32(0) ||
+ !out->WriteU32(0) ||
+ !out->WriteU32(0) ||
+ !out->WriteU32(0)) {
+ return OTS_FAILURE_MSG("Failed to write post header");
+ }
+
+ if (post->version != 0x00020000) {
+ return true; // v1.0 and v3.0 does not have glyph names.
+ }
+
+ const uint16_t num_indexes =
+ static_cast<uint16_t>(post->glyph_name_index.size());
+ if (num_indexes != post->glyph_name_index.size() ||
+ !out->WriteU16(num_indexes)) {
+ return OTS_FAILURE_MSG("Failed to write number of indices");
+ }
+
+ for (uint16_t i = 0; i < num_indexes; ++i) {
+ if (!out->WriteU16(post->glyph_name_index[i])) {
+ return OTS_FAILURE_MSG("Failed to write name index %d", i);
+ }
+ }
+
+ // Now we just have to write out the strings in the correct order
+ for (unsigned i = 0; i < post->names.size(); ++i) {
+ const std::string& s = post->names[i];
+ const uint8_t string_length = static_cast<uint8_t>(s.size());
+ if (string_length != s.size() ||
+ !out->Write(&string_length, 1)) {
+ return OTS_FAILURE_MSG("Failed to write string %d", i);
+ }
+ // Some ttf fonts (e.g., frank.ttf on Windows Vista) have zero-length name.
+ // We allow them.
+ if (string_length > 0 && !out->Write(s.data(), string_length)) {
+ return OTS_FAILURE_MSG("Failed to write string length for string %d", i);
+ }
+ }
+
+ return true;
+}
+
+void ots_post_free(OpenTypeFile *file) {
+ delete file->post;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/post.h b/third_party/ots/src/post.h
new file mode 100644
index 0000000..f220d4f
--- /dev/null
+++ b/third_party/ots/src/post.h
@@ -0,0 +1,29 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_POST_H_
+#define OTS_POST_H_
+
+#include "ots.h"
+
+#include <map>
+#include <string>
+#include <vector>
+
+namespace ots {
+
+struct OpenTypePOST {
+ uint32_t version;
+ uint32_t italic_angle;
+ int16_t underline;
+ int16_t underline_thickness;
+ uint32_t is_fixed_pitch;
+
+ std::vector<uint16_t> glyph_name_index;
+ std::vector<std::string> names;
+};
+
+} // namespace ots
+
+#endif // OTS_POST_H_
diff --git a/third_party/ots/src/prep.cc b/third_party/ots/src/prep.cc
new file mode 100644
index 0000000..ea3dec0
--- /dev/null
+++ b/third_party/ots/src/prep.cc
@@ -0,0 +1,54 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "prep.h"
+
+// prep - Control Value Program
+// http://www.microsoft.com/typography/otspec/prep.htm
+
+#define TABLE_NAME "prep"
+
+namespace ots {
+
+bool ots_prep_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+
+ OpenTypePREP *prep = new OpenTypePREP;
+ file->prep = prep;
+
+ if (length >= 128 * 1024u) {
+ return OTS_FAILURE_MSG("table length %ld > 120K", length); // almost all prep tables are less than 9k bytes.
+ }
+
+ if (!table.Skip(length)) {
+ return OTS_FAILURE_MSG("Failed to read table of length %ld", length);
+ }
+
+ prep->data = data;
+ prep->length = length;
+ return true;
+}
+
+bool ots_prep_should_serialise(OpenTypeFile *file) {
+ if (!file->glyf) return false; // this table is not for CFF fonts.
+ return file->prep != NULL;
+}
+
+bool ots_prep_serialise(OTSStream *out, OpenTypeFile *file) {
+ const OpenTypePREP *prep = file->prep;
+
+ if (!out->Write(prep->data, prep->length)) {
+ return OTS_FAILURE_MSG("Failed to write table length");
+ }
+
+ return true;
+}
+
+void ots_prep_free(OpenTypeFile *file) {
+ delete file->prep;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/prep.h b/third_party/ots/src/prep.h
new file mode 100644
index 0000000..935ca11
--- /dev/null
+++ b/third_party/ots/src/prep.h
@@ -0,0 +1,19 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_PREP_H_
+#define OTS_PREP_H_
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypePREP {
+ const uint8_t *data;
+ uint32_t length;
+};
+
+} // namespace ots
+
+#endif // OTS_PREP_H_
diff --git a/third_party/ots/src/vdmx.cc b/third_party/ots/src/vdmx.cc
new file mode 100644
index 0000000..4853d63
--- /dev/null
+++ b/third_party/ots/src/vdmx.cc
@@ -0,0 +1,181 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vdmx.h"
+
+// VDMX - Vertical Device Metrics
+// http://www.microsoft.com/typography/otspec/vdmx.htm
+
+#define TABLE_NAME "VDMX"
+
+#define DROP_THIS_TABLE(...) \
+ do { \
+ OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+ OTS_FAILURE_MSG("Table discarded"); \
+ delete file->vdmx; \
+ file->vdmx = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_vdmx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ file->vdmx = new OpenTypeVDMX;
+ OpenTypeVDMX * const vdmx = file->vdmx;
+
+ if (!table.ReadU16(&vdmx->version) ||
+ !table.ReadU16(&vdmx->num_recs) ||
+ !table.ReadU16(&vdmx->num_ratios)) {
+ return OTS_FAILURE_MSG("Failed to read table header");
+ }
+
+ if (vdmx->version > 1) {
+ DROP_THIS_TABLE("bad version: %u", vdmx->version);
+ return true; // continue transcoding
+ }
+
+ vdmx->rat_ranges.reserve(vdmx->num_ratios);
+ for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
+ OpenTypeVDMXRatioRecord rec;
+
+ if (!table.ReadU8(&rec.charset) ||
+ !table.ReadU8(&rec.x_ratio) ||
+ !table.ReadU8(&rec.y_start_ratio) ||
+ !table.ReadU8(&rec.y_end_ratio)) {
+ return OTS_FAILURE_MSG("Failed to read ratio header %d", i);
+ }
+
+ if (rec.charset > 1) {
+ DROP_THIS_TABLE("bad charset: %u", rec.charset);
+ return true;
+ }
+
+ if (rec.y_start_ratio > rec.y_end_ratio) {
+ DROP_THIS_TABLE("bad y ratio");
+ return true;
+ }
+
+ // All values set to zero signal the default grouping to use;
+ // if present, this must be the last Ratio group in the table.
+ if ((i < vdmx->num_ratios - 1u) &&
+ (rec.x_ratio == 0) &&
+ (rec.y_start_ratio == 0) &&
+ (rec.y_end_ratio == 0)) {
+ // workaround for fonts which have 2 or more {0, 0, 0} terminators.
+ DROP_THIS_TABLE("superfluous terminator found");
+ return true;
+ }
+
+ vdmx->rat_ranges.push_back(rec);
+ }
+
+ vdmx->offsets.reserve(vdmx->num_ratios);
+ const size_t current_offset = table.offset();
+ // current_offset is less than (2 bytes * 3) + (4 bytes * USHRT_MAX) = 256k.
+ for (unsigned i = 0; i < vdmx->num_ratios; ++i) {
+ uint16_t offset;
+ if (!table.ReadU16(&offset)) {
+ return OTS_FAILURE_MSG("Failed to read ratio offset %d", i);
+ }
+ if (current_offset + offset >= length) { // thus doesn't overflow.
+ return OTS_FAILURE_MSG("Bad ratio offset %d for ration %d", offset, i);
+ }
+
+ vdmx->offsets.push_back(offset);
+ }
+
+ vdmx->groups.reserve(vdmx->num_recs);
+ for (unsigned i = 0; i < vdmx->num_recs; ++i) {
+ OpenTypeVDMXGroup group;
+ if (!table.ReadU16(&group.recs) ||
+ !table.ReadU8(&group.startsz) ||
+ !table.ReadU8(&group.endsz)) {
+ return OTS_FAILURE_MSG("Failed to read record header %d", i);
+ }
+ group.entries.reserve(group.recs);
+ for (unsigned j = 0; j < group.recs; ++j) {
+ OpenTypeVDMXVTable vt;
+ if (!table.ReadU16(&vt.y_pel_height) ||
+ !table.ReadS16(&vt.y_max) ||
+ !table.ReadS16(&vt.y_min)) {
+ return OTS_FAILURE_MSG("Failed to read reacord %d group %d", i, j);
+ }
+ if (vt.y_max < vt.y_min) {
+ DROP_THIS_TABLE("bad y min/max");
+ return true;
+ }
+
+ // This table must appear in sorted order (sorted by yPelHeight),
+ // but need not be continuous.
+ if ((j != 0) && (group.entries[j - 1].y_pel_height >= vt.y_pel_height)) {
+ DROP_THIS_TABLE("the table is not sorted");
+ return true;
+ }
+
+ group.entries.push_back(vt);
+ }
+ vdmx->groups.push_back(group);
+ }
+
+ return true;
+}
+
+bool ots_vdmx_should_serialise(OpenTypeFile *file) {
+ if (!file->glyf) return false; // this table is not for CFF fonts.
+ return file->vdmx != NULL;
+}
+
+bool ots_vdmx_serialise(OTSStream *out, OpenTypeFile *file) {
+ OpenTypeVDMX * const vdmx = file->vdmx;
+
+ if (!out->WriteU16(vdmx->version) ||
+ !out->WriteU16(vdmx->num_recs) ||
+ !out->WriteU16(vdmx->num_ratios)) {
+ return OTS_FAILURE_MSG("Failed to write table header");
+ }
+
+ for (unsigned i = 0; i < vdmx->rat_ranges.size(); ++i) {
+ const OpenTypeVDMXRatioRecord& rec = vdmx->rat_ranges[i];
+ if (!out->Write(&rec.charset, 1) ||
+ !out->Write(&rec.x_ratio, 1) ||
+ !out->Write(&rec.y_start_ratio, 1) ||
+ !out->Write(&rec.y_end_ratio, 1)) {
+ return OTS_FAILURE_MSG("Failed to write ratio %d", i);
+ }
+ }
+
+ for (unsigned i = 0; i < vdmx->offsets.size(); ++i) {
+ if (!out->WriteU16(vdmx->offsets[i])) {
+ return OTS_FAILURE_MSG("Failed to write ratio offset %d", i);
+ }
+ }
+
+ for (unsigned i = 0; i < vdmx->groups.size(); ++i) {
+ const OpenTypeVDMXGroup& group = vdmx->groups[i];
+ if (!out->WriteU16(group.recs) ||
+ !out->Write(&group.startsz, 1) ||
+ !out->Write(&group.endsz, 1)) {
+ return OTS_FAILURE_MSG("Failed to write group %d", i);
+ }
+ for (unsigned j = 0; j < group.entries.size(); ++j) {
+ const OpenTypeVDMXVTable& vt = group.entries[j];
+ if (!out->WriteU16(vt.y_pel_height) ||
+ !out->WriteS16(vt.y_max) ||
+ !out->WriteS16(vt.y_min)) {
+ return OTS_FAILURE_MSG("Failed to write group %d entry %d", i, j);
+ }
+ }
+ }
+
+ return true;
+}
+
+void ots_vdmx_free(OpenTypeFile *file) {
+ delete file->vdmx;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/vdmx.h b/third_party/ots/src/vdmx.h
new file mode 100644
index 0000000..1d959ef
--- /dev/null
+++ b/third_party/ots/src/vdmx.h
@@ -0,0 +1,45 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_VDMX_H_
+#define OTS_VDMX_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeVDMXRatioRecord {
+ uint8_t charset;
+ uint8_t x_ratio;
+ uint8_t y_start_ratio;
+ uint8_t y_end_ratio;
+};
+
+struct OpenTypeVDMXVTable {
+ uint16_t y_pel_height;
+ int16_t y_max;
+ int16_t y_min;
+};
+
+struct OpenTypeVDMXGroup {
+ uint16_t recs;
+ uint8_t startsz;
+ uint8_t endsz;
+ std::vector<OpenTypeVDMXVTable> entries;
+};
+
+struct OpenTypeVDMX {
+ uint16_t version;
+ uint16_t num_recs;
+ uint16_t num_ratios;
+ std::vector<OpenTypeVDMXRatioRecord> rat_ranges;
+ std::vector<uint16_t> offsets;
+ std::vector<OpenTypeVDMXGroup> groups;
+};
+
+} // namespace ots
+
+#endif // OTS_VDMX_H_
diff --git a/third_party/ots/src/vhea.cc b/third_party/ots/src/vhea.cc
new file mode 100644
index 0000000..c689a83
--- /dev/null
+++ b/third_party/ots/src/vhea.cc
@@ -0,0 +1,59 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vhea.h"
+
+#include "gsub.h"
+#include "head.h"
+#include "maxp.h"
+
+// vhea - Vertical Header Table
+// http://www.microsoft.com/typography/otspec/vhea.htm
+
+#define TABLE_NAME "vhea"
+
+namespace ots {
+
+bool ots_vhea_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ OpenTypeVHEA *vhea = new OpenTypeVHEA;
+ file->vhea = vhea;
+
+ if (!table.ReadU32(&vhea->header.version)) {
+ return OTS_FAILURE_MSG("Failed to read version");
+ }
+ if (vhea->header.version != 0x00010000 &&
+ vhea->header.version != 0x00011000) {
+ return OTS_FAILURE_MSG("Bad vhea version %x", vhea->header.version);
+ }
+
+ if (!ParseMetricsHeader(file, &table, &vhea->header)) {
+ return OTS_FAILURE_MSG("Failed to parse metrics in vhea");
+ }
+
+ return true;
+}
+
+bool ots_vhea_should_serialise(OpenTypeFile *file) {
+ // vhea should'nt serialise when vmtx doesn't exist.
+ // Firefox developer pointed out that vhea/vmtx should serialise iff GSUB is
+ // preserved. See http://crbug.com/77386
+ return file->vhea != NULL && file->vmtx != NULL &&
+ ots_gsub_should_serialise(file);
+}
+
+bool ots_vhea_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!SerialiseMetricsHeader(file, out, &file->vhea->header)) {
+ return OTS_FAILURE_MSG("Failed to write vhea metrics");
+ }
+ return true;
+}
+
+void ots_vhea_free(OpenTypeFile *file) {
+ delete file->vhea;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/vhea.h b/third_party/ots/src/vhea.h
new file mode 100644
index 0000000..f8efde7
--- /dev/null
+++ b/third_party/ots/src/vhea.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_VHEA_H_
+#define OTS_VHEA_H_
+
+#include "metrics.h"
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeVHEA {
+ OpenTypeMetricsHeader header;
+};
+
+} // namespace ots
+
+#endif // OTS_VHEA_H_
+
diff --git a/third_party/ots/src/vmtx.cc b/third_party/ots/src/vmtx.cc
new file mode 100644
index 0000000..e29d32b
--- /dev/null
+++ b/third_party/ots/src/vmtx.cc
@@ -0,0 +1,55 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vmtx.h"
+
+#include "gsub.h"
+#include "maxp.h"
+#include "vhea.h"
+
+// vmtx - Vertical Metrics Table
+// http://www.microsoft.com/typography/otspec/vmtx.htm
+
+#define TABLE_NAME "vmtx"
+
+namespace ots {
+
+bool ots_vmtx_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ OpenTypeVMTX *vmtx = new OpenTypeVMTX;
+ file->vmtx = vmtx;
+
+ if (!file->vhea || !file->maxp) {
+ return OTS_FAILURE_MSG("vhea or maxp table missing as needed by vmtx");
+ }
+
+ if (!ParseMetricsTable(file, &table, file->maxp->num_glyphs,
+ &file->vhea->header, &vmtx->metrics)) {
+ return OTS_FAILURE_MSG("Failed to parse vmtx metrics");
+ }
+
+ return true;
+}
+
+bool ots_vmtx_should_serialise(OpenTypeFile *file) {
+ // vmtx should serialise when vhea and GSUB are preserved.
+ // See the comment in ots_vhea_should_serialise().
+ return file->vmtx != NULL && file->vhea != NULL &&
+ ots_gsub_should_serialise(file);
+}
+
+bool ots_vmtx_serialise(OTSStream *out, OpenTypeFile *file) {
+ if (!SerialiseMetricsTable(file, out, &file->vmtx->metrics)) {
+ return OTS_FAILURE_MSG("Failed to write vmtx metrics");
+ }
+ return true;
+}
+
+void ots_vmtx_free(OpenTypeFile *file) {
+ delete file->vmtx;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/vmtx.h b/third_party/ots/src/vmtx.h
new file mode 100644
index 0000000..061dc73
--- /dev/null
+++ b/third_party/ots/src/vmtx.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_VMTX_H_
+#define OTS_VMTX_H_
+
+#include "metrics.h"
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeVMTX {
+ OpenTypeMetricsTable metrics;
+};
+
+} // namespace ots
+
+#endif // OTS_VMTX_H_
+
diff --git a/third_party/ots/src/vorg.cc b/third_party/ots/src/vorg.cc
new file mode 100644
index 0000000..2662067
--- /dev/null
+++ b/third_party/ots/src/vorg.cc
@@ -0,0 +1,106 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "vorg.h"
+
+#include <vector>
+
+// VORG - Vertical Origin Table
+// http://www.microsoft.com/typography/otspec/vorg.htm
+
+#define TABLE_NAME "VORG"
+
+#define DROP_THIS_TABLE(...) \
+ do { \
+ OTS_FAILURE_MSG_(file, TABLE_NAME ": " __VA_ARGS__); \
+ OTS_FAILURE_MSG("Table discarded"); \
+ delete file->vorg; \
+ file->vorg = 0; \
+ } while (0)
+
+namespace ots {
+
+bool ots_vorg_parse(OpenTypeFile *file, const uint8_t *data, size_t length) {
+ Buffer table(data, length);
+ file->vorg = new OpenTypeVORG;
+ OpenTypeVORG * const vorg = file->vorg;
+
+ uint16_t num_recs;
+ if (!table.ReadU16(&vorg->major_version) ||
+ !table.ReadU16(&vorg->minor_version) ||
+ !table.ReadS16(&vorg->default_vert_origin_y) ||
+ !table.ReadU16(&num_recs)) {
+ return OTS_FAILURE_MSG("Failed to read header");
+ }
+ if (vorg->major_version != 1) {
+ DROP_THIS_TABLE("bad major version: %u", vorg->major_version);
+ return true;
+ }
+ if (vorg->minor_version != 0) {
+ DROP_THIS_TABLE("bad minor version: %u", vorg->minor_version);
+ return true;
+ }
+
+ // num_recs might be zero (e.g., DFHSMinchoPro5-W3-Demo.otf).
+ if (!num_recs) {
+ return true;
+ }
+
+ uint16_t last_glyph_index = 0;
+ vorg->metrics.reserve(num_recs);
+ for (unsigned i = 0; i < num_recs; ++i) {
+ OpenTypeVORGMetrics rec;
+
+ if (!table.ReadU16(&rec.glyph_index) ||
+ !table.ReadS16(&rec.vert_origin_y)) {
+ return OTS_FAILURE_MSG("Failed to read record %d", i);
+ }
+ if ((i != 0) && (rec.glyph_index <= last_glyph_index)) {
+ DROP_THIS_TABLE("the table is not sorted");
+ return true;
+ }
+ last_glyph_index = rec.glyph_index;
+
+ vorg->metrics.push_back(rec);
+ }
+
+ return true;
+}
+
+bool ots_vorg_should_serialise(OpenTypeFile *file) {
+ if (!file->cff) return false; // this table is not for fonts with TT glyphs.
+ return file->vorg != NULL;
+}
+
+bool ots_vorg_serialise(OTSStream *out, OpenTypeFile *file) {
+ OpenTypeVORG * const vorg = file->vorg;
+
+ const uint16_t num_metrics = static_cast<uint16_t>(vorg->metrics.size());
+ if (num_metrics != vorg->metrics.size() ||
+ !out->WriteU16(vorg->major_version) ||
+ !out->WriteU16(vorg->minor_version) ||
+ !out->WriteS16(vorg->default_vert_origin_y) ||
+ !out->WriteU16(num_metrics)) {
+ return OTS_FAILURE_MSG("Failed to write table header");
+ }
+
+ for (uint16_t i = 0; i < num_metrics; ++i) {
+ const OpenTypeVORGMetrics& rec = vorg->metrics[i];
+ if (!out->WriteU16(rec.glyph_index) ||
+ !out->WriteS16(rec.vert_origin_y)) {
+ return OTS_FAILURE_MSG("Failed to write record %d", i);
+ }
+ }
+
+ return true;
+}
+
+void ots_vorg_free(OpenTypeFile *file) {
+ delete file->vorg;
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
+#undef DROP_THIS_TABLE
diff --git a/third_party/ots/src/vorg.h b/third_party/ots/src/vorg.h
new file mode 100644
index 0000000..c3d3ffd
--- /dev/null
+++ b/third_party/ots/src/vorg.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_VORG_H_
+#define OTS_VORG_H_
+
+#include <vector>
+
+#include "ots.h"
+
+namespace ots {
+
+struct OpenTypeVORGMetrics {
+ uint16_t glyph_index;
+ int16_t vert_origin_y;
+};
+
+struct OpenTypeVORG {
+ uint16_t major_version;
+ uint16_t minor_version;
+ int16_t default_vert_origin_y;
+ std::vector<OpenTypeVORGMetrics> metrics;
+};
+
+} // namespace ots
+
+#endif // OTS_VORG_H_
diff --git a/third_party/ots/src/woff2.cc b/third_party/ots/src/woff2.cc
new file mode 100644
index 0000000..31b562d
--- /dev/null
+++ b/third_party/ots/src/woff2.cc
@@ -0,0 +1,991 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This is the implementation of decompression of the proposed WOFF Ultra
+// Condensed file format.
+
+#include <cassert>
+#include <cstdlib>
+#include <vector>
+
+#include "third_party/brotli/src/brotli/dec/decode.h"
+
+#include "opentype-sanitiser.h"
+#include "ots-memory-stream.h"
+#include "ots.h"
+#include "woff2.h"
+
+#define TABLE_NAME "WOFF2"
+
+namespace {
+
+// simple glyph flags
+const uint8_t kGlyfOnCurve = 1 << 0;
+const uint8_t kGlyfXShort = 1 << 1;
+const uint8_t kGlyfYShort = 1 << 2;
+const uint8_t kGlyfRepeat = 1 << 3;
+const uint8_t kGlyfThisXIsSame = 1 << 4;
+const uint8_t kGlyfThisYIsSame = 1 << 5;
+
+// composite glyph flags
+const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
+const int FLAG_WE_HAVE_A_SCALE = 1 << 3;
+const int FLAG_MORE_COMPONENTS = 1 << 5;
+const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
+const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
+const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
+
+const size_t kSfntHeaderSize = 12;
+const size_t kSfntEntrySize = 16;
+const size_t kCheckSumAdjustmentOffset = 8;
+
+const size_t kEndPtsOfContoursOffset = 10;
+const size_t kCompositeGlyphBegin = 10;
+
+// Note that the byte order is big-endian, not the same as ots.cc
+#define TAG(a, b, c, d) ((a << 24) | (b << 16) | (c << 8) | d)
+
+const unsigned int kWoff2FlagsTransform = 1 << 5;
+
+const uint32_t kKnownTags[] = {
+ TAG('c', 'm', 'a', 'p'), // 0
+ TAG('h', 'e', 'a', 'd'), // 1
+ TAG('h', 'h', 'e', 'a'), // 2
+ TAG('h', 'm', 't', 'x'), // 3
+ TAG('m', 'a', 'x', 'p'), // 4
+ TAG('n', 'a', 'm', 'e'), // 5
+ TAG('O', 'S', '/', '2'), // 6
+ TAG('p', 'o', 's', 't'), // 7
+ TAG('c', 'v', 't', ' '), // 8
+ TAG('f', 'p', 'g', 'm'), // 9
+ TAG('g', 'l', 'y', 'f'), // 10
+ TAG('l', 'o', 'c', 'a'), // 11
+ TAG('p', 'r', 'e', 'p'), // 12
+ TAG('C', 'F', 'F', ' '), // 13
+ TAG('V', 'O', 'R', 'G'), // 14
+ TAG('E', 'B', 'D', 'T'), // 15
+ TAG('E', 'B', 'L', 'C'), // 16
+ TAG('g', 'a', 's', 'p'), // 17
+ TAG('h', 'd', 'm', 'x'), // 18
+ TAG('k', 'e', 'r', 'n'), // 19
+ TAG('L', 'T', 'S', 'H'), // 20
+ TAG('P', 'C', 'L', 'T'), // 21
+ TAG('V', 'D', 'M', 'X'), // 22
+ TAG('v', 'h', 'e', 'a'), // 23
+ TAG('v', 'm', 't', 'x'), // 24
+ TAG('B', 'A', 'S', 'E'), // 25
+ TAG('G', 'D', 'E', 'F'), // 26
+ TAG('G', 'P', 'O', 'S'), // 27
+ TAG('G', 'S', 'U', 'B'), // 28
+ TAG('E', 'B', 'S', 'C'), // 29
+ TAG('J', 'S', 'T', 'F'), // 30
+ TAG('M', 'A', 'T', 'H'), // 31
+ TAG('C', 'B', 'D', 'T'), // 32
+ TAG('C', 'B', 'L', 'C'), // 33
+ TAG('C', 'O', 'L', 'R'), // 34
+ TAG('C', 'P', 'A', 'L'), // 35
+ TAG('S', 'V', 'G', ' '), // 36
+ TAG('s', 'b', 'i', 'x'), // 37
+ TAG('a', 'c', 'n', 't'), // 38
+ TAG('a', 'v', 'a', 'r'), // 39
+ TAG('b', 'd', 'a', 't'), // 40
+ TAG('b', 'l', 'o', 'c'), // 41
+ TAG('b', 's', 'l', 'n'), // 42
+ TAG('c', 'v', 'a', 'r'), // 43
+ TAG('f', 'd', 's', 'c'), // 44
+ TAG('f', 'e', 'a', 't'), // 45
+ TAG('f', 'm', 't', 'x'), // 46
+ TAG('f', 'v', 'a', 'r'), // 47
+ TAG('g', 'v', 'a', 'r'), // 48
+ TAG('h', 's', 't', 'y'), // 49
+ TAG('j', 'u', 's', 't'), // 50
+ TAG('l', 'c', 'a', 'r'), // 51
+ TAG('m', 'o', 'r', 't'), // 52
+ TAG('m', 'o', 'r', 'x'), // 53
+ TAG('o', 'p', 'b', 'd'), // 54
+ TAG('p', 'r', 'o', 'p'), // 55
+ TAG('t', 'r', 'a', 'k'), // 56
+ TAG('Z', 'a', 'p', 'f'), // 57
+ TAG('S', 'i', 'l', 'f'), // 58
+ TAG('G', 'l', 'a', 't'), // 59
+ TAG('G', 'l', 'o', 'c'), // 60
+ TAG('F', 'e', 'a', 't'), // 61
+ TAG('S', 'i', 'l', 'l'), // 62
+};
+
+struct Point {
+ int16_t x;
+ int16_t y;
+ bool on_curve;
+};
+
+struct Table {
+ uint32_t tag;
+ uint32_t flags;
+
+ uint32_t transform_length;
+
+ uint32_t dst_offset;
+ uint32_t dst_length;
+
+ Table()
+ : tag(0),
+ flags(0),
+ transform_length(0),
+ dst_offset(0),
+ dst_length(0) {}
+};
+
+// Based on section 6.1.1 of MicroType Express draft spec
+bool Read255UShort(ots::Buffer* buf, uint16_t* value) {
+ static const uint8_t kWordCode = 253;
+ static const uint8_t kOneMoreByteCode2 = 254;
+ static const uint8_t kOneMoreByteCode1 = 255;
+ static const uint8_t kLowestUCode = 253;
+ uint8_t code = 0;
+ if (!buf->ReadU8(&code)) {
+ return OTS_FAILURE();
+ }
+ if (code == kWordCode) {
+ uint16_t result = 0;
+ if (!buf->ReadU16(&result)) {
+ return OTS_FAILURE();
+ }
+ *value = result;
+ return true;
+ } else if (code == kOneMoreByteCode1) {
+ uint8_t result = 0;
+ if (!buf->ReadU8(&result)) {
+ return OTS_FAILURE();
+ }
+ *value = result + kLowestUCode;
+ return true;
+ } else if (code == kOneMoreByteCode2) {
+ uint8_t result = 0;
+ if (!buf->ReadU8(&result)) {
+ return OTS_FAILURE();
+ }
+ *value = result + kLowestUCode * 2;
+ return true;
+ } else {
+ *value = code;
+ return true;
+ }
+}
+
+bool ReadBase128(ots::Buffer* buf, uint32_t* value) {
+ uint32_t result = 0;
+ for (size_t i = 0; i < 5; ++i) {
+ uint8_t code = 0;
+ if (!buf->ReadU8(&code)) {
+ return OTS_FAILURE();
+ }
+ // If any of the top seven bits are set then we're about to overflow.
+ if (result & 0xfe000000U) {
+ return OTS_FAILURE();
+ }
+ result = (result << 7) | (code & 0x7f);
+ if ((code & 0x80) == 0) {
+ *value = result;
+ return true;
+ }
+ }
+ // Make sure not to exceed the size bound
+ return OTS_FAILURE();
+}
+
+// Caller must ensure that buffer overrun won't happen.
+// TODO(ksakamaoto): Consider creating 'writer' version of the Buffer class
+// and use it across the code.
+size_t StoreU32(uint8_t* dst, size_t offset, uint32_t x) {
+ dst[offset] = x >> 24;
+ dst[offset + 1] = (x >> 16) & 0xff;
+ dst[offset + 2] = (x >> 8) & 0xff;
+ dst[offset + 3] = x & 0xff;
+ return offset + 4;
+}
+
+size_t StoreU16(uint8_t* dst, size_t offset, uint16_t x) {
+ dst[offset] = x >> 8;
+ dst[offset + 1] = x & 0xff;
+ return offset + 2;
+}
+
+int WithSign(int flag, int baseval) {
+ assert(0 <= baseval && baseval < 65536);
+ return (flag & 1) ? baseval : -baseval;
+}
+
+bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
+ unsigned int n_points, std::vector<Point>* result,
+ size_t* in_bytes_consumed) {
+ int x = 0;
+ int y = 0;
+
+ // Early return if |in| buffer is too small. Each point consumes 1-4 bytes.
+ if (n_points > in_size) {
+ return OTS_FAILURE();
+ }
+ unsigned int triplet_index = 0;
+
+ for (unsigned int i = 0; i < n_points; ++i) {
+ uint8_t flag = flags_in[i];
+ bool on_curve = !(flag >> 7);
+ flag &= 0x7f;
+ unsigned int n_data_bytes;
+ if (flag < 84) {
+ n_data_bytes = 1;
+ } else if (flag < 120) {
+ n_data_bytes = 2;
+ } else if (flag < 124) {
+ n_data_bytes = 3;
+ } else {
+ n_data_bytes = 4;
+ }
+ if (triplet_index + n_data_bytes > in_size ||
+ triplet_index + n_data_bytes < triplet_index) {
+ return OTS_FAILURE();
+ }
+ int dx, dy;
+ if (flag < 10) {
+ dx = 0;
+ dy = WithSign(flag, ((flag & 14) << 7) + in[triplet_index]);
+ } else if (flag < 20) {
+ dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]);
+ dy = 0;
+ } else if (flag < 84) {
+ int b0 = flag - 20;
+ int b1 = in[triplet_index];
+ dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4));
+ dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f));
+ } else if (flag < 120) {
+ int b0 = flag - 84;
+ dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]);
+ dy = WithSign(flag >> 1,
+ 1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]);
+ } else if (flag < 124) {
+ int b2 = in[triplet_index + 1];
+ dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4));
+ dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]);
+ } else {
+ dx = WithSign(flag, (in[triplet_index] << 8) + in[triplet_index + 1]);
+ dy = WithSign(flag >> 1,
+ (in[triplet_index + 2] << 8) + in[triplet_index + 3]);
+ }
+ triplet_index += n_data_bytes;
+ // Possible overflow but coordinate values are not security sensitive
+ x += dx;
+ y += dy;
+ result->push_back(Point());
+ Point& back = result->back();
+ back.x = static_cast<int16_t>(x);
+ back.y = static_cast<int16_t>(y);
+ back.on_curve = on_curve;
+ }
+ *in_bytes_consumed = triplet_index;
+ return true;
+}
+
+// This function stores just the point data. On entry, dst points to the
+// beginning of a simple glyph. Returns true on success.
+bool StorePoints(const std::vector<Point>& points,
+ unsigned int n_contours, unsigned int instruction_length,
+ uint8_t* dst, size_t dst_size, size_t* glyph_size) {
+ // I believe that n_contours < 65536, in which case this is safe. However, a
+ // comment and/or an assert would be good.
+ unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
+ instruction_length;
+ uint8_t last_flag = 0xff;
+ uint8_t repeat_count = 0;
+ int last_x = 0;
+ int last_y = 0;
+ unsigned int x_bytes = 0;
+ unsigned int y_bytes = 0;
+
+ for (size_t i = 0; i < points.size(); ++i) {
+ const Point& point = points.at(i);
+ uint8_t flag = point.on_curve ? kGlyfOnCurve : 0;
+ int dx = point.x - last_x;
+ int dy = point.y - last_y;
+ if (dx == 0) {
+ flag |= kGlyfThisXIsSame;
+ } else if (dx > -256 && dx < 256) {
+ flag |= kGlyfXShort | (dx > 0 ? kGlyfThisXIsSame : 0);
+ x_bytes += 1;
+ } else {
+ x_bytes += 2;
+ }
+ if (dy == 0) {
+ flag |= kGlyfThisYIsSame;
+ } else if (dy > -256 && dy < 256) {
+ flag |= kGlyfYShort | (dy > 0 ? kGlyfThisYIsSame : 0);
+ y_bytes += 1;
+ } else {
+ y_bytes += 2;
+ }
+
+ if (flag == last_flag && repeat_count != 255) {
+ dst[flag_offset - 1] |= kGlyfRepeat;
+ repeat_count++;
+ } else {
+ if (repeat_count != 0) {
+ if (flag_offset >= dst_size) {
+ return OTS_FAILURE();
+ }
+ dst[flag_offset++] = repeat_count;
+ }
+ if (flag_offset >= dst_size) {
+ return OTS_FAILURE();
+ }
+ dst[flag_offset++] = flag;
+ repeat_count = 0;
+ }
+ last_x = point.x;
+ last_y = point.y;
+ last_flag = flag;
+ }
+
+ if (repeat_count != 0) {
+ if (flag_offset >= dst_size) {
+ return OTS_FAILURE();
+ }
+ dst[flag_offset++] = repeat_count;
+ }
+ unsigned int xy_bytes = x_bytes + y_bytes;
+ if (xy_bytes < x_bytes ||
+ flag_offset + xy_bytes < flag_offset ||
+ flag_offset + xy_bytes > dst_size) {
+ return OTS_FAILURE();
+ }
+
+ int x_offset = flag_offset;
+ int y_offset = flag_offset + x_bytes;
+ last_x = 0;
+ last_y = 0;
+ for (size_t i = 0; i < points.size(); ++i) {
+ int dx = points.at(i).x - last_x;
+ if (dx == 0) {
+ // pass
+ } else if (dx > -256 && dx < 256) {
+ dst[x_offset++] = static_cast<uint8_t>(std::abs(dx));
+ } else {
+ // will always fit for valid input, but overflow is harmless
+ x_offset = StoreU16(dst, x_offset, static_cast<uint16_t>(dx));
+ }
+ last_x += dx;
+ int dy = points.at(i).y - last_y;
+ if (dy == 0) {
+ // pass
+ } else if (dy > -256 && dy < 256) {
+ dst[y_offset++] = static_cast<uint8_t>(std::abs(dy));
+ } else {
+ y_offset = StoreU16(dst, y_offset, static_cast<uint16_t>(dy));
+ }
+ last_y += dy;
+ }
+ *glyph_size = y_offset;
+ return true;
+}
+
+// Compute the bounding box of the coordinates, and store into a glyf buffer.
+// A precondition is that there are at least 10 bytes available.
+void ComputeBbox(const std::vector<Point>& points, uint8_t* dst) {
+ int16_t x_min = 0;
+ int16_t y_min = 0;
+ int16_t x_max = 0;
+ int16_t y_max = 0;
+
+ for (size_t i = 0; i < points.size(); ++i) {
+ int16_t x = points.at(i).x;
+ int16_t y = points.at(i).y;
+ if (i == 0 || x < x_min) x_min = x;
+ if (i == 0 || x > x_max) x_max = x;
+ if (i == 0 || y < y_min) y_min = y;
+ if (i == 0 || y > y_max) y_max = y;
+ }
+ size_t offset = 2;
+ offset = StoreU16(dst, offset, x_min);
+ offset = StoreU16(dst, offset, y_min);
+ offset = StoreU16(dst, offset, x_max);
+ offset = StoreU16(dst, offset, y_max);
+}
+
+// Process entire bbox stream. This is done as a separate pass to allow for
+// composite bbox computations (an optional more aggressive transform).
+bool ProcessBboxStream(ots::Buffer* bbox_stream, unsigned int n_glyphs,
+ const std::vector<uint32_t>& loca_values, uint8_t* glyf_buf,
+ size_t glyf_buf_length) {
+ const uint8_t* buf = bbox_stream->buffer();
+ if (n_glyphs >= 65536 || loca_values.size() != n_glyphs + 1) {
+ return OTS_FAILURE();
+ }
+ // Safe because n_glyphs is bounded
+ unsigned int bitmap_length = ((n_glyphs + 31) >> 5) << 2;
+ if (!bbox_stream->Skip(bitmap_length)) {
+ return OTS_FAILURE();
+ }
+ for (unsigned int i = 0; i < n_glyphs; ++i) {
+ if (buf[i >> 3] & (0x80 >> (i & 7))) {
+ uint32_t loca_offset = loca_values.at(i);
+ if (loca_values.at(i + 1) - loca_offset < kEndPtsOfContoursOffset) {
+ return OTS_FAILURE();
+ }
+ if (glyf_buf_length < 2 + 10 ||
+ loca_offset > glyf_buf_length - 2 - 10) {
+ return OTS_FAILURE();
+ }
+ if (!bbox_stream->Read(glyf_buf + loca_offset + 2, 8)) {
+ return OTS_FAILURE();
+ }
+ }
+ }
+ return true;
+}
+
+bool ProcessComposite(ots::Buffer* composite_stream, uint8_t* dst,
+ size_t dst_size, size_t* glyph_size, bool* have_instructions) {
+ size_t start_offset = composite_stream->offset();
+ bool we_have_instructions = false;
+
+ uint16_t flags = FLAG_MORE_COMPONENTS;
+ while (flags & FLAG_MORE_COMPONENTS) {
+ if (!composite_stream->ReadU16(&flags)) {
+ return OTS_FAILURE();
+ }
+ we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0;
+ size_t arg_size = 2; // glyph index
+ if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) {
+ arg_size += 4;
+ } else {
+ arg_size += 2;
+ }
+ if (flags & FLAG_WE_HAVE_A_SCALE) {
+ arg_size += 2;
+ } else if (flags & FLAG_WE_HAVE_AN_X_AND_Y_SCALE) {
+ arg_size += 4;
+ } else if (flags & FLAG_WE_HAVE_A_TWO_BY_TWO) {
+ arg_size += 8;
+ }
+ if (!composite_stream->Skip(arg_size)) {
+ return OTS_FAILURE();
+ }
+ }
+ size_t composite_glyph_size = composite_stream->offset() - start_offset;
+ if (composite_glyph_size + kCompositeGlyphBegin > dst_size) {
+ return OTS_FAILURE();
+ }
+ StoreU16(dst, 0, 0xffff); // nContours = -1 for composite glyph
+ std::memcpy(dst + kCompositeGlyphBegin,
+ composite_stream->buffer() + start_offset,
+ composite_glyph_size);
+ *glyph_size = kCompositeGlyphBegin + composite_glyph_size;
+ *have_instructions = we_have_instructions;
+ return true;
+}
+
+// Build TrueType loca table
+bool StoreLoca(const std::vector<uint32_t>& loca_values, int index_format,
+ uint8_t* dst, size_t dst_size) {
+ const uint64_t loca_size = loca_values.size();
+ const uint64_t offset_size = index_format ? 4 : 2;
+ if ((loca_size << 2) >> 2 != loca_size) {
+ return OTS_FAILURE();
+ }
+ // No integer overflow here (loca_size <= 2^16).
+ if (offset_size * loca_size > dst_size) {
+ return OTS_FAILURE();
+ }
+ size_t offset = 0;
+ for (size_t i = 0; i < loca_values.size(); ++i) {
+ uint32_t value = loca_values.at(i);
+ if (index_format) {
+ offset = StoreU32(dst, offset, value);
+ } else {
+ offset = StoreU16(dst, offset, static_cast<uint16_t>(value >> 1));
+ }
+ }
+ return true;
+}
+
+// Reconstruct entire glyf table based on transformed original
+bool ReconstructGlyf(const uint8_t* data, size_t data_size,
+ uint8_t* dst, size_t dst_size,
+ uint8_t* loca_buf, size_t loca_size) {
+ static const int kNumSubStreams = 7;
+ ots::Buffer file(data, data_size);
+ uint32_t version;
+ std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
+
+ if (!file.ReadU32(&version)) {
+ return OTS_FAILURE();
+ }
+ uint16_t num_glyphs;
+ uint16_t index_format;
+ if (!file.ReadU16(&num_glyphs) ||
+ !file.ReadU16(&index_format)) {
+ return OTS_FAILURE();
+ }
+ unsigned int offset = (2 + kNumSubStreams) * 4;
+ if (offset > data_size) {
+ return OTS_FAILURE();
+ }
+ // Invariant from here on: data_size >= offset
+ for (int i = 0; i < kNumSubStreams; ++i) {
+ uint32_t substream_size;
+ if (!file.ReadU32(&substream_size)) {
+ return OTS_FAILURE();
+ }
+ if (substream_size > data_size - offset) {
+ return OTS_FAILURE();
+ }
+ substreams.at(i) = std::make_pair(data + offset, substream_size);
+ offset += substream_size;
+ }
+ ots::Buffer n_contour_stream(substreams.at(0).first, substreams.at(0).second);
+ ots::Buffer n_points_stream(substreams.at(1).first, substreams.at(1).second);
+ ots::Buffer flag_stream(substreams.at(2).first, substreams.at(2).second);
+ ots::Buffer glyph_stream(substreams.at(3).first, substreams.at(3).second);
+ ots::Buffer composite_stream(substreams.at(4).first, substreams.at(4).second);
+ ots::Buffer bbox_stream(substreams.at(5).first, substreams.at(5).second);
+ ots::Buffer instruction_stream(substreams.at(6).first,
+ substreams.at(6).second);
+
+ std::vector<uint32_t> loca_values;
+ loca_values.reserve(num_glyphs + 1);
+ std::vector<uint16_t> n_points_vec;
+ std::vector<Point> points;
+ uint32_t loca_offset = 0;
+ for (unsigned int i = 0; i < num_glyphs; ++i) {
+ size_t glyph_size = 0;
+ uint16_t n_contours = 0;
+ if (!n_contour_stream.ReadU16(&n_contours)) {
+ return OTS_FAILURE();
+ }
+ uint8_t* glyf_dst = dst + loca_offset;
+ size_t glyf_dst_size = dst_size - loca_offset;
+ if (n_contours == 0xffff) {
+ // composite glyph
+ bool have_instructions = false;
+ uint16_t instruction_size = 0;
+ if (!ProcessComposite(&composite_stream, glyf_dst, glyf_dst_size,
+ &glyph_size, &have_instructions)) {
+ return OTS_FAILURE();
+ }
+ if (have_instructions) {
+ if (!Read255UShort(&glyph_stream, &instruction_size)) {
+ return OTS_FAILURE();
+ }
+ // No integer overflow here (instruction_size < 2^16).
+ if (instruction_size + 2U > glyf_dst_size - glyph_size) {
+ return OTS_FAILURE();
+ }
+ StoreU16(glyf_dst, glyph_size, instruction_size);
+ if (!instruction_stream.Read(glyf_dst + glyph_size + 2,
+ instruction_size)) {
+ return OTS_FAILURE();
+ }
+ glyph_size += instruction_size + 2;
+ }
+ } else if (n_contours > 0) {
+ // simple glyph
+ n_points_vec.clear();
+ points.clear();
+ uint32_t total_n_points = 0;
+ uint16_t n_points_contour;
+ for (uint32_t j = 0; j < n_contours; ++j) {
+ if (!Read255UShort(&n_points_stream, &n_points_contour)) {
+ return OTS_FAILURE();
+ }
+ n_points_vec.push_back(n_points_contour);
+ if (total_n_points + n_points_contour < total_n_points) {
+ return OTS_FAILURE();
+ }
+ total_n_points += n_points_contour;
+ }
+ uint32_t flag_size = total_n_points;
+ if (flag_size > flag_stream.length() - flag_stream.offset()) {
+ return OTS_FAILURE();
+ }
+ const uint8_t* flags_buf = flag_stream.buffer() + flag_stream.offset();
+ const uint8_t* triplet_buf = glyph_stream.buffer() +
+ glyph_stream.offset();
+ size_t triplet_size = glyph_stream.length() - glyph_stream.offset();
+ size_t triplet_bytes_consumed = 0;
+ if (!TripletDecode(flags_buf, triplet_buf, triplet_size, total_n_points,
+ &points, &triplet_bytes_consumed)) {
+ return OTS_FAILURE();
+ }
+ const uint32_t header_and_endpts_contours_size =
+ kEndPtsOfContoursOffset + 2 * n_contours;
+ if (glyf_dst_size < header_and_endpts_contours_size) {
+ return OTS_FAILURE();
+ }
+ StoreU16(glyf_dst, 0, n_contours);
+ ComputeBbox(points, glyf_dst);
+ size_t endpts_offset = kEndPtsOfContoursOffset;
+ int end_point = -1;
+ for (unsigned int contour_ix = 0; contour_ix < n_contours; ++contour_ix) {
+ end_point += n_points_vec.at(contour_ix);
+ if (end_point >= 65536) {
+ return OTS_FAILURE();
+ }
+ endpts_offset = StoreU16(glyf_dst, endpts_offset, static_cast<uint16_t>(end_point));
+ }
+ if (!flag_stream.Skip(flag_size)) {
+ return OTS_FAILURE();
+ }
+ if (!glyph_stream.Skip(triplet_bytes_consumed)) {
+ return OTS_FAILURE();
+ }
+ uint16_t instruction_size;
+ if (!Read255UShort(&glyph_stream, &instruction_size)) {
+ return OTS_FAILURE();
+ }
+ // No integer overflow here (instruction_size < 2^16).
+ if (glyf_dst_size - header_and_endpts_contours_size <
+ instruction_size + 2U) {
+ return OTS_FAILURE();
+ }
+ uint8_t* instruction_dst = glyf_dst + header_and_endpts_contours_size;
+ StoreU16(instruction_dst, 0, instruction_size);
+ if (!instruction_stream.Read(instruction_dst + 2, instruction_size)) {
+ return OTS_FAILURE();
+ }
+ if (!StorePoints(points, n_contours, instruction_size,
+ glyf_dst, glyf_dst_size, &glyph_size)) {
+ return OTS_FAILURE();
+ }
+ } else {
+ glyph_size = 0;
+ }
+ loca_values.push_back(loca_offset);
+ if (glyph_size + 3 < glyph_size) {
+ return OTS_FAILURE();
+ }
+ glyph_size = ots::Round2(glyph_size);
+ if (glyph_size > dst_size - loca_offset) {
+ // This shouldn't happen, but this test defensively maintains the
+ // invariant that loca_offset <= dst_size.
+ return OTS_FAILURE();
+ }
+ loca_offset += glyph_size;
+ }
+ loca_values.push_back(loca_offset);
+ assert(loca_values.size() == static_cast<size_t>(num_glyphs + 1));
+ if (!ProcessBboxStream(&bbox_stream, num_glyphs, loca_values,
+ dst, dst_size)) {
+ return OTS_FAILURE();
+ }
+ return StoreLoca(loca_values, index_format, loca_buf, loca_size);
+}
+
+// This is linear search, but could be changed to binary because we
+// do have a guarantee that the tables are sorted by tag. But the total
+// cpu time is expected to be very small in any case.
+const Table* FindTable(const std::vector<Table>& tables, uint32_t tag) {
+ size_t n_tables = tables.size();
+ for (size_t i = 0; i < n_tables; ++i) {
+ if (tables.at(i).tag == tag) {
+ return &tables.at(i);
+ }
+ }
+ return NULL;
+}
+
+bool ReconstructTransformed(const std::vector<Table>& tables, uint32_t tag,
+ const uint8_t* transformed_buf, size_t transformed_size,
+ uint8_t* dst, size_t dst_length) {
+ if (tag == TAG('g', 'l', 'y', 'f')) {
+ const Table* glyf_table = FindTable(tables, tag);
+ const Table* loca_table = FindTable(tables, TAG('l', 'o', 'c', 'a'));
+ if (glyf_table == NULL || loca_table == NULL) {
+ return OTS_FAILURE();
+ }
+ if (static_cast<uint64_t>(glyf_table->dst_offset) + glyf_table->dst_length >
+ dst_length) {
+ return OTS_FAILURE();
+ }
+ if (static_cast<uint64_t>(loca_table->dst_offset) + loca_table->dst_length >
+ dst_length) {
+ return OTS_FAILURE();
+ }
+ return ReconstructGlyf(transformed_buf, transformed_size,
+ dst + glyf_table->dst_offset, glyf_table->dst_length,
+ dst + loca_table->dst_offset, loca_table->dst_length);
+ } else if (tag == TAG('l', 'o', 'c', 'a')) {
+ // processing was already done by glyf table, but validate
+ if (!FindTable(tables, TAG('g', 'l', 'y', 'f'))) {
+ return OTS_FAILURE();
+ }
+ } else {
+ // transform for the tag is not known
+ return OTS_FAILURE();
+ }
+ return true;
+}
+
+uint32_t ComputeChecksum(const uint8_t* buf, size_t size) {
+ uint32_t checksum = 0;
+ for (size_t i = 0; i < size; i += 4) {
+ // We assume the addition is mod 2^32, which is valid because unsigned
+ checksum += (buf[i] << 24) | (buf[i + 1] << 16) |
+ (buf[i + 2] << 8) | buf[i + 3];
+ }
+ return checksum;
+}
+
+bool FixChecksums(const std::vector<Table>& tables, uint8_t* dst) {
+ const Table* head_table = FindTable(tables, TAG('h', 'e', 'a', 'd'));
+ if (head_table == NULL ||
+ head_table->dst_length < kCheckSumAdjustmentOffset + 4) {
+ return OTS_FAILURE();
+ }
+ size_t adjustment_offset = head_table->dst_offset + kCheckSumAdjustmentOffset;
+ if (adjustment_offset < head_table->dst_offset) {
+ return OTS_FAILURE();
+ }
+ StoreU32(dst, adjustment_offset, 0);
+ size_t n_tables = tables.size();
+ uint32_t file_checksum = 0;
+ for (size_t i = 0; i < n_tables; ++i) {
+ const Table* table = &tables.at(i);
+ size_t table_length = table->dst_length;
+ uint8_t* table_data = dst + table->dst_offset;
+ uint32_t checksum = ComputeChecksum(table_data, table_length);
+ StoreU32(dst, kSfntHeaderSize + i * kSfntEntrySize + 4, checksum);
+ file_checksum += checksum; // The addition is mod 2^32
+ }
+ file_checksum += ComputeChecksum(dst,
+ kSfntHeaderSize + kSfntEntrySize * n_tables);
+ uint32_t checksum_adjustment = 0xb1b0afba - file_checksum;
+ StoreU32(dst, adjustment_offset, checksum_adjustment);
+ return true;
+}
+
+bool Woff2Uncompress(uint8_t* dst_buf, size_t dst_size,
+ const uint8_t* src_buf, size_t src_size) {
+ size_t uncompressed_size = dst_size;
+ int ok = BrotliDecompressBuffer(src_size, src_buf,
+ &uncompressed_size, dst_buf);
+ if (!ok || uncompressed_size != dst_size) {
+ return OTS_FAILURE();
+ }
+ return true;
+}
+
+bool ReadTableDirectory(ots::OpenTypeFile* file,
+ ots::Buffer* buffer, std::vector<Table>* tables,
+ size_t num_tables) {
+ for (size_t i = 0; i < num_tables; ++i) {
+ Table* table = &tables->at(i);
+ uint8_t flag_byte;
+ if (!buffer->ReadU8(&flag_byte)) {
+ return OTS_FAILURE_MSG("Failed to read the flags of table directory entry %d", i);
+ }
+ uint32_t tag;
+ if ((flag_byte & 0x3f) == 0x3f) {
+ if (!buffer->ReadU32(&tag)) {
+ return OTS_FAILURE_MSG("Failed to read the tag of table directory entry %d", i);
+ }
+ } else {
+ tag = kKnownTags[flag_byte & 0x3f];
+ }
+ // Bits 6 and 7 are reserved and must be 0.
+ if ((flag_byte & 0xc0) != 0) {
+ return OTS_FAILURE_MSG("Bits 6 and 7 are not 0 for table directory entry %d", i);
+ }
+ uint32_t flags = 0;
+ // Always transform the glyf and loca tables
+ if (tag == TAG('g', 'l', 'y', 'f') ||
+ tag == TAG('l', 'o', 'c', 'a')) {
+ flags |= kWoff2FlagsTransform;
+ }
+ uint32_t dst_length;
+ if (!ReadBase128(buffer, &dst_length)) {
+ return OTS_FAILURE_MSG("Failed to read \"origLength\" for table %4.4s", (char*)&tag);
+ }
+ uint32_t transform_length = dst_length;
+ if ((flags & kWoff2FlagsTransform) != 0) {
+ if (!ReadBase128(buffer, &transform_length)) {
+ return OTS_FAILURE_MSG("Failed to read \"transformLength\" for table %4.4s", (char*)&tag);
+ }
+ }
+ // Disallow huge numbers (> 1GB) for sanity.
+ if (transform_length > 1024 * 1024 * 1024 ||
+ dst_length > 1024 * 1024 * 1024) {
+ return OTS_FAILURE_MSG("\"origLength\" or \"transformLength\" > 1GB");
+ }
+ table->tag = tag;
+ table->flags = flags;
+ table->transform_length = transform_length;
+ table->dst_length = dst_length;
+ }
+ return true;
+}
+
+} // namespace
+
+namespace ots {
+
+size_t ComputeWOFF2FinalSize(const uint8_t* data, size_t length) {
+ ots::Buffer file(data, length);
+ uint32_t total_length;
+
+ if (!file.Skip(16) ||
+ !file.ReadU32(&total_length)) {
+ return 0;
+ }
+ return total_length;
+}
+
+bool ConvertWOFF2ToTTF(ots::OpenTypeFile* file,
+ uint8_t* result, size_t result_length,
+ const uint8_t* data, size_t length) {
+ static const uint32_t kWoff2Signature = 0x774f4632; // "wOF2"
+ ots::Buffer buffer(data, length);
+
+ uint32_t signature;
+ uint32_t flavor = 0;
+ if (!buffer.ReadU32(&signature) || signature != kWoff2Signature ||
+ !buffer.ReadU32(&flavor)) {
+ return OTS_FAILURE_MSG("Failed to read \"signature\" or \"flavor\", or not WOFF2 signature");
+ }
+
+ if (!IsValidVersionTag(ntohl(flavor))) {
+ return OTS_FAILURE_MSG("Invalid \"flavor\"");
+ }
+
+ uint32_t reported_length;
+ if (!buffer.ReadU32(&reported_length) || length != reported_length) {
+ return OTS_FAILURE_MSG("Failed to read \"length\" or it does not match the actual file size");
+ }
+ uint16_t num_tables;
+ if (!buffer.ReadU16(&num_tables) || !num_tables) {
+ return OTS_FAILURE_MSG("Failed to read \"numTables\"");
+ }
+ // We don't care about these fields of the header:
+ // uint16_t reserved
+ // uint32_t total_sfnt_size
+ if (!buffer.Skip(6)) {
+ return OTS_FAILURE_MSG("Failed to read \"reserve\" or \"totalSfntSize\"");
+ }
+ uint32_t compressed_length;
+ if (!buffer.ReadU32(&compressed_length)) {
+ return OTS_FAILURE_MSG("Failed to read \"totalCompressedSize\"");
+ }
+ if (compressed_length > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE();
+ }
+
+ // We don't care about these fields of the header:
+ // uint16_t major_version, minor_version
+ // uint32_t meta_offset, meta_length, meta_orig_length
+ // uint32_t priv_offset, priv_length
+ if (!buffer.Skip(24)) {
+ return OTS_FAILURE();
+ }
+ std::vector<Table> tables(num_tables);
+ if (!ReadTableDirectory(file, &buffer, &tables, num_tables)) {
+ return OTS_FAILURE_MSG("Failed to read table directory");
+ }
+ uint64_t compressed_offset = buffer.offset();
+ if (compressed_offset > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE();
+ }
+ uint64_t dst_offset = kSfntHeaderSize +
+ kSfntEntrySize * static_cast<uint64_t>(num_tables);
+ for (uint16_t i = 0; i < num_tables; ++i) {
+ Table* table = &tables.at(i);
+ table->dst_offset = static_cast<uint32_t>(dst_offset);
+ dst_offset += table->dst_length;
+ if (dst_offset > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE();
+ }
+ dst_offset = ots::Round4(dst_offset);
+ }
+ if (ots::Round4(compressed_offset + compressed_length) > length || dst_offset > result_length) {
+ return OTS_FAILURE();
+ }
+
+ const uint32_t sfnt_header_and_table_directory_size = 12 + 16 * num_tables;
+ if (sfnt_header_and_table_directory_size > result_length) {
+ return OTS_FAILURE();
+ }
+
+ // Start building the font
+ size_t offset = 0;
+ offset = StoreU32(result, offset, flavor);
+ offset = StoreU16(result, offset, num_tables);
+ uint8_t max_pow2 = 0;
+ while (1u << (max_pow2 + 1) <= num_tables) {
+ max_pow2++;
+ }
+ const uint16_t output_search_range = (1u << max_pow2) << 4;
+ offset = StoreU16(result, offset, output_search_range);
+ offset = StoreU16(result, offset, max_pow2);
+ offset = StoreU16(result, offset, (num_tables << 4) - output_search_range);
+ for (uint16_t i = 0; i < num_tables; ++i) {
+ const Table* table = &tables.at(i);
+ offset = StoreU32(result, offset, table->tag);
+ offset = StoreU32(result, offset, 0); // checksum, to fill in later
+ offset = StoreU32(result, offset, table->dst_offset);
+ offset = StoreU32(result, offset, table->dst_length);
+ }
+ std::vector<uint8_t> uncompressed_buf;
+ const uint8_t* transform_buf = NULL;
+ uint64_t total_size = 0;
+
+ for (uint16_t i = 0; i < num_tables; ++i) {
+ total_size += tables.at(i).transform_length;
+ if (total_size > std::numeric_limits<uint32_t>::max()) {
+ return OTS_FAILURE();
+ }
+ }
+ // Enforce same 30M limit on uncompressed tables as OTS
+ if (total_size > 30 * 1024 * 1024) {
+ return OTS_FAILURE();
+ }
+ const size_t total_size_size_t = static_cast<size_t>(total_size);
+ uncompressed_buf.resize(total_size_size_t);
+ const uint8_t* src_buf = data + compressed_offset;
+ if (!Woff2Uncompress(&uncompressed_buf[0], total_size_size_t,
+ src_buf, compressed_length)) {
+ return OTS_FAILURE();
+ }
+ transform_buf = &uncompressed_buf[0];
+
+ for (uint16_t i = 0; i < num_tables; ++i) {
+ const Table* table = &tables.at(i);
+ uint32_t flags = table->flags;
+ size_t transform_length = table->transform_length;
+
+ if ((flags & kWoff2FlagsTransform) == 0) {
+ if (transform_length != table->dst_length) {
+ return OTS_FAILURE();
+ }
+ if (static_cast<uint64_t>(table->dst_offset) + transform_length >
+ result_length) {
+ return OTS_FAILURE();
+ }
+ std::memcpy(result + table->dst_offset, transform_buf,
+ transform_length);
+ } else {
+ if (!ReconstructTransformed(tables, table->tag,
+ transform_buf, transform_length, result, result_length)) {
+ return OTS_FAILURE();
+ }
+ }
+
+ transform_buf += transform_length;
+ if (transform_buf > &uncompressed_buf[0] + uncompressed_buf.size()) {
+ return OTS_FAILURE();
+ }
+ }
+
+ return FixChecksums(tables, result);
+}
+
+} // namespace ots
+
+#undef TABLE_NAME
diff --git a/third_party/ots/src/woff2.h b/third_party/ots/src/woff2.h
new file mode 100644
index 0000000..1db259a
--- /dev/null
+++ b/third_party/ots/src/woff2.h
@@ -0,0 +1,20 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_WOFF2_H_
+#define OTS_WOFF2_H_
+
+namespace ots {
+
+// Compute the size of the final uncompressed font, or 0 on error.
+size_t ComputeWOFF2FinalSize(const uint8_t *data, size_t length);
+
+// Decompresses the font into the target buffer. The result_length should
+// be the same as determined by ComputeFinalSize(). Returns true on successful
+// decompression.
+bool ConvertWOFF2ToTTF(OpenTypeFile *file, uint8_t *result, size_t result_length,
+ const uint8_t *data, size_t length);
+}
+
+#endif // OTS_WOFF2_H_
diff --git a/third_party/ots/test/BLACKLIST.txt b/third_party/ots/test/BLACKLIST.txt
new file mode 100644
index 0000000..f3cd207
--- /dev/null
+++ b/third_party/ots/test/BLACKLIST.txt
@@ -0,0 +1,124 @@
+# Required table(s) are missing (e.g. OS/2 table).
+AppleGothic.ttf
+AppleMyungjo.ttf
+ArialHB.ttf
+ArialHBBold.ttf
+Corsiva.ttf
+CorsivaBold.ttf
+InaiMathi.ttf
+NISC18030.ttf
+NewPeninimMT.ttf
+NewPeninimMTBold.ttf
+NewPeninimMTBoldInclined.ttf
+NewPeninimMTInclined.ttf
+Raanana.ttf
+RaananaBold.ttf
+
+# The length field of a table is weird.
+homa.ttf
+nazli.ttf
+titr.ttf
+ume-tgc4.ttf
+ume-tgs4.ttf
+ume-tgc5.ttf
+ume-tgs5.ttf
+ume-tms3.ttf
+
+# Table(s) are not 4-byte aligned.
+UnBatang.ttf
+UnBom.ttf
+UnDotum.ttf
+UnGraphic.ttf
+UnGungseo.ttf
+UnJamoBatang.ttf
+UnJamoDotum.ttf
+UnJamoNovel.ttf
+UnJamoSora.ttf
+UnPenheulim.ttf
+UnPen.ttf
+UnPilgiBold.ttf
+UnPilgi.ttf
+UnShinmun.ttf
+UnTaza.ttf
+UnYetgul.ttf
+
+# Tables are not sorted by table tags.
+f500.ttf
+
+# non-ASCII characters are used in a table tag
+SyrCOMAdiabene.otf
+SyrCOMAntioch.otf
+SyrCOMBatnanBold.otf
+SyrCOMBatnan.otf
+SyrCOMCtesiphon.otf
+SyrCOMJerusalemBold.otf
+SyrCOMJerusalemItalic.otf
+SyrCOMJerusalem.otf
+SyrCOMJerusalemOutline.otf
+SyrCOMKharput.otf
+SyrCOMMalankara.otf
+SyrCOMMardinBold.otf
+SyrCOMMardin.otf
+SyrCOMMidyat.otf
+SyrCOMNisibin.otf
+SyrCOMNisibinOutline.otf
+SyrCOMQenNeshrin.otf
+SyrCOMTalada.otf
+SyrCOMTurAbdin.otf
+SyrCOMUrhoyBold.otf
+SyrCOMUrhoy.otf
+
+# Malformed SFNT table; unexpected entry selector
+misakimn.ttf
+misaki.ttf
+
+# Malformed CMAP table; Subtables are not sorted by platform ID
+ani.ttf
+Caliban.ttf
+
+# Malformed CMAP table; Entries in a 3-0-4 or 3-1-4 subtable are not sorted.
+LucidaSansOblique.ttf
+LucidaTypewriterOblique.ttf
+bkai00mp.ttf
+bsmi00lp.ttf
+modelwor.ttf
+
+# Malformed CMAP table; "search range" in a 3-0-4 or 3-1-4 subtable are invalid.
+cmmi10.ttf
+cmsy10.ttf
+msam10.ttf
+
+# Malformed CMAP table; The 3-10-12 table is too short.
+BPG_Chveulebrivi.ttf
+BPG_Chveulebrivi_bold.ttf
+
+# Unsupported CMAP table; ots doesn't support non-Unicode fonts.
+Apple Symbols.ttf
+儷宋 Pro.ttf
+儷黑 Pro.ttf
+华文仿宋.ttf
+华文宋体.ttf
+华文楷体.ttf
+华文细黑.ttf
+华文黑体.ttf
+
+# Unsupported CMAP table; The Unicode BMP table is missing, while the UCS-4 table is available.
+DroidSansJapanese.ttf
+DroidSansFallback.ttf
+
+# Malformed GLYF table; The content of flags array and the lengths of xCoordinates, yCoordinates are inconsistent.
+DecoTypeNaskh.ttf
+
+# Malformed HMTX table; The table is too short.
+mona.ttf
+
+# CMAP glyph id is out of range.
+Samyak-Oriya.ttf
+
+# Unsupported CFF table; "supplemental encoding" is not supported at the moment. This should be fixed in the future.
+Walbf___.otf
+
+# GDEF MarkAttachClassDef offset is invalid.
+ManchuFont.ttf
+arianamu.ttf
+summersby.ttf
diff --git a/third_party/ots/test/README b/third_party/ots/test/README
new file mode 100644
index 0000000..f634e06
--- /dev/null
+++ b/third_party/ots/test/README
@@ -0,0 +1,243 @@
+------------------------------------------------------------------------------
+ot-sanitise - TTF/OTF font validator/transcoder
+
+Description:
+ ot-sanitise is a program which validates and/or transcodes a truetype or
+ opentype font file using the OTS library:
+
+ transcoded_font = ValidateAndTranscode(original_font);
+ if (validation_error)
+ PrintErrorAndExit;
+ OutputToStdout(transcoded_font);
+
+Usage:
+ $ ./ot-sanitise ttf_or_otf_file [transcoded_file]
+
+Example:
+ $ ./ot-sanitise sample.otf transcoded_sample.otf
+ $ ./ot-sanitise malformed.ttf
+ WARNING at ots/src/ots.cc:158: bad range shift
+ ERROR at ots/src/ots.cc:199 (bool<unnamed>::do_ots_process(ots::OpenTypeFile*, ots::OTSStream*, const uint8_t*, size_t))
+ Failed to sanitise file!
+ $
+
+------------------------------------------------------------------------------
+idempotent - TTF/OTF font transcoder (for OTS debugging)
+
+Description:
+ idempotent is a program which validates and transcodes a truetype or opentype
+ font file using OTS. This tool transcodes the original font twice and then
+ verifies that the two transcoded fonts are identical:
+
+ t1 = ValidateAndTranscode(original_font);
+ if (validation_error)
+ PrintErrorAndExit;
+ t2 = ValidateAndTranscode(t1);
+ if (validation_error)
+ PrintErrorAndExit;
+ if (t1 != t2)
+ PrintErrorAndExit;
+
+ This tool is basically for OTS developers.
+
+Usage:
+ $ ./idempotent ttf_or_otf_file
+
+Example:
+ $ ./idempotent sample.otf
+ $ ./idempotent malformed.ttf
+ WARNING at ots/src/ots.cc:158: bad range shift
+ ERROR at ots/src/ots.cc:199 (bool<unnamed>::do_ots_process(ots::OpenTypeFile*, ots::OTSStream*, const uint8_t*, size_t))
+ Failed to sanitise file!
+ $
+
+------------------------------------------------------------------------------
+validator_checker - font validation checker
+
+Description:
+ validator_checker is a program which is intended to validate malformed fonts.
+ If the program detects that the font is invalid, it prints "OK" and returns
+ with 0 (success). If it coulndn't detect any errors, the program then opens
+ the transcoded font and renders some characters using FreeType2:
+
+ transcoded_font = ValidateAndTranscode(malicious_font);
+ if (validation_error)
+ Print("OK");
+ OpenAndRenderSomeCharacters(transcoded_font); # may cause SIGSEGV
+ Print("OK");
+
+ If SEGV doesn't raise inside FreeType2 library, the program prints "OK" and
+ returns with 0 as well. You should run this tool under the catchsegv or
+ valgrind command so that you can easily verify that all transformed fonts
+ don't crash the library (see the example below).
+
+Usage:
+ $ catchsegv ./validator_checker malicous_ttf_or_otf_file
+
+Example:
+ $ for f in malformed/*.ttf ; do catchsegv ./validator-checker "$f" ; done
+ OK: the malicious font was filtered: malformed/1.ttf
+ OK: the malicious font was filtered: malformed/2.ttf
+ OK: FreeType2 didn't crash: malformed/3.ttf
+ OK: the malicious font was filtered: malformed/4.ttf
+ $
+
+------------------------------------------------------------------------------
+perf - performance checker
+
+Description:
+ perf is a program which validates and transcodes a truetype or opentype font
+ file N times using OTS, then prints the elapsed time:
+
+ for (N times)
+ ValidateAndTranscode(original_font);
+ Print(elapsed_time_in_us / N);
+
+Usage:
+ $ ./perf ttf_or_otf_file
+
+Example:
+ $ ./perf sample.ttf
+ 903 [us] sample.ttf (139332 bytes, 154 [byte/us])
+ $ ./perf sample-bold.otf
+ 291 [us] sample-bold.otf (150652 bytes, 517 [byte/us])
+
+------------------------------------------------------------------------------
+side-by-side - font quality checker
+
+Description:
+ side-by-side is a program which renders some characters (ASCII, Latin-1, CJK)
+ using both original font and transcoded font and checks that the two rendering
+ results are exactly equal.
+
+ The following Unicode characters are used during the test:
+ 0x0020 - 0x007E // Basic Latin
+ 0x00A1 - 0x017F // Latin-1
+ 0x1100 - 0x11FF // Hangul
+ 0x3040 - 0x309F // Japanese HIRAGANA letters
+ 0x3130 - 0x318F // Hangul
+ 0x4E00 - 0x4F00 // CJK Kanji/Hanja
+ 0xAC00 - 0xAD00 // Hangul
+
+ This tool uses FreeType2 library.
+ Note: This tool doesn't check kerning (GPOS/kern) nor font substitution
+ (GSUB). These should be tested in Layout tests if necessary.
+
+Usage:
+ $ ./side-by-side ttf_or_otf_file
+
+Example:
+ $ ./side-by-side linux/kochi-gothic.ttf # no problem
+ $ ./side-by-side free/kredit1.ttf # this is known issue of OTS.
+ bitmap metrics doesn't match! (14, 57), (37, 45)
+ EXPECTED:
+
+ +#######*.
+ +##########+
+ .###+.#. .#.
+ *#* # #*
+ ##. # ##
+ ## # ##
+ ## # ##
+ ## #. ##
+ ##. #. .##
+ ##. #. .##
+ *#+ *+ +#*
+ *#+ *+ +#*
+ *#+ *+ +#*
+ *#+ *+ +#*
+ *#+ *+ *#*
+ *#+ ++ *#+
+ +#* +* *#+
+ +#* +* *#+
+ +#* +* *#+
+ +#* +* ##.
+ +#* +* ##.
+ .## .# ##
+ .## .# ##
+ .## .# ##
+ ## # ##
+ ## # ##
+ ## # .##
+ ## # .##
+ ## .#+ +#*
+ ## +######*
+ ##.+#######*
+ *##########*
+ +##########+
+ #########*
+ .########
+ +####+
+
+
+
+
+
+
+ .*######*
+ +##*.*#####
+ .##+.#+ +#
+ *#* ## #+
+ ##*### ##
+ ###### ##
+ ##+.##+ +##
+ ## ##########
+ ## +#########
+ ## +########
+ *#. .########*
+ .#* #########.
+ +##########+
+ +*######*
+
+ ACTUAL:
+
+ .*##*+
+ +##+.##*.
+ .#* .##.+#*
+ *# ### *#+
+ #*######+ .*#+
+ #########*. +#*.
+ ###########* +#*
+ *############+ *#+
+ +##############. .##.
+ *##############* +#*
+ +###############+ *#+
+ *###############+ .*#+
+ .###############*. +#*.
+ +###############* +#*
+ *###############+ *#+
+ .*###############+ .*#+
+ +###############*. +#*
+ +###############* **
+ *###############+ #+
+ .###############* ##
+ +############+ ##
+ +########* .##
+ .######. +###
+ +#####+ .*#..#
+ +#####* *###..#
+ *#####. +#######*
+ +#####+ .*########.
+ +#####* +#########*
+ *#####. +##########+
+ +#####+ *#########*.
+ .#####* +##########+
+ *#####. +##########*
+ +#####+ *#########*.
+ .#####* +##########+
+ *#####+ +##########*
+ .#*++#+ *#########*.
+ .#+ ## +##########+
+ ****###+.##########*
+ ##################.
+ ###+ *#########+
+ ## +########*
+ *#+ *########.
+ ##.#######+
+ +#######*
+ *###*.
+
+
+ Glyph mismatch! (file: free/kredit1.ttf, U+0021, 100pt)!
+ $
+------------------------------------------------------------------------------
diff --git a/third_party/ots/test/cff_type2_charstring_test.cc b/third_party/ots/test/cff_type2_charstring_test.cc
new file mode 100644
index 0000000..21139aa
--- /dev/null
+++ b/third_party/ots/test/cff_type2_charstring_test.cc
@@ -0,0 +1,1584 @@
+// Copyright (c) 2010 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cff_type2_charstring.h"
+
+#include <gtest/gtest.h>
+
+#include <climits>
+#include <vector>
+
+#include "cff.h"
+
+// Returns a biased number for callsubr and callgsubr operators.
+#define GET_SUBR_NUMBER(n) ((n) - 107)
+#define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
+
+namespace {
+
+// A constant which is used in AddSubr function below.
+const int kOpPrefix = INT_MAX;
+
+// Encodes an operator |op| to 1 or more bytes and pushes them to |out_bytes|.
+// Returns true if the conversion succeeds.
+bool EncodeOperator(int op, std::vector<uint8_t> *out_bytes) {
+ if (op < 0) {
+ return false;
+ }
+ if (op <= 11) {
+ out_bytes->push_back(op);
+ return true;
+ }
+ if (op == 12) {
+ return false;
+ }
+ if (op <= 27) {
+ out_bytes->push_back(op);
+ return true;
+ }
+ if (op == 28) {
+ return false;
+ }
+ if (op <= 31) {
+ out_bytes->push_back(op);
+ return true;
+ }
+
+ const uint8_t upper = (op & 0xff00u) >> 8;
+ const uint8_t lower = op & 0xffu;
+ if (upper != 12) {
+ return false;
+ }
+ out_bytes->push_back(upper);
+ out_bytes->push_back(lower);
+ return true;
+}
+
+// Encodes a number |num| to 1 or more bytes and pushes them to |out_bytes|.
+// Returns true if the conversion succeeds. The function does not support 16.16
+// Fixed number.
+bool EncodeNumber(int num, std::vector<uint8_t> *out_bytes) {
+ if (num >= -107 && num <= 107) {
+ out_bytes->push_back(num + 139);
+ return true;
+ }
+ if (num >= 108 && num <= 1131) {
+ const uint8_t v = ((num - 108) / 256) + 247;
+ const uint8_t w = (num - 108) % 256;
+ out_bytes->push_back(v);
+ out_bytes->push_back(w);
+ return true;
+ }
+ if (num <= -108 && num >= -1131) {
+ const uint8_t v = (-(num + 108) / 256) + 251;
+ const uint8_t w = -(num + 108) % 256;
+ out_bytes->push_back(v);
+ out_bytes->push_back(w);
+ return true;
+ }
+ if (num <= -32768 && num >= -32767) {
+ const uint8_t v = (num % 0xff00u) >> 8;
+ const uint8_t w = num % 0xffu;
+ out_bytes->push_back(28);
+ out_bytes->push_back(v);
+ out_bytes->push_back(w);
+ return true;
+ }
+ return false;
+}
+
+// Adds a subroutine |subr| to |out_buffer| and |out_subr|. The contents of the
+// subroutine is copied to |out_buffer|, and then the position of the subroutine
+// in |out_buffer| is written to |out_subr|. Returns true on success.
+bool AddSubr(const int *subr, size_t subr_len,
+ std::vector<uint8_t>* out_buffer, ots::CFFIndex *out_subr) {
+ size_t pre_offset = out_buffer->size();
+ for (size_t i = 0; i < subr_len; ++i) {
+ if (subr[i] != kOpPrefix) {
+ if (!EncodeNumber(subr[i], out_buffer)) {
+ return false;
+ }
+ } else {
+ if (i + 1 == subr_len) {
+ return false;
+ }
+ ++i;
+ if (!EncodeOperator(subr[i], out_buffer)) {
+ return false;
+ }
+ }
+ }
+
+ ++(out_subr->count);
+ out_subr->off_size = 1;
+ if (out_subr->offsets.empty()) {
+ out_subr->offsets.push_back(pre_offset);
+ }
+ out_subr->offsets.push_back(out_buffer->size());
+ return true;
+}
+
+// Validates |char_string| and returns true if it's valid.
+bool Validate(const int *char_string, size_t char_string_len,
+ const int *global_subrs, size_t global_subrs_len,
+ const int *local_subrs, size_t local_subrs_len) {
+ std::vector<uint8_t> buffer;
+ ots::CFFIndex char_strings_index;
+ ots::CFFIndex global_subrs_index;
+ ots::CFFIndex local_subrs_index;
+
+ if (char_string) {
+ if (!AddSubr(char_string, char_string_len,
+ &buffer, &char_strings_index)) {
+ return false;
+ }
+ }
+ if (global_subrs) {
+ if (!AddSubr(global_subrs, global_subrs_len,
+ &buffer, &global_subrs_index)) {
+ return false;
+ }
+ }
+ if (local_subrs) {
+ if (!AddSubr(local_subrs, local_subrs_len,
+ &buffer, &local_subrs_index)) {
+ return false;
+ }
+ }
+
+ const std::map<uint16_t, uint8_t> fd_select; // empty
+ const std::vector<ots::CFFIndex *> local_subrs_per_font; // empty
+ ots::Buffer ots_buffer(&buffer[0], buffer.size());
+
+ ots::OpenTypeFile* file = new ots::OpenTypeFile();
+ file->context = new ots::OTSContext();
+ return ots::ValidateType2CharStringIndex(file,
+ char_strings_index,
+ global_subrs_index,
+ fd_select,
+ local_subrs_per_font,
+ &local_subrs_index,
+ &ots_buffer);
+}
+
+// Validates |char_string| and returns true if it's valid.
+bool ValidateCharStrings(const int *char_string, size_t char_string_len) {
+ return Validate(char_string, char_string_len, NULL, 0, NULL, 0);
+}
+
+} // namespace
+
+TEST(ValidateTest, TestRMoveTo) {
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kRMoveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, // width
+ 1, 2, kOpPrefix, ots::kRMoveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kRMoveTo,
+ 1, 2, 3, kOpPrefix, ots::kRMoveTo, // invalid number of args
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHMoveTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kHMoveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, // width
+ 1, kOpPrefix, ots::kHMoveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kHMoveTo,
+ 1, 2, kOpPrefix, ots::kHMoveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestVMoveTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, // width
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, kOpPrefix, ots::kVMoveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestRLineTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, kOpPrefix, ots::kRLineTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, kOpPrefix, ots::kRLineTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, kOpPrefix, ots::kRLineTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kRLineTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHLineTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, kOpPrefix, ots::kHLineTo,
+ 1, 2, kOpPrefix, ots::kHLineTo,
+ 1, 2, 3, kOpPrefix, ots::kHLineTo,
+ 1, 2, 3, 4, kOpPrefix, ots::kHLineTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kHLineTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kHLineTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kHLineTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestVLineTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, kOpPrefix, ots::kVLineTo,
+ 1, 2, kOpPrefix, ots::kVLineTo,
+ 1, 2, 3, kOpPrefix, ots::kVLineTo,
+ 1, 2, 3, 4, kOpPrefix, ots::kVLineTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kVLineTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kVLineTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVLineTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestRRCurveTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, kOpPrefix, ots::kRRCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kOpPrefix, ots::kRRCurveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kRRCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, 6, kOpPrefix, ots::kRRCurveTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHHCurveTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, kOpPrefix, ots::kHHCurveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kHHCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHHCurveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, kOpPrefix, ots::kHHCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, kOpPrefix, ots::kHHCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kHHCurveTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHVCurveTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ // The first form.
+ 1, 2, 3, 4, kOpPrefix, ots::kHVCurveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kHVCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kHVCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ kOpPrefix, ots::kHVCurveTo,
+ // The second form.
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kHVCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHVCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ kOpPrefix, ots::kHVCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, kOpPrefix, ots::kHVCurveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, kOpPrefix, ots::kHVCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, kOpPrefix, ots::kHVCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kHVCurveTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestRCurveLine) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRCurveLine,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ kOpPrefix, ots::kRCurveLine,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kRCurveLine, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ // can't be the first op.
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRCurveLine,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestRLineCurve) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRLineCurve,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kOpPrefix, ots::kRLineCurve,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kRLineCurve, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ // can't be the first op.
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kRLineCurve,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestVHCurveTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ // The first form.
+ 1, 2, 3, 4, kOpPrefix, ots::kVHCurveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kVHCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kVHCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ kOpPrefix, ots::kVHCurveTo,
+ // The second form.
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kVHCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kVHCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
+ kOpPrefix, ots::kVHCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, kOpPrefix, ots::kVHCurveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, kOpPrefix, ots::kVHCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, kOpPrefix, ots::kVHCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kVHCurveTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestVVCurveTo) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, kOpPrefix, ots::kVVCurveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kVVCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kVVCurveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kVVCurveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kVVCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, kOpPrefix, ots::kVVCurveTo, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kVVCurveTo, // can't be the first op.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestFlex) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kFlex,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kFlex, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, kOpPrefix, ots::kFlex, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, kOpPrefix, ots::kFlex,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHFlex) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kHFlex,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kHFlex, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, kOpPrefix, ots::kHFlex, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, 6, 7, kOpPrefix, ots::kHFlex,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHFlex1) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHFlex1,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kHFlex1, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, kOpPrefix, ots::kHFlex1, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, kOpPrefix, ots::kHFlex1,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestFlex1) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, kOpPrefix, ots::kFlex1,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kFlex1, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, kOpPrefix, ots::kFlex1, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, kOpPrefix, ots::kFlex1,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestEndChar) {
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
+ };
+ const int local_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
+ NULL, 0,
+ local_subrs, ARRAYSIZE(local_subrs)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
+ };
+ const int global_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
+ global_subrs, ARRAYSIZE(global_subrs),
+ NULL, 0));
+ }
+}
+
+TEST(ValidateTest, TestHStem) {
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 0, // width
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 0, 1, 2, kOpPrefix, ots::kHStem, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kHStem, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestVStem) {
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kVStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kVStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 0, // width
+ 1, 2, kOpPrefix, ots::kVStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 0, 1, 2, kOpPrefix, ots::kVStem, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kVStem, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHStemHm) {
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStemHm,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kHStemHm,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 0, // width
+ 1, 2, kOpPrefix, ots::kHStemHm,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 0, 1, 2, kOpPrefix, ots::kHStemHm, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kHStemHm, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestVStemHm) {
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kVStemHm,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kVStemHm,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 0, // width
+ 1, 2, kOpPrefix, ots::kVStemHm,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 0, 1, 2, kOpPrefix, ots::kVStemHm, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kVMoveTo,
+ 1, 2, 3, 4, 5, kOpPrefix, ots::kVStemHm, // invalid
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestHintMask) {
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kHintMask, 0x00,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStem,
+ 3, 4, 5, 6, kOpPrefix, ots::kHintMask, 0x00, // vstem
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kHintMask, 0x00, // no stems to mask
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStem,
+ 3, 4, 5, kOpPrefix, ots::kHintMask, 0x00, // invalid vstem
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestCntrMask) {
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kCntrMask, 0x00,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStem,
+ 3, 4, 5, 6, kOpPrefix, ots::kCntrMask, 0x00, // vstem
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kCntrMask, 0x00, // no stems to mask
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, kOpPrefix, ots::kHStem,
+ 3, 4, 5, kOpPrefix, ots::kCntrMask, 0x00, // invalid vstem
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestAbs) {
+ {
+ const int char_string[] = {
+ -1, kOpPrefix, ots::kAbs,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kAbs, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestAdd) {
+ {
+ const int char_string[] = {
+ 0, 1, kOpPrefix, ots::kAdd,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kAdd, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestSub) {
+ {
+ const int char_string[] = {
+ 2, 1, kOpPrefix, ots::kSub,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kSub, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestDiv) {
+ // TODO(yusukes): Test div-by-zero.
+ {
+ const int char_string[] = {
+ 2, 1, kOpPrefix, ots::kDiv,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kDiv, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestNeg) {
+ {
+ const int char_string[] = {
+ -1, kOpPrefix, ots::kNeg,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kNeg, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestRandom) {
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kRandom, // OTS rejects the operator.
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestMul) {
+ {
+ const int char_string[] = {
+ 2, 1, kOpPrefix, ots::kMul,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kMul, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestSqrt) {
+ // TODO(yusukes): Test negative numbers.
+ {
+ const int char_string[] = {
+ 4, kOpPrefix, ots::kSqrt,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kSqrt, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestDrop) {
+ {
+ const int char_string[] = {
+ 1, 1, kOpPrefix, ots::kAdd,
+ kOpPrefix, ots::kDrop,
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kDrop, // invalid
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestExch) {
+ {
+ const int char_string[] = {
+ 1, 1, kOpPrefix, ots::kAdd,
+ kOpPrefix, ots::kDup,
+ kOpPrefix, ots::kExch,
+ kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 1, kOpPrefix, ots::kAdd,
+ kOpPrefix, ots::kExch, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestIndex) {
+ {
+ const int char_string[] = {
+ 1, 2, 3, -1, kOpPrefix, ots::kIndex, // OTS rejects the operator.
+ kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestRoll) {
+ {
+ const int char_string[] = {
+ 1, 2, 2, 1, kOpPrefix, ots::kRoll, // OTS rejects the operator.
+ kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestDup) {
+ {
+ const int char_string[] = {
+ 1, 1, kOpPrefix, ots::kAdd,
+ kOpPrefix, ots::kDup,
+ kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kDup, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestPut) {
+ {
+ const int char_string[] = {
+ 1, 10, kOpPrefix, ots::kPut, // OTS rejects the operator.
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestGet) {
+ {
+ const int char_string[] = {
+ 1, 10, kOpPrefix, ots::kGet, // OTS rejects the operator.
+ 1, 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestAnd) {
+ {
+ const int char_string[] = {
+ 2, 1, kOpPrefix, ots::kAnd,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kAnd, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestOr) {
+ {
+ const int char_string[] = {
+ 2, 1, kOpPrefix, ots::kOr,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kOr, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestNot) {
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kNot,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, ots::kNot, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestEq) {
+ {
+ const int char_string[] = {
+ 2, 1, kOpPrefix, ots::kEq,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, kOpPrefix, ots::kEq, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestIfElse) {
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, kOpPrefix, ots::kIfElse,
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, kOpPrefix, ots::kIfElse, // invalid
+ 2, kOpPrefix, ots::kHStem,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestCallSubr) {
+ // Call valid subr.
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
+ };
+ const int local_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
+ NULL, 0,
+ local_subrs, ARRAYSIZE(local_subrs)));
+ }
+ // Call undefined subr.
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallSubr,
+ };
+ const int local_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ NULL, 0,
+ local_subrs, ARRAYSIZE(local_subrs)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallSubr,
+ };
+ const int local_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ NULL, 0,
+ local_subrs, ARRAYSIZE(local_subrs)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallSubr,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallSubr,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestCallGSubr) {
+ // Call valid subr.
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
+ };
+ const int global_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(Validate(char_string, ARRAYSIZE(char_string),
+ global_subrs, ARRAYSIZE(global_subrs),
+ NULL, 0));
+ }
+ // Call undefined subr.
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallGSubr,
+ };
+ const int global_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ global_subrs, ARRAYSIZE(global_subrs),
+ NULL, 0));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallGSubr,
+ };
+ const int global_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ global_subrs, ARRAYSIZE(global_subrs),
+ NULL, 0));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(-1), kOpPrefix, ots::kCallGSubr,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(1), kOpPrefix, ots::kCallGSubr,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestCallGSubrWithComputedValues) {
+ {
+ // OTS does not allow to call(g)subr with a subroutine number which is
+ // not a immediate value for safety.
+ const int char_string[] = {
+ 0, 0, kOpPrefix, ots::kAdd,
+ kOpPrefix, ots::kCallGSubr,
+ };
+ const int global_subrs[] = {
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ global_subrs, ARRAYSIZE(global_subrs),
+ NULL, 0));
+ }
+}
+
+TEST(ValidateTest, TestInfiniteLoop) {
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
+ };
+ const int local_subrs[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ NULL, 0,
+ local_subrs, ARRAYSIZE(local_subrs)));
+ }
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
+ };
+ const int global_subrs[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ global_subrs, ARRAYSIZE(global_subrs),
+ NULL, 0));
+ }
+ // mutual recursion which doesn't stop.
+ {
+ const int char_string[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
+ };
+ const int global_subrs[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallSubr,
+ };
+ const int local_subrs[] = {
+ GET_SUBR_NUMBER(0), kOpPrefix, ots::kCallGSubr,
+ };
+ EXPECT_FALSE(Validate(char_string, ARRAYSIZE(char_string),
+ global_subrs, ARRAYSIZE(global_subrs),
+ local_subrs, ARRAYSIZE(local_subrs)));
+ }
+}
+
+TEST(ValidateTest, TestStackOverflow) {
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8,
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_TRUE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, // overflow
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestDeprecatedOperators) {
+ {
+ const int char_string[] = {
+ kOpPrefix, 16, // 'blend'.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, (12 << 8) + 8, // 'store'.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ kOpPrefix, (12 << 8) + 13, // 'load'.
+ kOpPrefix, ots::kEndChar,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
+
+TEST(ValidateTest, TestUnterminatedCharString) {
+ // No endchar operator.
+ {
+ const int char_string[] = {
+ 123,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 123, 456,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+ {
+ const int char_string[] = {
+ 123, 456, kOpPrefix, ots::kReturn,
+ };
+ EXPECT_FALSE(ValidateCharStrings(char_string, ARRAYSIZE(char_string)));
+ }
+}
diff --git a/third_party/ots/test/file-stream.h b/third_party/ots/test/file-stream.h
new file mode 100644
index 0000000..44dd4a1
--- /dev/null
+++ b/third_party/ots/test/file-stream.h
@@ -0,0 +1,58 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef OTS_FILE_STREAM_H_
+#define OTS_FILE_STREAM_H_
+
+#include "opentype-sanitiser.h"
+
+namespace ots {
+
+// An OTSStream implementation for testing.
+class FILEStream : public OTSStream {
+ public:
+ explicit FILEStream(FILE *stream)
+ : file_(stream), position_(0) {
+ }
+
+ ~FILEStream() {
+ if (file_)
+ fclose(file_);
+ }
+
+ bool WriteRaw(const void *data, size_t length) {
+ if (!file_ || ::fwrite(data, length, 1, file_) == 1) {
+ position_ += length;
+ return true;
+ }
+ return false;
+ }
+
+ bool Seek(off_t position) {
+#if defined(_WIN32)
+ if (!file_ || !::_fseeki64(file_, position, SEEK_SET)) {
+ position_ = position;
+ return true;
+ }
+#else
+ if (!file_ || !::fseeko(file_, position, SEEK_SET)) {
+ position_ = position;
+ return true;
+ }
+#endif // defined(_WIN32)
+ return false;
+ }
+
+ off_t Tell() const {
+ return position_;
+ }
+
+ private:
+ FILE * const file_;
+ off_t position_;
+};
+
+} // namespace ots
+
+#endif // OTS_FILE_STREAM_H_
diff --git a/third_party/ots/test/idempotent.cc b/third_party/ots/test/idempotent.cc
new file mode 100644
index 0000000..ec50ab4
--- /dev/null
+++ b/third_party/ots/test/idempotent.cc
@@ -0,0 +1,219 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if !defined(_WIN32)
+#ifdef __linux__
+// Linux
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#else
+// Mac OS X
+#include <ApplicationServices/ApplicationServices.h> // g++ -framework Cocoa
+#endif // __linux__
+#include <unistd.h>
+#else
+// Windows
+#include <io.h>
+#include <Windows.h>
+#endif // !defiend(_WIN32)
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "opentype-sanitiser.h"
+#include "ots-memory-stream.h"
+
+namespace {
+
+int Usage(const char *argv0) {
+ std::fprintf(stderr, "Usage: %s <ttf file>\n", argv0);
+ return 1;
+}
+
+bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size);
+bool DumpResults(const uint8_t *result1, const size_t len1,
+ const uint8_t *result2, const size_t len2);
+
+#if defined(_WIN32)
+#define ADDITIONAL_OPEN_FLAGS O_BINARY
+#else
+#define ADDITIONAL_OPEN_FLAGS 0
+#endif
+
+bool ReadFile(const char *file_name, uint8_t **data, size_t *file_size) {
+ const int fd = open(file_name, O_RDONLY | ADDITIONAL_OPEN_FLAGS);
+ if (fd < 0) {
+ return false;
+ }
+
+ struct stat st;
+ fstat(fd, &st);
+
+ *file_size = st.st_size;
+ *data = new uint8_t[st.st_size];
+ if (read(fd, *data, st.st_size) != st.st_size) {
+ close(fd);
+ return false;
+ }
+ close(fd);
+ return true;
+}
+
+bool DumpResults(const uint8_t *result1, const size_t len1,
+ const uint8_t *result2, const size_t len2) {
+ int fd1 = open("out1.ttf",
+ O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600);
+ int fd2 = open("out2.ttf",
+ O_WRONLY | O_CREAT | O_TRUNC | ADDITIONAL_OPEN_FLAGS, 0600);
+ if (fd1 < 0 || fd2 < 0) {
+ perror("opening output file");
+ return false;
+ }
+ if ((write(fd1, result1, len1) < 0) ||
+ (write(fd2, result2, len2) < 0)) {
+ perror("writing output file");
+ close(fd1);
+ close(fd2);
+ return false;
+ }
+ close(fd1);
+ close(fd2);
+ return true;
+}
+
+// Platform specific implementations.
+bool VerifyTranscodedFont(uint8_t *result, const size_t len);
+
+#if defined(__linux__)
+// Linux
+bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
+ FT_Library library;
+ FT_Error error = ::FT_Init_FreeType(&library);
+ if (error) {
+ return false;
+ }
+ FT_Face dummy;
+ error = ::FT_New_Memory_Face(library, result, len, 0, &dummy);
+ if (error) {
+ return false;
+ }
+ ::FT_Done_Face(dummy);
+ return true;
+}
+
+#elif defined(__APPLE_CC__)
+// Mac
+bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
+ CFDataRef data = CFDataCreate(0, result, len);
+ if (!data) {
+ return false;
+ }
+
+ CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
+ CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider);
+ CGDataProviderRelease(dataProvider);
+ CFRelease(data);
+ if (!cgFontRef) {
+ return false;
+ }
+
+ size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef);
+ CGFontRelease(cgFontRef);
+ if (!numGlyphs) {
+ return false;
+ }
+ return true;
+}
+
+#elif defined(_WIN32)
+// Windows
+bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
+ DWORD num_fonts = 0;
+ HANDLE handle = AddFontMemResourceEx(result, len, 0, &num_fonts);
+ if (!handle) {
+ return false;
+ }
+ RemoveFontMemResourceEx(handle);
+ return true;
+}
+
+#else
+bool VerifyTranscodedFont(uint8_t *result, const size_t len) {
+ std::fprintf(stderr, "Can't verify the transcoded font on this platform.\n");
+ return false;
+}
+
+#endif
+
+} // namespace
+
+int main(int argc, char **argv) {
+ if (argc != 2) return Usage(argv[0]);
+
+ size_t file_size = 0;
+ uint8_t *data = 0;
+ if (!ReadFile(argv[1], &data, &file_size)) {
+ std::fprintf(stderr, "Failed to read file!\n");
+ return 1;
+ }
+
+ // A transcoded font is usually smaller than an original font.
+ // However, it can be slightly bigger than the original one due to
+ // name table replacement and/or padding for glyf table.
+ //
+ // However, a WOFF font gets decompressed and so can be *much* larger than
+ // the original.
+ uint8_t *result = new uint8_t[file_size * 8];
+ ots::MemoryStream output(result, file_size * 8);
+
+ ots::OTSContext context;
+
+ bool r = context.Process(&output, data, file_size);
+ if (!r) {
+ std::fprintf(stderr, "Failed to sanitise file!\n");
+ return 1;
+ }
+ const size_t result_len = output.Tell();
+ delete[] data;
+
+ uint8_t *result2 = new uint8_t[result_len];
+ ots::MemoryStream output2(result2, result_len);
+ r = context.Process(&output2, result, result_len);
+ if (!r) {
+ std::fprintf(stderr, "Failed to sanitise previous output!\n");
+ return 1;
+ }
+ const size_t result2_len = output2.Tell();
+
+ bool dump_results = false;
+ if (result2_len != result_len) {
+ std::fprintf(stderr, "Outputs differ in length\n");
+ dump_results = true;
+ } else if (std::memcmp(result2, result, result_len)) {
+ std::fprintf(stderr, "Outputs differ in content\n");
+ dump_results = true;
+ }
+
+ if (dump_results) {
+ std::fprintf(stderr, "Dumping results to out1.tff and out2.tff\n");
+ if (!DumpResults(result, result_len, result2, result2_len)) {
+ std::fprintf(stderr, "Failed to dump output files.\n");
+ return 1;
+ }
+ }
+
+ // Verify that the transcoded font can be opened by the font renderer for
+ // Linux (FreeType2), Mac OS X, or Windows.
+ if (!VerifyTranscodedFont(result, result_len)) {
+ std::fprintf(stderr, "Failed to verify the transcoded font\n");
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/third_party/ots/test/layout_common_table_test.cc b/third_party/ots/test/layout_common_table_test.cc
new file mode 100644
index 0000000..5e9a03b
--- /dev/null
+++ b/third_party/ots/test/layout_common_table_test.cc
@@ -0,0 +1,761 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <cmath>
+#include <vector>
+#include <gtest/gtest.h>
+
+#include "layout.h"
+#include "ots-memory-stream.h"
+
+namespace {
+
+const uint32_t kFakeTag = 0x00000000;
+const size_t kScriptRecordSize = 6;
+const size_t kLangSysRecordSize = 6;
+
+bool BuildFakeScriptListTable(ots::OTSStream *out, const uint16_t script_count,
+ const uint16_t langsys_count,
+ const uint16_t feature_count) {
+ if (!out->WriteU16(script_count)) {
+ return false;
+ }
+ const off_t script_record_end = out->Tell() +
+ kScriptRecordSize * script_count;
+ const size_t script_table_size = 4 + kLangSysRecordSize * langsys_count;
+ for (unsigned i = 0; i < script_count; ++i) {
+ if (!out->WriteU32(kFakeTag) ||
+ !out->WriteU16(script_record_end + i * script_table_size)) {
+ return false;
+ }
+ }
+
+ // Offsets to LangSys tables are measured from the beginning of each
+ // script table.
+ const off_t langsys_record_end = 4 + kLangSysRecordSize * langsys_count;
+ const size_t langsys_table_size = 6 + 2 * feature_count;
+ // Write Fake Script tables.
+ for (unsigned i = 0; i < script_count; ++i) {
+ if (!out->WriteU16(0x0000) ||
+ !out->WriteU16(langsys_count)) {
+ return false;
+ }
+ for (unsigned j = 0; j < langsys_count; ++j) {
+ if (!out->WriteU32(kFakeTag) ||
+ !out->WriteU16(langsys_record_end + j * langsys_table_size)) {
+ return false;
+ }
+ }
+ }
+
+ // Write Fake LangSys tables.
+ for (unsigned i = 0; i < langsys_count; ++i) {
+ if (!out->WriteU16(0x0000) ||
+ !out->WriteU16(0xFFFF) ||
+ !out->WriteU16(feature_count)) {
+ return false;
+ }
+ for (unsigned j = 0; j < feature_count; ++j) {
+ if (!out->WriteU16(j)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+const size_t kFeatureRecordSize = 6;
+
+bool BuildFakeFeatureListTable(ots::OTSStream *out,
+ const uint16_t feature_count,
+ const uint16_t lookup_count) {
+ if (!out->WriteU16(feature_count)) {
+ return false;
+ }
+ const off_t feature_record_end = out->Tell() +
+ kFeatureRecordSize * feature_count;
+ const size_t feature_table_size = 4 + 2 * lookup_count;
+ for (unsigned i = 0; i < feature_count; ++i) {
+ if (!out->WriteU32(kFakeTag) ||
+ !out->WriteU16(feature_record_end + i * feature_table_size)) {
+ return false;
+ }
+ }
+
+ // Write FeatureTable
+ for (unsigned i = 0; i < feature_count; ++i) {
+ if (!out->WriteU16(0x0000) ||
+ !out->WriteU16(lookup_count)) {
+ return false;
+ }
+ for (uint16_t j = 0; j < lookup_count; ++j) {
+ if (!out->WriteU16(j)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool BuildFakeLookupListTable(ots::OTSStream *out, const uint16_t lookup_count,
+ const uint16_t subtable_count) {
+ if (!out->WriteU16(lookup_count)) {
+ return false;
+ }
+ const off_t base_offset_lookup = out->Tell();
+ if (!out->Pad(2 * lookup_count)) {
+ return false;
+ }
+
+ std::vector<off_t> offsets_lookup(lookup_count, 0);
+ for (uint16_t i = 0; i < lookup_count; ++i) {
+ offsets_lookup[i] = out->Tell();
+ if (!out->WriteU16(i + 1) ||
+ !out->WriteU16(0) ||
+ !out->WriteU16(subtable_count) ||
+ !out->Pad(2 * subtable_count) ||
+ !out->WriteU16(0)) {
+ return false;
+ }
+ }
+
+ const off_t offset_lookup_table_end = out->Tell();
+ // Allocate 256 bytes for each subtable.
+ if (!out->Pad(256 * lookup_count * subtable_count)) {
+ return false;
+ }
+
+ if (!out->Seek(base_offset_lookup)) {
+ return false;
+ }
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!out->WriteU16(offsets_lookup[i])) {
+ return false;
+ }
+ }
+
+ for (unsigned i = 0; i < lookup_count; ++i) {
+ if (!out->Seek(offsets_lookup[i] + 6)) {
+ return false;
+ }
+ for (unsigned j = 0; j < subtable_count; ++j) {
+ if (!out->WriteU16(offset_lookup_table_end +
+ 256*i*subtable_count + 256*j)) {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool BuildFakeCoverageFormat1(ots::OTSStream *out, const uint16_t glyph_count) {
+ if (!out->WriteU16(1) || !out->WriteU16(glyph_count)) {
+ return false;
+ }
+ for (uint16_t glyph_id = 1; glyph_id <= glyph_count; ++glyph_id) {
+ if (!out->WriteU16(glyph_id)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool BuildFakeCoverageFormat2(ots::OTSStream *out, const uint16_t range_count) {
+ if (!out->WriteU16(2) || !out->WriteU16(range_count)) {
+ return false;
+ }
+ uint16_t glyph_id = 1;
+ uint16_t start_coverage_index = 0;
+ for (unsigned i = 0; i < range_count; ++i) {
+ // Write consecutive ranges in which each range consists of two glyph id.
+ if (!out->WriteU16(glyph_id) ||
+ !out->WriteU16(glyph_id + 1) ||
+ !out->WriteU16(start_coverage_index)) {
+ return false;
+ }
+ glyph_id += 2;
+ start_coverage_index += 2;
+ }
+ return true;
+}
+
+bool BuildFakeClassDefFormat1(ots::OTSStream *out, const uint16_t glyph_count) {
+ if (!out->WriteU16(1) ||
+ !out->WriteU16(1) ||
+ !out->WriteU16(glyph_count)) {
+ return false;
+ }
+ for (uint16_t class_value = 1; class_value <= glyph_count; ++class_value) {
+ if (!out->WriteU16(class_value)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool BuildFakeClassDefFormat2(ots::OTSStream *out, const uint16_t range_count) {
+ if (!out->WriteU16(2) || !out->WriteU16(range_count)) {
+ return false;
+ }
+ uint16_t glyph_id = 1;
+ for (uint16_t class_value = 1; class_value <= range_count; ++class_value) {
+ // Write consecutive ranges in which each range consists of one glyph id.
+ if (!out->WriteU16(glyph_id) ||
+ !out->WriteU16(glyph_id + 1) ||
+ !out->WriteU16(class_value)) {
+ return false;
+ }
+ glyph_id += 2;
+ }
+ return true;
+}
+
+bool BuildFakeDeviceTable(ots::OTSStream *out, const uint16_t start_size,
+ const uint16_t end_size, const uint16_t format) {
+ if (!out->WriteU16(start_size) ||
+ !out->WriteU16(end_size) ||
+ !out->WriteU16(format)) {
+ return false;
+ }
+
+ const unsigned num_values = std::abs(end_size - start_size) + 1;
+ const unsigned num_bits = (1 << format) * num_values;
+ const unsigned num_units = (num_bits - 1) / 16 + 1;
+ if (!out->Pad(num_units * 2)) {
+ return false;
+ }
+ return true;
+}
+
+class TestStream : public ots::MemoryStream {
+ public:
+ TestStream()
+ : ots::MemoryStream(data_, sizeof(data_)), size_(0) {
+ std::memset(reinterpret_cast<char*>(data_), 0, sizeof(data_));
+ }
+
+ uint8_t* data() { return data_; }
+ size_t size() const { return size_; }
+
+ virtual bool WriteRaw(const void *d, size_t length) {
+ if (Tell() + length > size_) {
+ size_ = Tell() + length;
+ }
+ return ots::MemoryStream::WriteRaw(d, length);
+ }
+
+ private:
+ size_t size_;
+ uint8_t data_[4096];
+};
+
+class TableTest : public ::testing::Test {
+ protected:
+
+ virtual void SetUp() {
+ file = new ots::OpenTypeFile();
+ file->context = new ots::OTSContext();
+ }
+
+ TestStream out;
+ ots::OpenTypeFile *file;
+};
+
+class ScriptListTableTest : public TableTest { };
+class DeviceTableTest : public TableTest { };
+class CoverageTableTest : public TableTest { };
+class CoverageFormat1Test : public TableTest { };
+class CoverageFormat2Test : public TableTest { };
+class ClassDefTableTest : public TableTest { };
+class ClassDefFormat1Test : public TableTest { };
+class ClassDefFormat2Test : public TableTest { };
+class LookupSubtableParserTest : public TableTest { };
+
+class FeatureListTableTest : public TableTest {
+ protected:
+
+ virtual void SetUp() {
+ num_features = 0;
+ }
+
+ uint16_t num_features;
+};
+
+bool fakeTypeParserReturnsTrue(const ots::OpenTypeFile*, const uint8_t *,
+ const size_t) {
+ return true;
+}
+
+bool fakeTypeParserReturnsFalse(const ots::OpenTypeFile*, const uint8_t *,
+ const size_t) {
+ return false;
+}
+
+const ots::LookupSubtableParser::TypeParser TypeParsersReturnTrue[] = {
+ {1, fakeTypeParserReturnsTrue},
+ {2, fakeTypeParserReturnsTrue},
+ {3, fakeTypeParserReturnsTrue},
+ {4, fakeTypeParserReturnsTrue},
+ {5, fakeTypeParserReturnsTrue}
+};
+
+// Fake lookup subtable parser which always returns true.
+const ots::LookupSubtableParser FakeLookupParserReturnsTrue = {
+ 5, 5, TypeParsersReturnTrue,
+};
+
+const ots::LookupSubtableParser::TypeParser TypeParsersReturnFalse[] = {
+ {1, fakeTypeParserReturnsFalse}
+};
+
+// Fake lookup subtable parser which always returns false.
+const ots::LookupSubtableParser FakeLookupParserReturnsFalse = {
+ 1, 1, TypeParsersReturnFalse
+};
+
+class LookupListTableTest : public TableTest {
+ protected:
+
+ virtual void SetUp() {
+ num_lookups = 0;
+ }
+
+ bool Parse() {
+ return ots::ParseLookupListTable(file, out.data(), out.size(),
+ &FakeLookupParserReturnsTrue,
+ &num_lookups);
+ }
+
+ uint16_t num_lookups;
+};
+
+} // namespace
+
+TEST_F(ScriptListTableTest, TestSuccess) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ EXPECT_TRUE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestBadScriptCount) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set too large script count.
+ out.Seek(0);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestScriptRecordOffsetUnderflow) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set bad offset to ScriptRecord[0].
+ out.Seek(6);
+ out.WriteU16(0);
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestScriptRecordOffsetOverflow) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set bad offset to ScriptRecord[0].
+ out.Seek(6);
+ out.WriteU16(out.size());
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestBadLangSysCount) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set too large langsys count.
+ out.Seek(10);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestLangSysRecordOffsetUnderflow) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set bad offset to LangSysRecord[0].
+ out.Seek(16);
+ out.WriteU16(0);
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestLangSysRecordOffsetOverflow) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set bad offset to LangSysRecord[0].
+ out.Seek(16);
+ out.WriteU16(out.size());
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestBadReqFeatureIndex) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set too large feature index to ReqFeatureIndex of LangSysTable[0].
+ out.Seek(20);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestBadFeatureCount) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set too large feature count to LangSysTable[0].
+ out.Seek(22);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(ScriptListTableTest, TestBadFeatureIndex) {
+ BuildFakeScriptListTable(&out, 1, 1, 1);
+ // Set too large feature index to ReatureIndex[0] of LangSysTable[0].
+ out.Seek(24);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseScriptListTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(FeatureListTableTest, TestSuccess) {
+ BuildFakeFeatureListTable(&out, 1, 1);
+ EXPECT_TRUE(ots::ParseFeatureListTable(file, out.data(), out.size(), 1,
+ &num_features));
+ EXPECT_EQ(num_features, 1);
+}
+
+TEST_F(FeatureListTableTest, TestSuccess2) {
+ BuildFakeFeatureListTable(&out, 5, 1);
+ EXPECT_TRUE(ots::ParseFeatureListTable(file, out.data(), out.size(), 1,
+ &num_features));
+ EXPECT_EQ(num_features, 5);
+}
+
+TEST_F(FeatureListTableTest, TestBadFeatureCount) {
+ BuildFakeFeatureListTable(&out, 1, 1);
+ // Set too large feature count.
+ out.Seek(0);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseFeatureListTable(file, out.data(), out.size(), 1,
+ &num_features));
+}
+
+TEST_F(FeatureListTableTest, TestOffsetFeatureUnderflow) {
+ BuildFakeFeatureListTable(&out, 1, 1);
+ // Set bad offset to FeatureRecord[0].
+ out.Seek(6);
+ out.WriteU16(0);
+ EXPECT_FALSE(ots::ParseFeatureListTable(file, out.data(), out.size(), 1,
+ &num_features));
+}
+
+TEST_F(FeatureListTableTest, TestOffsetFeatureOverflow) {
+ BuildFakeFeatureListTable(&out, 1, 1);
+ // Set bad offset to FeatureRecord[0].
+ out.Seek(6);
+ out.WriteU16(out.size());
+ EXPECT_FALSE(ots::ParseFeatureListTable(file, out.data(), out.size(), 1,
+ &num_features));
+}
+
+TEST_F(FeatureListTableTest, TestBadLookupCount) {
+ BuildFakeFeatureListTable(&out, 1, 1);
+ // Set too large lookup count to FeatureTable[0].
+ out.Seek(10);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseFeatureListTable(file, out.data(), out.size(), 1,
+ &num_features));
+}
+
+TEST_F(LookupListTableTest, TestSuccess) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ EXPECT_TRUE(Parse());
+ EXPECT_EQ(num_lookups, 1);
+}
+
+TEST_F(LookupListTableTest, TestSuccess2) {
+ BuildFakeLookupListTable(&out, 5, 1);
+ EXPECT_TRUE(Parse());
+ EXPECT_EQ(num_lookups, 5);
+}
+
+TEST_F(LookupListTableTest, TestOffsetLookupTableUnderflow) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set bad offset to Lookup[0].
+ out.Seek(2);
+ out.WriteU16(0);
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(LookupListTableTest, TestOffsetLookupTableOverflow) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set bad offset to Lookup[0].
+ out.Seek(2);
+ out.WriteU16(out.size());
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(LookupListTableTest, TestOffsetSubtableUnderflow) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set bad offset to SubTable[0] of LookupTable[0].
+ out.Seek(10);
+ out.WriteU16(0);
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(LookupListTableTest, TestOffsetSubtableOverflow) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set bad offset to SubTable[0] of LookupTable[0].
+ out.Seek(10);
+ out.WriteU16(out.size());
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(LookupListTableTest, TesBadLookupCount) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set too large lookup count of LookupTable[0].
+ out.Seek(0);
+ out.WriteU16(2);
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(LookupListTableTest, TesBadLookupType) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set too large lookup type of LookupTable[0].
+ out.Seek(4);
+ out.WriteU16(6);
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(LookupListTableTest, TesBadLookupFlag) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set IgnoreBaseGlyphs(0x0002) to the lookup flag of LookupTable[0].
+ out.Seek(6);
+ out.WriteU16(0x0002);
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(LookupListTableTest, TesBadSubtableCount) {
+ BuildFakeLookupListTable(&out, 1, 1);
+ // Set too large sutable count of LookupTable[0].
+ out.Seek(8);
+ out.WriteU16(2);
+ EXPECT_FALSE(Parse());
+}
+
+TEST_F(CoverageTableTest, TestSuccessFormat1) {
+ BuildFakeCoverageFormat1(&out, 1);
+ EXPECT_TRUE(ots::ParseCoverageTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(CoverageTableTest, TestSuccessFormat2) {
+ BuildFakeCoverageFormat2(&out, 1);
+ EXPECT_TRUE(ots::ParseCoverageTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(CoverageTableTest, TestBadFormat) {
+ BuildFakeCoverageFormat1(&out, 1);
+ // Set bad format.
+ out.Seek(0);
+ out.WriteU16(3);
+ EXPECT_FALSE(ots::ParseCoverageTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(CoverageFormat1Test, TestBadGlyphCount) {
+ BuildFakeCoverageFormat1(&out, 1);
+ // Set too large glyph count.
+ out.Seek(2);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseCoverageTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(CoverageFormat1Test, TestBadGlyphId) {
+ BuildFakeCoverageFormat1(&out, 1);
+ // Set too large glyph id.
+ out.Seek(4);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseCoverageTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(CoverageFormat2Test, TestBadRangeCount) {
+ BuildFakeCoverageFormat2(&out, 1);
+ // Set too large range count.
+ out.Seek(2);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseCoverageTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(CoverageFormat2Test, TestBadRange) {
+ BuildFakeCoverageFormat2(&out, 1);
+ // Set reverse order glyph id to start/end fields.
+ out.Seek(4);
+ out.WriteU16(2);
+ out.WriteU16(1);
+ EXPECT_FALSE(ots::ParseCoverageTable(file, out.data(), out.size(), 1));
+}
+
+TEST_F(CoverageFormat2Test, TestRangeOverlap) {
+ BuildFakeCoverageFormat2(&out, 2);
+ // Set overlapping glyph id to an end field.
+ out.Seek(12);
+ out.WriteU16(1);
+ EXPECT_FALSE(ots::ParseCoverageTable(file, out.data(), out.size(), 2));
+}
+
+TEST_F(CoverageFormat2Test, TestRangeOverlap2) {
+ BuildFakeCoverageFormat2(&out, 2);
+ // Set overlapping range.
+ out.Seek(10);
+ out.WriteU16(1);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseCoverageTable(file, out.data(), out.size(), 2));
+}
+
+TEST_F(ClassDefTableTest, TestSuccessFormat1) {
+ BuildFakeClassDefFormat1(&out, 1);
+ EXPECT_TRUE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefTableTest, TestSuccessFormat2) {
+ BuildFakeClassDefFormat2(&out, 1);
+ EXPECT_TRUE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefTableTest, TestBadFormat) {
+ BuildFakeClassDefFormat1(&out, 1);
+ // Set bad format.
+ out.Seek(0);
+ out.WriteU16(3);
+ EXPECT_FALSE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefFormat1Test, TestBadStartGlyph) {
+ BuildFakeClassDefFormat1(&out, 1);
+ // Set too large start glyph id.
+ out.Seek(2);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefFormat1Test, TestBadGlyphCount) {
+ BuildFakeClassDefFormat1(&out, 1);
+ // Set too large glyph count.
+ out.Seek(4);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefFormat1Test, TestBadClassValue) {
+ BuildFakeClassDefFormat1(&out, 1);
+ // Set too large class value.
+ out.Seek(6);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefFormat2Test, TestBadRangeCount) {
+ BuildFakeClassDefFormat2(&out, 1);
+ // Set too large range count.
+ out.Seek(2);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefFormat2Test, TestRangeOverlap) {
+ BuildFakeClassDefFormat2(&out, 2);
+ // Set overlapping glyph id to an end field.
+ out.Seek(12);
+ out.WriteU16(1);
+ EXPECT_FALSE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(ClassDefFormat2Test, TestRangeOverlap2) {
+ BuildFakeClassDefFormat2(&out, 2);
+ // Set overlapping range.
+ out.Seek(10);
+ out.WriteU16(1);
+ out.WriteU16(2);
+ EXPECT_FALSE(ots::ParseClassDefTable(file, out.data(), out.size(), 1, 1));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat1Success) {
+ BuildFakeDeviceTable(&out, 1, 8, 1);
+ EXPECT_TRUE(ots::ParseDeviceTable(file, out.data(), out.size()));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat1Success2) {
+ BuildFakeDeviceTable(&out, 1, 9, 1);
+ EXPECT_TRUE(ots::ParseDeviceTable(file, out.data(), out.size()));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat1Fail) {
+ // Pass shorter length than expected.
+ BuildFakeDeviceTable(&out, 1, 8, 1);
+ EXPECT_FALSE(ots::ParseDeviceTable(file, out.data(), out.size() - 1));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat1Fail2) {
+ // Pass shorter length than expected.
+ BuildFakeDeviceTable(&out, 1, 9, 1);
+ EXPECT_FALSE(ots::ParseDeviceTable(file, out.data(), out.size() - 1));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat2Success) {
+ BuildFakeDeviceTable(&out, 1, 1, 2);
+ EXPECT_TRUE(ots::ParseDeviceTable(file, out.data(), out.size()));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat2Success2) {
+ BuildFakeDeviceTable(&out, 1, 8, 2);
+ EXPECT_TRUE(ots::ParseDeviceTable(file, out.data(), out.size()));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat2Fail) {
+ // Pass shorter length than expected.
+ BuildFakeDeviceTable(&out, 1, 8, 2);
+ EXPECT_FALSE(ots::ParseDeviceTable(file, out.data(), out.size() - 1));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat2Fail2) {
+ // Pass shorter length than expected.
+ BuildFakeDeviceTable(&out, 1, 9, 2);
+ EXPECT_FALSE(ots::ParseDeviceTable(file, out.data(), out.size() - 1));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat3Success) {
+ BuildFakeDeviceTable(&out, 1, 1, 3);
+ EXPECT_TRUE(ots::ParseDeviceTable(file, out.data(), out.size()));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat3Success2) {
+ BuildFakeDeviceTable(&out, 1, 8, 3);
+ EXPECT_TRUE(ots::ParseDeviceTable(file, out.data(), out.size()));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat3Fail) {
+ // Pass shorter length than expected.
+ BuildFakeDeviceTable(&out, 1, 8, 3);
+ EXPECT_FALSE(ots::ParseDeviceTable(file, out.data(), out.size() - 1));
+}
+
+TEST_F(DeviceTableTest, TestDeltaFormat3Fail2) {
+ // Pass shorter length than expected.
+ BuildFakeDeviceTable(&out, 1, 9, 3);
+ EXPECT_FALSE(ots::ParseDeviceTable(file, out.data(), out.size() - 1));
+}
+
+TEST_F(LookupSubtableParserTest, TestSuccess) {
+ {
+ EXPECT_TRUE(FakeLookupParserReturnsTrue.Parse(file, 0, 0, 1));
+ }
+ {
+ EXPECT_TRUE(FakeLookupParserReturnsTrue.Parse(file, 0, 0, 5));
+ }
+}
+
+TEST_F(LookupSubtableParserTest, TestFail) {
+ {
+ // Pass bad lookup type which less than the smallest type.
+ EXPECT_FALSE(FakeLookupParserReturnsTrue.Parse(file, 0, 0, 0));
+ }
+ {
+ // Pass bad lookup type which greater than the maximum type.
+ EXPECT_FALSE(FakeLookupParserReturnsTrue.Parse(file, 0, 0, 6));
+ }
+ {
+ // Check the type parser failure.
+ EXPECT_FALSE(FakeLookupParserReturnsFalse.Parse(file, 0, 0, 1));
+ }
+}
diff --git a/third_party/ots/test/ot-sanitise.cc b/third_party/ots/test/ot-sanitise.cc
new file mode 100644
index 0000000..2d4526a
--- /dev/null
+++ b/third_party/ots/test/ot-sanitise.cc
@@ -0,0 +1,101 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// A very simple driver program while sanitises the file given as argv[1] and
+// writes the sanitised version to stdout.
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#if defined(_WIN32)
+#include <io.h>
+#else
+#include <unistd.h>
+#endif // defined(_WIN32)
+
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+
+#include "file-stream.h"
+#include "opentype-sanitiser.h"
+
+#if defined(_WIN32)
+#define ADDITIONAL_OPEN_FLAGS O_BINARY
+#else
+#define ADDITIONAL_OPEN_FLAGS 0
+#endif
+
+namespace {
+
+int Usage(const char *argv0) {
+ std::fprintf(stderr, "Usage: %s ttf_file [dest_ttf_file]\n", argv0);
+ return 1;
+}
+
+class Context: public ots::OTSContext {
+ public:
+ virtual void Message(int level, const char *format, ...) {
+ va_list va;
+
+ if (level == 0)
+ std::fprintf(stderr, "ERROR: ");
+ else
+ std::fprintf(stderr, "WARNING: ");
+ va_start(va, format);
+ std::vfprintf(stderr, format, va);
+ std::fprintf(stderr, "\n");
+ va_end(va);
+ }
+
+ virtual ots::TableAction GetTableAction(uint32_t tag) {
+#define TAG(a, b, c, d) ((a) << 24 | (b) << 16 | (c) << 8 | (d))
+ switch (tag) {
+ case TAG('S','i','l','f'):
+ case TAG('S','i','l','l'):
+ case TAG('G','l','o','c'):
+ case TAG('G','l','a','t'):
+ case TAG('F','e','a','t'):
+ return ots::TABLE_ACTION_PASSTHRU;
+ default:
+ return ots::TABLE_ACTION_DEFAULT;
+ }
+#undef TAG
+ }
+};
+
+} // namespace
+
+int main(int argc, char **argv) {
+ if (argc < 2 || argc > 3) return Usage(argv[0]);
+
+ const int fd = ::open(argv[1], O_RDONLY | ADDITIONAL_OPEN_FLAGS);
+ if (fd < 0) {
+ ::perror("open");
+ return 1;
+ }
+
+ struct stat st;
+ ::fstat(fd, &st);
+
+ uint8_t *data = new uint8_t[st.st_size];
+ if (::read(fd, data, st.st_size) != st.st_size) {
+ ::perror("read");
+ return 1;
+ }
+ ::close(fd);
+
+ Context context;
+
+ FILE* out = NULL;
+ if (argc == 3)
+ out = fopen(argv[2], "wb");
+
+ ots::FILEStream output(out);
+ const bool result = context.Process(&output, data, st.st_size);
+
+ if (!result) {
+ std::fprintf(stderr, "Failed to sanitise file!\n");
+ }
+ return !result;
+}
diff --git a/third_party/ots/test/perf.cc b/third_party/ots/test/perf.cc
new file mode 100644
index 0000000..de7ee41
--- /dev/null
+++ b/third_party/ots/test/perf.cc
@@ -0,0 +1,80 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "opentype-sanitiser.h"
+#include "ots-memory-stream.h"
+
+namespace {
+
+int Usage(const char *argv0) {
+ std::fprintf(stderr, "Usage: %s <ttf file>\n", argv0);
+ return 1;
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ if (argc != 2) return Usage(argv[0]);
+
+ const int fd = ::open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ ::perror("open");
+ return 1;
+ }
+
+ struct stat st;
+ ::fstat(fd, &st);
+
+ uint8_t *data = new uint8_t[st.st_size];
+ if (::read(fd, data, st.st_size) != st.st_size) {
+ std::fprintf(stderr, "Failed to read file!\n");
+ return 1;
+ }
+
+ // A transcoded font is usually smaller than an original font.
+ // However, it can be slightly bigger than the original one due to
+ // name table replacement and/or padding for glyf table.
+ static const size_t kPadLen = 20 * 1024;
+ uint8_t *result = new uint8_t[st.st_size + kPadLen];
+
+ int num_repeat = 250;
+ if (st.st_size < 1024 * 1024) {
+ num_repeat = 2500;
+ }
+ if (st.st_size < 1024 * 100) {
+ num_repeat = 5000;
+ }
+
+ struct timeval start, end, elapsed;
+ ::gettimeofday(&start, 0);
+ for (int i = 0; i < num_repeat; ++i) {
+ ots::MemoryStream output(result, st.st_size + kPadLen);
+ ots::OTSContext context;
+ bool r = context.Process(&output, data, st.st_size);
+ if (!r) {
+ std::fprintf(stderr, "Failed to sanitise file!\n");
+ return 1;
+ }
+ }
+ ::gettimeofday(&end, 0);
+ timersub(&end, &start, &elapsed);
+
+ long long unsigned us
+ = ((elapsed.tv_sec * 1000 * 1000) + elapsed.tv_usec) / num_repeat;
+ std::fprintf(stderr, "%llu [us] %s (%llu bytes, %llu [byte/us])\n",
+ us, argv[1], static_cast<long long>(st.st_size),
+ (us ? st.st_size / us : 0));
+
+ return 0;
+}
diff --git a/third_party/ots/test/side-by-side.cc b/third_party/ots/test/side-by-side.cc
new file mode 100644
index 0000000..9034a7c
--- /dev/null
+++ b/third_party/ots/test/side-by-side.cc
@@ -0,0 +1,281 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <fcntl.h>
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "opentype-sanitiser.h"
+#include "ots-memory-stream.h"
+
+namespace {
+
+void DumpBitmap(const FT_Bitmap *bitmap) {
+ for (int i = 0; i < bitmap->rows * bitmap->width; ++i) {
+ if (bitmap->buffer[i] > 192) {
+ std::fprintf(stderr, "#");
+ } else if (bitmap->buffer[i] > 128) {
+ std::fprintf(stderr, "*");
+ } else if (bitmap->buffer[i] > 64) {
+ std::fprintf(stderr, "+");
+ } else if (bitmap->buffer[i] > 32) {
+ std::fprintf(stderr, ".");
+ } else {
+ std::fprintf(stderr, " ");
+ }
+
+ if ((i + 1) % bitmap->width == 0) {
+ std::fprintf(stderr, "\n");
+ }
+ }
+}
+
+int CompareBitmaps(const FT_Bitmap *orig, const FT_Bitmap *trans) {
+ int ret = 0;
+
+ if (orig->width == trans->width &&
+ orig->rows == trans->rows) {
+ for (int i = 0; i < orig->rows * orig->width; ++i) {
+ if (orig->buffer[i] != trans->buffer[i]) {
+ std::fprintf(stderr, "bitmap data doesn't match!\n");
+ ret = 1;
+ break;
+ }
+ }
+ } else {
+ std::fprintf(stderr, "bitmap metrics doesn't match! (%d, %d), (%d, %d)\n",
+ orig->width, orig->rows, trans->width, trans->rows);
+ ret = 1;
+ }
+
+ if (ret) {
+ std::fprintf(stderr, "EXPECTED:\n");
+ DumpBitmap(orig);
+ std::fprintf(stderr, "\nACTUAL:\n");
+ DumpBitmap(trans);
+ std::fprintf(stderr, "\n\n");
+ }
+
+ delete[] orig->buffer;
+ delete[] trans->buffer;
+ return ret;
+}
+
+int GetBitmap(FT_Library library, FT_Outline *outline, FT_Bitmap *bitmap) {
+ FT_BBox bbox;
+ FT_Outline_Get_CBox(outline, &bbox);
+
+ bbox.xMin &= ~63;
+ bbox.yMin &= ~63;
+ bbox.xMax = (bbox.xMax + 63) & ~63;
+ bbox.yMax = (bbox.yMax + 63) & ~63;
+ FT_Outline_Translate(outline, -bbox.xMin, -bbox.yMin);
+
+ const int w = (bbox.xMax - bbox.xMin) >> 6;
+ const int h = (bbox.yMax - bbox.yMin) >> 6;
+
+ if (w == 0 || h == 0) {
+ return -1; // white space
+ }
+ if (w < 0 || h < 0) {
+ std::fprintf(stderr, "bad width/height\n");
+ return 1; // error
+ }
+
+ uint8_t *buf = new uint8_t[w * h];
+ std::memset(buf, 0x0, w * h);
+
+ bitmap->width = w;
+ bitmap->rows = h;
+ bitmap->pitch = w;
+ bitmap->buffer = buf;
+ bitmap->pixel_mode = FT_PIXEL_MODE_GRAY;
+ bitmap->num_grays = 256;
+ if (FT_Outline_Get_Bitmap(library, outline, bitmap)) {
+ std::fprintf(stderr, "can't get outline\n");
+ delete[] buf;
+ return 1; // error.
+ }
+
+ return 0;
+}
+
+int LoadChar(FT_Face face, bool use_bitmap, int pt, FT_ULong c) {
+ static const int kDpi = 72;
+
+ FT_Matrix matrix;
+ matrix.xx = matrix.yy = 1 << 16;
+ matrix.xy = matrix.yx = 0 << 16;
+
+ FT_Int32 flags = FT_LOAD_DEFAULT | FT_LOAD_TARGET_NORMAL;
+ if (!use_bitmap) {
+ // Since the transcoder drops embedded bitmaps from the transcoded one,
+ // we have to use FT_LOAD_NO_BITMAP flag for the original face.
+ flags |= FT_LOAD_NO_BITMAP;
+ }
+
+ FT_Error error = FT_Set_Char_Size(face, pt * (1 << 6), 0, kDpi, 0);
+ if (error) {
+ std::fprintf(stderr, "Failed to set the char size!\n");
+ return 1;
+ }
+
+ FT_Set_Transform(face, &matrix, 0);
+
+ error = FT_Load_Char(face, c, flags);
+ if (error) return -1; // no such glyf in the font.
+
+ if (face->glyph->format != FT_GLYPH_FORMAT_OUTLINE) {
+ std::fprintf(stderr, "bad format\n");
+ return 1;
+ }
+
+ return 0;
+}
+
+int LoadCharThenCompare(FT_Library library,
+ FT_Face orig_face, FT_Face trans_face,
+ int pt, FT_ULong c) {
+ FT_Bitmap orig_bitmap, trans_bitmap;
+
+ // Load original bitmap.
+ int ret = LoadChar(orig_face, false, pt, c);
+ if (ret) return ret; // 1: error, -1: no such glyph
+
+ FT_Outline *outline = &orig_face->glyph->outline;
+ ret = GetBitmap(library, outline, &orig_bitmap);
+ if (ret) return ret; // white space?
+
+ // Load transformed bitmap.
+ ret = LoadChar(trans_face, true, pt, c);
+ if (ret == -1) {
+ std::fprintf(stderr, "the glyph is not found on the transcoded font\n");
+ }
+ if (ret) return 1; // -1 should be treated as error.
+ outline = &trans_face->glyph->outline;
+ ret = GetBitmap(library, outline, &trans_bitmap);
+ if (ret) return ret; // white space?
+
+ return CompareBitmaps(&orig_bitmap, &trans_bitmap);
+}
+
+int SideBySide(FT_Library library, const char *file_name,
+ uint8_t *orig_font, size_t orig_len,
+ uint8_t *trans_font, size_t trans_len) {
+ FT_Face orig_face;
+ FT_Error error
+ = FT_New_Memory_Face(library, orig_font, orig_len, 0, &orig_face);
+ if (error) {
+ std::fprintf(stderr, "Failed to open the original font: %s!\n", file_name);
+ return 1;
+ }
+
+ FT_Face trans_face;
+ error = FT_New_Memory_Face(library, trans_font, trans_len, 0, &trans_face);
+ if (error) {
+ std::fprintf(stderr, "Failed to open the transcoded font: %s!\n",
+ file_name);
+ return 1;
+ }
+
+ static const int kPts[] = {100, 20, 18, 16, 12, 10, 8}; // pt
+ static const size_t kPtsLen = sizeof(kPts) / sizeof(kPts[0]);
+
+ static const int kUnicodeRanges[] = {
+ 0x0020, 0x007E, // Basic Latin (ASCII)
+ 0x00A1, 0x017F, // Latin-1
+ 0x1100, 0x11FF, // Hangul
+ 0x3040, 0x309F, // Japanese HIRAGANA letters
+ 0x3130, 0x318F, // Hangul
+ 0x4E00, 0x4F00, // CJK Kanji/Hanja
+ 0xAC00, 0xAD00, // Hangul
+ };
+ static const size_t kUnicodeRangesLen
+ = sizeof(kUnicodeRanges) / sizeof(kUnicodeRanges[0]);
+
+ for (size_t i = 0; i < kPtsLen; ++i) {
+ for (size_t j = 0; j < kUnicodeRangesLen; j += 2) {
+ for (int k = 0; k <= kUnicodeRanges[j + 1] - kUnicodeRanges[j]; ++k) {
+ int ret = LoadCharThenCompare(library, orig_face, trans_face,
+ kPts[i],
+ kUnicodeRanges[j] + k);
+ if (ret > 0) {
+ std::fprintf(stderr, "Glyph mismatch! (file: %s, U+%04x, %dpt)!\n",
+ file_name, kUnicodeRanges[j] + k, kPts[i]);
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+} // namespace
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ std::fprintf(stderr, "Usage: %s ttf_or_otf_filename\n", argv[0]);
+ return 1;
+ }
+
+ // load the font to memory.
+ const int fd = ::open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ ::perror("open");
+ return 1;
+ }
+
+ struct stat st;
+ ::fstat(fd, &st);
+ const off_t orig_len = st.st_size;
+
+ uint8_t *orig_font = new uint8_t[orig_len];
+ if (::read(fd, orig_font, orig_len) != orig_len) {
+ std::fprintf(stderr, "Failed to read file!\n");
+ return 1;
+ }
+ ::close(fd);
+
+ // check if FreeType2 can open the original font.
+ FT_Library library;
+ FT_Error error = FT_Init_FreeType(&library);
+ if (error) {
+ std::fprintf(stderr, "Failed to initialize FreeType2!\n");
+ return 1;
+ }
+ FT_Face dummy;
+ error = FT_New_Memory_Face(library, orig_font, orig_len, 0, &dummy);
+ if (error) {
+ std::fprintf(stderr, "Failed to open the original font with FT2! %s\n",
+ argv[1]);
+ return 1;
+ }
+
+ // transcode the original font.
+ static const size_t kPadLen = 20 * 1024;
+ uint8_t *trans_font = new uint8_t[orig_len + kPadLen];
+ ots::MemoryStream output(trans_font, orig_len + kPadLen);
+ ots::OTSContext context;
+
+ bool result = context.Process(&output, orig_font, orig_len);
+ if (!result) {
+ std::fprintf(stderr, "Failed to sanitise file! %s\n", argv[1]);
+ return 1;
+ }
+ const size_t trans_len = output.Tell();
+
+ // perform side-by-side tests.
+ return SideBySide(library, argv[1],
+ orig_font, orig_len,
+ trans_font, trans_len);
+}
diff --git a/third_party/ots/test/table_dependencies_test.cc b/third_party/ots/test/table_dependencies_test.cc
new file mode 100644
index 0000000..bbaaa30
--- /dev/null
+++ b/third_party/ots/test/table_dependencies_test.cc
@@ -0,0 +1,78 @@
+// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <gtest/gtest.h>
+
+#include "gsub.h"
+#include "ots.h"
+#include "ots-memory-stream.h"
+#include "vhea.h"
+#include "vmtx.h"
+
+#define SET_TABLE(name, capname) \
+ do { file.name = new ots::OpenType##capname; } while (0)
+#define SET_LAYOUT_TABLE(name, capname) \
+ do { \
+ if (!file.name) { \
+ SET_TABLE(name, capname); \
+ } \
+ file.name->data = reinterpret_cast<const uint8_t*>(1); \
+ file.name->length = 1; \
+ } while (0)
+#define DROP_TABLE(name) \
+ do { delete file.name; file.name = NULL; } while (0)
+#define DROP_LAYOUT_TABLE(name) \
+ do { file.name->data = NULL; file.name->length = 0; } while (0)
+
+namespace {
+
+class TableDependenciesTest : public ::testing::Test {
+ protected:
+ virtual void SetUp() {
+ SET_LAYOUT_TABLE(gsub, GSUB);
+ SET_TABLE(vhea, VHEA);
+ SET_TABLE(vmtx, VMTX);
+ }
+
+ virtual void TearDown() {
+ DROP_TABLE(gsub);
+ DROP_TABLE(vhea);
+ DROP_TABLE(vmtx);
+ }
+ ots::OpenTypeFile file;
+};
+} // namespace
+
+TEST_F(TableDependenciesTest, TestVhea) {
+ EXPECT_TRUE(ots::ots_vhea_should_serialise(&file));
+}
+
+TEST_F(TableDependenciesTest, TestVmtx) {
+ EXPECT_TRUE(ots::ots_vmtx_should_serialise(&file));
+}
+
+TEST_F(TableDependenciesTest, TestVheaVmtx) {
+ DROP_TABLE(vmtx);
+ EXPECT_FALSE(ots::ots_vhea_should_serialise(&file));
+}
+
+TEST_F(TableDependenciesTest, TestVmtxVhea) {
+ DROP_TABLE(vhea);
+ EXPECT_FALSE(ots::ots_vmtx_should_serialise(&file));
+}
+
+TEST_F(TableDependenciesTest, TestVheaGsub) {
+ DROP_LAYOUT_TABLE(gsub);
+ EXPECT_FALSE(ots::ots_vhea_should_serialise(&file));
+ DROP_TABLE(gsub);
+ EXPECT_FALSE(ots::ots_vhea_should_serialise(&file));
+}
+
+TEST_F(TableDependenciesTest, TestVmtxGsub) {
+ DROP_LAYOUT_TABLE(gsub);
+ EXPECT_FALSE(ots::ots_vmtx_should_serialise(&file));
+ DROP_TABLE(gsub);
+ EXPECT_FALSE(ots::ots_vmtx_should_serialise(&file));
+}
+
diff --git a/third_party/ots/test/test_malicious_fonts.sh b/third_party/ots/test/test_malicious_fonts.sh
new file mode 100755
index 0000000..7a35f26
--- /dev/null
+++ b/third_party/ots/test/test_malicious_fonts.sh
@@ -0,0 +1,39 @@
+#!/bin/bash
+
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Usage: ./test_malicious_fonts.sh [ttf_or_otf_file_name]
+
+BASE_DIR=~/malicious/
+CHECKER=./validator-checker
+
+if [ ! -x "$CHECKER" ] ; then
+ echo "$CHECKER is not found."
+ exit 1
+fi
+
+if [ $# -eq 0 ] ; then
+ # No font file is specified. Apply this script to all TT/OT files under the
+ # BASE_DIR.
+ if [ ! -d $BASE_DIR ] ; then
+ echo "$BASE_DIR does not exist."
+ exit 1
+ fi
+
+ # Recursively call this script.
+ find $BASE_DIR -type f -name '*tf' -exec "$0" {} \;
+ echo
+ exit 0
+fi
+
+if [ $# -gt 1 ] ; then
+ echo "Usage: $0 [ttf_or_otf_file_name]"
+ exit 1
+fi
+
+# Confirm that the malicious font file does not crash OTS nor OS font renderer.
+base=`basename "$1"`
+"$CHECKER" "$1" > /dev/null 2>&1 || (echo ; echo "\nFAIL: $1 (Run $CHECKER $1 for more information.)")
+echo -n "."
diff --git a/third_party/ots/test/test_unmalicious_fonts.sh b/third_party/ots/test/test_unmalicious_fonts.sh
new file mode 100755
index 0000000..ae3a5bb
--- /dev/null
+++ b/third_party/ots/test/test_unmalicious_fonts.sh
@@ -0,0 +1,50 @@
+#!/bin/bash
+
+# Copyright (c) 2009 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Usage: ./test_unmalicious_fonts.sh [ttf_or_otf_file_name]
+
+BLACKLIST=./BLACKLIST.txt
+CHECKER=./idempotent
+
+if [ ! -r "$BLACKLIST" ] ; then
+ echo "$BLACKLIST is not found."
+ exit 1
+fi
+
+if [ ! -x "$CHECKER" ] ; then
+ echo "$CHECKER is not found."
+ exit 1
+fi
+
+if [ $# -eq 0 ] ; then
+ # No font file is specified. Apply this script to all TT/OT files under the
+ # BASE_DIR below.
+
+ # On Ubuntu Linux (>= 8.04), You can install ~1800 TrueType/OpenType fonts
+ # to /usr/share/fonts/truetype by:
+ # % sudo apt-get install ttf-.*[^0]$
+ BASE_DIR=/usr/share/fonts/truetype/
+ if [ ! -d $BASE_DIR ] ; then
+ # Mac OS X
+ BASE_DIR="/Library/Fonts/ /System/Library/Fonts/"
+ fi
+ # TODO(yusukes): Support Cygwin.
+
+ # Recursively call this script.
+ find $BASE_DIR -type f -name '*tf' -exec "$0" {} \;
+ echo
+ exit 0
+fi
+
+if [ $# -gt 1 ] ; then
+ echo "Usage: $0 [ttf_or_otf_file_name]"
+ exit 1
+fi
+
+# Check the font file using idempotent iff the font is not blacklisted.
+base=`basename "$1"`
+egrep -i -e "^$base" "$BLACKLIST" > /dev/null 2>&1 || "$CHECKER" "$1" > /dev/null 2>&1 || (echo ; echo "FAIL: $1 (Run $CHECKER $1 for more information.)")
+echo -n "."
diff --git a/third_party/ots/test/validator-checker.cc b/third_party/ots/test/validator-checker.cc
new file mode 100644
index 0000000..6cb5bca
--- /dev/null
+++ b/third_party/ots/test/validator-checker.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#if !defined(_MSC_VER)
+#ifdef __linux__
+// Linux
+#include <ft2build.h>
+#include FT_FREETYPE_H
+#include FT_OUTLINE_H
+#else
+// Mac OS X
+#include <ApplicationServices/ApplicationServices.h> // g++ -framework Cocoa
+#endif // __linux__
+#else
+// Windows
+// TODO(yusukes): Support Windows.
+#endif // _MSC_VER
+
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+
+#include "opentype-sanitiser.h"
+#include "ots-memory-stream.h"
+
+namespace {
+
+#if !defined(_MSC_VER)
+#ifdef __linux__
+// Linux
+void LoadChar(FT_Face face, int pt, FT_ULong c) {
+ FT_Matrix matrix;
+ matrix.xx = matrix.yy = 1 << 16;
+ matrix.xy = matrix.yx = 0 << 16;
+
+ FT_Set_Char_Size(face, pt * (1 << 6), 0, 72, 0);
+ FT_Set_Transform(face, &matrix, 0);
+ FT_Load_Char(face, c, FT_LOAD_RENDER);
+}
+
+int OpenAndLoadChars(
+ const char *file_name, uint8_t *trans_font, size_t trans_len) {
+ FT_Library library;
+ FT_Error error = FT_Init_FreeType(&library);
+ if (error) {
+ std::fprintf(stderr, "Failed to initialize FreeType2!\n");
+ return 1;
+ }
+
+ FT_Face trans_face;
+ error = FT_New_Memory_Face(library, trans_font, trans_len, 0, &trans_face);
+ if (error) {
+ std::fprintf(stderr,
+ "OK: FreeType2 couldn't open the transcoded font: %s\n",
+ file_name);
+ return 0;
+ }
+
+ static const int kPts[] = {100, 20, 18, 16, 12, 10, 8}; // pt
+ static const size_t kPtsLen = sizeof(kPts) / sizeof(kPts[0]);
+
+ static const int kUnicodeRanges[] = {
+ 0x0020, 0x007E, // Basic Latin (ASCII)
+ 0x00A1, 0x017F, // Latin-1
+ 0x1100, 0x11FF, // Hangul
+ 0x3040, 0x309F, // Japanese HIRAGANA letters
+ 0x3130, 0x318F, // Hangul
+ 0x4E00, 0x4F00, // CJK Kanji/Hanja
+ 0xAC00, 0xAD00, // Hangul
+ };
+ static const size_t kUnicodeRangesLen
+ = sizeof(kUnicodeRanges) / sizeof(kUnicodeRanges[0]);
+
+ for (size_t i = 0; i < kPtsLen; ++i) {
+ for (size_t j = 0; j < kUnicodeRangesLen; j += 2) {
+ for (int k = 0; k <= kUnicodeRanges[j + 1] - kUnicodeRanges[j]; ++k) {
+ LoadChar(trans_face, kPts[i], kUnicodeRanges[j] + k);
+ }
+ }
+ }
+
+ std::fprintf(stderr, "OK: FreeType2 didn't crash: %s\n", file_name);
+ return 0;
+}
+#else
+// Mac OS X
+int OpenAndLoadChars(
+ const char *file_name, uint8_t *trans_font, size_t trans_len) {
+ CFDataRef data = CFDataCreate(0, trans_font, trans_len);
+ if (!data) {
+ std::fprintf(stderr,
+ "OK: font renderer couldn't open the transcoded font: %s\n",
+ file_name);
+ return 0;
+ }
+
+ CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData(data);
+ CGFontRef cgFontRef = CGFontCreateWithDataProvider(dataProvider);
+ CGDataProviderRelease(dataProvider);
+ CFRelease(data);
+ if (!cgFontRef) {
+ std::fprintf(stderr,
+ "OK: font renderer couldn't open the transcoded font: %s\n",
+ file_name);
+ return 0;
+ }
+
+ size_t numGlyphs = CGFontGetNumberOfGlyphs(cgFontRef);
+ CGFontRelease(cgFontRef);
+ if (!numGlyphs) {
+ std::fprintf(stderr,
+ "OK: font renderer couldn't open the transcoded font: %s\n",
+ file_name);
+ return 0;
+ }
+ std::fprintf(stderr, "OK: font renderer didn't crash: %s\n", file_name);
+ // TODO(yusukes): would be better to perform LoadChar() like Linux.
+ return 0;
+}
+#endif // __linux__
+#else
+// Windows
+// TODO(yusukes): Support Windows.
+#endif // _MSC_VER
+
+} // namespace
+
+int main(int argc, char **argv) {
+ if (argc != 2) {
+ std::fprintf(stderr, "Usage: %s ttf_or_otf_filename\n", argv[0]);
+ return 1;
+ }
+
+ // load the font to memory.
+ const int fd = ::open(argv[1], O_RDONLY);
+ if (fd < 0) {
+ ::perror("open");
+ return 1;
+ }
+
+ struct stat st;
+ ::fstat(fd, &st);
+ const off_t orig_len = st.st_size;
+
+ uint8_t *orig_font = new uint8_t[orig_len];
+ if (::read(fd, orig_font, orig_len) != orig_len) {
+ std::fprintf(stderr, "Failed to read file!\n");
+ return 1;
+ }
+ ::close(fd);
+
+ // transcode the malicious font.
+ static const size_t kBigPadLen = 1024 * 1024; // 1MB
+ uint8_t *trans_font = new uint8_t[orig_len + kBigPadLen];
+ ots::MemoryStream output(trans_font, orig_len + kBigPadLen);
+ ots::OTSContext context;
+
+ bool result = context.Process(&output, orig_font, orig_len);
+ if (!result) {
+ std::fprintf(stderr, "OK: the malicious font was filtered: %s\n", argv[1]);
+ return 0;
+ }
+ const size_t trans_len = output.Tell();
+
+ return OpenAndLoadChars(argv[1], trans_font, trans_len);
+}
diff --git a/third_party/ots/third_party/brotli.gyp b/third_party/ots/third_party/brotli.gyp
new file mode 100644
index 0000000..9903110
--- /dev/null
+++ b/third_party/ots/third_party/brotli.gyp
@@ -0,0 +1,32 @@
+# Copyright 2013 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'targets': [
+ {
+ 'target_name': 'brotli',
+ 'type': 'static_library',
+ 'include_dirs': [
+ 'brotli/dec',
+ ],
+ 'sources': [
+ 'brotli/dec/bit_reader.c',
+ 'brotli/dec/bit_reader.h',
+ 'brotli/dec/context.h',
+ 'brotli/dec/decode.c',
+ 'brotli/dec/decode.h',
+ 'brotli/dec/dictionary.h',
+ 'brotli/dec/huffman.c',
+ 'brotli/dec/huffman.h',
+ 'brotli/dec/prefix.h',
+ 'brotli/dec/safe_malloc.c',
+ 'brotli/dec/safe_malloc.h',
+ 'brotli/dec/streams.c',
+ 'brotli/dec/streams.h',
+ 'brotli/dec/transform.h',
+ 'brotli/dec/types.h',
+ ],
+ },
+ ],
+}
diff --git a/third_party/ots/tools/ttf-checksum.py b/third_party/ots/tools/ttf-checksum.py
new file mode 100644
index 0000000..802e3cc
--- /dev/null
+++ b/third_party/ots/tools/ttf-checksum.py
@@ -0,0 +1,44 @@
+import struct
+import sys
+
+def readU32(contents, offset):
+ wordBytes = contents[offset:offset + 4]
+ return struct.unpack('>I', wordBytes)[0]
+
+def readU16(contents, offset):
+ wordBytes = contents[offset:offset + 2]
+ return struct.unpack('>H', wordBytes)[0]
+
+def checkChecksum(infile):
+ contents = infile.read()
+ if len(contents) % 4:
+ print 'File length is not a multiple of 4'
+
+ sum = 0
+ for offset in range(0, len(contents), 4):
+ sum += readU32(contents, offset)
+ while sum >= 2**32:
+ sum -= 2**32
+ print 'Sum of whole file: %x' % sum
+
+ numTables = readU16(contents, 4)
+
+ for offset in range(12, 12 + numTables * 16, 16):
+ tag = contents[offset:offset + 4]
+ chksum = readU32(contents, offset + 4)
+ toffset = readU32(contents, offset + 8)
+ tlength = readU32(contents, offset + 12)
+
+ sum = 0
+ for offset2 in range(toffset, toffset + tlength, 4):
+ sum += readU32(contents, offset2)
+ while sum >= 2**32:
+ sum -= 2**32
+ if sum != chksum:
+ print 'Bad chksum: %s' % tag
+
+if __name__ == '__main__':
+ if len(sys.argv) != 2:
+ print 'Usage: %s <ttf filename>' % sys.argv[0]
+ else:
+ checkChecksum(file(sys.argv[1], 'r'))
diff --git a/third_party/protobuf/BUILD.gn b/third_party/protobuf/BUILD.gn
index 1367d8a..6825f1e 100644
--- a/third_party/protobuf/BUILD.gn
+++ b/third_party/protobuf/BUILD.gn
@@ -17,11 +17,6 @@
"GOOGLE_PROTOBUF_NO_RTTI",
"GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER",
]
-
- if (is_win) {
- # TODO(jschuh): http://crbug.com/167187 size_t -> int.
- cflags = [ "/wd4267" ]
- }
}
if (component_mode == "shared_library") {
@@ -98,7 +93,11 @@
if (is_win) {
configs -= [ "//build/config/win:lean_and_mean" ]
}
- public_configs = [ ":protobuf_config" ]
+ public_configs = [
+ ":protobuf_config",
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ "//build/config/compiler:no_size_t_to_int_warning",
+ ]
cflags = protobuf_lite_cflags
@@ -177,7 +176,11 @@
if (is_win) {
configs -= [ "//build/config/win:lean_and_mean" ]
}
- public_configs = [ ":protobuf_config" ]
+ public_configs = [
+ ":protobuf_config",
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ "//build/config/compiler:no_size_t_to_int_warning",
+ ]
cflags = protobuf_lite_cflags
}
diff --git a/third_party/qcms/BUILD.gn b/third_party/qcms/BUILD.gn
index b059319..ee62b8e 100644
--- a/third_party/qcms/BUILD.gn
+++ b/third_party/qcms/BUILD.gn
@@ -25,10 +25,10 @@
configs += [ "//build/config/compiler:no_chromium_code" ]
public_configs = [ ":qcms_config" ]
- if (cpu_arch == "x86" || cpu_arch == "x64") {
+ if (current_cpu == "x86" || current_cpu == "x64") {
defines = [ "SSE2_ENABLE" ]
sources += [ "src/transform-sse2.c" ]
- if (!(is_win && cpu_arch == "x64")) {
+ if (!(is_win && current_cpu == "x64")) {
# QCMS assumes this target isn't compiled since MSVC x64 doesn't support
# the MMX intrinsics present in the SSE1 code.
sources += [ "src/transform-sse1.c" ]
diff --git a/third_party/re2/BUILD.gn b/third_party/re2/BUILD.gn
index d022e4f..2bc130a 100644
--- a/third_party/re2/BUILD.gn
+++ b/third_party/re2/BUILD.gn
@@ -67,10 +67,7 @@
if (is_win) {
include_dirs = [ "mswin" ]
- cflags = [
- "/wd4267", # Conversion from size_t.
- "/wd4722", # Destructor never terminates.
- ]
+ cflags = [ "/wd4722" ] # Destructor never terminates.
} else {
sources -= [ "mswin/stdint.h" ]
}
diff --git a/third_party/smhasher/BUILD.gn b/third_party/smhasher/BUILD.gn
index e1bbb5e..fd9088c 100644
--- a/third_party/smhasher/BUILD.gn
+++ b/third_party/smhasher/BUILD.gn
@@ -27,9 +27,4 @@
]
configs -= [ "//build/config/compiler:chromium_code" ]
configs += [ "//build/config/compiler:no_chromium_code" ]
-
- if (is_win) {
- # TODO(jschuh): http://code.google.com/p/smhasher/issues/detail?id=19
- cflags = [ "/wd4267" ]
- }
}
diff --git a/third_party/yasm/BUILD.gn b/third_party/yasm/BUILD.gn
index cd9b453..a09a495 100644
--- a/third_party/yasm/BUILD.gn
+++ b/third_party/yasm/BUILD.gn
@@ -30,18 +30,14 @@
if (current_toolchain == host_toolchain) {
# Various files referenced by multiple targets.
yasm_gen_include_dir = "$target_gen_dir/include"
- yasm_os = os
- if (is_chromeos) {
- yasm_os = "linux"
- }
- config_makefile = "source/config/$yasm_os/Makefile"
+ config_makefile = "source/config/$host_os/Makefile"
version_file = "version.mac"
import("//build/compiled_action.gni")
config("yasm_config") {
include_dirs = [
- "source/config/$yasm_os",
+ "source/config/$host_os",
"source/patched-yasm",
]
defines = [ "HAVE_CONFIG_H" ]
@@ -148,8 +144,6 @@
# re2c is missing CLOSEVOP from one switch.
if (is_posix) {
cflags = [ "-Wno-switch" ]
- } else if (is_win) {
- cflags = [ "/wd4267" ] # size_t to int conversion.
}
}
@@ -248,9 +242,7 @@
# directory, but the gen_x86_insn.py script does not make this easy.
include_dirs = [ yasm_gen_include_dir ]
- if (is_win) {
- cflags = [ "/wd4267" ] # size_t to int conversion.
- } else {
+ if (!is_win) {
cflags = [
"-ansi",
"-pedantic",
diff --git a/third_party/yasm/yasm_assemble.gni b/third_party/yasm/yasm_assemble.gni
index 56d7e11..1a84d51 100644
--- a/third_party/yasm/yasm_assemble.gni
+++ b/third_party/yasm/yasm_assemble.gni
@@ -42,13 +42,13 @@
# }
if (is_mac || is_ios) {
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
_yasm_flags = [
"-fmacho32",
"-m",
"x86",
]
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
_yasm_flags = [
"-fmacho64",
"-m",
@@ -56,13 +56,13 @@
]
}
} else if (is_posix) {
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
_yasm_flags = [
"-felf32",
"-m",
"x86",
]
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
_yasm_flags = [
"-DPIC",
"-felf64",
@@ -71,14 +71,14 @@
]
}
} else if (is_win) {
- if (cpu_arch == "x86") {
+ if (current_cpu == "x86") {
_yasm_flags = [
"-DPREFIX",
"-fwin32",
"-m",
"x86",
]
- } else if (cpu_arch == "x64") {
+ } else if (current_cpu == "x64") {
_yasm_flags = [
"-fwin64",
"-m",
@@ -99,7 +99,7 @@
# Only depend on YASM on x86 systems. Force compilation of .asm files for
# ARM to fail.
- assert(cpu_arch == "x86" || cpu_arch == "x64")
+ assert(current_cpu == "x86" || current_cpu == "x64")
action_name = "${target_name}_action"
source_set_name = target_name
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index e49b5e9..1cea9ac 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -7,7 +7,7 @@
}
static_library("zlib_x86_simd") {
- if (!is_ios && (cpu_arch == "x86" || cpu_arch == "x64")) {
+ if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
sources = [
"crc_folding.c",
"fill_window_sse.c",
@@ -65,7 +65,7 @@
"zutil.h",
]
- if (!is_ios && (cpu_arch == "x86" || cpu_arch == "x64")) {
+ if (!is_ios && (current_cpu == "x86" || current_cpu == "x64")) {
sources += [ "x86.c" ]
}
diff --git a/tools/android/common/BUILD.gn b/tools/android/common/BUILD.gn
index 8307a91..3c86741 100644
--- a/tools/android/common/BUILD.gn
+++ b/tools/android/common/BUILD.gn
@@ -12,4 +12,8 @@
"net.cc",
"net.h",
]
+
+ deps = [
+ "//base",
+ ]
}
diff --git a/tools/android/memconsumer/memconsumer.gyp b/tools/android/memconsumer/memconsumer.gyp
index f721fc1..b0e2517 100644
--- a/tools/android/memconsumer/memconsumer.gyp
+++ b/tools/android/memconsumer/memconsumer.gyp
@@ -28,6 +28,11 @@
{
'target_name': 'libmemconsumer',
'type': 'shared_library',
+ 'variables': {
+ # This library uses native JNI exports; tell gyp so that the required
+ # symbols will be kept.
+ 'use_native_jni_exports': 1,
+ },
'sources': [
'memconsumer_hook.cc',
],
diff --git a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
index 473ad20..7dae381 100644
--- a/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
+++ b/tools/clang/blink_gc_plugin/BlinkGCPlugin.cpp
@@ -470,12 +470,17 @@
if (!fn || !Config::IsTraceMethod(fn, nullptr))
return false;
- // Currently, a manually dispatched class cannot have mixin bases (having
- // one would add a vtable which we explicitly check against). This means
- // that we can only make calls to a trace method of the same name. Revisit
- // this if our mixin/vtable assumption changes.
- if (fn->getName() != trace_->getName())
- return false;
+ if (trace_->getName() == kTraceImplName) {
+ if (fn->getName() != kTraceName)
+ return false;
+ } else {
+ // Currently, a manually dispatched class cannot have mixin bases (having
+ // one would add a vtable which we explicitly check against). This means
+ // that we can only make calls to a trace method of the same name. Revisit
+ // this if our mixin/vtable assumption changes.
+ if (fn->getName() != trace_->getName())
+ return false;
+ }
CXXRecordDecl* decl = 0;
if (callee && callee->hasQualifier()) {
diff --git a/tools/clang/blink_gc_plugin/Config.h b/tools/clang/blink_gc_plugin/Config.h
index d508fda..814a4ac 100644
--- a/tools/clang/blink_gc_plugin/Config.h
+++ b/tools/clang/blink_gc_plugin/Config.h
@@ -195,7 +195,7 @@
formal_type.getTypePtr())) {
if (parm_type->getDecl()->getName() == kVisitorDispatcherName) {
// Unresolved, but its parameter name is VisitorDispatcher.
- return false;
+ return true;
}
}
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl.cpp b/tools/clang/blink_gc_plugin/tests/traceimpl.cpp
index 61d8560..c8849cc 100644
--- a/tools/clang/blink_gc_plugin/tests/traceimpl.cpp
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl.cpp
@@ -12,6 +12,17 @@
template <typename VisitorDispatcher>
inline void TraceImplExtern::traceImpl(VisitorDispatcher visitor) {
- visitor->trace(m_x);
+ visitor->trace(x_);
}
+
+void TraceImplBaseExtern::trace(Visitor* visitor) {
+ traceImpl(visitor);
+}
+
+template <typename VisitorDispatcher>
+inline void TraceImplBaseExtern::traceImpl(VisitorDispatcher visitor) {
+ visitor->trace(x_);
+ Base::trace(visitor);
+}
+
}
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl.h b/tools/clang/blink_gc_plugin/tests/traceimpl.h
index 26f4615..64fae26 100644
--- a/tools/clang/blink_gc_plugin/tests/traceimpl.h
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl.h
@@ -20,11 +20,11 @@
template <typename VisitorDispatcher>
void traceImpl(VisitorDispatcher visitor) {
- visitor->trace(m_x);
+ visitor->trace(x_);
}
private:
- Member<X> m_x;
+ Member<X> x_;
};
class TraceImplExtern : public GarbageCollected<TraceImplExtern> {
@@ -34,8 +34,35 @@
inline void traceImpl(VisitorDispatcher);
private:
- Member<X> m_x;
+ Member<X> x_;
};
+
+class Base : public GarbageCollected<Base> {
+ public:
+ virtual void trace(Visitor* visitor) {}
+};
+
+class TraceImplBaseInlined : public Base {
+ public:
+ void trace(Visitor* visitor) override { traceImpl(visitor); }
+
+ template <typename VisitorDispatcher>
+ void traceImpl(VisitorDispatcher visitor) {
+ Base::trace(visitor);
+ }
+};
+
+class TraceImplBaseExtern : public Base {
+ public:
+ void trace(Visitor* visitor) override;
+
+ template <typename VisitorDispatcher>
+ void traceImpl(VisitorDispatcher);
+
+ private:
+ Member<X> x_;
+};
+
}
#endif
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_error.cpp b/tools/clang/blink_gc_plugin/tests/traceimpl_error.cpp
new file mode 100644
index 0000000..041c565
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_error.cpp
@@ -0,0 +1,29 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "traceimpl_error.h"
+
+namespace blink {
+
+void TraceImplExternWithUntracedMember::trace(Visitor* visitor) {
+ traceImpl(visitor);
+}
+
+template <typename VisitorDispatcher>
+inline void TraceImplExternWithUntracedMember::traceImpl(
+ VisitorDispatcher visitor) {
+ // Should get a warning as well.
+}
+
+void TraceImplExternWithUntracedBase::trace(Visitor* visitor) {
+ traceImpl(visitor);
+}
+
+template <typename VisitorDispatcher>
+inline void TraceImplExternWithUntracedBase::traceImpl(
+ VisitorDispatcher visitor) {
+ // Ditto.
+}
+
+}
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_error.h b/tools/clang/blink_gc_plugin/tests/traceimpl_error.h
new file mode 100644
index 0000000..5a883b4
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_error.h
@@ -0,0 +1,68 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef TRACEIMPL_ERROR_H_
+#define TRACEIMPL_ERROR_H_
+
+#include "heap/stubs.h"
+
+namespace blink {
+
+class X : public GarbageCollected<X> {
+ public:
+ virtual void trace(Visitor*) {}
+};
+
+class TraceImplInlinedWithUntracedMember
+ : public GarbageCollected<TraceImplInlinedWithUntracedMember> {
+ public:
+ void trace(Visitor* visitor) { traceImpl(visitor); }
+
+ template <typename VisitorDispatcher>
+ void traceImpl(VisitorDispatcher visitor) {
+ // Empty; should get complaints from the plugin for untraced x_.
+ }
+
+ private:
+ Member<X> x_;
+};
+
+class TraceImplExternWithUntracedMember
+ : public GarbageCollected<TraceImplExternWithUntracedMember> {
+ public:
+ void trace(Visitor* visitor);
+
+ template <typename VisitorDispatcher>
+ inline void traceImpl(VisitorDispatcher);
+
+ private:
+ Member<X> x_;
+};
+
+class Base : public GarbageCollected<Base> {
+ public:
+ virtual void trace(Visitor*) {}
+};
+
+class TraceImplInlineWithUntracedBase : public Base {
+ public:
+ void trace(Visitor* visitor) override { traceImpl(visitor); }
+
+ template <typename VisitorDispatcher>
+ void traceImpl(VisitorDispatcher visitor) {
+ // Empty; should get complaints from the plugin for untraced Base.
+ }
+};
+
+class TraceImplExternWithUntracedBase : public Base {
+ public:
+ void trace(Visitor*) override;
+
+ template <typename VisitorDispatcher>
+ void traceImpl(VisitorDispatcher visitor);
+};
+
+}
+
+#endif // TRACEIMPL_ERROR_H_
diff --git a/tools/clang/blink_gc_plugin/tests/traceimpl_error.txt b/tools/clang/blink_gc_plugin/tests/traceimpl_error.txt
new file mode 100644
index 0000000..070b029
--- /dev/null
+++ b/tools/clang/blink_gc_plugin/tests/traceimpl_error.txt
@@ -0,0 +1,20 @@
+In file included from traceimpl_error.cpp:5:
+./traceimpl_error.h:23:3: warning: [blink-gc] Class 'TraceImplInlinedWithUntracedMember' has untraced fields that require tracing.
+ void traceImpl(VisitorDispatcher visitor) {
+ ^
+./traceimpl_error.h:28:3: note: [blink-gc] Untraced field 'x_' declared here:
+ Member<X> x_;
+ ^
+./traceimpl_error.h:53:3: warning: [blink-gc] Base class 'Base' of derived class 'TraceImplInlineWithUntracedBase' requires tracing.
+ void traceImpl(VisitorDispatcher visitor) {
+ ^
+traceimpl_error.cpp:14:1: warning: [blink-gc] Class 'TraceImplExternWithUntracedMember' has untraced fields that require tracing.
+inline void TraceImplExternWithUntracedMember::traceImpl(
+^
+./traceimpl_error.h:40:3: note: [blink-gc] Untraced field 'x_' declared here:
+ Member<X> x_;
+ ^
+traceimpl_error.cpp:24:1: warning: [blink-gc] Base class 'Base' of derived class 'TraceImplExternWithUntracedBase' requires tracing.
+inline void TraceImplExternWithUntracedBase::traceImpl(
+^
+4 warnings generated.
diff --git a/tools/clang/plugins/FindBadConstructsAction.cpp b/tools/clang/plugins/FindBadConstructsAction.cpp
index f302fd1..6c39d72 100644
--- a/tools/clang/plugins/FindBadConstructsAction.cpp
+++ b/tools/clang/plugins/FindBadConstructsAction.cpp
@@ -53,8 +53,6 @@
// TODO(tsepez): Enable this by default once http://crbug.com/356815
// and http://crbug.com/356816 are fixed.
options_.check_enum_last_value = true;
- } else if (args[i] == "strict-virtual-specifiers") {
- options_.strict_virtual_specifiers = true;
} else if (args[i] == "with-ast-visitor") {
options_.with_ast_visitor = true;
} else if (args[i] == "check-templates") {
diff --git a/tools/clang/plugins/FindBadConstructsConsumer.cpp b/tools/clang/plugins/FindBadConstructsConsumer.cpp
index 46e1df8..fe868c0 100644
--- a/tools/clang/plugins/FindBadConstructsConsumer.cpp
+++ b/tools/clang/plugins/FindBadConstructsConsumer.cpp
@@ -283,6 +283,9 @@
for (CXXRecordDecl::ctor_iterator it = record->ctor_begin();
it != record->ctor_end();
++it) {
+ // The current check is buggy. An implicit copy constructor does not
+ // have an inline body, so this check never fires for classes with a
+ // user-declared out-of-line constructor.
if (it->hasInlineBody()) {
if (it->isCopyConstructor() &&
!record->hasUserDeclaredCopyConstructor()) {
@@ -293,6 +296,15 @@
emitWarning(it->getInnerLocStart(),
"Complex constructor has an inlined body.");
}
+ } else if (it->isInlined() && (!it->isCopyOrMoveConstructor() ||
+ it->isExplicitlyDefaulted())) {
+ // isInlined() is a more reliable check than hasInlineBody(), but
+ // unfortunately, it results in warnings for implicit copy/move
+ // constructors in the previously mentioned situation. To preserve
+ // compatibility with existing Chromium code, only warn if it's an
+ // explicitly defaulted copy or move constructor.
+ emitWarning(it->getInnerLocStart(),
+ "Complex constructor has an inlined body.");
}
}
}
@@ -306,7 +318,7 @@
"Complex class/struct needs an explicit out-of-line "
"destructor.");
} else if (CXXDestructorDecl* dtor = record->getDestructor()) {
- if (dtor->hasInlineBody()) {
+ if (dtor->isInlined()) {
emitWarning(dtor->getInnerLocStart(),
"Complex destructor has an inline body.");
}
@@ -331,8 +343,7 @@
// magic to try to make sure SetUp()/TearDown() aren't capitalized
// incorrectly, but having the plugin enforce override is also nice.
(InTestingNamespace(overridden) &&
- (!options_.strict_virtual_specifiers ||
- !IsGtestTestFixture(overridden->getParent())))) {
+ !IsGtestTestFixture(overridden->getParent()))) {
return true;
}
}
@@ -393,20 +404,13 @@
OverrideAttr* override_attr = method->getAttr<OverrideAttr>();
FinalAttr* final_attr = method->getAttr<FinalAttr>();
- if (method->isPure() && !options_.strict_virtual_specifiers)
- return;
-
if (IsMethodInBannedOrTestingNamespace(method))
return;
- if (isa<CXXDestructorDecl>(method) && !options_.strict_virtual_specifiers)
- return;
-
SourceManager& manager = instance().getSourceManager();
// Complain if a method is annotated virtual && (override || final).
- if (has_virtual && (override_attr || final_attr) &&
- options_.strict_virtual_specifiers) {
+ if (has_virtual && (override_attr || final_attr)) {
diagnostic().Report(method->getLocStart(),
diag_redundant_virtual_specifier_)
<< "'virtual'"
@@ -436,14 +440,14 @@
}
}
- if (final_attr && override_attr && options_.strict_virtual_specifiers) {
+ if (final_attr && override_attr) {
diagnostic().Report(override_attr->getLocation(),
diag_redundant_virtual_specifier_)
<< override_attr << final_attr
<< FixItHint::CreateRemoval(override_attr->getRange());
}
- if (final_attr && !is_override && options_.strict_virtual_specifiers) {
+ if (final_attr && !is_override) {
diagnostic().Report(method->getLocStart(),
diag_base_method_virtual_and_final_)
<< FixItRemovalForVirtual(manager, method)
diff --git a/tools/clang/plugins/Options.h b/tools/clang/plugins/Options.h
index 5ef4977..112ec10 100644
--- a/tools/clang/plugins/Options.h
+++ b/tools/clang/plugins/Options.h
@@ -11,13 +11,11 @@
Options()
: check_base_classes(false),
check_enum_last_value(false),
- strict_virtual_specifiers(false),
with_ast_visitor(false),
check_templates(false) {}
bool check_base_classes;
bool check_enum_last_value;
- bool strict_virtual_specifiers;
bool with_ast_visitor;
bool check_templates;
};
diff --git a/tools/clang/plugins/tests/base_refcounted.cpp b/tools/clang/plugins/tests/base_refcounted.cpp
index 698bf7b..46e8975 100644
--- a/tools/clang/plugins/tests/base_refcounted.cpp
+++ b/tools/clang/plugins/tests/base_refcounted.cpp
@@ -13,7 +13,7 @@
: public ProtectedRefCountedVirtualDtorInHeader {
public:
AnonymousDerivedProtectedToPublicInImpl() {}
- virtual ~AnonymousDerivedProtectedToPublicInImpl() {}
+ ~AnonymousDerivedProtectedToPublicInImpl() override {}
};
// Unsafe; but we should only warn on the base class.
diff --git a/tools/clang/plugins/tests/base_refcounted.h b/tools/clang/plugins/tests/base_refcounted.h
index 4b4077c..4a489ee 100644
--- a/tools/clang/plugins/tests/base_refcounted.h
+++ b/tools/clang/plugins/tests/base_refcounted.h
@@ -107,7 +107,7 @@
: public ProtectedRefCountedVirtualDtorInHeader {
public:
DerivedProtectedToPublicInHeader() {}
- virtual ~DerivedProtectedToPublicInHeader() {}
+ ~DerivedProtectedToPublicInHeader() override {}
};
// Unsafe; A grandchild ends up implicitly exposing their parent and
@@ -146,10 +146,10 @@
: public APublicInterface,
public base::RefCounted<ImplementsAPublicInterface> {
public:
- virtual void DoFoo() override {}
+ void DoFoo() override {}
protected:
- virtual ~ImplementsAPublicInterface() {}
+ ~ImplementsAPublicInterface() override {}
private:
friend class base::RefCounted<ImplementsAPublicInterface>;
@@ -165,7 +165,7 @@
: public AnImplicitInterface,
public base::RefCounted<ImplementsAnImplicitInterface> {
public:
- virtual void DoBar() override {}
+ void DoBar() override {}
private:
friend class base::RefCounted<ImplementsAnImplicitInterface>;
@@ -177,11 +177,11 @@
: private APublicInterface,
public base::RefCounted<PrivatelyImplementsAPublicInterface> {
public:
- virtual void DoFoo() override {}
+ void DoFoo() override {}
private:
friend class base::RefCounted<PrivatelyImplementsAPublicInterface>;
- virtual ~PrivatelyImplementsAPublicInterface() {}
+ ~PrivatelyImplementsAPublicInterface() override {}
};
// Unsafe.
@@ -192,7 +192,7 @@
};
class DerivedInterface : public BaseInterface {
protected:
- virtual ~DerivedInterface() {}
+ ~DerivedInterface() override {}
};
class SomeOtherInterface {
public:
@@ -211,13 +211,13 @@
public RefcountedType {
public:
// DerivedInterface
- virtual void DoFoo() override {}
+ void DoFoo() override {}
// SomeOtherInterface
- virtual void DoBar() override {}
+ void DoBar() override {}
protected:
- virtual ~UnsafeInheritanceChain() {}
+ ~UnsafeInheritanceChain() override {}
};
#endif // BASE_REFCOUNTED_H_
diff --git a/tools/clang/plugins/tests/base_refcounted.txt b/tools/clang/plugins/tests/base_refcounted.txt
index 20c0cdf..ae91986 100644
--- a/tools/clang/plugins/tests/base_refcounted.txt
+++ b/tools/clang/plugins/tests/base_refcounted.txt
@@ -15,7 +15,7 @@
~ProtectedRefCountedDtorInHeader() {}
^
./base_refcounted.h:110:3: warning: [chromium-style] Classes that are ref-counted should have destructors that are declared protected or private.
- virtual ~DerivedProtectedToPublicInHeader() {}
+ ~DerivedProtectedToPublicInHeader() override {}
^
./base_refcounted.h:107:7: note: [chromium-style] 'DerivedProtectedToPublicInHeader' inherits from 'ProtectedRefCountedVirtualDtorInHeader' here
: public ProtectedRefCountedVirtualDtorInHeader {
@@ -61,7 +61,7 @@
^
./base_refcounted.h:204:3: warning: [chromium-style] Classes that are ref-counted and have non-private destructors should declare their destructor virtual.
base_refcounted.cpp:16:3: warning: [chromium-style] Classes that are ref-counted should have destructors that are declared protected or private.
- virtual ~AnonymousDerivedProtectedToPublicInImpl() {}
+ ~AnonymousDerivedProtectedToPublicInImpl() override {}
^
base_refcounted.cpp:13:7: note: [chromium-style] 'AnonymousDerivedProtectedToPublicInImpl' inherits from 'ProtectedRefCountedVirtualDtorInHeader' here
: public ProtectedRefCountedVirtualDtorInHeader {
diff --git a/tools/clang/plugins/tests/missing_ctor.h b/tools/clang/plugins/tests/missing_ctor.h
index 1050457..0551fd7 100644
--- a/tools/clang/plugins/tests/missing_ctor.h
+++ b/tools/clang/plugins/tests/missing_ctor.h
@@ -8,6 +8,8 @@
#include <string>
#include <vector>
+// Note: this should warn for an implicit copy constructor too, but currently
+// doesn't, due to a plugin bug.
class MissingCtorsArentOKInHeader {
public:
@@ -16,4 +18,33 @@
std::vector<std::string> two_;
};
+// Inline move ctors shouldn't be warned about. Similar to the previous test
+// case, this also incorrectly fails to warn for the implicit copy ctor.
+class InlineImplicitMoveCtorOK {
+ public:
+ InlineImplicitMoveCtorOK();
+
+ private:
+ // ctor weight = 12, dtor weight = 9.
+ std::string one_;
+ std::string two_;
+ std::string three_;
+ int four_;
+ int five_;
+ int six_;
+};
+
+class ExplicitlyDefaultedInlineAlsoWarns {
+ public:
+ ExplicitlyDefaultedInlineAlsoWarns() = default;
+ ~ExplicitlyDefaultedInlineAlsoWarns() = default;
+ ExplicitlyDefaultedInlineAlsoWarns(
+ const ExplicitlyDefaultedInlineAlsoWarns&) = default;
+
+ private:
+ std::vector<int> one_;
+ std::vector<std::string> two_;
+
+};
+
#endif // MISSING_CTOR_H_
diff --git a/tools/clang/plugins/tests/missing_ctor.txt b/tools/clang/plugins/tests/missing_ctor.txt
index 301449c..0bc5696 100644
--- a/tools/clang/plugins/tests/missing_ctor.txt
+++ b/tools/clang/plugins/tests/missing_ctor.txt
@@ -1,6 +1,15 @@
In file included from missing_ctor.cpp:5:
-./missing_ctor.h:11:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
+./missing_ctor.h:13:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line constructor.
class MissingCtorsArentOKInHeader {
^
-./missing_ctor.h:11:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor.
-2 warnings generated.
+./missing_ctor.h:13:1: warning: [chromium-style] Complex class/struct needs an explicit out-of-line destructor.
+./missing_ctor.h:39:3: warning: [chromium-style] Complex constructor has an inlined body.
+ ExplicitlyDefaultedInlineAlsoWarns() = default;
+ ^
+./missing_ctor.h:41:3: warning: [chromium-style] Complex constructor has an inlined body.
+ ExplicitlyDefaultedInlineAlsoWarns(
+ ^
+./missing_ctor.h:40:3: warning: [chromium-style] Complex destructor has an inline body.
+ ~ExplicitlyDefaultedInlineAlsoWarns() = default;
+ ^
+5 warnings generated.
diff --git a/tools/clang/plugins/tests/overridden_methods.cpp b/tools/clang/plugins/tests/overridden_methods.cpp
index 398d6a4..8b0340c 100644
--- a/tools/clang/plugins/tests/overridden_methods.cpp
+++ b/tools/clang/plugins/tests/overridden_methods.cpp
@@ -11,19 +11,19 @@
class ImplementationInterimClass : public BaseClass {
public:
- // Should not warn about pure virtual methods.
+ // Should warn about pure virtual methods.
virtual void SomeMethod() = 0;
};
class ImplementationDerivedClass : public ImplementationInterimClass,
public webkit_glue::WebKitObserverImpl {
public:
- // Should not warn about destructors.
+ // Should warn about destructors.
virtual ~ImplementationDerivedClass() {}
// Should warn.
virtual void SomeMethod();
// Should not warn if marked as override.
- virtual void SomeOtherMethod() override;
+ void SomeOtherMethod() override;
// Should not warn for inline implementations in implementation files.
virtual void SomeInlineMethod() {}
// Should not warn if overriding a method whose origin is blink.
diff --git a/tools/clang/plugins/tests/overridden_methods.h b/tools/clang/plugins/tests/overridden_methods.h
index c5af914..69ee100 100644
--- a/tools/clang/plugins/tests/overridden_methods.h
+++ b/tools/clang/plugins/tests/overridden_methods.h
@@ -21,7 +21,7 @@
};
class InterimClass : public BaseClass {
- // Should not warn about pure virtual methods.
+ // Should warn about pure virtual methods.
virtual void SomeMethod() = 0;
};
@@ -42,12 +42,12 @@
class DerivedClass : public InterimClass,
public webkit_glue::WebKitObserverImpl {
public:
- // Should not warn about destructors.
+ // Should warn about destructors.
virtual ~DerivedClass() {}
// Should warn.
virtual void SomeMethod();
// Should not warn if marked as override.
- virtual void SomeOtherMethod() override;
+ void SomeOtherMethod() override;
// Should warn for inline implementations.
virtual void SomeInlineMethod() {}
// Should not warn if overriding a method whose origin is blink.
diff --git a/tools/clang/plugins/tests/overridden_methods.txt b/tools/clang/plugins/tests/overridden_methods.txt
index 3ee0333..69ff2b1 100644
--- a/tools/clang/plugins/tests/overridden_methods.txt
+++ b/tools/clang/plugins/tests/overridden_methods.txt
@@ -1,4 +1,12 @@
In file included from overridden_methods.cpp:5:
+./overridden_methods.h:25:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+ virtual void SomeMethod() = 0;
+ ^
+ override
+./overridden_methods.h:46:26: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+ virtual ~DerivedClass() {}
+ ^
+ override
./overridden_methods.h:48:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethod();
^
@@ -31,6 +39,14 @@
virtual void SomeMethodWithCommentAndBody() {} // This is a comment.
^
override
+overridden_methods.cpp:15:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+ virtual void SomeMethod() = 0;
+ ^
+ override
+overridden_methods.cpp:22:40: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
+ virtual ~ImplementationDerivedClass() {}
+ ^
+ override
overridden_methods.cpp:24:28: warning: [chromium-style] Overriding method must be marked with 'override' or 'final'.
virtual void SomeMethod();
^
@@ -63,4 +79,4 @@
virtual void SomeMethodWithCommentAndBody() {} // This is a comment.
^
override
-16 warnings generated.
+20 warnings generated.
diff --git a/tools/clang/plugins/tests/virtual_base_method_also_final.flags b/tools/clang/plugins/tests/virtual_base_method_also_final.flags
deleted file mode 100644
index a8915fc..0000000
--- a/tools/clang/plugins/tests/virtual_base_method_also_final.flags
+++ /dev/null
@@ -1 +0,0 @@
--Xclang -plugin-arg-find-bad-constructs -Xclang strict-virtual-specifiers
diff --git a/tools/clang/plugins/tests/virtual_bodies.cpp b/tools/clang/plugins/tests/virtual_bodies.cpp
index 8815dc2..4f37a67 100644
--- a/tools/clang/plugins/tests/virtual_bodies.cpp
+++ b/tools/clang/plugins/tests/virtual_bodies.cpp
@@ -16,13 +16,13 @@
// Stubs to fill in the abstract method
class ConcreteVirtualMethodsInHeaders : public VirtualMethodsInHeaders {
public:
- virtual void MethodIsAbstract() override {}
+ void MethodIsAbstract() override {}
};
class ConcreteVirtualMethodsInImplementation
: public VirtualMethodsInImplementation {
public:
- virtual void MethodIsAbstract() override {}
+ void MethodIsAbstract() override {}
};
// Fill in the implementations
diff --git a/tools/clang/plugins/tests/virtual_specifiers.flags b/tools/clang/plugins/tests/virtual_specifiers.flags
deleted file mode 100644
index a8915fc..0000000
--- a/tools/clang/plugins/tests/virtual_specifiers.flags
+++ /dev/null
@@ -1 +0,0 @@
--Xclang -plugin-arg-find-bad-constructs -Xclang strict-virtual-specifiers
diff --git a/tools/clang/plugins/tests/weak_ptr_factory.flags b/tools/clang/plugins/tests/weak_ptr_factory.flags
index 7d9476e..52b35b5 100644
--- a/tools/clang/plugins/tests/weak_ptr_factory.flags
+++ b/tools/clang/plugins/tests/weak_ptr_factory.flags
@@ -1 +1 @@
--Xclang -plugin-arg-find-bad-constructs -Xclang check-templates -Xclang -plugin-arg-find-bad-constructs -Xclang check-weak-ptr-factory-order
+-Xclang -plugin-arg-find-bad-constructs -Xclang check-templates
diff --git a/tools/clang/scripts/plugin_flags.sh b/tools/clang/scripts/plugin_flags.sh
index 76a82c5..81fe0f1 100755
--- a/tools/clang/scripts/plugin_flags.sh
+++ b/tools/clang/scripts/plugin_flags.sh
@@ -17,5 +17,6 @@
fi
echo -Xclang -load -Xclang $CLANG_LIB_PATH/libFindBadConstructs.$LIBSUFFIX \
- -Xclang -add-plugin -Xclang find-bad-constructs -Xclang \
- -plugin-arg-find-bad-constructs -Xclang check-weak-ptr-factory-order
+ -Xclang -add-plugin -Xclang find-bad-constructs \
+ -Xclang -plugin-arg-find-bad-constructs -Xclang check-weak-ptr-factory-order \
+ -Xclang -plugin-arg-find-bad-constructs -Xclang strict-virtual-specifiers
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 6e55d0c..cb0878d 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -24,7 +24,7 @@
# in bringup. Use a pinned revision to make it slightly more stable.
if (re.search(r'\b(asan)=1', os.environ.get('GYP_DEFINES', '')) and
not 'LLVM_FORCE_HEAD_REVISION' in os.environ):
- LLVM_WIN_REVISION = '228702'
+ LLVM_WIN_REVISION = '229860'
# Path constants. (All of these should be absolute paths.)
THIS_DIR = os.path.abspath(os.path.dirname(__file__))
diff --git a/tools/git/move_source_file.py b/tools/git/move_source_file.py
index 1a25e44..18ef1ce 100755
--- a/tools/git/move_source_file.py
+++ b/tools/git/move_source_file.py
@@ -31,6 +31,7 @@
# classpath.
sys.path.append(os.path.abspath(os.path.join(sys.path[0], '..')))
sort_headers = __import__('sort-headers')
+import sort_sources
HANDLED_EXTENSIONS = ['.cc', '.mm', '.h', '.hh', '.cpp']
@@ -142,11 +143,13 @@
from_rest = from_path
to_rest = to_path
while True:
- mffr.MultiFileFindReplace(
+ files_with_changed_sources = mffr.MultiFileFindReplace(
r'([\'"])%s([\'"])' % from_rest,
r'\1%s\2' % to_rest,
[os.path.join(visiting_directory, 'BUILD.gn'),
os.path.join(visiting_directory, '*.gyp*')])
+ for changed_file in files_with_changed_sources:
+ sort_sources.ProcessFile(changed_file, should_confirm=False)
from_first, from_rest = SplitByFirstComponent(from_rest)
to_first, to_rest = SplitByFirstComponent(to_rest)
visiting_directory = os.path.join(visiting_directory, from_first)
diff --git a/tools/relocation_packer/BUILD.gn b/tools/relocation_packer/BUILD.gn
index 0b29c91..e95dbcf 100644
--- a/tools/relocation_packer/BUILD.gn
+++ b/tools/relocation_packer/BUILD.gn
@@ -7,9 +7,9 @@
assert(relocation_packing_supported)
-if (target_arch == "arm") {
+if (target_cpu == "arm") {
target_define = "TARGET_ARM"
-} else if (target_arch == "arm64") {
+} else if (target_cpu == "arm64") {
target_define = "TARGET_ARM64"
}
@@ -78,7 +78,7 @@
}
if (current_toolchain == default_toolchain &&
- (target_arch == "arm" || target_arch == "arm64")) {
+ (target_cpu == "arm" || target_cpu == "arm64")) {
# Targets to build test data. These participate only in building test
# data for use with elf_file_unittest.cc, and are not part of the main
# relocation packer build. Unit test data files are checked in to the
@@ -102,11 +102,11 @@
action("relocation_packer_unittests_test_data") {
script = "test_data/generate_elf_file_unittest_relocs.py"
test_file = "$root_build_dir/librelocation_packer_test_data.so"
- if (target_arch == "arm") {
+ if (target_cpu == "arm") {
added_section = ".android.rel.dyn"
packed_output = "elf_file_unittest_relocs_arm32_packed.so"
unpacked_output = "elf_file_unittest_relocs_arm32.so"
- } else if (target_arch == "arm64") {
+ } else if (target_cpu == "arm64") {
added_section = ".android.rela.dyn"
packed_output = "elf_file_unittest_relocs_arm64_packed.so"
unpacked_output = "elf_file_unittest_relocs_arm64.so"
diff --git a/tools/relocation_packer/config.gni b/tools/relocation_packer/config.gni
index 90e3979..4cdd945 100644
--- a/tools/relocation_packer/config.gni
+++ b/tools/relocation_packer/config.gni
@@ -2,7 +2,7 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
-relocation_packing_supported = target_arch == "arm" || target_arch == "arm64"
+relocation_packing_supported = target_cpu == "arm" || target_cpu == "arm64"
if (relocation_packing_supported) {
relocation_packer_target = "//tools/relocation_packer($host_toolchain)"
@@ -10,9 +10,9 @@
get_label_info("$relocation_packer_target", "root_out_dir")
relocation_packer_exe = "${relocation_packer_dir}/relocation_packer"
- if (target_arch == "arm") {
+ if (target_cpu == "arm") {
relocations_have_addends = 0
- } else if (target_arch == "arm64") {
+ } else if (target_cpu == "arm64") {
relocations_have_addends = 1
}
} else {
diff --git a/tools/valgrind/drmemory/suppressions_full.txt b/tools/valgrind/drmemory/suppressions_full.txt
index d2db1bf..eae85e5 100644
--- a/tools/valgrind/drmemory/suppressions_full.txt
+++ b/tools/valgrind/drmemory/suppressions_full.txt
@@ -1103,13 +1103,6 @@
# at the peak set of tests we plan to run and remove the unused ones.
UNINITIALIZED READ
-name=bug_99307
-*!modp_b64_encode
-*!base::Base64Encode*
-*!web_ui_util::GetImageDataUrl
-*!::NetworkInfoDictionary::set_icon
-
-UNINITIALIZED READ
name=bug_101781
*!encode_one_block
*!encode_mcu_huff
diff --git a/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt
index bdc0e84..e7f3488 100644
--- a/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt
+++ b/tools/valgrind/gtest_exclude/cc_unittests.gtest-drmemory_win32.txt
@@ -26,3 +26,6 @@
PixelResourceTest/LayerTreeHostMasksPixelTest.MaskOfReplica/6
PixelResourceTest/LayerTreeHostMasksPixelTest.MaskOfReplicaOfClippedLayer/5
PixelResourceTest/LayerTreeHostMasksPixelTest.MaskOfReplicaOfClippedLayer/6
+
+# https://crbug.com/460581
+LayerTreeHostPictureTestRSLLMembershipWithScale.RunMultiThread_DirectRenderer_ImplSidePaint
diff --git a/tools/valgrind/gtest_exclude/content_unittests.gtest.txt b/tools/valgrind/gtest_exclude/content_unittests.gtest.txt
index d47ad75..60e98f2 100644
--- a/tools/valgrind/gtest_exclude/content_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/content_unittests.gtest.txt
@@ -10,3 +10,7 @@
# https://crbug.com/449103
WebInputEventAuraTest.TestMakeWebKeyboardEventWindowsKeyCode
+
+# Flaky: https://crbug.com/460578
+DesktopCaptureDeviceTest.InvertedFrame
+DesktopCaptureDeviceTest.UnpackedFrame
diff --git a/tools/valgrind/gtest_exclude/installer_util_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/installer_util_unittests.gtest-drmemory_win32.txt
new file mode 100644
index 0000000..7428628
--- /dev/null
+++ b/tools/valgrind/gtest_exclude/installer_util_unittests.gtest-drmemory_win32.txt
@@ -0,0 +1,2 @@
+# https://crbug.com/460584
+CopyTreeWorkItemTest.NewNameAndCopyTest
diff --git a/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt b/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt
index 6491f45..c322014 100644
--- a/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt
+++ b/tools/valgrind/gtest_exclude/remoting_unittests.gtest.txt
@@ -1,5 +1,2 @@
# http://crbug.com/241856
VideoSchedulerTest.StartAndStop
-
-# crbug.com/458691
-ClientSessionTest.ClipboardStubFilter
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 67243d1..9ea9570 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -1245,14 +1245,6 @@
obj:*
}
{
- bug_99307
- Memcheck:Uninitialized
- fun:modp_b64_encode
- fun:_ZN4base12Base64Encode*
- fun:_ZN11web_ui_util15GetImageDataUrlERK8SkBitmap
- fun:_ZN12_GLOBAL__N_121NetworkInfoDictionary8set_iconERK8SkBitmap
-}
-{
bug_100982
Memcheck:Leak
fun:_Znw*
@@ -3653,3 +3645,4 @@
fun:_ZN4base12_GLOBAL__N_112WorkerThread10ThreadMainEv
fun:_ZN4base12_GLOBAL__N_110ThreadFuncEPv
}
+
diff --git a/ui/events/gestures/gesture_provider_impl.cc b/ui/events/gestures/gesture_provider_impl.cc
index 561273e..58862d1 100644
--- a/ui/events/gestures/gesture_provider_impl.cc
+++ b/ui/events/gestures/gesture_provider_impl.cc
@@ -91,7 +91,7 @@
ui::INPUT_EVENT_LATENCY_UI_COMPONENT);
gesture_latency->CopyLatencyFrom(
last_touch_event_latency_info_,
- ui::INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT);
+ ui::INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT);
if (!handling_event_) {
// Dispatching event caused by timer.
diff --git a/ui/events/latency_info.cc b/ui/events/latency_info.cc
index 9d16b29..02586d6 100644
--- a/ui/events/latency_info.cc
+++ b/ui/events/latency_info.cc
@@ -20,17 +20,19 @@
CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_PLUGIN_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_SCROLL_UPDATE_MAIN_COMPONENT);
- CASE_TYPE(INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_UI_COMPONENT);
- CASE_TYPE(INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT);
- CASE_TYPE(INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT);
CASE_TYPE(WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT);
CASE_TYPE(WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT);
- CASE_TYPE(INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT);
- CASE_TYPE(INPUT_EVENT_BROWSER_SWAP_BUFFER_COMPONENT);
+ CASE_TYPE(TAB_SHOW_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT);
+ CASE_TYPE(INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT);
CASE_TYPE(INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_MOUSE_COMPONENT);
CASE_TYPE(INPUT_EVENT_LATENCY_TERMINATED_TOUCH_COMPONENT);
@@ -71,7 +73,8 @@
}
// This class is for converting latency info to trace buffer friendly format.
-class LatencyInfoTracedValue : public base::trace_event::ConvertableToTraceFormat {
+class LatencyInfoTracedValue
+ : public base::trace_event::ConvertableToTraceFormat {
public:
static scoped_refptr<ConvertableToTraceFormat> FromValue(
scoped_ptr<base::Value> value);
@@ -253,7 +256,7 @@
}
TRACE_EVENT_FLOW_BEGIN0(
- "input", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
+ "input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
}
LatencyMap::key_type key = std::make_pair(component, id);
@@ -288,7 +291,7 @@
}
TRACE_EVENT_FLOW_END0(
- "input", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
+ "input,benchmark", "LatencyInfo.Flow", TRACE_ID_DONT_MANGLE(trace_id));
}
}
diff --git a/ui/events/latency_info.h b/ui/events/latency_info.h
index 1a18f9b..b6724b8 100644
--- a/ui/events/latency_info.h
+++ b/ui/events/latency_info.h
@@ -25,26 +25,25 @@
// Timestamp when a scroll update for the main thread is begun.
INPUT_EVENT_LATENCY_BEGIN_SCROLL_UPDATE_MAIN_COMPONENT,
// ---------------------------NORMAL COMPONENT-------------------------------
- // Timestamp when the scroll update gesture event is sent from RWH to
- // renderer. In Aura, touch event's LatencyInfo is carried over to the gesture
- // event. So gesture event's INPUT_EVENT_LATENCY_RWH_COMPONENT is the
- // timestamp when its original touch events is sent from RWH to renderer.
- // In non-aura platform, INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT
- // is the same as INPUT_EVENT_LATENCY_RWH_COMPONENT.
- INPUT_EVENT_LATENCY_SCROLL_UPDATE_RWH_COMPONENT,
// The original timestamp of the touch event which converts to scroll update.
INPUT_EVENT_LATENCY_SCROLL_UPDATE_ORIGINAL_COMPONENT,
+ // The original timestamp of the touch event which converts to the *first*
+ // scroll update in a scroll gesture sequence.
+ INPUT_EVENT_LATENCY_FIRST_SCROLL_UPDATE_ORIGINAL_COMPONENT,
// Original timestamp for input event (e.g. timestamp from kernel).
INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
// Timestamp when the UI event is created.
INPUT_EVENT_LATENCY_UI_COMPONENT,
// This is special component indicating there is rendering scheduled for
- // the event associated with this LatencyInfo.
- INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_COMPONENT,
+ // the event associated with this LatencyInfo on main thread.
+ INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_MAIN_COMPONENT,
+ // This is special component indicating there is rendering scheduled for
+ // the event associated with this LatencyInfo on impl thread.
+ INPUT_EVENT_LATENCY_RENDERING_SCHEDULED_IMPL_COMPONENT,
// Timestamp when a scroll update is forwarded to the main thread.
INPUT_EVENT_LATENCY_FORWARD_SCROLL_UPDATE_TO_MAIN_COMPONENT,
- // Timestamp when the touch event is acked.
- INPUT_EVENT_LATENCY_ACKED_TOUCH_COMPONENT,
+ // Timestamp when the event's ack is received by the RWH.
+ INPUT_EVENT_LATENCY_ACK_RWH_COMPONENT,
// Frame number when a window snapshot was requested. The snapshot
// is taken when the rendering results actually reach the screen.
WINDOW_SNAPSHOT_FRAME_NUMBER_COMPONENT,
@@ -54,12 +53,13 @@
WINDOW_OLD_SNAPSHOT_FRAME_NUMBER_COMPONENT,
// Timestamp when a tab is requested to be shown.
TAB_SHOW_COMPONENT,
- // Timestamp of when the Browser process began compositing
- INPUT_EVENT_BROWSER_COMPOSITE_COMPONENT,
- // Timestamp of when the Browser process began swap buffers
- INPUT_EVENT_BROWSER_SWAP_BUFFER_COMPONENT,
+ // Timestamp when the frame is swapped in renderer.
+ INPUT_EVENT_LATENCY_RENDERER_SWAP_COMPONENT,
+ // Timestamp of when the browser process receives a buffer swap notification
+ // from the renderer.
+ INPUT_EVENT_BROWSER_RECEIVED_RENDERER_SWAP_COMPONENT,
// Timestamp of when the gpu service began swap buffers, unlike
- // INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT which measure after
+ // INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT which measures after.
INPUT_EVENT_GPU_SWAP_BUFFER_COMPONENT,
// ---------------------------TERMINAL COMPONENT-----------------------------
// TERMINAL COMPONENT is when we show the latency end in chrome://tracing.
@@ -111,7 +111,7 @@
};
// Empirically determined constant based on a typical scroll sequence.
- enum { kTypicalMaxComponentsPerLatencyInfo = 9 };
+ enum { kTypicalMaxComponentsPerLatencyInfo = 10 };
enum { kMaxInputCoordinates = 2 };
diff --git a/ui/gl/generate_bindings.py b/ui/gl/generate_bindings.py
index 639ec7e..3b91dd3 100755
--- a/ui/gl/generate_bindings.py
+++ b/ui/gl/generate_bindings.py
@@ -562,6 +562,9 @@
{ 'return_type': 'void',
'names': ['glGetProgramiv'],
'arguments': 'GLuint program, GLenum pname, GLint* params', },
+{ 'return_type': 'GLint',
+ 'names': ['glGetProgramResourceLocation'],
+ 'arguments': 'GLuint program, GLenum programInterface, const char* name', },
{ 'return_type': 'void',
'versions': [{ 'name': 'glGetQueryiv' }],
'arguments': 'GLenum target, GLenum pname, GLint* params', },
@@ -621,6 +624,9 @@
{ 'return_type': 'const GLubyte*',
'names': ['glGetString'],
'arguments': 'GLenum name', },
+{ 'return_type': 'const GLubyte*',
+ 'names': ['glGetStringi'],
+ 'arguments': 'GLenum name, GLuint index', },
{ 'return_type': 'void',
'versions': [{ 'name': 'glGetSynciv',
'extensions': ['GL_ARB_sync'] }],
diff --git a/ui/gl/gl_bindings_api_autogen_gl.h b/ui/gl/gl_bindings_api_autogen_gl.h
index c886a23..9b0366c 100644
--- a/ui/gl/gl_bindings_api_autogen_gl.h
+++ b/ui/gl/gl_bindings_api_autogen_gl.h
@@ -343,6 +343,9 @@
GLsizei* length,
char* infolog) override;
void glGetProgramivFn(GLuint program, GLenum pname, GLint* params) override;
+GLint glGetProgramResourceLocationFn(GLuint program,
+ GLenum programInterface,
+ const char* name) override;
void glGetQueryivFn(GLenum target, GLenum pname, GLint* params) override;
void glGetQueryivARBFn(GLenum target, GLenum pname, GLint* params) override;
void glGetQueryObjecti64vFn(GLuint id, GLenum pname, GLint64* params) override;
@@ -376,6 +379,7 @@
GLsizei* length,
char* source) override;
const GLubyte* glGetStringFn(GLenum name) override;
+const GLubyte* glGetStringiFn(GLenum name, GLuint index) override;
void glGetSyncivFn(GLsync sync,
GLenum pname,
GLsizei bufSize,
diff --git a/ui/gl/gl_bindings_autogen_gl.cc b/ui/gl/gl_bindings_autogen_gl.cc
index f1100e8..a655717 100644
--- a/ui/gl/gl_bindings_autogen_gl.cc
+++ b/ui/gl/gl_bindings_autogen_gl.cc
@@ -212,6 +212,7 @@
GetGLProcAddress("glGetProgramInfoLog"));
fn.glGetProgramivFn =
reinterpret_cast<glGetProgramivProc>(GetGLProcAddress("glGetProgramiv"));
+ fn.glGetProgramResourceLocationFn = 0;
fn.glGetQueryivFn = 0;
fn.glGetQueryivARBFn = 0;
fn.glGetQueryObjecti64vFn = 0;
@@ -232,6 +233,7 @@
GetGLProcAddress("glGetShaderSource"));
fn.glGetStringFn =
reinterpret_cast<glGetStringProc>(GetGLProcAddress("glGetString"));
+ fn.glGetStringiFn = 0;
fn.glGetSyncivFn = 0;
fn.glGetTexLevelParameterfvFn = 0;
fn.glGetTexLevelParameterivFn = 0;
@@ -1272,6 +1274,14 @@
DCHECK(fn.glGetProgramBinaryFn);
}
+ debug_fn.glGetProgramResourceLocationFn = 0;
+ if (ver->IsAtLeastGL(4u, 3u) || ver->IsAtLeastGLES(3u, 1u)) {
+ fn.glGetProgramResourceLocationFn =
+ reinterpret_cast<glGetProgramResourceLocationProc>(
+ GetGLProcAddress("glGetProgramResourceLocation"));
+ DCHECK(fn.glGetProgramResourceLocationFn);
+ }
+
debug_fn.glGetQueryivFn = 0;
if (!ver->is_es || ver->IsAtLeastGLES(3u, 0u)) {
fn.glGetQueryivFn =
@@ -1387,6 +1397,13 @@
DCHECK(fn.glGetShaderPrecisionFormatFn);
}
+ debug_fn.glGetStringiFn = 0;
+ if (ver->IsAtLeastGL(3u, 0u) || ver->IsAtLeastGLES(3u, 0u)) {
+ fn.glGetStringiFn =
+ reinterpret_cast<glGetStringiProc>(GetGLProcAddress("glGetStringi"));
+ DCHECK(fn.glGetStringiFn);
+ }
+
debug_fn.glGetSyncivFn = 0;
if (ver->IsAtLeastGL(3u, 2u) || ver->IsAtLeastGLES(3u, 0u) ||
ext.b_GL_ARB_sync) {
@@ -3246,6 +3263,20 @@
g_driver_gl.debug_fn.glGetProgramivFn(program, pname, params);
}
+static GLint GL_BINDING_CALL
+Debug_glGetProgramResourceLocation(GLuint program,
+ GLenum programInterface,
+ const char* name) {
+ GL_SERVICE_LOG("glGetProgramResourceLocation"
+ << "(" << program << ", "
+ << GLEnums::GetStringEnum(programInterface) << ", " << name
+ << ")");
+ GLint result = g_driver_gl.debug_fn.glGetProgramResourceLocationFn(
+ program, programInterface, name);
+ GL_SERVICE_LOG("GL_RESULT: " << result);
+ return result;
+}
+
static void GL_BINDING_CALL
Debug_glGetQueryiv(GLenum target, GLenum pname, GLint* params) {
GL_SERVICE_LOG("glGetQueryiv"
@@ -3391,6 +3422,16 @@
return result;
}
+static const GLubyte* GL_BINDING_CALL
+Debug_glGetStringi(GLenum name, GLuint index) {
+ GL_SERVICE_LOG("glGetStringi"
+ << "(" << GLEnums::GetStringEnum(name) << ", " << index
+ << ")");
+ const GLubyte* result = g_driver_gl.debug_fn.glGetStringiFn(name, index);
+ GL_SERVICE_LOG("GL_RESULT: " << result);
+ return result;
+}
+
static void GL_BINDING_CALL Debug_glGetSynciv(GLsync sync,
GLenum pname,
GLsizei bufSize,
@@ -5243,6 +5284,10 @@
debug_fn.glGetProgramivFn = fn.glGetProgramivFn;
fn.glGetProgramivFn = Debug_glGetProgramiv;
}
+ if (!debug_fn.glGetProgramResourceLocationFn) {
+ debug_fn.glGetProgramResourceLocationFn = fn.glGetProgramResourceLocationFn;
+ fn.glGetProgramResourceLocationFn = Debug_glGetProgramResourceLocation;
+ }
if (!debug_fn.glGetQueryivFn) {
debug_fn.glGetQueryivFn = fn.glGetQueryivFn;
fn.glGetQueryivFn = Debug_glGetQueryiv;
@@ -5309,6 +5354,10 @@
debug_fn.glGetStringFn = fn.glGetStringFn;
fn.glGetStringFn = Debug_glGetString;
}
+ if (!debug_fn.glGetStringiFn) {
+ debug_fn.glGetStringiFn = fn.glGetStringiFn;
+ fn.glGetStringiFn = Debug_glGetStringi;
+ }
if (!debug_fn.glGetSyncivFn) {
debug_fn.glGetSyncivFn = fn.glGetSyncivFn;
fn.glGetSyncivFn = Debug_glGetSynciv;
@@ -6652,6 +6701,13 @@
driver_->fn.glGetProgramivFn(program, pname, params);
}
+GLint GLApiBase::glGetProgramResourceLocationFn(GLuint program,
+ GLenum programInterface,
+ const char* name) {
+ return driver_->fn.glGetProgramResourceLocationFn(program, programInterface,
+ name);
+}
+
void GLApiBase::glGetQueryivFn(GLenum target, GLenum pname, GLint* params) {
driver_->fn.glGetQueryivFn(target, pname, params);
}
@@ -6740,6 +6796,10 @@
return driver_->fn.glGetStringFn(name);
}
+const GLubyte* GLApiBase::glGetStringiFn(GLenum name, GLuint index) {
+ return driver_->fn.glGetStringiFn(name, index);
+}
+
void GLApiBase::glGetSyncivFn(GLsync sync,
GLenum pname,
GLsizei bufSize,
@@ -8452,6 +8512,15 @@
gl_api_->glGetProgramivFn(program, pname, params);
}
+GLint TraceGLApi::glGetProgramResourceLocationFn(GLuint program,
+ GLenum programInterface,
+ const char* name) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu",
+ "TraceGLAPI::glGetProgramResourceLocation")
+ return gl_api_->glGetProgramResourceLocationFn(program, programInterface,
+ name);
+}
+
void TraceGLApi::glGetQueryivFn(GLenum target, GLenum pname, GLint* params) {
TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetQueryiv")
gl_api_->glGetQueryivFn(target, pname, params);
@@ -8559,6 +8628,11 @@
return gl_api_->glGetStringFn(name);
}
+const GLubyte* TraceGLApi::glGetStringiFn(GLenum name, GLuint index) {
+ TRACE_EVENT_BINARY_EFFICIENT0("gpu", "TraceGLAPI::glGetStringi")
+ return gl_api_->glGetStringiFn(name, index);
+}
+
void TraceGLApi::glGetSyncivFn(GLsync sync,
GLenum pname,
GLsizei bufSize,
@@ -10539,6 +10613,16 @@
LOG(ERROR) << "Trying to call glGetProgramiv() without current GL context";
}
+GLint NoContextGLApi::glGetProgramResourceLocationFn(GLuint program,
+ GLenum programInterface,
+ const char* name) {
+ NOTREACHED() << "Trying to call glGetProgramResourceLocation() without "
+ "current GL context";
+ LOG(ERROR) << "Trying to call glGetProgramResourceLocation() without current "
+ "GL context";
+ return 0;
+}
+
void NoContextGLApi::glGetQueryivFn(GLenum target,
GLenum pname,
GLint* params) {
@@ -10676,6 +10760,12 @@
return NULL;
}
+const GLubyte* NoContextGLApi::glGetStringiFn(GLenum name, GLuint index) {
+ NOTREACHED() << "Trying to call glGetStringi() without current GL context";
+ LOG(ERROR) << "Trying to call glGetStringi() without current GL context";
+ return NULL;
+}
+
void NoContextGLApi::glGetSyncivFn(GLsync sync,
GLenum pname,
GLsizei bufSize,
diff --git a/ui/gl/gl_bindings_autogen_gl.h b/ui/gl/gl_bindings_autogen_gl.h
index b930484..643a236 100644
--- a/ui/gl/gl_bindings_autogen_gl.h
+++ b/ui/gl/gl_bindings_autogen_gl.h
@@ -406,6 +406,10 @@
typedef void(GL_BINDING_CALL* glGetProgramivProc)(GLuint program,
GLenum pname,
GLint* params);
+typedef GLint(GL_BINDING_CALL* glGetProgramResourceLocationProc)(
+ GLuint program,
+ GLenum programInterface,
+ const char* name);
typedef void(GL_BINDING_CALL* glGetQueryivProc)(GLenum target,
GLenum pname,
GLint* params);
@@ -457,6 +461,8 @@
GLsizei* length,
char* source);
typedef const GLubyte*(GL_BINDING_CALL* glGetStringProc)(GLenum name);
+typedef const GLubyte*(GL_BINDING_CALL* glGetStringiProc)(GLenum name,
+ GLuint index);
typedef void(GL_BINDING_CALL* glGetSyncivProc)(GLsync sync,
GLenum pname,
GLsizei bufSize,
@@ -1072,6 +1078,7 @@
glGetProgramBinaryProc glGetProgramBinaryFn;
glGetProgramInfoLogProc glGetProgramInfoLogFn;
glGetProgramivProc glGetProgramivFn;
+ glGetProgramResourceLocationProc glGetProgramResourceLocationFn;
glGetQueryivProc glGetQueryivFn;
glGetQueryivARBProc glGetQueryivARBFn;
glGetQueryObjecti64vProc glGetQueryObjecti64vFn;
@@ -1088,6 +1095,7 @@
glGetShaderPrecisionFormatProc glGetShaderPrecisionFormatFn;
glGetShaderSourceProc glGetShaderSourceFn;
glGetStringProc glGetStringFn;
+ glGetStringiProc glGetStringiFn;
glGetSyncivProc glGetSyncivFn;
glGetTexLevelParameterfvProc glGetTexLevelParameterfvFn;
glGetTexLevelParameterivProc glGetTexLevelParameterivFn;
@@ -1579,6 +1587,9 @@
virtual void glGetProgramivFn(GLuint program,
GLenum pname,
GLint* params) = 0;
+ virtual GLint glGetProgramResourceLocationFn(GLuint program,
+ GLenum programInterface,
+ const char* name) = 0;
virtual void glGetQueryivFn(GLenum target, GLenum pname, GLint* params) = 0;
virtual void glGetQueryivARBFn(GLenum target,
GLenum pname,
@@ -1622,6 +1633,7 @@
GLsizei* length,
char* source) = 0;
virtual const GLubyte* glGetStringFn(GLenum name) = 0;
+ virtual const GLubyte* glGetStringiFn(GLenum name, GLuint index) = 0;
virtual void glGetSyncivFn(GLsync sync,
GLenum pname,
GLsizei bufSize,
@@ -2181,6 +2193,8 @@
#define glGetProgramBinary ::gfx::g_current_gl_context->glGetProgramBinaryFn
#define glGetProgramInfoLog ::gfx::g_current_gl_context->glGetProgramInfoLogFn
#define glGetProgramiv ::gfx::g_current_gl_context->glGetProgramivFn
+#define glGetProgramResourceLocation \
+ ::gfx::g_current_gl_context->glGetProgramResourceLocationFn
#define glGetQueryiv ::gfx::g_current_gl_context->glGetQueryivFn
#define glGetQueryivARB ::gfx::g_current_gl_context->glGetQueryivARBFn
#define glGetQueryObjecti64v ::gfx::g_current_gl_context->glGetQueryObjecti64vFn
@@ -2204,6 +2218,7 @@
::gfx::g_current_gl_context->glGetShaderPrecisionFormatFn
#define glGetShaderSource ::gfx::g_current_gl_context->glGetShaderSourceFn
#define glGetString ::gfx::g_current_gl_context->glGetStringFn
+#define glGetStringi ::gfx::g_current_gl_context->glGetStringiFn
#define glGetSynciv ::gfx::g_current_gl_context->glGetSyncivFn
#define glGetTexLevelParameterfv \
::gfx::g_current_gl_context->glGetTexLevelParameterfvFn
diff --git a/ui/gl/gl_bindings_autogen_mock.cc b/ui/gl/gl_bindings_autogen_mock.cc
index 8d3614b..bf0a857 100644
--- a/ui/gl/gl_bindings_autogen_mock.cc
+++ b/ui/gl/gl_bindings_autogen_mock.cc
@@ -1223,6 +1223,15 @@
interface_->GetProgramInfoLog(program, bufsize, length, infolog);
}
+GLint GL_BINDING_CALL
+MockGLInterface::Mock_glGetProgramResourceLocation(GLuint program,
+ GLenum programInterface,
+ const char* name) {
+ MakeFunctionUnique("glGetProgramResourceLocation");
+ return interface_->GetProgramResourceLocation(program, programInterface,
+ name);
+}
+
void GL_BINDING_CALL MockGLInterface::Mock_glGetProgramiv(GLuint program,
GLenum pname,
GLint* params) {
@@ -1398,6 +1407,12 @@
return interface_->GetString(name);
}
+const GLubyte* GL_BINDING_CALL
+MockGLInterface::Mock_glGetStringi(GLenum name, GLuint index) {
+ MakeFunctionUnique("glGetStringi");
+ return interface_->GetStringi(name, index);
+}
+
void GL_BINDING_CALL MockGLInterface::Mock_glGetSynciv(GLsync sync,
GLenum pname,
GLsizei bufSize,
@@ -2860,6 +2875,8 @@
return reinterpret_cast<void*>(Mock_glGetProgramBinaryOES);
if (strcmp(name, "glGetProgramInfoLog") == 0)
return reinterpret_cast<void*>(Mock_glGetProgramInfoLog);
+ if (strcmp(name, "glGetProgramResourceLocation") == 0)
+ return reinterpret_cast<void*>(Mock_glGetProgramResourceLocation);
if (strcmp(name, "glGetProgramiv") == 0)
return reinterpret_cast<void*>(Mock_glGetProgramiv);
if (strcmp(name, "glGetQueryObjecti64v") == 0)
@@ -2906,6 +2923,8 @@
return reinterpret_cast<void*>(Mock_glGetShaderiv);
if (strcmp(name, "glGetString") == 0)
return reinterpret_cast<void*>(Mock_glGetString);
+ if (strcmp(name, "glGetStringi") == 0)
+ return reinterpret_cast<void*>(Mock_glGetStringi);
if (strcmp(name, "glGetSynciv") == 0)
return reinterpret_cast<void*>(Mock_glGetSynciv);
if (strcmp(name, "glGetTexLevelParameterfv") == 0)
diff --git a/ui/gl/gl_bindings_autogen_mock.h b/ui/gl/gl_bindings_autogen_mock.h
index 52abdae..54c8993 100644
--- a/ui/gl/gl_bindings_autogen_mock.h
+++ b/ui/gl/gl_bindings_autogen_mock.h
@@ -441,6 +441,10 @@
GLsizei bufsize,
GLsizei* length,
char* infolog);
+static GLint GL_BINDING_CALL
+Mock_glGetProgramResourceLocation(GLuint program,
+ GLenum programInterface,
+ const char* name);
static void GL_BINDING_CALL
Mock_glGetProgramiv(GLuint program, GLenum pname, GLint* params);
static void GL_BINDING_CALL
@@ -494,6 +498,8 @@
static void GL_BINDING_CALL
Mock_glGetShaderiv(GLuint shader, GLenum pname, GLint* params);
static const GLubyte* GL_BINDING_CALL Mock_glGetString(GLenum name);
+static const GLubyte* GL_BINDING_CALL
+Mock_glGetStringi(GLenum name, GLuint index);
static void GL_BINDING_CALL Mock_glGetSynciv(GLsync sync,
GLenum pname,
GLsizei bufSize,
diff --git a/ui/gl/gl_bindings_skia_in_process.cc b/ui/gl/gl_bindings_skia_in_process.cc
index 91d0b0f..25dd698 100644
--- a/ui/gl/gl_bindings_skia_in_process.cc
+++ b/ui/gl/gl_bindings_skia_in_process.cc
@@ -229,6 +229,11 @@
glFlush();
}
+GLvoid StubGLFlushMappedBufferRange(GLenum target, GLintptr offset,
+ GLsizeiptr length) {
+ glFlushMappedBufferRange(target, offset, length);
+}
+
GLvoid StubGLFramebufferRenderbuffer(GLenum target, GLenum attachment,
GLenum renderbuffertarget,
GLuint renderbuffer) {
@@ -331,6 +336,10 @@
return glGetString(name);
}
+const GLubyte* StubGLGetStringi(GLenum name, GLuint index) {
+ return glGetStringi(name, index);
+}
+
GLvoid StubGLGetQueryiv(GLenum target, GLenum pname, GLint* params) {
glGetQueryiv(target, pname, params);
}
@@ -364,6 +373,20 @@
glInsertEventMarkerEXT(length, marker);
}
+GLvoid StubGLInvalidateFramebuffer(GLenum target, GLsizei numAttachments,
+ const GLenum* attachments) {
+ glInvalidateFramebuffer(target, numAttachments, attachments);
+}
+
+GLvoid StubGLInvalidateSubFramebuffer(GLenum target,
+ GLsizei numAttachments,
+ const GLenum* attachments,
+ GLint x, GLint y,
+ GLsizei width, GLsizei height) {
+ glInvalidateSubFramebuffer(target, numAttachments, attachments,
+ x, y, width, height);
+}
+
GLvoid StubGLLineWidth(GLfloat width) {
glLineWidth(width);
}
@@ -376,6 +399,11 @@
return glMapBuffer(target, access);
}
+void* StubGLMapBufferRange(GLenum target, GLintptr offset, GLsizeiptr length,
+ GLbitfield access) {
+ return glMapBufferRange(target, offset, length, access);
+}
+
GLvoid StubGLPixelStorei(GLenum pname, GLint param) {
glPixelStorei(pname, param);
}
@@ -589,6 +617,13 @@
GLvoid StubGLViewport(GLint x, GLint y, GLsizei width, GLsizei height) {
glViewport(x, y, width, height);
}
+
+GLint StubGLGetProgramResourceLocation(GLuint program,
+ GLenum programInterface,
+ const char* name) {
+ return glGetProgramResourceLocation(program, programInterface, name);
+}
+
} // extern "C"
} // namespace
@@ -622,7 +657,7 @@
interface->fStandard = standard;
interface->fExtensions.init(standard,
StubGLGetString,
- NULL,
+ StubGLGetStringi,
StubGLGetIntegerv);
GrGLInterface::Functions* functions = &interface->fFunctions;
@@ -667,6 +702,7 @@
functions->fEndQuery = StubGLEndQuery;
functions->fFinish = StubGLFinish;
functions->fFlush = StubGLFlush;
+ functions->fFlushMappedBufferRange = StubGLFlushMappedBufferRange;
functions->fFrontFace = StubGLFrontFace;
functions->fGenBuffers = StubGLGenBuffers;
functions->fGenQueries = StubGLGenQueries;
@@ -687,11 +723,15 @@
functions->fGetShaderiv = StubGLGetShaderiv;
functions->fGetShaderPrecisionFormat = StubGLGetShaderPrecisionFormat;
functions->fGetString = StubGLGetString;
+ functions->fGetStringi = StubGLGetStringi;
functions->fGetTexLevelParameteriv = StubGLGetTexLevelParameteriv;
functions->fGetUniformLocation = StubGLGetUniformLocation;
functions->fInsertEventMarker = StubGLInsertEventMarker;
+ functions->fInvalidateFramebuffer = StubGLInvalidateFramebuffer;
+ functions->fInvalidateSubFramebuffer = StubGLInvalidateSubFramebuffer;
functions->fLineWidth = StubGLLineWidth;
functions->fLinkProgram = StubGLLinkProgram;
+ functions->fMapBufferRange = StubGLMapBufferRange;
functions->fPixelStorei = StubGLPixelStorei;
functions->fPopGroupMarker = StubGLPopGroupMarker;
functions->fPushGroupMarker = StubGLPushGroupMarker;
@@ -754,11 +794,14 @@
functions->fRenderbufferStorage = StubGLRenderbufferStorage;
functions->fRenderbufferStorageMultisample =
StubGLRenderbufferStorageMultisample;
+ functions->fRenderbufferStorageMultisampleES2EXT =
+ StubGLRenderbufferStorageMultisample;
functions->fBlitFramebuffer = StubGLBlitFramebuffer;
functions->fMapBuffer = StubGLMapBuffer;
functions->fUnmapBuffer = StubGLUnmapBuffer;
functions->fBindFragDataLocationIndexed =
StubGLBindFragDataLocationIndexed;
+ functions->fGetProgramResourceLocation = StubGLGetProgramResourceLocation;
return interface;
}
diff --git a/ui/gl/gl_context.cc b/ui/gl/gl_context.cc
index f89f1d2..720e8e2 100644
--- a/ui/gl/gl_context.cc
+++ b/ui/gl/gl_context.cc
@@ -106,8 +106,8 @@
if(!version_info_) {
std::string version = GetGLVersion();
std::string renderer = GetGLRenderer();
- version_info_ = scoped_ptr<GLVersionInfo>(
- new GLVersionInfo(version.c_str(), renderer.c_str()));
+ version_info_ =
+ make_scoped_ptr(new GLVersionInfo(version.c_str(), renderer.c_str()));
}
return version_info_.get();
}
diff --git a/ui/gl/gl_context_cgl.cc b/ui/gl/gl_context_cgl.cc
index d4bc780..102407c 100644
--- a/ui/gl/gl_context_cgl.cc
+++ b/ui/gl/gl_context_cgl.cc
@@ -122,12 +122,15 @@
void GLContextCGL::Destroy() {
if (discrete_pixelformat_) {
- // Delay releasing the pixel format for 10 seconds to reduce the number of
- // unnecessary GPU switches.
- base::MessageLoop::current()->PostDelayedTask(
- FROM_HERE,
- base::Bind(&CGLReleasePixelFormat, discrete_pixelformat_),
- base::TimeDelta::FromSeconds(10));
+ if (base::MessageLoop::current() != NULL) {
+ // Delay releasing the pixel format for 10 seconds to reduce the number of
+ // unnecessary GPU switches.
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE, base::Bind(&CGLReleasePixelFormat, discrete_pixelformat_),
+ base::TimeDelta::FromSeconds(10));
+ } else {
+ CGLReleasePixelFormat(discrete_pixelformat_);
+ }
discrete_pixelformat_ = NULL;
}
if (context_) {
diff --git a/ui/gl/gl_mock_autogen_gl.h b/ui/gl/gl_mock_autogen_gl.h
index 5b47058..7bec019 100644
--- a/ui/gl/gl_mock_autogen_gl.h
+++ b/ui/gl/gl_mock_autogen_gl.h
@@ -346,6 +346,8 @@
GetProgramInfoLog,
void(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog));
MOCK_METHOD3(GetProgramiv, void(GLuint program, GLenum pname, GLint* params));
+MOCK_METHOD3(GetProgramResourceLocation,
+ GLint(GLuint program, GLenum programInterface, const char* name));
MOCK_METHOD3(GetQueryiv, void(GLenum target, GLenum pname, GLint* params));
MOCK_METHOD3(GetQueryivARB, void(GLenum target, GLenum pname, GLint* params));
MOCK_METHOD3(GetQueryObjecti64v,
@@ -376,6 +378,7 @@
GetShaderSource,
void(GLuint shader, GLsizei bufsize, GLsizei* length, char* source));
MOCK_METHOD1(GetString, const GLubyte*(GLenum name));
+MOCK_METHOD2(GetStringi, const GLubyte*(GLenum name, GLuint index));
MOCK_METHOD5(GetSynciv,
void(GLsync sync,
GLenum pname,
diff --git a/url/BUILD.gn b/url/BUILD.gn
index 03e90cb..964a08b 100644
--- a/url/BUILD.gn
+++ b/url/BUILD.gn
@@ -58,11 +58,11 @@
defines = [ "URL_IMPLEMENTATION" ]
- configs += [ ":url_icu_config" ]
-
- if (is_win) {
- cflags = [ "/wd4267" ] # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- }
+ configs += [
+ ":url_icu_config",
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ "//build/config/compiler:no_size_t_to_int_warning",
+ ]
deps = [
"//base",
@@ -101,19 +101,15 @@
"url_util_unittest.cc",
]
+ # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
+ configs += [ "//build/config/compiler:no_size_t_to_int_warning" ]
+
#if (is_posix && !is_mac && !is_ios) {
# if (use_allocator!="none") {
# deps += "//base/allocator"
# }
#}
- if (is_win) {
- cflags = [
- # TODO(jschuh): crbug.com/167187 fix size_t to int truncations.
- "/wd4267",
- ]
- }
-
deps = [
":url",
"//base",
diff --git a/url/url_canon.h b/url/url_canon.h
index 89e3509..432f291 100644
--- a/url/url_canon.h
+++ b/url/url_canon.h
@@ -734,8 +734,8 @@
// Returns a pointer to a static empty string that is used as a placeholder
// to indicate a component should be deleted (see below).
const CHAR* Placeholder() {
- static const CHAR empty_string = 0;
- return &empty_string;
+ static const CHAR empty_cstr = 0;
+ return &empty_cstr;
}
// We support three states: