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: