Update from https://crrev.com/304715

Includes patches to sky/viewer/cc/ and ui/compositor/ for the following:

cc: Toggle LCD text at raster time instead of record time.
https://codereview.chromium.org/684543006
https://crrev.com/304623

and

Make Keyframe use TimeTicks/TimeDelta to represent time instead of double.
https://codereview.chromium.org/719453007
https://crrev.com/304612

Review URL: https://codereview.chromium.org/737943002
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 959d462..2cce16c 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1108,6 +1108,13 @@
   ]
 }
 
+# TODO(pasko): Remove this target when crbug.com/424562 is fixed.
+source_set("protect_file_posix") {
+  sources = [
+    "files/protect_file_posix.cc",
+  ]
+}
+
 test("base_unittests") {
   sources = [
     "android/application_status_listener_unittest.cc",
diff --git a/base/base.gyp b/base/base.gyp
index ad4dd22..e31cf18 100644
--- a/base/base.gyp
+++ b/base/base.gyp
@@ -377,6 +377,18 @@
       ],
     },
     {
+      # TODO(pasko): Remove this target when crbug.com/424562 is fixed.
+      # GN: //base:protect_file_posix
+      'target_name': 'protect_file_posix',
+      'type': 'static_library',
+      'dependencies': [
+        'base',
+      ],
+      'sources': [
+        'files/protect_file_posix.cc',
+      ],
+    },
+    {
       'target_name': 'base_prefs_test_support',
       'type': 'static_library',
       'dependencies': [
diff --git a/base/files/file.cc b/base/files/file.cc
index ea8dbf2..a997074 100644
--- a/base/files/file.cc
+++ b/base/files/file.cc
@@ -5,6 +5,10 @@
 #include "base/files/file.h"
 #include "base/files/file_path.h"
 
+#if defined(OS_POSIX)
+#include "base/files/file_posix_hooks_internal.h"
+#endif
+
 namespace base {
 
 File::Info::Info()
@@ -38,6 +42,8 @@
       async_(false) {
 #if defined(OS_POSIX)
   DCHECK_GE(platform_file, -1);
+  if (IsValid())
+    ProtectFileDescriptor(platform_file);
 #endif
 }
 
@@ -52,6 +58,10 @@
       error_details_(other.object->error_details()),
       created_(other.object->created()),
       async_(other.object->async_) {
+#if defined(OS_POSIX)
+   if (IsValid())
+     ProtectFileDescriptor(GetPlatformFile());
+#endif
 }
 
 File::~File() {
diff --git a/base/files/file_posix.cc b/base/files/file_posix.cc
index 3d229e4..245ea6a 100644
--- a/base/files/file_posix.cc
+++ b/base/files/file_posix.cc
@@ -10,6 +10,7 @@
 #include <unistd.h>
 
 #include "base/files/file_path.h"
+#include "base/files/file_posix_hooks_internal.h"
 #include "base/logging.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/posix/eintr_wrapper.h"
@@ -166,6 +167,14 @@
                                   Time::kNanosecondsPerMicrosecond);
 }
 
+// Default implementations of Protect/Unprotect hooks defined as weak symbols
+// where possible.
+void ProtectFileDescriptor(int fd) {
+}
+
+void UnprotectFileDescriptor(int fd) {
+}
+
 // NaCl doesn't implement system calls to open files directly.
 #if !defined(OS_NACL)
 // TODO(erikkay): does it make sense to support FLAG_EXCLUSIVE_* here?
@@ -252,6 +261,7 @@
   async_ = ((flags & FLAG_ASYNC) == FLAG_ASYNC);
   error_details_ = FILE_OK;
   file_.reset(descriptor);
+  ProtectFileDescriptor(descriptor);
 }
 #endif  // !defined(OS_NACL)
 
@@ -264,6 +274,8 @@
 }
 
 PlatformFile File::TakePlatformFile() {
+  if (IsValid())
+    UnprotectFileDescriptor(GetPlatformFile());
   return file_.release();
 }
 
@@ -272,6 +284,7 @@
     return;
 
   base::ThreadRestrictions::AssertIOAllowed();
+  UnprotectFileDescriptor(GetPlatformFile());
   file_.reset();
 }
 
@@ -527,8 +540,10 @@
 }
 
 void File::SetPlatformFile(PlatformFile file) {
-  DCHECK(!file_.is_valid());
+  CHECK(!file_.is_valid());
   file_.reset(file);
+  if (file_.is_valid())
+    ProtectFileDescriptor(GetPlatformFile());
 }
 
 }  // namespace base
diff --git a/base/files/file_posix_hooks_internal.h b/base/files/file_posix_hooks_internal.h
new file mode 100644
index 0000000..1137b48
--- /dev/null
+++ b/base/files/file_posix_hooks_internal.h
@@ -0,0 +1,31 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BASE_FILES_FILE_POSIX_HOOKS_INTERNAL_H_
+#define BASE_FILES_FILE_POSIX_HOOKS_INTERNAL_H_
+
+#include "base/base_export.h"
+
+namespace base {
+
+// Define empty hooks for blacklisting file descriptors used in base::File.
+// These functions should be declared 'weak', i.e. the functions declared in
+// a default way would have precedence over the weak ones at link time. This
+// works for both static and dynamic linking.
+// TODO(pasko): Remove these hooks when crbug.com/424562 is fixed.
+//
+// With compilers other than GCC/Clang define strong no-op symbols for
+// simplicity.
+#if defined(COMPILER_GCC)
+#define ATTRIBUTE_WEAK __attribute__ ((weak))
+#else
+#define ATTRIBUTE_WEAK
+#endif
+BASE_EXPORT void ProtectFileDescriptor(int fd) ATTRIBUTE_WEAK;
+BASE_EXPORT void UnprotectFileDescriptor(int fd) ATTRIBUTE_WEAK;
+#undef ATTRIBUTE_WEAK
+
+}  // namespace base
+
+#endif  // BASE_FILES_FILE_POSIX_HOOKS_INTERNAL_H_
diff --git a/base/files/protect_file_posix.cc b/base/files/protect_file_posix.cc
new file mode 100644
index 0000000..e4753c4
--- /dev/null
+++ b/base/files/protect_file_posix.cc
@@ -0,0 +1,106 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "base/containers/hash_tables.h"
+#include "base/files/file.h"
+#include "base/lazy_instance.h"
+#include "base/logging.h"
+#include "base/posix/eintr_wrapper.h"
+#include "base/synchronization/lock.h"
+
+// These hooks provided for base::File perform additional sanity checks when
+// files are closed. These extra checks are hard to understand and maintain,
+// hence they are temporary. TODO(pasko): Remove these extra checks as soon as
+// crbug.com/424562 is fixed.
+//
+// Background:
+//   1. The browser process crashes if a call to close() provided by the C
+//      library (i.e. close(3)) fails. This is done for security purposes. See
+//      base/files/scoped_file.cc. When a crash like this happens, there is not
+//      enough context in the minidump to triage the problem.
+//   2. base::File provides a good abstraction to prevent closing incorrect
+//      file descriptors or double-closing. Closing non-owned file descriptors
+//      would more likely happen from outside base::File and base::ScopedFD.
+//
+// These hooks intercept base::File operations to 'protect' file handles /
+// descriptors from accidental close(3) by other portions of the code being
+// linked into the browser. Also, this file provides an interceptor for the
+// close(3) itself, and requires to be linked with cooperation of
+// --Wl,--wrap=close (i.e. linker wrapping).
+//
+// Wrapping close(3) on all libraries can lead to confusion, particularly for
+// the libraries that do not use ::base (I am also looking at you,
+// crazy_linker). Instead two hooks are added to base::File, which are
+// implemented as no-op by default. This file should be linked into the Chrome
+// native binary(-ies) for a whitelist of targets where "file descriptor
+// protection" is useful.
+
+// With compilers other than GCC/Clang the wrapper is trivial. This is to avoid
+// overexercising mechanisms for overriding weak symbols.
+#if !defined(COMPILER_GCC)
+extern "C" {
+
+int __real_close(int fd);
+
+BASE_EXPORT int __wrap_close(int fd) {
+  return __real_close(fd);
+}
+
+}  // extern "C"
+
+#else  // defined(COMPILER_GCC)
+
+namespace {
+
+// Protects the |g_protected_fd_set|.
+base::LazyInstance<base::Lock>::Leaky g_lock = LAZY_INSTANCE_INITIALIZER;
+
+// Holds the set of all 'protected' file descriptors.
+base::LazyInstance<base::hash_set<int> >::Leaky g_protected_fd_set =
+    LAZY_INSTANCE_INITIALIZER;
+
+bool IsFileDescriptorProtected(int fd) {
+  base::AutoLock lock(*g_lock.Pointer());
+  return g_protected_fd_set.Get().count(fd) != 0;
+}
+
+}  // namespace
+
+namespace base {
+
+BASE_EXPORT void ProtectFileDescriptor(int fd) {
+  base::AutoLock lock(g_lock.Get());
+  CHECK(!g_protected_fd_set.Get().count(fd)) << "fd: " << fd;
+  g_protected_fd_set.Get().insert(fd);
+}
+
+BASE_EXPORT void UnprotectFileDescriptor(int fd) {
+  base::AutoLock lock(*g_lock.Pointer());
+  CHECK(g_protected_fd_set.Get().erase(fd)) << "fd: " << fd;
+}
+
+}  // namespace base
+
+extern "C" {
+
+int __real_close(int fd);
+
+BASE_EXPORT int __wrap_close(int fd) {
+  // The crash happens here if a protected file descriptor was attempted to be
+  // closed without first being unprotected. Unprotection happens only in
+  // base::File. In other words this is an "early crash" as compared to the one
+  // happening in scoped_file.cc.
+  //
+  // Getting an earlier crash provides a more useful stack trace (minidump)
+  // allowing to debug deeper into the thread that freed the wrong resource.
+  CHECK(!IsFileDescriptorProtected(fd)) << "fd: " << fd;
+
+  // Crash by the same reason as in scoped_file.cc.
+  PCHECK(0 == IGNORE_EINTR(__real_close(fd)));
+  return 0;
+}
+
+}  // extern "C"
+
+#endif  // defined(COMPILER_GCC)
diff --git a/base/files/protect_file_posix.gypi b/base/files/protect_file_posix.gypi
new file mode 100644
index 0000000..017fd87
--- /dev/null
+++ b/base/files/protect_file_posix.gypi
@@ -0,0 +1,31 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# Provides sanity-checks and early crashes on some improper use of posix file
+# descriptors. See protect_file_posix.cc for details.
+#
+# Usage:
+#   {
+#     'target_name': 'libsomething',
+#     'type': 'shared_library',  // Do *not* use it for static libraries.
+#     'includes': [
+#       'base/files/protect_file_posix.gypi',
+#     ],
+#     ...
+#   }
+{
+   'conditions': [
+     # In the component build the interceptors have to be declared with
+     # non-hidden visibility, which is not desirable for the release build.
+     # Disable the extra checks for the component build for simplicity.
+     ['component != "shared_library"', {
+       'ldflags': [
+         '-Wl,--wrap=close',
+       ],
+       'dependencies': [
+         '<(DEPTH)/base/base.gyp:protect_file_posix',
+       ],
+     }],
+   ],
+}
diff --git a/base/process/process.h b/base/process/process.h
index 7019474..50ccf8d 100644
--- a/base/process/process.h
+++ b/base/process/process.h
@@ -48,6 +48,12 @@
   // Returns an object for the current process.
   static Process Current();
 
+  // Creates an object from a |handle| owned by someone else.
+  // Don't use this for new code. It is only intended to ease the migration to
+  // a strict ownership model.
+  // TODO(rvargas) crbug.com/417532: Remove this code.
+  static Process DeprecatedGetProcessFromHandle(ProcessHandle handle);
+
   // Returns true if processes can be backgrounded.
   static bool CanBackgroundProcesses();
 
diff --git a/base/process/process_posix.cc b/base/process/process_posix.cc
index ea8fd8c..270438e 100644
--- a/base/process/process_posix.cc
+++ b/base/process/process_posix.cc
@@ -37,6 +37,12 @@
   return process.Pass();
 }
 
+// static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+  DCHECK_NE(handle, GetCurrentProcessHandle());
+  return Process(handle);
+}
+
 #if !defined(OS_LINUX)
 // static
 bool Process::CanBackgroundProcesses() {
diff --git a/base/process/process_unittest.cc b/base/process/process_unittest.cc
index 66d6e63..a5ba834 100644
--- a/base/process/process_unittest.cc
+++ b/base/process/process_unittest.cc
@@ -92,6 +92,21 @@
   ASSERT_TRUE(process2.IsValid());
 }
 
+TEST_F(ProcessTest, DeprecatedGetProcessFromHandle) {
+  Process process1(SpawnChild("SimpleChildProcess"));
+  ASSERT_TRUE(process1.IsValid());
+
+  Process process2 = Process::DeprecatedGetProcessFromHandle(process1.Handle());
+  ASSERT_TRUE(process1.IsValid());
+  ASSERT_TRUE(process2.IsValid());
+  EXPECT_EQ(process1.pid(), process2.pid());
+  EXPECT_FALSE(process1.is_current());
+  EXPECT_FALSE(process2.is_current());
+
+  process1.Close();
+  ASSERT_TRUE(process2.IsValid());
+}
+
 MULTIPROCESS_TEST_MAIN(SleepyChildProcess) {
   PlatformThread::Sleep(TestTimeouts::action_max_timeout());
   return 0;
diff --git a/base/process/process_win.cc b/base/process/process_win.cc
index 05041b2..3e0d79f 100644
--- a/base/process/process_win.cc
+++ b/base/process/process_win.cc
@@ -39,6 +39,18 @@
 }
 
 // static
+Process Process::DeprecatedGetProcessFromHandle(ProcessHandle handle) {
+  DCHECK_NE(handle, ::GetCurrentProcess());
+  ProcessHandle out_handle;
+  if (!::DuplicateHandle(GetCurrentProcess(), handle,
+                         GetCurrentProcess(), &out_handle,
+                         0, FALSE, DUPLICATE_SAME_ACCESS)) {
+    return Process();
+  }
+  return Process(out_handle);
+}
+
+// static
 bool Process::CanBackgroundProcesses() {
   return true;
 }
diff --git a/build/all.gyp b/build/all.gyp
index a11ee7a..c3443f9 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -56,7 +56,6 @@
             '../mojo/public/mojo_public.gyp:mojo_system',
             '../google_apis/google_apis.gyp:google_apis_unittests',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-            '../ui/base/ui_base_tests.gyp:ui_unittests',
             '../ui/ios/ui_ios_tests.gyp:ui_ios_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
           ],
@@ -308,7 +307,6 @@
         '../sql/sql.gyp:sql_unittests',
         '../sync/sync.gyp:sync_unit_tests',
         '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-        '../ui/base/ui_base_tests.gyp:ui_unittests',
         '../ui/display/display.gyp:display_unittests',
         '../ui/gfx/gfx_tests.gyp:gfx_unittests',
         '../url/url.gyp:url_unittests',
@@ -825,7 +823,6 @@
             '../tools/android/android_tools.gyp:memconsumer',
             '../tools/android/findbugs_plugin/findbugs_plugin.gyp:findbugs_plugin_test',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-            '../ui/base/ui_base_tests.gyp:ui_unittests',
             '../ui/events/events.gyp:events_unittests',
             # Unit test bundles packaged as an apk.
             '../android_webview/android_webview.gyp:android_webview_test_apk',
@@ -852,7 +849,6 @@
             '../sync/sync.gyp:sync_unit_tests_apk',
             '../tools/android/heap_profiler/heap_profiler.gyp:heap_profiler_unittests_apk',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests_apk',
-            '../ui/base/ui_base_tests.gyp:ui_unittests_apk',
             '../ui/events/events.gyp:events_unittests_apk',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
           ],
@@ -860,7 +856,6 @@
             ['enable_webrtc==1 and "<(libpeer_target_type)"=="static_library"', {
               'dependencies': [
                 '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
-                '../components/devtools_bridge.gyp:devtools_bridge_tests2_apk',
               ],
             }],
           ],
@@ -876,7 +871,6 @@
             '../tools/android/android_tools.gyp:memconsumer',
             # Unit test bundles packaged as an apk.
             '../components/devtools_bridge.gyp:devtools_bridge_tests_apk',
-            '../components/devtools_bridge.gyp:devtools_bridge_tests2_apk',
             '../content/content_shell_and_tests.gyp:content_browsertests_apk',
           ],
         },  # target_name: android_builder_chromium_webrtc
@@ -930,7 +924,6 @@
             '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
             '../tools/telemetry/telemetry.gyp:*',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-            '../ui/base/ui_base_tests.gyp:ui_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../url/url.gyp:url_unittests',
           ],
@@ -968,7 +961,6 @@
             '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
             '../tools/telemetry/telemetry.gyp:*',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-            '../ui/base/ui_base_tests.gyp:ui_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../url/url.gyp:url_unittests',
           ],
@@ -1017,7 +1009,6 @@
             '../third_party/libaddressinput/libaddressinput.gyp:libaddressinput_unittests',
             '../third_party/libphonenumber/libphonenumber.gyp:libphonenumber_unittests',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-            '../ui/base/ui_base_tests.gyp:ui_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../url/url.gyp:url_unittests',
           ],
@@ -1069,7 +1060,6 @@
             '../tools/perf/clear_system_cache/clear_system_cache.gyp:*',
             '../tools/telemetry/telemetry.gyp:*',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-            '../ui/base/ui_base_tests.gyp:ui_unittests',
             '../ui/events/events.gyp:events_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../ui/views/views.gyp:views_unittests',
@@ -1215,7 +1205,6 @@
                 '../sync/sync.gyp:sync_unit_tests',
                 '../third_party/widevine/cdm/widevine_cdm.gyp:widevinecdmadapter',
                 '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-                '../ui/base/ui_base_tests.gyp:ui_unittests',
                 '../ui/gfx/gfx_tests.gyp:gfx_unittests',
                 '../ui/views/views.gyp:views_unittests',
                 '../url/url.gyp:url_unittests',
@@ -1258,7 +1247,6 @@
             '../ui/app_list/app_list.gyp:*',
             '../ui/aura/aura.gyp:*',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
-            '../ui/base/ui_base_tests.gyp:ui_unittests',
             '../ui/compositor/compositor.gyp:*',
             '../ui/display/display.gyp:display_unittests',
             '../ui/events/events.gyp:*',
diff --git a/build/android/findbugs_filter/findbugs_known_bugs.txt b/build/android/findbugs_filter/findbugs_known_bugs.txt
index 7be93ec..6ad2b3a 100644
--- a/build/android/findbugs_filter/findbugs_known_bugs.txt
+++ b/build/android/findbugs_filter/findbugs_known_bugs.txt
@@ -22,6 +22,4 @@
 M M LI: Incorrect lazy initialization of static field org.chromium.chrome.browser.sync.ProfileSyncService.sSyncSetupManager in org.chromium.chrome.browser.sync.ProfileSyncService.get(Context)  At ProfileSyncService.java
 M V EI2: org.chromium.content_public.browser.LoadUrlParams.setPostData(byte[]) may expose internal representation by storing an externally mutable object into LoadUrlParams.mPostData  At LoadUrlParams.java
 M V EI: org.chromium.content_public.browser.LoadUrlParams.getPostData() may expose internal representation by returning LoadUrlParams.mPostData  At LoadUrlParams.java
-M D NP: Read of unwritten public or protected field data in org.chromium.components.devtools_bridge.SessionDependencyFactory$DataChannelObserverAdapter.onMessage(DataChannel$Buffer)  At SessionDependencyFactory.java
-M D NP: Read of unwritten public or protected field mandatory in org.chromium.components.devtools_bridge.SessionDependencyFactory.createPeerConnectionConstraints()  At SessionDependencyFactory.java
 M V EI2: org.chromium.net.ChromiumUrlRequest.setUploadData(String, byte[]) may expose internal representation by storing an externally mutable object into ChromiumUrlRequest.mUploadData  At ChromiumUrlRequest.java
diff --git a/build/android/pylib/android_commands.py b/build/android/pylib/android_commands.py
index ea86e6d..6981afc 100644
--- a/build/android/pylib/android_commands.py
+++ b/build/android/pylib/android_commands.py
@@ -1927,7 +1927,8 @@
     # to the device.
     while True:
       if t0 + timeout - time.time() < 0:
-        raise pexpect.TIMEOUT('Unable to enable USB charging in time.')
+        raise pexpect.TIMEOUT('Unable to disable USB charging in time: %s' % (
+            self.GetBatteryInfo()))
       self.RunShellCommand(disable_command)
       if not self.IsDeviceCharging():
         break
diff --git a/build/android/pylib/gtest/gtest_config.py b/build/android/pylib/gtest/gtest_config.py
index 3b51a42..e671e0a 100644
--- a/build/android/pylib/gtest/gtest_config.py
+++ b/build/android/pylib/gtest/gtest_config.py
@@ -32,7 +32,6 @@
     'sql_unittests',
     'sync_unit_tests',
     'ui_base_unittests',
-    'ui_unittests',
     'unit_tests',
     'webkit_unit_tests',
 ]
diff --git a/build/android/pylib/gtest/setup.py b/build/android/pylib/gtest/setup.py
index 3206bda..e3df9c7 100644
--- a/build/android/pylib/gtest/setup.py
+++ b/build/android/pylib/gtest/setup.py
@@ -40,7 +40,6 @@
     'net_unittests': 'net/net_unittests.isolate',
     'sql_unittests': 'sql/sql_unittests.isolate',
     'ui_base_unittests': 'ui/base/ui_base_tests.isolate',
-    'ui_unittests': 'ui/base/ui_base_tests.isolate',
     'unit_tests': 'chrome/unit_tests.isolate',
     'webkit_unit_tests':
       'third_party/WebKit/Source/web/WebKitUnitTests.isolate',
diff --git a/build/android/pylib/instrumentation/test_jar.py b/build/android/pylib/instrumentation/test_jar.py
index a3d8849..7b97e59 100644
--- a/build/android/pylib/instrumentation/test_jar.py
+++ b/build/android/pylib/instrumentation/test_jar.py
@@ -140,7 +140,7 @@
         key = filters[0]
         value_list = filters[1].split(',')
         for value in value_list:
-          if key in annotations and value == annotations['key']:
+          if key in annotations and value == annotations[key]:
             return True
       elif annotation_filter in annotations:
         return True
diff --git a/build/android/pylib/uiautomator/test_runner.py b/build/android/pylib/uiautomator/test_runner.py
index c7239b4..b47a236 100644
--- a/build/android/pylib/uiautomator/test_runner.py
+++ b/build/android/pylib/uiautomator/test_runner.py
@@ -64,7 +64,7 @@
     self.device.ClearApplicationState(self._package)
     if self.flags:
       annotations = self.test_pkg.GetTestAnnotations(test)
-      if ('FirstRunExperience' == annotations(test).get('Feature', None)):
+      if ('FirstRunExperience' == annotations.get('Feature', None)):
         self.flags.RemoveFlags(['--disable-fre'])
       else:
         self.flags.AddFlags(['--disable-fre'])
diff --git a/build/common.gypi b/build/common.gypi
index 7fa5d83..0d7d385 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -787,7 +787,8 @@
           'disable_ftp_support%': 1,
           'enable_extensions%': 0,
           'enable_google_now%': 0,
-          'cld_version%': 1,
+          'cld_version%': 2,
+          'cld2_table_size%': 0,
           'enable_basic_printing%': 0,
           'enable_print_preview%': 0,
           'enable_session_service%': 0,
diff --git a/build/config/features.gni b/build/config/features.gni
index 575a89c..82247b9 100644
--- a/build/config/features.gni
+++ b/build/config/features.gni
@@ -47,7 +47,7 @@
 #   0: Don't specify the version. This option is for the Finch testing.
 #   1: Use only CLD1.
 #   2: Use only CLD2.
-if (is_android || is_ios) {
+if (is_android) {
   cld_version = 1
 } else {
   cld_version = 2
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h
index c03feb8..f4c697c 100644
--- a/cc/animation/animation_curve.h
+++ b/cc/animation/animation_curve.h
@@ -48,7 +48,7 @@
  public:
   ~ColorAnimationCurve() override {}
 
-  virtual SkColor GetValue(double t) const = 0;
+  virtual SkColor GetValue(base::TimeDelta t) const = 0;
 
   // Partial Animation implementation.
   CurveType Type() const override;
@@ -58,7 +58,7 @@
  public:
   ~FloatAnimationCurve() override {}
 
-  virtual float GetValue(double t) const = 0;
+  virtual float GetValue(base::TimeDelta t) const = 0;
 
   // Partial Animation implementation.
   CurveType Type() const override;
@@ -68,7 +68,7 @@
  public:
   ~TransformAnimationCurve() override {}
 
-  virtual gfx::Transform GetValue(double t) const = 0;
+  virtual gfx::Transform GetValue(base::TimeDelta t) const = 0;
 
   // Sets |bounds| to be the bounding box for the region within which |box|
   // will move during this animation. If this region cannot be computed,
@@ -98,7 +98,7 @@
  public:
   ~FilterAnimationCurve() override {}
 
-  virtual FilterOperations GetValue(double t) const = 0;
+  virtual FilterOperations GetValue(base::TimeDelta t) const = 0;
   virtual bool HasFilterThatMovesPixels() const = 0;
 
   // Partial Animation implementation.
diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc
index a6dc8c5..9642329 100644
--- a/cc/animation/keyframed_animation_curve.cc
+++ b/cc/animation/keyframed_animation_curve.cc
@@ -5,6 +5,7 @@
 #include <algorithm>
 
 #include "cc/animation/keyframed_animation_curve.h"
+#include "cc/base/time_util.h"
 #include "ui/gfx/animation/tween.h"
 #include "ui/gfx/geometry/box_f.h"
 
@@ -30,16 +31,18 @@
 }
 
 template <typename KeyframeType>
-double TransformedAnimationTime(
+base::TimeDelta TransformedAnimationTime(
     const ScopedPtrVector<KeyframeType>& keyframes,
     const scoped_ptr<TimingFunction>& timing_function,
-    double time) {
+    base::TimeDelta time) {
   if (timing_function) {
-    double start_time = keyframes.front()->Time();
-    double duration = keyframes.back()->Time() - start_time;
-    double progress = (time - start_time) / duration;
+    base::TimeDelta start_time = keyframes.front()->Time();
+    base::TimeDelta duration =
+        keyframes.back()->Time() - keyframes.front()->Time();
+    double progress = TimeUtil::Divide(time - start_time, duration);
 
-    time = timing_function->GetValue(progress) * duration + start_time;
+    time = TimeUtil::Scale(duration, timing_function->GetValue(progress)) +
+           start_time;
   }
 
   return time;
@@ -47,7 +50,7 @@
 
 template <typename KeyframeType>
 size_t GetActiveKeyframe(const ScopedPtrVector<KeyframeType>& keyframes,
-                         double time) {
+                         base::TimeDelta time) {
   DCHECK_GE(keyframes.size(), 2ul);
   size_t i = 0;
   for (; i < keyframes.size() - 2; ++i) {  // Last keyframe is never active.
@@ -61,10 +64,11 @@
 template <typename KeyframeType>
 double TransformedKeyframeProgress(
     const ScopedPtrVector<KeyframeType>& keyframes,
-    double time,
+    base::TimeDelta time,
     size_t i) {
-  double progress = (time - keyframes[i]->Time()) /
-                    (keyframes[i + 1]->Time() - keyframes[i]->Time());
+  double progress =
+      TimeUtil::Divide(time - keyframes[i]->Time(),
+                       keyframes[i + 1]->Time() - keyframes[i]->Time());
 
   if (keyframes[i]->timing_function()) {
     progress = keyframes[i]->timing_function()->GetValue(progress);
@@ -75,29 +79,30 @@
 
 }  // namespace
 
-Keyframe::Keyframe(double time, scoped_ptr<TimingFunction> timing_function)
-    : time_(time),
-      timing_function_(timing_function.Pass()) {}
+Keyframe::Keyframe(base::TimeDelta time,
+                   scoped_ptr<TimingFunction> timing_function)
+    : time_(time), timing_function_(timing_function.Pass()) {
+}
 
 Keyframe::~Keyframe() {}
 
-double Keyframe::Time() const {
+base::TimeDelta Keyframe::Time() const {
   return time_;
 }
 
 scoped_ptr<ColorKeyframe> ColorKeyframe::Create(
-    double time,
+    base::TimeDelta time,
     SkColor value,
     scoped_ptr<TimingFunction> timing_function) {
   return make_scoped_ptr(
       new ColorKeyframe(time, value, timing_function.Pass()));
 }
 
-ColorKeyframe::ColorKeyframe(double time,
+ColorKeyframe::ColorKeyframe(base::TimeDelta time,
                              SkColor value,
                              scoped_ptr<TimingFunction> timing_function)
-    : Keyframe(time, timing_function.Pass()),
-      value_(value) {}
+    : Keyframe(time, timing_function.Pass()), value_(value) {
+}
 
 ColorKeyframe::~ColorKeyframe() {}
 
@@ -111,18 +116,18 @@
 }
 
 scoped_ptr<FloatKeyframe> FloatKeyframe::Create(
-    double time,
+    base::TimeDelta time,
     float value,
     scoped_ptr<TimingFunction> timing_function) {
   return make_scoped_ptr(
       new FloatKeyframe(time, value, timing_function.Pass()));
 }
 
-FloatKeyframe::FloatKeyframe(double time,
+FloatKeyframe::FloatKeyframe(base::TimeDelta time,
                              float value,
                              scoped_ptr<TimingFunction> timing_function)
-    : Keyframe(time, timing_function.Pass()),
-      value_(value) {}
+    : Keyframe(time, timing_function.Pass()), value_(value) {
+}
 
 FloatKeyframe::~FloatKeyframe() {}
 
@@ -138,18 +143,18 @@
 }
 
 scoped_ptr<TransformKeyframe> TransformKeyframe::Create(
-    double time,
+    base::TimeDelta time,
     const TransformOperations& value,
     scoped_ptr<TimingFunction> timing_function) {
   return make_scoped_ptr(
       new TransformKeyframe(time, value, timing_function.Pass()));
 }
 
-TransformKeyframe::TransformKeyframe(double time,
+TransformKeyframe::TransformKeyframe(base::TimeDelta time,
                                      const TransformOperations& value,
                                      scoped_ptr<TimingFunction> timing_function)
-    : Keyframe(time, timing_function.Pass()),
-      value_(value) {}
+    : Keyframe(time, timing_function.Pass()), value_(value) {
+}
 
 TransformKeyframe::~TransformKeyframe() {}
 
@@ -165,18 +170,18 @@
 }
 
 scoped_ptr<FilterKeyframe> FilterKeyframe::Create(
-    double time,
+    base::TimeDelta time,
     const FilterOperations& value,
     scoped_ptr<TimingFunction> timing_function) {
   return make_scoped_ptr(
       new FilterKeyframe(time, value, timing_function.Pass()));
 }
 
-FilterKeyframe::FilterKeyframe(double time,
+FilterKeyframe::FilterKeyframe(base::TimeDelta time,
                                const FilterOperations& value,
                                scoped_ptr<TimingFunction> timing_function)
-    : Keyframe(time, timing_function.Pass()),
-      value_(value) {}
+    : Keyframe(time, timing_function.Pass()), value_(value) {
+}
 
 FilterKeyframe::~FilterKeyframe() {}
 
@@ -206,8 +211,7 @@
 }
 
 base::TimeDelta KeyframedColorAnimationCurve::Duration() const {
-  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
-                                       keyframes_.front()->Time());
+  return keyframes_.back()->Time() - keyframes_.front()->Time();
 }
 
 scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
@@ -222,7 +226,7 @@
   return to_return.Pass();
 }
 
-SkColor KeyframedColorAnimationCurve::GetValue(double t) const {
+SkColor KeyframedColorAnimationCurve::GetValue(base::TimeDelta t) const {
   if (t <= keyframes_.front()->Time())
     return keyframes_.front()->Value();
 
@@ -254,8 +258,7 @@
 }
 
 base::TimeDelta KeyframedFloatAnimationCurve::Duration() const {
-  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
-                                       keyframes_.front()->Time());
+  return keyframes_.back()->Time() - keyframes_.front()->Time();
 }
 
 scoped_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const {
@@ -270,7 +273,7 @@
   return to_return.Pass();
 }
 
-float KeyframedFloatAnimationCurve::GetValue(double t) const {
+float KeyframedFloatAnimationCurve::GetValue(base::TimeDelta t) const {
   if (t <= keyframes_.front()->Time())
     return keyframes_.front()->Value();
 
@@ -300,8 +303,7 @@
 }
 
 base::TimeDelta KeyframedTransformAnimationCurve::Duration() const {
-  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
-                                       keyframes_.front()->Time());
+  return keyframes_.back()->Time() - keyframes_.front()->Time();
 }
 
 scoped_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone() const {
@@ -316,7 +318,8 @@
   return to_return.Pass();
 }
 
-gfx::Transform KeyframedTransformAnimationCurve::GetValue(double t) const {
+gfx::Transform KeyframedTransformAnimationCurve::GetValue(
+    base::TimeDelta t) const {
   if (t <= keyframes_.front()->Time())
     return keyframes_.front()->Value().Apply();
 
@@ -412,8 +415,7 @@
 }
 
 base::TimeDelta KeyframedFilterAnimationCurve::Duration() const {
-  return base::TimeDelta::FromSecondsD(keyframes_.back()->Time() -
-                                       keyframes_.front()->Time());
+  return keyframes_.back()->Time() - keyframes_.front()->Time();
 }
 
 scoped_ptr<AnimationCurve> KeyframedFilterAnimationCurve::Clone() const {
@@ -428,7 +430,8 @@
   return to_return.Pass();
 }
 
-FilterOperations KeyframedFilterAnimationCurve::GetValue(double t) const {
+FilterOperations KeyframedFilterAnimationCurve::GetValue(
+    base::TimeDelta t) const {
   if (t <= keyframes_.front()->Time())
     return keyframes_.front()->Value();
 
diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h
index ff746fe..e68f4f8 100644
--- a/cc/animation/keyframed_animation_curve.h
+++ b/cc/animation/keyframed_animation_curve.h
@@ -16,17 +16,17 @@
 
 class CC_EXPORT Keyframe {
  public:
-  double Time() const;
+  base::TimeDelta Time() const;
   const TimingFunction* timing_function() const {
     return timing_function_.get();
   }
 
  protected:
-  Keyframe(double time, scoped_ptr<TimingFunction> timing_function);
+  Keyframe(base::TimeDelta time, scoped_ptr<TimingFunction> timing_function);
   virtual ~Keyframe();
 
  private:
-  double time_;
+  base::TimeDelta time_;
   scoped_ptr<TimingFunction> timing_function_;
 
   DISALLOW_COPY_AND_ASSIGN(Keyframe);
@@ -35,7 +35,7 @@
 class CC_EXPORT ColorKeyframe : public Keyframe {
  public:
   static scoped_ptr<ColorKeyframe> Create(
-      double time,
+      base::TimeDelta time,
       SkColor value,
       scoped_ptr<TimingFunction> timing_function);
   ~ColorKeyframe() override;
@@ -45,7 +45,7 @@
   scoped_ptr<ColorKeyframe> Clone() const;
 
  private:
-  ColorKeyframe(double time,
+  ColorKeyframe(base::TimeDelta time,
                 SkColor value,
                 scoped_ptr<TimingFunction> timing_function);
 
@@ -55,7 +55,7 @@
 class CC_EXPORT FloatKeyframe : public Keyframe {
  public:
   static scoped_ptr<FloatKeyframe> Create(
-      double time,
+      base::TimeDelta time,
       float value,
       scoped_ptr<TimingFunction> timing_function);
   ~FloatKeyframe() override;
@@ -65,7 +65,7 @@
   scoped_ptr<FloatKeyframe> Clone() const;
 
  private:
-  FloatKeyframe(double time,
+  FloatKeyframe(base::TimeDelta time,
                 float value,
                 scoped_ptr<TimingFunction> timing_function);
 
@@ -75,7 +75,7 @@
 class CC_EXPORT TransformKeyframe : public Keyframe {
  public:
   static scoped_ptr<TransformKeyframe> Create(
-      double time,
+      base::TimeDelta time,
       const TransformOperations& value,
       scoped_ptr<TimingFunction> timing_function);
   ~TransformKeyframe() override;
@@ -85,10 +85,9 @@
   scoped_ptr<TransformKeyframe> Clone() const;
 
  private:
-  TransformKeyframe(
-      double time,
-      const TransformOperations& value,
-      scoped_ptr<TimingFunction> timing_function);
+  TransformKeyframe(base::TimeDelta time,
+                    const TransformOperations& value,
+                    scoped_ptr<TimingFunction> timing_function);
 
   TransformOperations value_;
 };
@@ -96,7 +95,7 @@
 class CC_EXPORT FilterKeyframe : public Keyframe {
  public:
   static scoped_ptr<FilterKeyframe> Create(
-      double time,
+      base::TimeDelta time,
       const FilterOperations& value,
       scoped_ptr<TimingFunction> timing_function);
   ~FilterKeyframe() override;
@@ -106,10 +105,9 @@
   scoped_ptr<FilterKeyframe> Clone() const;
 
  private:
-  FilterKeyframe(
-      double time,
-      const FilterOperations& value,
-      scoped_ptr<TimingFunction> timing_function);
+  FilterKeyframe(base::TimeDelta time,
+                 const FilterOperations& value,
+                 scoped_ptr<TimingFunction> timing_function);
 
   FilterOperations value_;
 };
@@ -131,7 +129,7 @@
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // BackgrounColorAnimationCurve implementation
-  SkColor GetValue(double t) const override;
+  SkColor GetValue(base::TimeDelta t) const override;
 
  private:
   KeyframedColorAnimationCurve();
@@ -161,7 +159,7 @@
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // FloatAnimationCurve implementation
-  float GetValue(double t) const override;
+  float GetValue(base::TimeDelta t) const override;
 
  private:
   KeyframedFloatAnimationCurve();
@@ -192,7 +190,7 @@
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // TransformAnimationCurve implementation
-  gfx::Transform GetValue(double t) const override;
+  gfx::Transform GetValue(base::TimeDelta t) const override;
   bool AnimatedBoundsForBox(const gfx::BoxF& box,
                             gfx::BoxF* bounds) const override;
   bool AffectsScale() const override;
@@ -229,7 +227,7 @@
   scoped_ptr<AnimationCurve> Clone() const override;
 
   // FilterAnimationCurve implementation
-  FilterOperations GetValue(double t) const override;
+  FilterOperations GetValue(base::TimeDelta t) const override;
   bool HasFilterThatMovesPixels() const override;
 
  private:
diff --git a/cc/animation/keyframed_animation_curve_unittest.cc b/cc/animation/keyframed_animation_curve_unittest.cc
index 71fd521..314ce9d 100644
--- a/cc/animation/keyframed_animation_curve_unittest.cc
+++ b/cc/animation/keyframed_animation_curve_unittest.cc
@@ -29,13 +29,15 @@
   SkColor color = SkColorSetARGB(255, 255, 255, 255);
   scoped_ptr<KeyframedColorAnimationCurve> curve(
       KeyframedColorAnimationCurve::Create());
-  curve->AddKeyframe(ColorKeyframe::Create(0.0, color, nullptr));
+  curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta(), color, nullptr));
 
-  EXPECT_SKCOLOR_EQ(color, curve->GetValue(-1.f));
-  EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.f));
-  EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.5f));
-  EXPECT_SKCOLOR_EQ(color, curve->GetValue(1.f));
-  EXPECT_SKCOLOR_EQ(color, curve->GetValue(2.f));
+  EXPECT_SKCOLOR_EQ(color,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_SKCOLOR_EQ(color,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a color animation with two keyframes works as expected.
@@ -45,14 +47,21 @@
   SkColor color_midpoint = gfx::Tween::ColorValueBetween(0.5, color_a, color_b);
   scoped_ptr<KeyframedColorAnimationCurve> curve(
       KeyframedColorAnimationCurve::Create());
-  curve->AddKeyframe(ColorKeyframe::Create(0.0, color_a, nullptr));
-  curve->AddKeyframe(ColorKeyframe::Create(1.0, color_b, nullptr));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+  curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+                                           color_b, nullptr));
 
-  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
-  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
-  EXPECT_SKCOLOR_EQ(color_midpoint, curve->GetValue(0.5f));
-  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
-  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f));
+  EXPECT_SKCOLOR_EQ(color_a,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_SKCOLOR_EQ(color_a,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_SKCOLOR_EQ(color_midpoint,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_SKCOLOR_EQ(color_b,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_SKCOLOR_EQ(color_b,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a color animation with three keyframes works as expected.
@@ -66,17 +75,27 @@
       gfx::Tween::ColorValueBetween(0.5, color_b, color_c);
   scoped_ptr<KeyframedColorAnimationCurve> curve(
       KeyframedColorAnimationCurve::Create());
-  curve->AddKeyframe(ColorKeyframe::Create(0.0, color_a, nullptr));
-  curve->AddKeyframe(ColorKeyframe::Create(1.0, color_b, nullptr));
-  curve->AddKeyframe(ColorKeyframe::Create(2.0, color_c, nullptr));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+  curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+                                           color_b, nullptr));
+  curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+                                           color_c, nullptr));
 
-  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
-  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
-  EXPECT_SKCOLOR_EQ(color_midpoint1, curve->GetValue(0.5f));
-  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
-  EXPECT_SKCOLOR_EQ(color_midpoint2, curve->GetValue(1.5f));
-  EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(2.f));
-  EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(3.f));
+  EXPECT_SKCOLOR_EQ(color_a,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_SKCOLOR_EQ(color_a,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_SKCOLOR_EQ(color_midpoint1,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_SKCOLOR_EQ(color_b,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_SKCOLOR_EQ(color_midpoint2,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  EXPECT_SKCOLOR_EQ(color_c,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  EXPECT_SKCOLOR_EQ(color_c,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a colro animation with multiple keys at a given time works sanely.
@@ -86,87 +105,103 @@
 
   scoped_ptr<KeyframedColorAnimationCurve> curve(
       KeyframedColorAnimationCurve::Create());
-  curve->AddKeyframe(ColorKeyframe::Create(0.0, color_a, nullptr));
-  curve->AddKeyframe(ColorKeyframe::Create(1.0, color_a, nullptr));
-  curve->AddKeyframe(ColorKeyframe::Create(1.0, color_b, nullptr));
-  curve->AddKeyframe(ColorKeyframe::Create(2.0, color_b, nullptr));
+  curve->AddKeyframe(
+      ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr));
+  curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+                                           color_a, nullptr));
+  curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+                                           color_b, nullptr));
+  curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
+                                           color_b, nullptr));
 
-  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
-  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
-  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.5f));
+  EXPECT_SKCOLOR_EQ(color_a,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_SKCOLOR_EQ(color_a,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_SKCOLOR_EQ(color_a,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
 
-  SkColor value = curve->GetValue(1.0f);
+  SkColor value = curve->GetValue(base::TimeDelta::FromSecondsD(1.0f));
   EXPECT_EQ(255u, SkColorGetA(value));
   int red_value = SkColorGetR(value);
   EXPECT_LE(64, red_value);
   EXPECT_GE(192, red_value);
 
-  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.5f));
-  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f));
-  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(3.f));
+  EXPECT_SKCOLOR_EQ(color_b,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  EXPECT_SKCOLOR_EQ(color_b,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  EXPECT_SKCOLOR_EQ(color_b,
+                    curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a float animation with one keyframe works as expected.
 TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.5f));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(1.f));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(2.f));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a float animation with two keyframes works as expected.
 TEST(KeyframedAnimationCurveTest, TwoFloatKeyframe) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
-  EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
-  EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
-  EXPECT_FLOAT_EQ(4.f, curve->GetValue(2.f));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a float animation with three keyframes works as expected.
 TEST(KeyframedAnimationCurveTest, ThreeFloatKeyframe) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(2.0, 8.f, nullptr));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
-  EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
-  EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
-  EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
-  EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f));
-  EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 8.f, nullptr));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a float animation with multiple keys at a given time works sanely.
 TEST(KeyframedAnimationCurveTest, RepeatedFloatKeyTimes) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 4.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 6.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(2.0, 6.f, nullptr));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 4.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 6.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 6.f, nullptr));
 
-  EXPECT_FLOAT_EQ(4.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.f));
-  EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.5f));
+  EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
 
   // There is a discontinuity at 1. Any value between 4 and 6 is valid.
-  float value = curve->GetValue(1.f);
+  float value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
   EXPECT_TRUE(value >= 4 && value <= 6);
 
-  EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
-  EXPECT_FLOAT_EQ(6.f, curve->GetValue(2.f));
-  EXPECT_FLOAT_EQ(6.f, curve->GetValue(3.f));
+  EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a transform animation with one keyframe works as expected.
@@ -175,13 +210,14 @@
       KeyframedTransformAnimationCurve::Create());
   TransformOperations operations;
   operations.AppendTranslate(2.f, 0.f, 0.f);
-  curve->AddKeyframe(TransformKeyframe::Create(0.f, operations, nullptr));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
 
-  ExpectTranslateX(2.f, curve->GetValue(-1.f));
-  ExpectTranslateX(2.f, curve->GetValue(0.f));
-  ExpectTranslateX(2.f, curve->GetValue(0.5f));
-  ExpectTranslateX(2.f, curve->GetValue(1.f));
-  ExpectTranslateX(2.f, curve->GetValue(2.f));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a transform animation with two keyframes works as expected.
@@ -193,13 +229,15 @@
   TransformOperations operations2;
   operations2.AppendTranslate(4.f, 0.f, 0.f);
 
-  curve->AddKeyframe(TransformKeyframe::Create(0.f, operations1, nullptr));
-  curve->AddKeyframe(TransformKeyframe::Create(1.f, operations2, nullptr));
-  ExpectTranslateX(2.f, curve->GetValue(-1.f));
-  ExpectTranslateX(2.f, curve->GetValue(0.f));
-  ExpectTranslateX(3.f, curve->GetValue(0.5f));
-  ExpectTranslateX(4.f, curve->GetValue(1.f));
-  ExpectTranslateX(4.f, curve->GetValue(2.f));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a transform animation with three keyframes works as expected.
@@ -212,16 +250,19 @@
   operations2.AppendTranslate(4.f, 0.f, 0.f);
   TransformOperations operations3;
   operations3.AppendTranslate(8.f, 0.f, 0.f);
-  curve->AddKeyframe(TransformKeyframe::Create(0.f, operations1, nullptr));
-  curve->AddKeyframe(TransformKeyframe::Create(1.f, operations2, nullptr));
-  curve->AddKeyframe(TransformKeyframe::Create(2.f, operations3, nullptr));
-  ExpectTranslateX(2.f, curve->GetValue(-1.f));
-  ExpectTranslateX(2.f, curve->GetValue(0.f));
-  ExpectTranslateX(3.f, curve->GetValue(0.5f));
-  ExpectTranslateX(4.f, curve->GetValue(1.f));
-  ExpectTranslateX(6.f, curve->GetValue(1.5f));
-  ExpectTranslateX(8.f, curve->GetValue(2.f));
-  ExpectTranslateX(8.f, curve->GetValue(3.f));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(2.0), operations3, nullptr));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a transform animation with multiple keys at a given time works
@@ -238,23 +279,27 @@
   operations3.AppendTranslate(6.f, 0.f, 0.f);
   TransformOperations operations4;
   operations4.AppendTranslate(6.f, 0.f, 0.f);
-  curve->AddKeyframe(TransformKeyframe::Create(0.f, operations1, nullptr));
-  curve->AddKeyframe(TransformKeyframe::Create(1.f, operations2, nullptr));
-  curve->AddKeyframe(TransformKeyframe::Create(1.f, operations3, nullptr));
-  curve->AddKeyframe(TransformKeyframe::Create(2.f, operations4, nullptr));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(2.0), operations4, nullptr));
 
-  ExpectTranslateX(4.f, curve->GetValue(-1.f));
-  ExpectTranslateX(4.f, curve->GetValue(0.f));
-  ExpectTranslateX(4.f, curve->GetValue(0.5f));
+  ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
 
   // There is a discontinuity at 1. Any value between 4 and 6 is valid.
-  gfx::Transform value = curve->GetValue(1.f);
+  gfx::Transform value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
   EXPECT_GE(value.matrix().get(0, 3), 4.f);
   EXPECT_LE(value.matrix().get(0, 3), 6.f);
 
-  ExpectTranslateX(6.f, curve->GetValue(1.5f));
-  ExpectTranslateX(6.f, curve->GetValue(2.f));
-  ExpectTranslateX(6.f, curve->GetValue(3.f));
+  ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a filter animation with one keyframe works as expected.
@@ -263,13 +308,14 @@
       KeyframedFilterAnimationCurve::Create());
   FilterOperations operations;
   operations.Append(FilterOperation::CreateBrightnessFilter(2.f));
-  curve->AddKeyframe(FilterKeyframe::Create(0.f, operations, nullptr));
+  curve->AddKeyframe(
+      FilterKeyframe::Create(base::TimeDelta(), operations, nullptr));
 
-  ExpectBrightness(2.f, curve->GetValue(-1.f));
-  ExpectBrightness(2.f, curve->GetValue(0.f));
-  ExpectBrightness(2.f, curve->GetValue(0.5f));
-  ExpectBrightness(2.f, curve->GetValue(1.f));
-  ExpectBrightness(2.f, curve->GetValue(2.f));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a filter animation with two keyframes works as expected.
@@ -281,13 +327,15 @@
   FilterOperations operations2;
   operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
 
-  curve->AddKeyframe(FilterKeyframe::Create(0.f, operations1, nullptr));
-  curve->AddKeyframe(FilterKeyframe::Create(1.f, operations2, nullptr));
-  ExpectBrightness(2.f, curve->GetValue(-1.f));
-  ExpectBrightness(2.f, curve->GetValue(0.f));
-  ExpectBrightness(3.f, curve->GetValue(0.5f));
-  ExpectBrightness(4.f, curve->GetValue(1.f));
-  ExpectBrightness(4.f, curve->GetValue(2.f));
+  curve->AddKeyframe(
+      FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+                                            operations2, nullptr));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that a filter animation with three keyframes works as expected.
@@ -300,16 +348,19 @@
   operations2.Append(FilterOperation::CreateBrightnessFilter(4.f));
   FilterOperations operations3;
   operations3.Append(FilterOperation::CreateBrightnessFilter(8.f));
-  curve->AddKeyframe(FilterKeyframe::Create(0.f, operations1, nullptr));
-  curve->AddKeyframe(FilterKeyframe::Create(1.f, operations2, nullptr));
-  curve->AddKeyframe(FilterKeyframe::Create(2.f, operations3, nullptr));
-  ExpectBrightness(2.f, curve->GetValue(-1.f));
-  ExpectBrightness(2.f, curve->GetValue(0.f));
-  ExpectBrightness(3.f, curve->GetValue(0.5f));
-  ExpectBrightness(4.f, curve->GetValue(1.f));
-  ExpectBrightness(6.f, curve->GetValue(1.5f));
-  ExpectBrightness(8.f, curve->GetValue(2.f));
-  ExpectBrightness(8.f, curve->GetValue(3.f));
+  curve->AddKeyframe(
+      FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+                                            operations2, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
+                                            operations3, nullptr));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a filter animation with multiple keys at a given time works
@@ -326,41 +377,47 @@
   operations3.Append(FilterOperation::CreateBrightnessFilter(6.f));
   FilterOperations operations4;
   operations4.Append(FilterOperation::CreateBrightnessFilter(6.f));
-  curve->AddKeyframe(FilterKeyframe::Create(0.f, operations1, nullptr));
-  curve->AddKeyframe(FilterKeyframe::Create(1.f, operations2, nullptr));
-  curve->AddKeyframe(FilterKeyframe::Create(1.f, operations3, nullptr));
-  curve->AddKeyframe(FilterKeyframe::Create(2.f, operations4, nullptr));
+  curve->AddKeyframe(
+      FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+                                            operations2, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f),
+                                            operations3, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f),
+                                            operations4, nullptr));
 
-  ExpectBrightness(4.f, curve->GetValue(-1.f));
-  ExpectBrightness(4.f, curve->GetValue(0.f));
-  ExpectBrightness(4.f, curve->GetValue(0.5f));
+  ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
 
   // There is a discontinuity at 1. Any value between 4 and 6 is valid.
-  FilterOperations value = curve->GetValue(1.f);
+  FilterOperations value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f));
   EXPECT_EQ(1u, value.size());
   EXPECT_EQ(FilterOperation::BRIGHTNESS, value.at(0).type());
   EXPECT_GE(value.at(0).amount(), 4);
   EXPECT_LE(value.at(0).amount(), 6);
 
-  ExpectBrightness(6.f, curve->GetValue(1.5f));
-  ExpectBrightness(6.f, curve->GetValue(2.f));
-  ExpectBrightness(6.f, curve->GetValue(3.f));
+  ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that the keyframes may be added out of order.
 TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(2.0, 8.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 2.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 4.f, nullptr));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
-  EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
-  EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
-  EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
-  EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f));
-  EXPECT_FLOAT_EQ(8.f, curve->GetValue(3.f));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 8.f, nullptr));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 4.f, nullptr));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
+  EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
 }
 
 // Tests that a cubic bezier timing function works as expected.
@@ -368,16 +425,19 @@
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
   curve->AddKeyframe(FloatKeyframe::Create(
-      0.0, 0.f, CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f)));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
+      base::TimeDelta(), 0.f,
+      CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f)));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
 
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
-  EXPECT_LT(0.f, curve->GetValue(0.25f));
-  EXPECT_GT(0.25f, curve->GetValue(0.25f));
-  EXPECT_NEAR(curve->GetValue(0.5f), 0.5f, 0.00015f);
-  EXPECT_LT(0.75f, curve->GetValue(0.75f));
-  EXPECT_GT(1.f, curve->GetValue(0.75f));
-  EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_LT(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+  EXPECT_GT(0.25f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)));
+  EXPECT_NEAR(curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)), 0.5f,
+              0.00015f);
+  EXPECT_LT(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+  EXPECT_GT(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)));
+  EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
 }
 
 // Tests that animated bounds are computed as expected.
@@ -386,13 +446,16 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendTranslate(2.0, 3.0, -1.0);
-  curve->AddKeyframe(TransformKeyframe::Create(0.5, operations1, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(0.5f), operations1, nullptr));
   TransformOperations operations2;
   operations2.AppendTranslate(4.0, 1.0, 2.0);
-  curve->AddKeyframe(TransformKeyframe::Create(
-      1.0, operations2, EaseTimingFunction::Create()));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations2,
+                                EaseTimingFunction::Create()));
 
   gfx::BoxF box(2.f, 3.f, 4.f, 1.f, 3.f, 2.f);
   gfx::BoxF bounds;
@@ -408,23 +471,27 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendTranslate(2.0, 3.0, -1.0);
   TransformOperations operations2;
   operations2.AppendTranslate(4.0, 1.0, 2.0);
-  curve->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.f), operations2, nullptr));
 
   EXPECT_FALSE(curve->AffectsScale());
 
   TransformOperations operations3;
   operations3.AppendScale(2.f, 2.f, 2.f);
-  curve->AddKeyframe(TransformKeyframe::Create(2.0, operations3, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(2.f), operations3, nullptr));
 
   EXPECT_TRUE(curve->AffectsScale());
 
   TransformOperations operations4;
   operations3.AppendTranslate(2.f, 2.f, 2.f);
-  curve->AddKeyframe(TransformKeyframe::Create(3.0, operations4, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(3.f), operations4, nullptr));
 
   EXPECT_TRUE(curve->AffectsScale());
 }
@@ -435,23 +502,27 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendTranslate(2.0, 3.0, -1.0);
   TransformOperations operations2;
   operations2.AppendTranslate(4.0, 1.0, 2.0);
-  curve->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.f), operations2, nullptr));
 
   EXPECT_TRUE(curve->IsTranslation());
 
   TransformOperations operations3;
   operations3.AppendScale(2.f, 2.f, 2.f);
-  curve->AddKeyframe(TransformKeyframe::Create(2.0, operations3, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(2.f), operations3, nullptr));
 
   EXPECT_FALSE(curve->IsTranslation());
 
   TransformOperations operations4;
   operations3.AppendTranslate(2.f, 2.f, 2.f);
-  curve->AddKeyframe(TransformKeyframe::Create(3.0, operations4, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(3.f), operations4, nullptr));
 
   EXPECT_FALSE(curve->IsTranslation());
 }
@@ -462,10 +533,12 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendScale(2.f, -3.f, 1.f);
-  curve->AddKeyframe(TransformKeyframe::Create(
-      1.0, operations1, EaseTimingFunction::Create()));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations1,
+                                EaseTimingFunction::Create()));
 
   float maximum_scale = 0.f;
   EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale));
@@ -473,16 +546,18 @@
 
   TransformOperations operations2;
   operations2.AppendScale(6.f, 3.f, 2.f);
-  curve->AddKeyframe(TransformKeyframe::Create(
-      2.0, operations2, EaseTimingFunction::Create()));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), operations2,
+                                EaseTimingFunction::Create()));
 
   EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale));
   EXPECT_EQ(6.f, maximum_scale);
 
   TransformOperations operations3;
   operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
-  curve->AddKeyframe(TransformKeyframe::Create(
-      3.0, operations3, EaseTimingFunction::Create()));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), operations3,
+                                EaseTimingFunction::Create()));
 
   EXPECT_FALSE(curve->MaximumTargetScale(true, &maximum_scale));
 
@@ -492,12 +567,13 @@
 
   TransformOperations operations4;
   operations4.AppendScale(0.4f, 0.2f, 0.6f);
-  curve2->AddKeyframe(TransformKeyframe::Create(
-      0.0, operations4, EaseTimingFunction::Create()));
+  curve2->AddKeyframe(TransformKeyframe::Create(base::TimeDelta(), operations4,
+                                                EaseTimingFunction::Create()));
   TransformOperations operations5;
   operations5.AppendScale(0.5f, 0.3f, -0.8f);
-  curve2->AddKeyframe(TransformKeyframe::Create(
-      1.0, operations5, EaseTimingFunction::Create()));
+  curve2->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations5,
+                                EaseTimingFunction::Create()));
 
   EXPECT_TRUE(curve2->MaximumTargetScale(true, &maximum_scale));
   EXPECT_EQ(0.8f, maximum_scale);
@@ -510,17 +586,20 @@
 TEST(KeyframedAnimationCurveTest, CurveTiming) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
   curve->SetTimingFunction(
       CubicBezierTimingFunction::Create(0.75f, 0.f, 0.25f, 1.f).Pass());
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
-  EXPECT_NEAR(0.05f, curve->GetValue(0.25f), 0.005f);
-  EXPECT_FLOAT_EQ(0.5f, curve->GetValue(0.5f));
-  EXPECT_NEAR(0.95f, curve->GetValue(0.75f), 0.005f);
-  EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f));
-  EXPECT_FLOAT_EQ(1.f, curve->GetValue(2.f));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_NEAR(0.05f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)),
+              0.005f);
+  EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_NEAR(0.95f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)),
+              0.005f);
+  EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that an animation with a curve and keyframe timing function works as
@@ -529,22 +608,26 @@
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
   curve->AddKeyframe(FloatKeyframe::Create(
-      0.0,
-      0.f,
+      base::TimeDelta(), 0.f,
       CubicBezierTimingFunction::Create(0.35f, 0.f, 0.65f, 1.f).Pass()));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
   // Curve timing function producing outputs outside of range [0,1].
   curve->SetTimingFunction(
       CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass());
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.25f));        // Clamped. c(.25) < 0
-  EXPECT_NEAR(0.17f, curve->GetValue(0.42f), 0.005f);  // c(.42)=.27, k(.27)=.17
-  EXPECT_FLOAT_EQ(0.5f, curve->GetValue(0.5f));
-  EXPECT_NEAR(0.83f, curve->GetValue(0.58f), 0.005f);  // c(.58)=.73, k(.73)=.83
-  EXPECT_FLOAT_EQ(1.f, curve->GetValue(0.75f));        // Clamped. c(.75) > 1
-  EXPECT_FLOAT_EQ(1.f, curve->GetValue(1.f));
-  EXPECT_FLOAT_EQ(1.f, curve->GetValue(2.f));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(
+                           0.25f)));  // Clamped. c(.25) < 0
+  EXPECT_NEAR(0.17f, curve->GetValue(base::TimeDelta::FromSecondsD(0.42f)),
+              0.005f);  // c(.42)=.27, k(.27)=.17
+  EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
+  EXPECT_NEAR(0.83f, curve->GetValue(base::TimeDelta::FromSecondsD(0.58f)),
+              0.005f);  // c(.58)=.73, k(.73)=.83
+  EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(
+                           0.75f)));  // Clamped. c(.75) > 1
+  EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
+  EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
 }
 
 // Tests that an animation with a curve timing function and multiple keyframes
@@ -552,21 +635,28 @@
 TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(2.0, 3.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(3.0, 6.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(4.0, 9.f, nullptr));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 3.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), 6.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.f), 9.f, nullptr));
   curve->SetTimingFunction(
       CubicBezierTimingFunction::Create(0.5f, 0.f, 0.5f, 1.f).Pass());
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(-1.f));
-  EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
-  EXPECT_NEAR(0.42f, curve->GetValue(1.f), 0.005f);
-  EXPECT_NEAR(1.f, curve->GetValue(1.455f), 0.005f);
-  EXPECT_FLOAT_EQ(3.f, curve->GetValue(2.f));
-  EXPECT_NEAR(8.72f, curve->GetValue(3.5f), 0.01f);
-  EXPECT_FLOAT_EQ(9.f, curve->GetValue(4.f));
-  EXPECT_FLOAT_EQ(9.f, curve->GetValue(5.f));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
+  EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
+  EXPECT_NEAR(0.42f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
+              0.005f);
+  EXPECT_NEAR(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.455f)),
+              0.005f);
+  EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
+  EXPECT_NEAR(8.72f, curve->GetValue(base::TimeDelta::FromSecondsD(3.5f)),
+              0.01f);
+  EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(4.f)));
+  EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(5.f)));
 }
 
 // Tests that an animation with a curve timing function that overshoots works as
@@ -574,16 +664,22 @@
 TEST(KeyframedAnimationCurveTest, CurveTimingOvershootMultipeKeyframes) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve(
       KeyframedFloatAnimationCurve::Create());
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 1.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(2.0, 3.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(3.0, 6.f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(4.0, 9.f, nullptr));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 3.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.0), 6.f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.0), 9.f, nullptr));
   // Curve timing function producing outputs outside of range [0,1].
   curve->SetTimingFunction(
       CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass());
-  EXPECT_LE(curve->GetValue(1.f), 0.f);  // c(.25) < 0
-  EXPECT_GE(curve->GetValue(3.f), 9.f);  // c(.75) > 1
+  EXPECT_LE(curve->GetValue(base::TimeDelta::FromSecondsD(1.f)),
+            0.f);  // c(.25) < 0
+  EXPECT_GE(curve->GetValue(base::TimeDelta::FromSecondsD(3.f)),
+            9.f);  // c(.75) > 1
 }
 
 }  // namespace
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc
index f621ad3..c9d81cf 100644
--- a/cc/animation/layer_animation_controller.cc
+++ b/cc/animation/layer_animation_controller.cc
@@ -148,8 +148,8 @@
     if (!animation->InEffect(monotonic_time))
       continue;
 
-    double trimmed =
-        animation->TrimTimeToCurrentIteration(monotonic_time).InSecondsF();
+    base::TimeDelta trimmed =
+        animation->TrimTimeToCurrentIteration(monotonic_time);
     switch (animation->target_property()) {
       case Animation::Opacity: {
         AnimationEvent event(AnimationEvent::PropertyUpdate,
@@ -861,9 +861,8 @@
       if (!animations_[i]->InEffect(monotonic_time))
         continue;
 
-      double trimmed = animations_[i]
-                           ->TrimTimeToCurrentIteration(monotonic_time)
-                           .InSecondsF();
+      base::TimeDelta trimmed =
+          animations_[i]->TrimTimeToCurrentIteration(monotonic_time);
 
       switch (animations_[i]->target_property()) {
         case Animation::Transform: {
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc
index 4fa3d84..464a973 100644
--- a/cc/animation/layer_animation_controller_unittest.cc
+++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -510,9 +510,11 @@
 
   // Create simple Transform animation.
   TransformOperations operations;
-  curve->AddKeyframe(TransformKeyframe::Create(0, operations, nullptr));
+  curve->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations, nullptr));
   operations.AppendTranslate(delta_x, delta_y, 0);
-  curve->AddKeyframe(TransformKeyframe::Create(1, operations, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations, nullptr));
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve.Pass(), 1, 0, Animation::Transform));
@@ -559,10 +561,12 @@
 
   FilterOperations start_filters;
   start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f));
-  curve->AddKeyframe(FilterKeyframe::Create(0, start_filters, nullptr));
+  curve->AddKeyframe(
+      FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr));
   FilterOperations end_filters;
   end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f));
-  curve->AddKeyframe(FilterKeyframe::Create(1, end_filters, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+                                            end_filters, nullptr));
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve.Pass(), 1, 0, Animation::Filter));
@@ -606,10 +610,12 @@
   // Create simple Filter animation.
   FilterOperations start_filters;
   start_filters.Append(FilterOperation::CreateBrightnessFilter(1.f));
-  curve->AddKeyframe(FilterKeyframe::Create(0, start_filters, nullptr));
+  curve->AddKeyframe(
+      FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr));
   FilterOperations end_filters;
   end_filters.Append(FilterOperation::CreateBrightnessFilter(2.f));
-  curve->AddKeyframe(FilterKeyframe::Create(1, end_filters, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
+                                            end_filters, nullptr));
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve.Pass(), 1, 0, Animation::Filter));
@@ -1465,9 +1471,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve1->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendTranslate(10.0, 15.0, 0.0);
-  curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
@@ -1477,9 +1485,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations2;
-  curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+  curve2->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
   operations2.AppendScale(2.0, 3.0, 4.0);
-  curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
 
   animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform);
   controller_impl->AddAnimation(animation.Pass());
@@ -1511,9 +1521,11 @@
   TransformOperations operations3;
   gfx::Transform transform3;
   transform3.Scale3d(1.0, 2.0, 3.0);
-  curve3->AddKeyframe(TransformKeyframe::Create(0.0, operations3, nullptr));
+  curve3->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations3, nullptr));
   operations3.AppendMatrix(transform3);
-  curve3->AddKeyframe(TransformKeyframe::Create(1.0, operations3, nullptr));
+  curve3->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
   animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform);
   controller_impl->AddAnimation(animation.Pass());
   EXPECT_FALSE(controller_impl->TransformAnimationBoundsForBox(box, &bounds));
@@ -1781,9 +1793,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve1->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendTranslate(10.0, 15.0, 0.0);
-  curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve1.Pass(), 2, 2, Animation::Transform));
@@ -1796,9 +1810,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations2;
-  curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+  curve2->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
   operations2.AppendScale(2.0, 3.0, 4.0);
-  curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
 
   animation = Animation::Create(curve2.Pass(), 3, 3, Animation::Transform);
   controller_impl->AddAnimation(animation.Pass());
@@ -1831,9 +1847,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve1->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendTranslate(10.0, 15.0, 0.0);
-  curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve1.Pass(), 2, 2, Animation::Transform));
@@ -1846,9 +1864,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations2;
-  curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+  curve2->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
   operations2.AppendScale(2.0, 3.0, 4.0);
-  curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
 
   animation = Animation::Create(curve2.Pass(), 3, 3, Animation::Transform);
   controller_impl->AddAnimation(animation.Pass());
@@ -1876,9 +1896,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations1;
-  curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve1->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   operations1.AppendScale(2.0, 3.0, 4.0);
-  curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations1, nullptr));
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations1, nullptr));
 
   scoped_ptr<Animation> animation(
       Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
@@ -1891,9 +1913,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations2;
-  curve2->AddKeyframe(TransformKeyframe::Create(0.0, operations2, nullptr));
+  curve2->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations2, nullptr));
   operations2.AppendScale(6.0, 5.0, 4.0);
-  curve2->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+  curve2->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
 
   animation = Animation::Create(curve2.Pass(), 2, 2, Animation::Transform);
   controller_impl->AddAnimation(animation.Pass());
@@ -1905,9 +1929,11 @@
       KeyframedTransformAnimationCurve::Create());
 
   TransformOperations operations3;
-  curve3->AddKeyframe(TransformKeyframe::Create(0.0, operations3, nullptr));
+  curve3->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations3, nullptr));
   operations3.AppendPerspective(6.0);
-  curve3->AddKeyframe(TransformKeyframe::Create(1.0, operations3, nullptr));
+  curve3->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations3, nullptr));
 
   animation = Animation::Create(curve3.Pass(), 3, 3, Animation::Transform);
   controller_impl->AddAnimation(animation.Pass());
@@ -1933,10 +1959,12 @@
       KeyframedTransformAnimationCurve::Create());
   TransformOperations operations1;
   operations1.AppendScale(1.0, 2.0, 3.0);
-  curve1->AddKeyframe(TransformKeyframe::Create(0.0, operations1, nullptr));
+  curve1->AddKeyframe(
+      TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr));
   TransformOperations operations2;
   operations2.AppendScale(4.0, 5.0, 6.0);
-  curve1->AddKeyframe(TransformKeyframe::Create(1.0, operations2, nullptr));
+  curve1->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(1.0), operations2, nullptr));
 
   scoped_ptr<Animation> animation_owned(
       Animation::Create(curve1.Pass(), 1, 1, Animation::Transform));
diff --git a/cc/animation/scroll_offset_animation_curve.cc b/cc/animation/scroll_offset_animation_curve.cc
index e0b1a3b..9567263 100644
--- a/cc/animation/scroll_offset_animation_curve.cc
+++ b/cc/animation/scroll_offset_animation_curve.cc
@@ -9,6 +9,7 @@
 
 #include "base/logging.h"
 #include "cc/animation/timing_function.h"
+#include "cc/base/time_util.h"
 #include "ui/gfx/animation/tween.h"
 
 const double kDurationDivisor = 60.0;
@@ -65,17 +66,18 @@
       target_value_.DeltaFrom(initial_value_));
 }
 
-gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue(double t) const {
-  double duration = (total_animation_duration_ - last_retarget_).InSecondsF();
-  t -= last_retarget_.InSecondsF();
+gfx::ScrollOffset ScrollOffsetAnimationCurve::GetValue(
+    base::TimeDelta t) const {
+  base::TimeDelta duration = total_animation_duration_ - last_retarget_;
+  t -= last_retarget_;
 
-  if (t <= 0)
+  if (t <= base::TimeDelta())
     return initial_value_;
 
   if (t >= duration)
     return target_value_;
 
-  double progress = (timing_function_->GetValue(t / duration));
+  double progress = timing_function_->GetValue(TimeUtil::Divide(t, duration));
   return gfx::ScrollOffset(
       gfx::Tween::FloatValueBetween(
           progress, initial_value_.x(), target_value_.x()),
@@ -105,7 +107,8 @@
 void ScrollOffsetAnimationCurve::UpdateTarget(
     double t,
     const gfx::ScrollOffset& new_target) {
-  gfx::ScrollOffset current_position = GetValue(t);
+  gfx::ScrollOffset current_position =
+      GetValue(base::TimeDelta::FromSecondsD(t));
   gfx::Vector2dF old_delta = target_value_.DeltaFrom(initial_value_);
   gfx::Vector2dF new_delta = new_target.DeltaFrom(current_position);
 
diff --git a/cc/animation/scroll_offset_animation_curve.h b/cc/animation/scroll_offset_animation_curve.h
index 50dfb17..c4ae70b 100644
--- a/cc/animation/scroll_offset_animation_curve.h
+++ b/cc/animation/scroll_offset_animation_curve.h
@@ -24,7 +24,7 @@
   ~ScrollOffsetAnimationCurve() override;
 
   void SetInitialValue(const gfx::ScrollOffset& initial_value);
-  gfx::ScrollOffset GetValue(double t) const;
+  gfx::ScrollOffset GetValue(base::TimeDelta t) const;
   gfx::ScrollOffset target_value() const { return target_value_; }
   void UpdateTarget(double t, const gfx::ScrollOffset& new_target);
 
diff --git a/cc/animation/scroll_offset_animation_curve_unittest.cc b/cc/animation/scroll_offset_animation_curve_unittest.cc
index d57814e..cb3e914 100644
--- a/cc/animation/scroll_offset_animation_curve_unittest.cc
+++ b/cc/animation/scroll_offset_animation_curve_unittest.cc
@@ -5,6 +5,7 @@
 #include "cc/animation/scroll_offset_animation_curve.h"
 
 #include "cc/animation/timing_function.h"
+#include "cc/base/time_util.h"
 #include "cc/test/geometry_test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,24 +64,28 @@
           EaseInOutTimingFunction::Create().Pass()));
   curve->SetInitialValue(initial_value);
 
-  double duration_in_seconds = curve->Duration().InSecondsF();
+  base::TimeDelta duration = curve->Duration();
   EXPECT_GT(curve->Duration().InSecondsF(), 0);
   EXPECT_LT(curve->Duration().InSecondsF(), 0.1);
 
   EXPECT_EQ(AnimationCurve::ScrollOffset, curve->Type());
-  EXPECT_EQ(duration_in_seconds, curve->Duration().InSecondsF());
+  EXPECT_EQ(duration, curve->Duration());
 
-  EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(-1.0));
-  EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(0.0));
-  EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(6.f, 30.f),
-                      curve->GetValue(duration_in_seconds / 2.0));
-  EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration_in_seconds));
-  EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration_in_seconds + 1.0));
+  EXPECT_VECTOR2DF_EQ(initial_value,
+                      curve->GetValue(base::TimeDelta::FromSecondsD(-1.0)));
+  EXPECT_VECTOR2DF_EQ(initial_value, curve->GetValue(base::TimeDelta()));
+  EXPECT_VECTOR2DF_NEAR(gfx::ScrollOffset(6.f, 30.f),
+                        curve->GetValue(TimeUtil::Scale(duration, 0.5f)),
+                        0.00025);
+  EXPECT_VECTOR2DF_EQ(target_value, curve->GetValue(duration));
+  EXPECT_VECTOR2DF_EQ(
+      target_value,
+      curve->GetValue(duration + base::TimeDelta::FromSecondsD(1.0)));
 
   // Verify that GetValue takes the timing function into account.
-  gfx::ScrollOffset value = curve->GetValue(duration_in_seconds / 4.0);
-  EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
-  EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
+  gfx::ScrollOffset value = curve->GetValue(TimeUtil::Scale(duration, 0.25f));
+  EXPECT_NEAR(3.0333f, value.x(), 0.0002f);
+  EXPECT_NEAR(37.4168f, value.y(), 0.0002f);
 }
 
 // Verify that a clone behaves exactly like the original.
@@ -92,32 +97,34 @@
           target_value,
           EaseInOutTimingFunction::Create().Pass()));
   curve->SetInitialValue(initial_value);
-  double duration_in_seconds = curve->Duration().InSecondsF();
+  base::TimeDelta duration = curve->Duration();
 
   scoped_ptr<AnimationCurve> clone(curve->Clone().Pass());
 
   EXPECT_EQ(AnimationCurve::ScrollOffset, clone->Type());
-  EXPECT_EQ(duration_in_seconds, clone->Duration().InSecondsF());
+  EXPECT_EQ(duration, clone->Duration());
 
   EXPECT_VECTOR2DF_EQ(initial_value,
-                      clone->ToScrollOffsetAnimationCurve()->GetValue(-1.0));
-  EXPECT_VECTOR2DF_EQ(initial_value,
-                      clone->ToScrollOffsetAnimationCurve()->GetValue(0.0));
-  EXPECT_VECTOR2DF_EQ(gfx::ScrollOffset(6.f, 30.f),
                       clone->ToScrollOffsetAnimationCurve()->GetValue(
-                          duration_in_seconds / 2.0));
+                          base::TimeDelta::FromSecondsD(-1.0)));
   EXPECT_VECTOR2DF_EQ(
-      target_value,
-      clone->ToScrollOffsetAnimationCurve()->GetValue(duration_in_seconds));
+      initial_value,
+      clone->ToScrollOffsetAnimationCurve()->GetValue(base::TimeDelta()));
+  EXPECT_VECTOR2DF_NEAR(gfx::ScrollOffset(6.f, 30.f),
+                        clone->ToScrollOffsetAnimationCurve()->GetValue(
+                            TimeUtil::Scale(duration, 0.5f)),
+                        0.00025);
+  EXPECT_VECTOR2DF_EQ(
+      target_value, clone->ToScrollOffsetAnimationCurve()->GetValue(duration));
   EXPECT_VECTOR2DF_EQ(target_value,
                       clone->ToScrollOffsetAnimationCurve()->GetValue(
-                          duration_in_seconds + 1.0));
+                          duration + base::TimeDelta::FromSecondsD(1.f)));
 
   // Verify that the timing function was cloned correctly.
   gfx::ScrollOffset value = clone->ToScrollOffsetAnimationCurve()->GetValue(
-      duration_in_seconds / 4.0);
-  EXPECT_NEAR(3.0333f, value.x(), 0.00015f);
-  EXPECT_NEAR(37.4168f, value.y(), 0.00015f);
+      TimeUtil::Scale(duration, 0.25f));
+  EXPECT_NEAR(3.0333f, value.x(), 0.0002f);
+  EXPECT_NEAR(37.4168f, value.y(), 0.0002f);
 }
 
 TEST(ScrollOffsetAnimationCurveTest, UpdateTarget) {
@@ -128,21 +135,23 @@
           target_value, EaseInOutTimingFunction::Create().Pass()));
   curve->SetInitialValue(initial_value);
   EXPECT_EQ(1.0, curve->Duration().InSecondsF());
-  EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
-  EXPECT_EQ(3600.0, curve->GetValue(1.0).y());
+  EXPECT_EQ(1800.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.5)).y());
+  EXPECT_EQ(3600.0, curve->GetValue(base::TimeDelta::FromSecondsD(1.0)).y());
 
   curve->UpdateTarget(0.5, gfx::ScrollOffset(0.0, 9900.0));
 
   EXPECT_EQ(2.0, curve->Duration().InSecondsF());
-  EXPECT_EQ(1800.0, curve->GetValue(0.5).y());
-  EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
-  EXPECT_EQ(9900.0, curve->GetValue(2.0).y());
+  EXPECT_EQ(1800.0, curve->GetValue(base::TimeDelta::FromSecondsD(0.5)).y());
+  EXPECT_NEAR(5566.49, curve->GetValue(base::TimeDelta::FromSecondsD(1.0)).y(),
+              0.01);
+  EXPECT_EQ(9900.0, curve->GetValue(base::TimeDelta::FromSecondsD(2.0)).y());
 
   curve->UpdateTarget(1.0, gfx::ScrollOffset(0.0, 7200.0));
 
   EXPECT_NEAR(1.674, curve->Duration().InSecondsF(), 0.01);
-  EXPECT_NEAR(5566.49, curve->GetValue(1.0).y(), 0.01);
-  EXPECT_EQ(7200.0, curve->GetValue(1.674).y());
+  EXPECT_NEAR(5566.49, curve->GetValue(base::TimeDelta::FromSecondsD(1.0)).y(),
+              0.01);
+  EXPECT_EQ(7200.0, curve->GetValue(base::TimeDelta::FromSecondsD(1.674)).y());
 }
 
 }  // namespace
diff --git a/cc/base/time_util.h b/cc/base/time_util.h
index dc07e74..06682c2 100644
--- a/cc/base/time_util.h
+++ b/cc/base/time_util.h
@@ -18,6 +18,11 @@
         static_cast<double>(time_delta.ToInternalValue()) * value));
   }
 
+  static double Divide(base::TimeDelta dividend, base::TimeDelta divisor) {
+    return static_cast<double>(dividend.ToInternalValue()) /
+           static_cast<double>(divisor.ToInternalValue());
+  }
+
   static base::TimeDelta Mod(base::TimeDelta dividend,
                              base::TimeDelta divisor) {
     return base::TimeDelta::FromInternalValue(dividend.ToInternalValue() %
diff --git a/cc/blink/web_content_layer_impl.cc b/cc/blink/web_content_layer_impl.cc
index 6dfdad9..d0a4cca 100644
--- a/cc/blink/web_content_layer_impl.cc
+++ b/cc/blink/web_content_layer_impl.cc
@@ -19,13 +19,12 @@
 namespace cc_blink {
 
 WebContentLayerImpl::WebContentLayerImpl(blink::WebContentLayerClient* client)
-    : client_(client), ignore_lcd_text_change_(false) {
+    : client_(client) {
   if (WebLayerImpl::UsingPictureLayer())
     layer_ = make_scoped_ptr(new WebLayerImpl(PictureLayer::Create(this)));
   else
     layer_ = make_scoped_ptr(new WebLayerImpl(ContentLayer::Create(this)));
   layer_->layer()->SetIsDrawable(true);
-  can_use_lcd_text_ = layer_->layer()->can_use_lcd_text();
 }
 
 WebContentLayerImpl::~WebContentLayerImpl() {
@@ -54,30 +53,16 @@
   if (!client_)
     return;
 
+  // TODO(danakj): Stop passing this to blink it should always use LCD when it
+  // wants to. crbug.com/430617
+  bool can_use_lcd_text = true;
   client_->paintContents(
-      canvas,
-      clip,
-      can_use_lcd_text_,
+      canvas, clip, can_use_lcd_text,
       graphics_context_status == ContentLayerClient::GRAPHICS_CONTEXT_ENABLED
           ? blink::WebContentLayerClient::GraphicsContextEnabled
           : blink::WebContentLayerClient::GraphicsContextDisabled);
 }
 
-void WebContentLayerImpl::DidChangeLayerCanUseLCDText() {
-  // It is important to make this comparison because the LCD text status
-  // here can get out of sync with that in the layer.
-  if (can_use_lcd_text_ == layer_->layer()->can_use_lcd_text())
-    return;
-
-  // LCD text cannot be enabled once disabled.
-  if (layer_->layer()->can_use_lcd_text() && ignore_lcd_text_change_)
-    return;
-
-  can_use_lcd_text_ = layer_->layer()->can_use_lcd_text();
-  ignore_lcd_text_change_ = true;
-  layer_->invalidate();
-}
-
 bool WebContentLayerImpl::FillsBoundsCompletely() const {
   return false;
 }
diff --git a/cc/blink/web_content_layer_impl.h b/cc/blink/web_content_layer_impl.h
index b9bb871..2966bd4 100644
--- a/cc/blink/web_content_layer_impl.h
+++ b/cc/blink/web_content_layer_impl.h
@@ -40,7 +40,6 @@
                      const gfx::Rect& clip,
                      ContentLayerClient::GraphicsContextStatus
                          graphics_context_status) override;
-  void DidChangeLayerCanUseLCDText() override;
   bool FillsBoundsCompletely() const override;
 
   scoped_ptr<WebLayerImpl> layer_;
diff --git a/cc/blink/web_filter_animation_curve_impl.cc b/cc/blink/web_filter_animation_curve_impl.cc
index 606929e..bdbffe8 100644
--- a/cc/blink/web_filter_animation_curve_impl.cc
+++ b/cc/blink/web_filter_animation_curve_impl.cc
@@ -32,7 +32,8 @@
       static_cast<const WebFilterOperationsImpl&>(keyframe.value())
           .AsFilterOperations();
   curve_->AddKeyframe(cc::FilterKeyframe::Create(
-      keyframe.time(), filter_operations, CreateTimingFunction(type)));
+      base::TimeDelta::FromSecondsD(keyframe.time()), filter_operations,
+      CreateTimingFunction(type)));
 }
 
 void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe,
@@ -44,8 +45,7 @@
       static_cast<const WebFilterOperationsImpl&>(keyframe.value())
           .AsFilterOperations();
   curve_->AddKeyframe(cc::FilterKeyframe::Create(
-      keyframe.time(),
-      filter_operations,
+      base::TimeDelta::FromSecondsD(keyframe.time()), filter_operations,
       cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)));
 }
 
diff --git a/cc/blink/web_float_animation_curve_impl.cc b/cc/blink/web_float_animation_curve_impl.cc
index e5eee53..d85f57c 100644
--- a/cc/blink/web_float_animation_curve_impl.cc
+++ b/cc/blink/web_float_animation_curve_impl.cc
@@ -31,8 +31,9 @@
 
 void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
                                      TimingFunctionType type) {
-  curve_->AddKeyframe(cc::FloatKeyframe::Create(
-      keyframe.time, keyframe.value, CreateTimingFunction(type)));
+  curve_->AddKeyframe(
+      cc::FloatKeyframe::Create(base::TimeDelta::FromSecondsD(keyframe.time),
+                                keyframe.value, CreateTimingFunction(type)));
 }
 
 void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
@@ -41,8 +42,7 @@
                                      double x2,
                                      double y2) {
   curve_->AddKeyframe(cc::FloatKeyframe::Create(
-      keyframe.time,
-      keyframe.value,
+      base::TimeDelta::FromSecondsD(keyframe.time), keyframe.value,
       cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)));
 }
 
@@ -59,7 +59,7 @@
 }
 
 float WebFloatAnimationCurveImpl::getValue(double time) const {
-  return curve_->GetValue(time);
+  return curve_->GetValue(base::TimeDelta::FromSecondsD(time));
 }
 
 scoped_ptr<cc::AnimationCurve>
diff --git a/cc/blink/web_scroll_offset_animation_curve_impl.cc b/cc/blink/web_scroll_offset_animation_curve_impl.cc
index ba55d5b..cef276c 100644
--- a/cc/blink/web_scroll_offset_animation_curve_impl.cc
+++ b/cc/blink/web_scroll_offset_animation_curve_impl.cc
@@ -34,7 +34,8 @@
 }
 
 WebFloatPoint WebScrollOffsetAnimationCurveImpl::getValue(double time) const {
-  gfx::ScrollOffset value = curve_->GetValue(time);
+  gfx::ScrollOffset value =
+      curve_->GetValue(base::TimeDelta::FromSecondsD(time));
   return WebFloatPoint(value.x(), value.y());
 }
 
diff --git a/cc/blink/web_transform_animation_curve_impl.cc b/cc/blink/web_transform_animation_curve_impl.cc
index f91d94b..86f3602 100644
--- a/cc/blink/web_transform_animation_curve_impl.cc
+++ b/cc/blink/web_transform_animation_curve_impl.cc
@@ -36,7 +36,8 @@
       static_cast<const WebTransformOperationsImpl&>(keyframe.value())
           .AsTransformOperations();
   curve_->AddKeyframe(cc::TransformKeyframe::Create(
-      keyframe.time(), transform_operations, CreateTimingFunction(type)));
+      base::TimeDelta::FromSecondsD(keyframe.time()), transform_operations,
+      CreateTimingFunction(type)));
 }
 
 void WebTransformAnimationCurveImpl::add(const WebTransformKeyframe& keyframe,
@@ -48,8 +49,7 @@
       static_cast<const WebTransformOperationsImpl&>(keyframe.value())
           .AsTransformOperations();
   curve_->AddKeyframe(cc::TransformKeyframe::Create(
-      keyframe.time(),
-      transform_operations,
+      base::TimeDelta::FromSecondsD(keyframe.time()), transform_operations,
       cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2)));
 }
 
diff --git a/cc/input/top_controls_manager.cc b/cc/input/top_controls_manager.cc
index cd3534c..ddde672 100644
--- a/cc/input/top_controls_manager.cc
+++ b/cc/input/top_controls_manager.cc
@@ -167,7 +167,7 @@
   if (!top_controls_animation_ || !client_->HaveRootScrollLayer())
     return gfx::Vector2dF();
 
-  double time = (monotonic_time - base::TimeTicks()).InMillisecondsF();
+  base::TimeDelta time = monotonic_time - base::TimeTicks();
 
   float old_offset = client_->ControlsTopOffset();
   SetControlsTopOffset(top_controls_animation_->GetValue(time));
@@ -199,16 +199,15 @@
     return;
 
   top_controls_animation_ = KeyframedFloatAnimationCurve::Create();
-  double start_time =
-      (gfx::FrameTime::Now() - base::TimeTicks()).InMillisecondsF();
+  base::TimeDelta start_time = gfx::FrameTime::Now() - base::TimeTicks();
   top_controls_animation_->AddKeyframe(
       FloatKeyframe::Create(start_time, client_->ControlsTopOffset(), nullptr));
   float max_ending_offset =
       (direction == SHOWING_CONTROLS ? 1 : -1) * top_controls_height_;
-  top_controls_animation_->AddKeyframe(
-      FloatKeyframe::Create(start_time + kShowHideMaxDurationMs,
-                            client_->ControlsTopOffset() + max_ending_offset,
-                            EaseTimingFunction::Create()));
+  top_controls_animation_->AddKeyframe(FloatKeyframe::Create(
+      start_time + base::TimeDelta::FromMilliseconds(kShowHideMaxDurationMs),
+      client_->ControlsTopOffset() + max_ending_offset,
+      EaseTimingFunction::Create()));
   animation_direction_ = direction;
   client_->DidChangeTopControlsPosition();
 }
@@ -241,8 +240,8 @@
   if (!top_controls_animation_)
     return true;
 
-  double time_ms = (time - base::TimeTicks()).InMillisecondsF();
-  float new_offset = top_controls_animation_->GetValue(time_ms);
+  base::TimeDelta animation_time = time - base::TimeTicks();
+  float new_offset = top_controls_animation_->GetValue(animation_time);
 
   if ((animation_direction_ == SHOWING_CONTROLS && new_offset >= 0) ||
       (animation_direction_ == HIDING_CONTROLS
diff --git a/cc/layers/content_layer.cc b/cc/layers/content_layer.cc
index 88031e4..53c7120 100644
--- a/cc/layers/content_layer.cc
+++ b/cc/layers/content_layer.cc
@@ -36,9 +36,7 @@
 }
 
 ContentLayer::ContentLayer(ContentLayerClient* client)
-    : TiledLayer(),
-      client_(client),
-      can_use_lcd_text_last_frame_(can_use_lcd_text()) {
+    : TiledLayer(), client_(client) {
 }
 
 ContentLayer::~ContentLayer() {}
@@ -74,7 +72,6 @@
                                                   true);
 
     CreateUpdaterIfNeeded();
-    UpdateCanUseLCDText();
   }
 
   bool updated = TiledLayer::Update(queue, occlusion);
@@ -118,15 +115,6 @@
     updater_->SetOpaque(opaque);
 }
 
-void ContentLayer::UpdateCanUseLCDText() {
-  if (can_use_lcd_text_last_frame_ == can_use_lcd_text())
-    return;
-
-  can_use_lcd_text_last_frame_ = can_use_lcd_text();
-  if (client_)
-    client_->DidChangeLayerCanUseLCDText();
-}
-
 bool ContentLayer::SupportsLCDText() const {
   return true;
 }
diff --git a/cc/layers/content_layer.h b/cc/layers/content_layer.h
index fe0bd37..22dd8fd 100644
--- a/cc/layers/content_layer.h
+++ b/cc/layers/content_layer.h
@@ -65,11 +65,8 @@
   // TiledLayer implementation.
   void CreateUpdaterIfNeeded() override;
 
-  void UpdateCanUseLCDText();
-
   ContentLayerClient* client_;
   scoped_refptr<ContentLayerUpdater> updater_;
-  bool can_use_lcd_text_last_frame_;
 
   DISALLOW_COPY_AND_ASSIGN(ContentLayer);
 };
diff --git a/cc/layers/content_layer_client.h b/cc/layers/content_layer_client.h
index 0140513..ea22e97 100644
--- a/cc/layers/content_layer_client.h
+++ b/cc/layers/content_layer_client.h
@@ -27,10 +27,6 @@
                              const gfx::Rect& clip,
                              GraphicsContextStatus gc_status) = 0;
 
-  // Called by the content layer during the update phase.
-  // If the client paints LCD text, it may want to invalidate the layer.
-  virtual void DidChangeLayerCanUseLCDText() = 0;
-
   // If true the layer may skip clearing the background before rasterizing,
   // because it will cover any uncleared data with content.
   virtual bool FillsBoundsCompletely() const = 0;
diff --git a/cc/layers/layer_unittest.cc b/cc/layers/layer_unittest.cc
index 4dfe86a..460726f 100644
--- a/cc/layers/layer_unittest.cc
+++ b/cc/layers/layer_unittest.cc
@@ -1144,8 +1144,9 @@
 static bool AddTestAnimation(Layer* layer) {
   scoped_ptr<KeyframedFloatAnimationCurve> curve =
       KeyframedFloatAnimationCurve::Create();
-  curve->AddKeyframe(FloatKeyframe::Create(0.0, 0.3f, nullptr));
-  curve->AddKeyframe(FloatKeyframe::Create(1.0, 0.7f, nullptr));
+  curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.3f, nullptr));
+  curve->AddKeyframe(
+      FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 0.7f, nullptr));
   scoped_ptr<Animation> animation =
       Animation::Create(curve.Pass(), 0, 0, Animation::Opacity);
 
diff --git a/cc/layers/picture_image_layer.h b/cc/layers/picture_image_layer.h
index 3575d88..3f8d68d 100644
--- a/cc/layers/picture_image_layer.h
+++ b/cc/layers/picture_image_layer.h
@@ -27,7 +27,6 @@
       SkCanvas* canvas,
       const gfx::Rect& clip,
       ContentLayerClient::GraphicsContextStatus gc_status) override;
-  void DidChangeLayerCanUseLCDText() override {}
   bool FillsBoundsCompletely() const override;
 
  protected:
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc
index 029e99d..d734538 100644
--- a/cc/layers/picture_layer.cc
+++ b/cc/layers/picture_layer.cc
@@ -23,7 +23,7 @@
       recording_source_(new PicturePile),
       instrumentation_object_tracker_(id()),
       update_source_frame_number_(-1),
-      can_use_lcd_text_last_frame_(can_use_lcd_text()),
+      can_use_lcd_text_for_update_(true),
       is_mask_(false) {
 }
 
@@ -101,18 +101,14 @@
   update_source_frame_number_ = layer_tree_host()->source_frame_number();
   bool updated = Layer::Update(queue, occlusion);
 
-  {
-    base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
-                                                  true);
-    UpdateCanUseLCDText();
-  }
+  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 &&
+      recording_source_->GetSize() == layer_size && !can_use_lcd_text_changed &&
       pending_invalidation_.IsEmpty()) {
     // Only early out if the visible content rect of this layer hasn't changed.
     return updated;
@@ -141,8 +137,9 @@
   // for them.
   DCHECK(client_);
   updated |= recording_source_->UpdateAndExpandInvalidation(
-      client_, &recording_invalidation_, layer_size, visible_layer_rect,
-      update_source_frame_number_, Picture::RECORD_NORMALLY);
+      client_, &recording_invalidation_, can_use_lcd_text_for_update_,
+      layer_size, visible_layer_rect, update_source_frame_number_,
+      Picture::RECORD_NORMALLY);
   last_updated_visible_content_rect_ = visible_content_rect();
 
   if (updated) {
@@ -164,13 +161,14 @@
   return true;
 }
 
-void PictureLayer::UpdateCanUseLCDText() {
-  if (can_use_lcd_text_last_frame_ == can_use_lcd_text())
-    return;
+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_last_frame_ = can_use_lcd_text();
-  if (client_)
-    client_->DidChangeLayerCanUseLCDText();
+  can_use_lcd_text_for_update_ = can_use_lcd_text();
+  return true;
 }
 
 skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
diff --git a/cc/layers/picture_layer.h b/cc/layers/picture_layer.h
index e4acb1f..01a37a3 100644
--- a/cc/layers/picture_layer.h
+++ b/cc/layers/picture_layer.h
@@ -50,7 +50,7 @@
   ~PictureLayer() override;
 
   bool HasDrawableContent() const override;
-  void UpdateCanUseLCDText();
+  bool UpdateCanUseLCDText();
 
  private:
   ContentLayerClient* client_;
@@ -64,7 +64,7 @@
   gfx::Rect last_updated_visible_content_rect_;
 
   int update_source_frame_number_;
-  bool can_use_lcd_text_last_frame_;
+  bool can_use_lcd_text_for_update_;
   bool is_mask_;
 
   DISALLOW_COPY_AND_ASSIGN(PictureLayer);
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 111a0e7..937aa77 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -645,7 +645,7 @@
   // TODO(danakj): Remove this when no longer swapping tilings.
   if (!twin_layer->tilings_)
     return nullptr;
-  return twin_layer->tilings_->TilingAtScale(tiling->contents_scale());
+  return twin_layer->tilings_->FindTilingWithScale(tiling->contents_scale());
 }
 
 PictureLayerTiling* PictureLayerImpl::GetRecycledTwinTiling(
@@ -653,7 +653,7 @@
   PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
   if (!recycled_twin || !recycled_twin->tilings_)
     return nullptr;
-  return recycled_twin->tilings_->TilingAtScale(tiling->contents_scale());
+  return recycled_twin->tilings_->FindTilingWithScale(tiling->contents_scale());
 }
 
 TilePriority::PriorityBin PictureLayerImpl::GetMaxTilePriorityBin() const {
@@ -889,13 +889,7 @@
   if (!tilings_ || tilings_->num_tilings() == 0)
     return;
 
-  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
-    PictureLayerTiling* tiling = tilings_->tiling_at(i);
-    if (tiling->contents_scale() == contents_scale) {
-      tilings_->Remove(tiling);
-      break;
-    }
-  }
+  tilings_->RemoveTilingWithScale(contents_scale);
   if (tilings_->num_tilings() == 0)
     ResetRasterScale();
   SanityCheckTilingState();
@@ -908,44 +902,32 @@
   ResetRasterScale();
 }
 
-namespace {
-
-inline float PositiveRatio(float float1, float float2) {
-  DCHECK_GT(float1, 0);
-  DCHECK_GT(float2, 0);
-  return float1 > float2 ? float1 / float2 : float2 / float1;
-}
-
-}  // namespace
-
 void PictureLayerImpl::AddTilingsForRasterScale() {
-  PictureLayerTiling* high_res = nullptr;
-  PictureLayerTiling* low_res = nullptr;
+  // Reset all resolution enums on tilings, we'll be setting new values in this
+  // function.
+  tilings_->MarkAllTilingsNonIdeal();
 
-  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
-    PictureLayerTiling* tiling = tilings_->tiling_at(i);
-    if (tiling->contents_scale() == raster_contents_scale_)
-      high_res = tiling;
-    if (tiling->contents_scale() == low_res_raster_contents_scale_)
-      low_res = tiling;
-
-    // Reset all tilings to non-ideal until the end of this function.
-    tiling->set_resolution(NON_IDEAL_RESOLUTION);
-  }
-
-  if (!high_res) {
+  PictureLayerTiling* high_res =
+      tilings_->FindTilingWithScale(raster_contents_scale_);
+  // We always need a high res tiling, so create one if it doesn't exist.
+  if (!high_res)
     high_res = AddTiling(raster_contents_scale_);
-    if (raster_contents_scale_ == low_res_raster_contents_scale_)
-      low_res = high_res;
-  }
+
+  // Try and find a low res tiling.
+  PictureLayerTiling* low_res = nullptr;
+  if (raster_contents_scale_ == low_res_raster_contents_scale_)
+    low_res = high_res;
+  else
+    low_res = tilings_->FindTilingWithScale(low_res_raster_contents_scale_);
 
   // Only create new low res tilings when the transform is static.  This
   // prevents wastefully creating a paired low res tiling for every new high res
   // tiling during a pinch or a CSS animation.
+  bool can_have_low_res = layer_tree_impl()->create_low_res_tiling();
+  bool needs_low_res = !low_res;
   bool is_pinching = layer_tree_impl()->PinchGestureActive();
-  if (layer_tree_impl()->create_low_res_tiling() && !is_pinching &&
-      !draw_properties().screen_space_transform_is_animating && !low_res &&
-      low_res != high_res)
+  bool is_animating = draw_properties().screen_space_transform_is_animating;
+  if (can_have_low_res && needs_low_res && !is_pinching && !is_animating)
     low_res = AddTiling(low_res_raster_contents_scale_);
 
   // Set low-res if we have one.
@@ -999,21 +981,6 @@
   return false;
 }
 
-float PictureLayerImpl::SnappedContentsScale(float scale) {
-  // If a tiling exists within the max snapping ratio, snap to its scale.
-  float snapped_contents_scale = scale;
-  float snapped_ratio = kSnapToExistingTilingRatio;
-  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
-    float tiling_contents_scale = tilings_->tiling_at(i)->contents_scale();
-    float ratio = PositiveRatio(tiling_contents_scale, scale);
-    if (ratio < snapped_ratio) {
-      snapped_contents_scale = tiling_contents_scale;
-      snapped_ratio = ratio;
-    }
-  }
-  return snapped_contents_scale;
-}
-
 void PictureLayerImpl::RecalculateRasterScales() {
   float old_raster_contents_scale = raster_contents_scale_;
   float old_raster_page_scale = raster_page_scale_;
@@ -1058,7 +1025,8 @@
       while (desired_contents_scale < ideal_contents_scale_)
         desired_contents_scale *= kMaxScaleRatioDuringPinch;
     }
-    raster_contents_scale_ = SnappedContentsScale(desired_contents_scale);
+    raster_contents_scale_ = tilings_->GetSnappedContentsScale(
+        desired_contents_scale, kSnapToExistingTilingRatio);
     raster_page_scale_ =
         raster_contents_scale_ / raster_device_scale_ / raster_source_scale_;
   }
@@ -1142,14 +1110,14 @@
     // TODO(danakj): Remove the tilings_ check when we create them in the
     // constructor.
     if (twin->tilings_) {
-      for (size_t i = 0; i < twin->tilings_->num_tilings(); ++i) {
-        PictureLayerTiling* tiling = twin->tilings_->tiling_at(i);
-        if (tiling->resolution() == LOW_RESOLUTION)
-          twin_low_res_scale = tiling->contents_scale();
-      }
+      PictureLayerTiling* tiling =
+          twin->tilings_->FindTilingWithResolution(LOW_RESOLUTION);
+      if (tiling)
+        twin_low_res_scale = tiling->contents_scale();
     }
   }
 
+  // TODO(vmpstr): Put this logic into PictureLayerTilingSet.
   std::vector<PictureLayerTiling*> to_remove;
   for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
     PictureLayerTiling* tiling = tilings_->tiling_at(i);
@@ -1269,12 +1237,8 @@
 }
 
 float PictureLayerImpl::MaximumTilingContentsScale() const {
-  float max_contents_scale = MinimumContentsScale();
-  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
-    const PictureLayerTiling* tiling = tilings_->tiling_at(i);
-    max_contents_scale = std::max(max_contents_scale, tiling->contents_scale());
-  }
-  return max_contents_scale;
+  float max_contents_scale = tilings_->GetMaximumContentsScale();
+  return std::max(max_contents_scale, MinimumContentsScale());
 }
 
 void PictureLayerImpl::UpdateIdealScales() {
@@ -1310,9 +1274,7 @@
     std::set<const Tile*>* tiles) const {
   if (!tilings_)
     return;
-
-  for (size_t i = 0; i < tilings_->num_tilings(); ++i)
-    tilings_->tiling_at(i)->GetAllTilesForTracing(tiles);
+  tilings_->GetAllTilesForTracing(tiles);
 }
 
 void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
@@ -1394,31 +1356,34 @@
   gfx::Rect rect = GetViewportForTilePriorityInContentSpace();
   rect.Intersect(visible_rect_for_tile_priority_);
 
-  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
-    PictureLayerTiling* tiling = tilings_->tiling_at(i);
-    if (tiling->resolution() != HIGH_RESOLUTION &&
-        tiling->resolution() != LOW_RESOLUTION)
+  // The high resolution tiling is the only tiling that can mark tiles as
+  // requiring either draw or activation. There is an explicit check in those
+  // callbacks to return false if they are not high resolution tilings. This
+  // check needs to remain since there are other callers of that function that
+  // rely on it. However, for the purposes of this function, we don't have to
+  // check other tilings.
+  PictureLayerTiling* tiling =
+      tilings_->FindTilingWithResolution(HIGH_RESOLUTION);
+  if (!tiling)
+    return true;
+
+  for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
+       ++iter) {
+    const Tile* tile = *iter;
+    // A null tile (i.e. missing recording) can just be skipped.
+    // TODO(vmpstr): Verify this is true if we create tiles in raster
+    // iterators.
+    if (!tile)
       continue;
 
-    for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
-         ++iter) {
-      const Tile* tile = *iter;
-      // A null tile (i.e. missing recording) can just be skipped.
-      // TODO(vmpstr): Verify this is true if we create tiles in raster
-      // iterators.
-      if (!tile)
-        continue;
-
-      // We can't check tile->required_for_activation, because that value might
-      // be out of date. It is updated in the raster/eviction iterators.
-      // TODO(vmpstr): Remove the comment once you can't access this information
-      // from the tile.
-      if ((tiling->*is_tile_required_callback)(tile) &&
-          !tile->IsReadyToDraw()) {
-        TRACE_EVENT_INSTANT0("cc", "Tile required, but not ready to draw.",
-                             TRACE_EVENT_SCOPE_THREAD);
-        return false;
-      }
+    // We can't check tile->required_for_activation, because that value might
+    // be out of date. It is updated in the raster/eviction iterators.
+    // TODO(vmpstr): Remove the comment once you can't access this information
+    // from the tile.
+    if ((tiling->*is_tile_required_callback)(tile) && !tile->IsReadyToDraw()) {
+      TRACE_EVENT_INSTANT0("cc", "Tile required, but not ready to draw.",
+                           TRACE_EVENT_SCOPE_THREAD);
+      return false;
     }
   }
 
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 78b13fc..12209a8 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -168,7 +168,6 @@
   void CleanUpTilingsOnActiveLayer(
       std::vector<PictureLayerTiling*> used_tilings);
   float MinimumContentsScale() const;
-  float SnappedContentsScale(float new_contents_scale);
   void ResetRasterScale();
   gfx::Rect GetViewportForTilePriorityInContentSpace() const;
   PictureLayerImpl* GetRecycledTwinLayer() const;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index 1d7e2ee..931e979 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -2283,9 +2283,9 @@
   float new_scale = 1.f;
   active_layer_->ReleaseResources();
   pending_layer_->ReleaseResources();
-  EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(new_scale));
+  EXPECT_FALSE(active_layer_->tilings()->FindTilingWithScale(new_scale));
   pending_layer_->AddTiling(new_scale);
-  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(new_scale));
+  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(new_scale));
 
   // UpdateDrawProperties early-outs if the tree doesn't need it.  It is also
   // responsible for calling ManageTilings.  These checks verify that
@@ -2294,7 +2294,7 @@
   EXPECT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
   host_impl_.active_tree()->UpdateDrawProperties();
   PictureLayerTiling* high_res =
-      active_layer_->tilings()->TilingAtScale(new_scale);
+      active_layer_->tilings()->FindTilingWithScale(new_scale);
   ASSERT_TRUE(!!high_res);
   EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
 }
@@ -2304,8 +2304,8 @@
 
   const float kScale = 1.f;
   pending_layer_->AddTiling(kScale);
-  EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
-  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(kScale));
+  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(kScale));
 
   // Gpu rasterization is disabled by default.
   EXPECT_FALSE(host_impl_.use_gpu_rasterization());
@@ -2317,8 +2317,8 @@
   // Make sure that we can still add tiling to the pending layer,
   // that gets synced to the active layer.
   pending_layer_->AddTiling(kScale);
-  EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
-  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+  EXPECT_TRUE(pending_layer_->tilings()->FindTilingWithScale(kScale));
+  EXPECT_TRUE(active_layer_->tilings()->FindTilingWithScale(kScale));
 
   // Toggling the gpu rasterization clears all tilings on both trees.
   EXPECT_TRUE(host_impl_.use_gpu_rasterization());
@@ -2347,7 +2347,7 @@
 
   // Sanity checks.
   ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
-  ASSERT_EQ(tiling, active_layer_->tilings()->TilingAtScale(0.5f));
+  ASSERT_EQ(tiling, active_layer_->tilings()->FindTilingWithScale(0.5f));
 
   // Now, set the bounds to be 1x1 (so that minimum contents scale becomes
   // 1.0f). Note that we should also ensure that the pending layer needs post
@@ -2368,12 +2368,12 @@
   // violate minimum contents scale. At the same time, we should've created a
   // new high res tiling at scale 1.0f.
   EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
-  ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.0f));
+  ASSERT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.0f));
   EXPECT_EQ(HIGH_RESOLUTION,
-            pending_layer_->tilings()->TilingAtScale(1.0f)->resolution());
-  ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.5f));
+            pending_layer_->tilings()->FindTilingWithScale(1.0f)->resolution());
+  ASSERT_TRUE(pending_layer_->tilings()->FindTilingWithScale(1.5f));
   EXPECT_EQ(NON_IDEAL_RESOLUTION,
-            pending_layer_->tilings()->TilingAtScale(1.5f)->resolution());
+            pending_layer_->tilings()->FindTilingWithScale(1.5f)->resolution());
 }
 
 TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) {
@@ -4504,7 +4504,7 @@
 
   Region invalidation(layer_rect);
   recording_source->UpdateAndExpandInvalidation(
-      &client, &invalidation, layer_bounds, layer_rect, frame_number++,
+      &client, &invalidation, false, layer_bounds, layer_rect, frame_number++,
       Picture::RECORD_NORMALLY);
 
   scoped_refptr<RasterSource> pending_raster_source =
@@ -4571,7 +4571,7 @@
 
   Region invalidation1(layer_rect);
   recording_source->UpdateAndExpandInvalidation(
-      &client, &invalidation1, layer_bounds, layer_rect, frame_number++,
+      &client, &invalidation1, false, layer_bounds, layer_rect, frame_number++,
       Picture::RECORD_NORMALLY);
 
   scoped_refptr<RasterSource> raster_source1 =
@@ -4589,7 +4589,7 @@
 
   Region invalidation2(layer_rect);
   recording_source->UpdateAndExpandInvalidation(
-      &client, &invalidation2, layer_bounds, layer_rect, frame_number++,
+      &client, &invalidation2, false, layer_bounds, layer_rect, frame_number++,
       Picture::RECORD_NORMALLY);
 
   scoped_refptr<RasterSource> raster_source2 =
diff --git a/cc/layers/picture_layer_unittest.cc b/cc/layers/picture_layer_unittest.cc
index 7873b48..3f81ef8 100644
--- a/cc/layers/picture_layer_unittest.cc
+++ b/cc/layers/picture_layer_unittest.cc
@@ -24,7 +24,6 @@
       SkCanvas* canvas,
       const gfx::Rect& clip,
       ContentLayerClient::GraphicsContextStatus gc_status) override {}
-  void DidChangeLayerCanUseLCDText() override {}
   bool FillsBoundsCompletely() const override { return false; };
 };
 
diff --git a/cc/resources/gpu_raster_worker_pool.cc b/cc/resources/gpu_raster_worker_pool.cc
index c913970..d29855a 100644
--- a/cc/resources/gpu_raster_worker_pool.cc
+++ b/cc/resources/gpu_raster_worker_pool.cc
@@ -41,15 +41,19 @@
     bool use_distance_field_text =
         use_distance_field_text_ ||
         raster_source->ShouldAttemptToUseDistanceFieldText();
-    SkSurface* sk_surface = lock_.GetSkSurface(use_distance_field_text);
+    SkSurface* sk_surface = lock_.GetSkSurface(use_distance_field_text,
+                                               raster_source->CanUseLCDText());
 
     if (!sk_surface)
       return;
 
     SkPictureRecorder recorder;
     gfx::Size size = resource_->size();
+    const int flags = SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag;
     skia::RefPtr<SkCanvas> canvas =
-        skia::SharePtr(recorder.beginRecording(size.width(), size.height()));
+        skia::SharePtr(recorder.beginRecording(size.width(), size.height(),
+                                               NULL, flags));
+
 
     canvas->save();
     raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
diff --git a/cc/resources/picture.cc b/cc/resources/picture.cc
index c35da96..9a45ad1 100644
--- a/cc/resources/picture.cc
+++ b/cc/resources/picture.cc
@@ -210,12 +210,14 @@
   DCHECK(!picture_);
   DCHECK(!tile_grid_info.fTileInterval.isEmpty());
 
-  SkTileGridFactory factory(tile_grid_info);
+  // TODO(mtklein): If SkRTree sticks, clean up tile_grid_info.  skbug.com/3085
+  SkRTreeFactory factory;
   SkPictureRecorder recorder;
 
   skia::RefPtr<SkCanvas> canvas;
   canvas = skia::SharePtr(recorder.beginRecording(
-      layer_rect_.width(), layer_rect_.height(), &factory));
+      layer_rect_.width(), layer_rect_.height(), &factory,
+      SkPictureRecorder::kComputeSaveLayerInfo_RecordFlag));
 
   ContentLayerClient::GraphicsContextStatus graphics_context_status =
       ContentLayerClient::GRAPHICS_CONTEXT_ENABLED;
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index 060bd27..35170a0 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -5,6 +5,7 @@
 #include "cc/resources/picture_layer_tiling_set.h"
 
 #include <limits>
+#include <set>
 
 namespace cc {
 
@@ -17,6 +18,12 @@
   }
 };
 
+inline float LargerRatio(float float1, float float2) {
+  DCHECK_GT(float1, 0.f);
+  DCHECK_GT(float2, 0.f);
+  return float1 > float2 ? float1 / float2 : float2 / float1;
+}
+
 }  // namespace
 
 // static
@@ -43,6 +50,11 @@
     tilings_[i]->RemoveTilesInRegion(region);
 }
 
+void PictureLayerTilingSet::MarkAllTilingsNonIdeal() {
+  for (auto* tiling : tilings_)
+    tiling->set_resolution(NON_IDEAL_RESOLUTION);
+}
+
 bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other,
                                         const gfx::Size& new_layer_bounds,
                                         const Region& layer_invalidation,
@@ -58,7 +70,7 @@
   // Remove any tilings that aren't in |other| or don't meet the minimum.
   for (size_t i = 0; i < tilings_.size(); ++i) {
     float scale = tilings_[i]->contents_scale();
-    if (scale >= minimum_contents_scale && !!other.TilingAtScale(scale))
+    if (scale >= minimum_contents_scale && !!other.FindTilingWithScale(scale))
       continue;
     // Swap with the last element and remove it.
     tilings_.swap(tilings_.begin() + i, tilings_.end() - 1);
@@ -73,7 +85,7 @@
     float contents_scale = other.tilings_[i]->contents_scale();
     if (contents_scale < minimum_contents_scale)
       continue;
-    if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
+    if (PictureLayerTiling* this_tiling = FindTilingWithScale(contents_scale)) {
       this_tiling->set_resolution(other.tilings_[i]->resolution());
 
       this_tiling->UpdateTilesToCurrentRasterSource(
@@ -127,7 +139,8 @@
   return num_high_res;
 }
 
-PictureLayerTiling* PictureLayerTilingSet::TilingAtScale(float scale) const {
+PictureLayerTiling* PictureLayerTilingSet::FindTilingWithScale(
+    float scale) const {
   for (size_t i = 0; i < tilings_.size(); ++i) {
     if (tilings_[i]->contents_scale() == scale)
       return tilings_[i];
@@ -135,6 +148,17 @@
   return NULL;
 }
 
+PictureLayerTiling* PictureLayerTilingSet::FindTilingWithResolution(
+    TileResolution resolution) const {
+  auto iter = std::find_if(tilings_.begin(), tilings_.end(),
+                           [resolution](const PictureLayerTiling* tiling) {
+    return tiling->resolution() == resolution;
+  });
+  if (iter == tilings_.end())
+    return NULL;
+  return *iter;
+}
+
 void PictureLayerTilingSet::RemoveAllTilings() {
   tilings_.clear();
 }
@@ -147,11 +171,45 @@
   tilings_.erase(iter);
 }
 
+void PictureLayerTilingSet::RemoveTilingWithScale(float scale) {
+  auto iter = std::find_if(tilings_.begin(), tilings_.end(),
+                           [scale](const PictureLayerTiling* tiling) {
+    return tiling->contents_scale() == scale;
+  });
+  if (iter == tilings_.end())
+    return;
+  tilings_.erase(iter);
+}
+
 void PictureLayerTilingSet::RemoveAllTiles() {
   for (size_t i = 0; i < tilings_.size(); ++i)
     tilings_[i]->Reset();
 }
 
+float PictureLayerTilingSet::GetSnappedContentsScale(
+    float start_scale,
+    float snap_to_existing_tiling_ratio) const {
+  // If a tiling exists within the max snapping ratio, snap to its scale.
+  float snapped_contents_scale = start_scale;
+  float snapped_ratio = snap_to_existing_tiling_ratio;
+  for (const auto* tiling : tilings_) {
+    float tiling_contents_scale = tiling->contents_scale();
+    float ratio = LargerRatio(tiling_contents_scale, start_scale);
+    if (ratio < snapped_ratio) {
+      snapped_contents_scale = tiling_contents_scale;
+      snapped_ratio = ratio;
+    }
+  }
+  return snapped_contents_scale;
+}
+
+float PictureLayerTilingSet::GetMaximumContentsScale() const {
+  if (tilings_.empty())
+    return 0.f;
+  // The first tiling has the largest contents scale.
+  return tilings_[0]->contents_scale();
+}
+
 bool PictureLayerTilingSet::UpdateTilePriorities(
     const gfx::Rect& required_rect_in_layer_space,
     float ideal_contents_scale,
@@ -181,6 +239,12 @@
   return true;
 }
 
+void PictureLayerTilingSet::GetAllTilesForTracing(
+    std::set<const Tile*>* tiles) const {
+  for (auto* tiling : tilings_)
+    tiling->GetAllTilesForTracing(tiles);
+}
+
 PictureLayerTilingSet::CoverageIterator::CoverageIterator(
     const PictureLayerTilingSet* set,
     float contents_scale,
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h
index 489bc0c..661dd24 100644
--- a/cc/resources/picture_layer_tiling_set.h
+++ b/cc/resources/picture_layer_tiling_set.h
@@ -5,6 +5,8 @@
 #ifndef CC_RESOURCES_PICTURE_LAYER_TILING_SET_H_
 #define CC_RESOURCES_PICTURE_LAYER_TILING_SET_H_
 
+#include <set>
+
 #include "cc/base/region.h"
 #include "cc/base/scoped_ptr_vector.h"
 #include "cc/resources/picture_layer_tiling.h"
@@ -64,13 +66,28 @@
     return tilings_[idx];
   }
 
-  PictureLayerTiling* TilingAtScale(float scale) const;
+  PictureLayerTiling* FindTilingWithScale(float scale) const;
+  PictureLayerTiling* FindTilingWithResolution(TileResolution resolution) const;
+
+  void MarkAllTilingsNonIdeal();
+
+  // If a tiling exists whose scale is within |snap_to_existing_tiling_ratio|
+  // ratio of |start_scale|, then return that tiling's scale. Otherwise, return
+  // |start_scale|. If multiple tilings match the criteria, return the one with
+  // the least ratio to |start_scale|.
+  float GetSnappedContentsScale(float start_scale,
+                                float snap_to_existing_tiling_ratio) const;
+
+  // Returns the maximum contents scale of all tilings, or 0 if no tilings
+  // exist.
+  float GetMaximumContentsScale() const;
 
   // Remove all tilings.
   void RemoveAllTilings();
 
   // Remove one tiling.
   void Remove(PictureLayerTiling* tiling);
+  void RemoveTilingWithScale(float scale);
 
   // Remove all tiles; keep all tilings.
   void RemoveAllTiles();
@@ -82,6 +99,8 @@
                             const Occlusion& occlusion_in_layer_space,
                             bool can_require_tiles_for_activation);
 
+  void GetAllTilesForTracing(std::set<const Tile*>* tiles) const;
+
   // For a given rect, iterates through tiles that can fill it.  If no
   // set of tiles with resources can fill the rect, then it will iterate
   // through null tiles with valid geometry_rect() until the rect is full.
diff --git a/cc/resources/picture_layer_tiling_set_unittest.cc b/cc/resources/picture_layer_tiling_set_unittest.cc
index 2a215a8..7acc55b 100644
--- a/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -430,14 +430,14 @@
   for (size_t i = 0; i < arraysize(target_scales); ++i)
     target_->AddTiling(target_scales[i], target_bounds_);
 
-  PictureLayerTiling* tiling1 = source_->TilingAtScale(1.f);
+  PictureLayerTiling* tiling1 = source_->FindTilingWithScale(1.f);
   ASSERT_TRUE(tiling1);
   tiling1->CreateAllTilesForTesting();
   EXPECT_EQ(tiling1->contents_scale(), 1.f);
   Tile* tile1 = FindTileAtOrigin(tiling1);
   ASSERT_TRUE(tile1);
 
-  PictureLayerTiling* tiling2 = source_->TilingAtScale(2.f);
+  PictureLayerTiling* tiling2 = source_->FindTilingWithScale(2.f);
   tiling2->CreateAllTilesForTesting();
   ASSERT_TRUE(tiling2);
   EXPECT_EQ(tiling2->contents_scale(), 2.f);
@@ -448,11 +448,11 @@
   SyncTilings(new_bounds);
   VerifyTargetEqualsSource(new_bounds);
 
-  EXPECT_EQ(tiling1, source_->TilingAtScale(1.f));
+  EXPECT_EQ(tiling1, source_->FindTilingWithScale(1.f));
   EXPECT_EQ(tile1, FindTileAtOrigin(tiling1));
   EXPECT_FALSE(tiling1->live_tiles_rect().IsEmpty());
 
-  EXPECT_EQ(tiling2, source_->TilingAtScale(2.f));
+  EXPECT_EQ(tiling2, source_->FindTilingWithScale(2.f));
   EXPECT_EQ(tile2, FindTileAtOrigin(tiling2));
   EXPECT_FALSE(tiling2->live_tiles_rect().IsEmpty());
 }
diff --git a/cc/resources/picture_pile.cc b/cc/resources/picture_pile.cc
index eed12ea..97cd127 100644
--- a/cc/resources/picture_pile.cc
+++ b/cc/resources/picture_pile.cc
@@ -164,6 +164,7 @@
 PicturePile::PicturePile()
     : min_contents_scale_(0),
       slow_down_raster_scale_factor_for_debug_(0),
+      can_use_lcd_text_(true),
       has_any_recordings_(false),
       is_solid_color_(false),
       solid_color_(SK_ColorTRANSPARENT),
@@ -181,18 +182,30 @@
 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,
     Picture::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;
+
   bool updated = false;
 
-  Region resize_invalidation;
+  Region synthetic_invalidation;
   gfx::Size old_tiling_size = GetSize();
   if (old_tiling_size != layer_size) {
     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 = visible_layer_rect;
   interest_rect.Inset(-pixel_record_distance_, -pixel_record_distance_);
@@ -356,11 +369,11 @@
                              exposed_top,
                              exposed_left_until - exposed_left,
                              exposed_bottom - exposed_top);
-      resize_invalidation.Union(left_rect);
-      resize_invalidation.Union(right_rect);
-      resize_invalidation.Union(top_rect);
-      resize_invalidation.Union(bottom_rect);
-      resize_invalidation.Union(exposed_rect);
+      synthetic_invalidation.Union(left_rect);
+      synthetic_invalidation.Union(right_rect);
+      synthetic_invalidation.Union(top_rect);
+      synthetic_invalidation.Union(bottom_rect);
+      synthetic_invalidation.Union(exposed_rect);
     }
     if (min_toss_y < tiling_.num_tiles_y()) {
       // The same thing occurs here as in the case above, but the invalidation
@@ -392,11 +405,11 @@
                              exposed_top,
                              exposed_right - exposed_left,
                              exposed_top_until - exposed_top);
-      resize_invalidation.Union(left_rect);
-      resize_invalidation.Union(right_rect);
-      resize_invalidation.Union(top_rect);
-      resize_invalidation.Union(bottom_rect);
-      resize_invalidation.Union(exposed_rect);
+      synthetic_invalidation.Union(left_rect);
+      synthetic_invalidation.Union(right_rect);
+      synthetic_invalidation.Union(top_rect);
+      synthetic_invalidation.Union(bottom_rect);
+      synthetic_invalidation.Union(exposed_rect);
     }
   }
 
@@ -458,7 +471,7 @@
     invalidation->Union(invalidation_expanded_to_full_tiles);
   }
 
-  invalidation->Union(resize_invalidation);
+  invalidation->Union(synthetic_invalidation);
 
   // Make a list of all invalid tiles; we will attempt to
   // cluster these into multiple invalidation regions.
diff --git a/cc/resources/picture_pile.h b/cc/resources/picture_pile.h
index e252e97..e1c1b46 100644
--- a/cc/resources/picture_pile.h
+++ b/cc/resources/picture_pile.h
@@ -25,6 +25,7 @@
   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,
@@ -94,6 +95,7 @@
   float min_contents_scale_;
   SkTileGridFactory::TileGridInfo tile_grid_info_;
   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_;
diff --git a/cc/resources/picture_pile_impl.cc b/cc/resources/picture_pile_impl.cc
index 7416538..2655d24 100644
--- a/cc/resources/picture_pile_impl.cc
+++ b/cc/resources/picture_pile_impl.cc
@@ -38,6 +38,7 @@
 PicturePileImpl::PicturePileImpl()
     : background_color_(SK_ColorTRANSPARENT),
       requires_clear_(true),
+      can_use_lcd_text_(false),
       is_solid_color_(false),
       solid_color_(SK_ColorTRANSPARENT),
       has_any_recordings_(false),
@@ -52,6 +53,7 @@
       tiling_(other->tiling_),
       background_color_(SK_ColorTRANSPARENT),
       requires_clear_(true),
+      can_use_lcd_text_(other->can_use_lcd_text_),
       is_solid_color_(other->is_solid_color_),
       solid_color_(other->solid_color_),
       recorded_viewport_(other->recorded_viewport_),
@@ -437,6 +439,10 @@
   }
 }
 
+bool PicturePileImpl::CanUseLCDText() const {
+  return 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 b4209e3..d7d0399 100644
--- a/cc/resources/picture_pile_impl.h
+++ b/cc/resources/picture_pile_impl.h
@@ -61,6 +61,7 @@
   bool IsSolidColor() const override;
   SkColor GetSolidColor() const override;
   bool HasRecordings() const override;
+  bool CanUseLCDText() const override;
 
   // Tracing functionality.
   void DidBeginTracing() override;
@@ -110,6 +111,7 @@
   TilingData tiling_;
   SkColor background_color_;
   bool requires_clear_;
+  bool can_use_lcd_text_;
   bool is_solid_color_;
   SkColor solid_color_;
   gfx::Rect recorded_viewport_;
diff --git a/cc/resources/picture_pile_unittest.cc b/cc/resources/picture_pile_unittest.cc
index 0a9a907..98ce3b1 100644
--- a/cc/resources/picture_pile_unittest.cc
+++ b/cc/resources/picture_pile_unittest.cc
@@ -39,9 +39,9 @@
                                    const gfx::Size& layer_size,
                                    const gfx::Rect& visible_layer_rect) {
     frame_number_++;
-    return pile_.UpdateAndExpandInvalidation(&client_, invalidation, layer_size,
-                                             visible_layer_rect, frame_number_,
-                                             Picture::RECORD_NORMALLY);
+    return pile_.UpdateAndExpandInvalidation(
+        &client_, invalidation, false, layer_size, visible_layer_rect,
+        frame_number_, Picture::RECORD_NORMALLY);
   }
 
   bool UpdateWholePile() {
diff --git a/cc/resources/raster_source.h b/cc/resources/raster_source.h
index 5f200db..3584436 100644
--- a/cc/resources/raster_source.h
+++ b/cc/resources/raster_source.h
@@ -93,6 +93,9 @@
   virtual void AsValueInto(base::debug::TracedValue* array) const = 0;
   virtual skia::RefPtr<SkPicture> GetFlattenedPicture() = 0;
 
+  // Return true if LCD anti-aliasing may be used when rastering text.
+  virtual bool CanUseLCDText() const = 0;
+
  protected:
   friend class base::RefCountedThreadSafe<RasterSource>;
 
diff --git a/cc/resources/raster_worker_pool.cc b/cc/resources/raster_worker_pool.cc
index ca26edd..4511f9d 100644
--- a/cc/resources/raster_worker_pool.cc
+++ b/cc/resources/raster_worker_pool.cc
@@ -228,28 +228,26 @@
   SkColorType buffer_color_type = ResourceFormatToSkColorType(format);
   bool needs_copy = buffer_color_type != info.colorType();
 
-  // TODO(danakj): Make a SkSurfaceProps with an SkPixelGeometry to enable or
-  // disable LCD text.
-  // TODO(danakj): Disable LCD text on Mac during layout tests:
-  // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/mac/FontPlatformDataMac.mm&l=55
-  // TODO(danakj): On Windows when LCD text is disabled, ask skia to draw LCD
-  // text offscreen and downsample it to AA text.
-  // https://cs.chromium.org#chromium/src/third_party/WebKit/Source/platform/fonts/win/FontPlatformDataWin.cpp&l=86
-  SkSurfaceProps* surface_props = nullptr;
+  // Use unknown pixel geometry to disable LCD text.
+  SkSurfaceProps surface_props(0, kUnknown_SkPixelGeometry);
+  if (raster_source->CanUseLCDText()) {
+    // LegacyFontHost will get LCD text and skia figures out what type to use.
+    surface_props = SkSurfaceProps(SkSurfaceProps::kLegacyFontHost_InitType);
+  }
 
   if (!stride)
     stride = info.minRowBytes();
 
   if (!needs_copy) {
     skia::RefPtr<SkSurface> surface = skia::AdoptRef(
-        SkSurface::NewRasterDirect(info, memory, stride, surface_props));
+        SkSurface::NewRasterDirect(info, memory, stride, &surface_props));
     skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
     raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
     return;
   }
 
   skia::RefPtr<SkSurface> surface =
-      skia::AdoptRef(SkSurface::NewRaster(info, surface_props));
+      skia::AdoptRef(SkSurface::NewRaster(info, &surface_props));
   skia::RefPtr<SkCanvas> canvas = skia::SharePtr(surface->getCanvas());
   raster_source->PlaybackToCanvas(canvas.get(), rect, scale);
 
diff --git a/cc/resources/recording_source.h b/cc/resources/recording_source.h
index 19eea72..173e1a0 100644
--- a/cc/resources/recording_source.h
+++ b/cc/resources/recording_source.h
@@ -28,6 +28,7 @@
   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,
diff --git a/cc/resources/resource_provider.cc b/cc/resources/resource_provider.cc
index 2518972..06bb5f0 100644
--- a/cc/resources/resource_provider.cc
+++ b/cc/resources/resource_provider.cc
@@ -1112,15 +1112,15 @@
 }
 
 SkSurface* ResourceProvider::ScopedWriteLockGr::GetSkSurface(
-    bool use_distance_field_text) {
+    bool use_distance_field_text,
+    bool can_use_lcd_text) {
   DCHECK(thread_checker_.CalledOnValidThread());
   DCHECK(resource_->locked_for_write);
 
-  // If the surface doesn't exist, or doesn't have the correct dff setting,
-  // recreate the surface within the resource.
-  if (!resource_->sk_surface ||
-      use_distance_field_text !=
-          resource_->sk_surface->props().isUseDistanceFieldFonts()) {
+  bool create_surface =
+      !resource_->sk_surface.get() ||
+      !SurfaceHasMatchingProperties(use_distance_field_text, can_use_lcd_text);
+  if (create_surface) {
     class GrContext* gr_context = resource_provider_->GrContext();
     // TODO(alokp): Implement TestContextProvider::GrContext().
     if (!gr_context)
@@ -1139,15 +1139,34 @@
         skia::AdoptRef(gr_context->wrapBackendTexture(desc));
     if (!gr_texture)
       return nullptr;
-    SkSurface::TextRenderMode text_render_mode =
-        use_distance_field_text ? SkSurface::kDistanceField_TextRenderMode
-                                : SkSurface::kStandard_TextRenderMode;
+    uint32_t flags = use_distance_field_text
+                         ? SkSurfaceProps::kUseDistanceFieldFonts_Flag
+                         : 0;
+    // Use unknown pixel geometry to disable LCD text.
+    SkSurfaceProps surface_props(flags, kUnknown_SkPixelGeometry);
+    if (can_use_lcd_text) {
+      // LegacyFontHost will get LCD text and skia figures out what type to use.
+      surface_props =
+          SkSurfaceProps(flags, SkSurfaceProps::kLegacyFontHost_InitType);
+    }
     resource_->sk_surface = skia::AdoptRef(SkSurface::NewRenderTargetDirect(
-        gr_texture->asRenderTarget(), text_render_mode));
+        gr_texture->asRenderTarget(), &surface_props));
   }
   return resource_->sk_surface.get();
 }
 
+bool ResourceProvider::ScopedWriteLockGr::SurfaceHasMatchingProperties(
+    bool use_distance_field_text,
+    bool can_use_lcd_text) const {
+  const SkSurface* surface = resource_->sk_surface.get();
+  bool surface_uses_distance_field_text =
+      surface->props().isUseDistanceFieldFonts();
+  bool surface_can_use_lcd_text =
+      surface->props().pixelGeometry() != kUnknown_SkPixelGeometry;
+  return use_distance_field_text == surface_uses_distance_field_text &&
+         can_use_lcd_text == surface_can_use_lcd_text;
+}
+
 ResourceProvider::SynchronousFence::SynchronousFence(
     gpu::gles2::GLES2Interface* gl)
     : gl_(gl), has_synchronized_(true) {
diff --git a/cc/resources/resource_provider.h b/cc/resources/resource_provider.h
index 40103f6..c2f349f 100644
--- a/cc/resources/resource_provider.h
+++ b/cc/resources/resource_provider.h
@@ -335,9 +335,13 @@
                       ResourceProvider::ResourceId resource_id);
     ~ScopedWriteLockGr();
 
-    SkSurface* GetSkSurface(bool use_distance_field_text);
+    SkSurface* GetSkSurface(bool use_distance_field_text,
+                            bool can_use_lcd_text);
 
    private:
+    bool SurfaceHasMatchingProperties(bool use_distance_field_text,
+                                      bool can_use_lcd_text) const;
+
     ResourceProvider* resource_provider_;
     ResourceProvider::Resource* resource_;
     base::ThreadChecker thread_checker_;
diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc
index fba3166..602374f 100644
--- a/cc/test/animation_test_common.cc
+++ b/cc/test/animation_test_common.cc
@@ -8,6 +8,7 @@
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/animation/layer_animation_controller.h"
 #include "cc/animation/transform_operations.h"
+#include "cc/base/time_util.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 
@@ -35,8 +36,10 @@
   if (!use_timing_function)
     func = EaseTimingFunction::Create();
   if (duration > 0.0)
-    curve->AddKeyframe(FloatKeyframe::Create(0.0, start_opacity, func.Pass()));
-  curve->AddKeyframe(FloatKeyframe::Create(duration, end_opacity, nullptr));
+    curve->AddKeyframe(
+        FloatKeyframe::Create(base::TimeDelta(), start_opacity, func.Pass()));
+  curve->AddKeyframe(FloatKeyframe::Create(
+      base::TimeDelta::FromSecondsD(duration), end_opacity, nullptr));
 
   int id = AnimationIdProvider::NextAnimationId();
 
@@ -60,11 +63,12 @@
       curve(KeyframedTransformAnimationCurve::Create());
 
   if (duration > 0.0) {
-    curve->AddKeyframe(
-        TransformKeyframe::Create(0.0, start_operations, nullptr));
+    curve->AddKeyframe(TransformKeyframe::Create(base::TimeDelta(),
+                                                 start_operations, nullptr));
   }
 
-  curve->AddKeyframe(TransformKeyframe::Create(duration, operations, nullptr));
+  curve->AddKeyframe(TransformKeyframe::Create(
+      base::TimeDelta::FromSecondsD(duration), operations, nullptr));
 
   int id = AnimationIdProvider::NextAnimationId();
 
@@ -106,12 +110,14 @@
     FilterOperations start_filters;
     start_filters.Append(
         FilterOperation::CreateBrightnessFilter(start_brightness));
-    curve->AddKeyframe(FilterKeyframe::Create(0.0, start_filters, nullptr));
+    curve->AddKeyframe(
+        FilterKeyframe::Create(base::TimeDelta(), start_filters, nullptr));
   }
 
   FilterOperations filters;
   filters.Append(FilterOperation::CreateBrightnessFilter(end_brightness));
-  curve->AddKeyframe(FilterKeyframe::Create(duration, filters, nullptr));
+  curve->AddKeyframe(FilterKeyframe::Create(
+      base::TimeDelta::FromSecondsD(duration), filters, nullptr));
 
   int id = AnimationIdProvider::NextAnimationId();
 
@@ -137,7 +143,7 @@
   return duration_;
 }
 
-float FakeFloatAnimationCurve::GetValue(double now) const {
+float FakeFloatAnimationCurve::GetValue(base::TimeDelta now) const {
   return 0.0f;
 }
 
@@ -155,7 +161,7 @@
   return duration_;
 }
 
-gfx::Transform FakeTransformTransition::GetValue(double time) const {
+gfx::Transform FakeTransformTransition::GetValue(base::TimeDelta time) const {
   return gfx::Transform();
 }
 
@@ -188,11 +194,11 @@
   return duration_;
 }
 
-float FakeFloatTransition::GetValue(double time) const {
-  time /= duration_.InSecondsF();
-  if (time >= 1.0)
-    time = 1.0;
-  return (1.0 - time) * from_ + time * to_;
+float FakeFloatTransition::GetValue(base::TimeDelta time) const {
+  double progress = TimeUtil::Divide(time, duration_);
+  if (progress >= 1.0)
+    progress = 1.0;
+  return (1.0 - progress) * from_ + progress * to_;
 }
 
 FakeLayerAnimationValueObserver::FakeLayerAnimationValueObserver()
diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h
index a69f0c9..2c41518 100644
--- a/cc/test/animation_test_common.h
+++ b/cc/test/animation_test_common.h
@@ -27,7 +27,7 @@
   ~FakeFloatAnimationCurve() override;
 
   base::TimeDelta Duration() const override;
-  float GetValue(double now) const override;
+  float GetValue(base::TimeDelta now) const override;
   scoped_ptr<AnimationCurve> Clone() const override;
 
  private:
@@ -40,7 +40,7 @@
   ~FakeTransformTransition() override;
 
   base::TimeDelta Duration() const override;
-  gfx::Transform GetValue(double time) const override;
+  gfx::Transform GetValue(base::TimeDelta time) const override;
   bool AnimatedBoundsForBox(const gfx::BoxF& box,
                             gfx::BoxF* bounds) const override;
   bool AffectsScale() const override;
@@ -60,7 +60,7 @@
   ~FakeFloatTransition() override;
 
   base::TimeDelta Duration() const override;
-  float GetValue(double time) const override;
+  float GetValue(base::TimeDelta time) const override;
 
   scoped_ptr<AnimationCurve> Clone() const override;
 
diff --git a/cc/test/fake_content_layer_client.h b/cc/test/fake_content_layer_client.h
index 7a7cc44..141bc97 100644
--- a/cc/test/fake_content_layer_client.h
+++ b/cc/test/fake_content_layer_client.h
@@ -31,7 +31,6 @@
       SkCanvas* canvas,
       const gfx::Rect& rect,
       ContentLayerClient::GraphicsContextStatus gc_status) override;
-  void DidChangeLayerCanUseLCDText() override {}
   bool FillsBoundsCompletely() const override;
 
   void set_fill_with_nonsolid_color(bool nonsolid) {
diff --git a/cc/test/fake_picture_layer.cc b/cc/test/fake_picture_layer.cc
index 1a19bc7..a475667 100644
--- a/cc/test/fake_picture_layer.cc
+++ b/cc/test/fake_picture_layer.cc
@@ -13,7 +13,8 @@
       update_count_(0),
       push_properties_count_(0),
       output_surface_created_count_(0),
-      always_update_resources_(false) {
+      always_update_resources_(false),
+      disable_lcd_text_(false) {
   SetBounds(gfx::Size(1, 1));
   SetIsDrawable(true);
 }
@@ -38,6 +39,8 @@
 
 bool FakePictureLayer::Update(ResourceUpdateQueue* queue,
                               const OcclusionTracker<Layer>* occlusion) {
+  if (disable_lcd_text_)
+    draw_properties().can_use_lcd_text = false;
   bool updated = PictureLayer::Update(queue, occlusion);
   update_count_++;
   return updated || always_update_resources_;
diff --git a/cc/test/fake_picture_layer.h b/cc/test/fake_picture_layer.h
index f42a14d..d101155 100644
--- a/cc/test/fake_picture_layer.h
+++ b/cc/test/fake_picture_layer.h
@@ -35,6 +35,8 @@
     always_update_resources_ = always_update_resources;
   }
 
+  void disable_lcd_text() { disable_lcd_text_ = true; }
+
   bool Update(ResourceUpdateQueue* queue,
               const OcclusionTracker<Layer>* occlusion) override;
 
@@ -55,6 +57,7 @@
   size_t push_properties_count_;
   size_t output_surface_created_count_;
   bool always_update_resources_;
+  bool disable_lcd_text_;
 };
 
 }  // namespace cc
diff --git a/cc/test/geometry_test_utils.h b/cc/test/geometry_test_utils.h
index d8829e0..b743f58 100644
--- a/cc/test/geometry_test_utils.h
+++ b/cc/test/geometry_test_utils.h
@@ -68,6 +68,12 @@
   EXPECT_FLOAT_EQ((expected).y(), (actual).y()); \
 } while (false)
 
+#define EXPECT_VECTOR2DF_NEAR(expected, actual, abs_error)  \
+  do {                                                      \
+    EXPECT_NEAR((expected).x(), (actual).x(), (abs_error)); \
+    EXPECT_NEAR((expected).y(), (actual).y(), (abs_error)); \
+  } while (false)
+
 #define EXPECT_FLOAT_ARRAY_EQ(expected, actual, count) \
 do { \
   for (int i = 0; i < count; i++) { \
diff --git a/cc/test/layer_tree_host_common_test.cc b/cc/test/layer_tree_host_common_test.cc
index 33e0caf..8441657 100644
--- a/cc/test/layer_tree_host_common_test.cc
+++ b/cc/test/layer_tree_host_common_test.cc
@@ -59,7 +59,8 @@
     float device_scale_factor,
     float page_scale_factor,
     Layer* page_scale_application_layer,
-    bool can_use_lcd_text) {
+    bool can_use_lcd_text,
+    bool layers_always_allowed_lcd_text) {
   EXPECT_TRUE(page_scale_application_layer || (page_scale_factor == 1.f));
   gfx::Transform identity_matrix;
   gfx::Size device_viewport_size =
@@ -77,6 +78,7 @@
   inputs.page_scale_factor = page_scale_factor;
   inputs.page_scale_application_layer = page_scale_application_layer;
   inputs.can_use_lcd_text = can_use_lcd_text;
+  inputs.layers_always_allowed_lcd_text = layers_always_allowed_lcd_text;
   inputs.can_adjust_raster_scales = true;
   LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 }
@@ -86,7 +88,8 @@
     float device_scale_factor,
     float page_scale_factor,
     LayerImpl* page_scale_application_layer,
-    bool can_use_lcd_text) {
+    bool can_use_lcd_text,
+    bool layers_always_allowed_lcd_text) {
   gfx::Transform identity_matrix;
   gfx::Size device_viewport_size =
       gfx::Size(root_layer->bounds().width() * device_scale_factor,
@@ -103,6 +106,7 @@
   inputs.page_scale_factor = page_scale_factor;
   inputs.page_scale_application_layer = page_scale_application_layer;
   inputs.can_use_lcd_text = can_use_lcd_text;
+  inputs.layers_always_allowed_lcd_text = layers_always_allowed_lcd_text;
   inputs.can_adjust_raster_scales = true;
 
   ++render_surface_layer_list_count_;
diff --git a/cc/test/layer_tree_host_common_test.h b/cc/test/layer_tree_host_common_test.h
index 38b57d4..456183f 100644
--- a/cc/test/layer_tree_host_common_test.h
+++ b/cc/test/layer_tree_host_common_test.h
@@ -68,30 +68,29 @@
                                       float device_scale_factor,
                                       float page_scale_factor,
                                       Layer* page_scale_application_layer,
-                                      bool can_use_lcd_text);
+                                      bool can_use_lcd_text,
+                                      bool layers_always_allowed_lcd_text);
 
   void ExecuteCalculateDrawProperties(LayerImpl* root_layer,
                                       float device_scale_factor,
                                       float page_scale_factor,
                                       LayerImpl* page_scale_application_layer,
-                                      bool can_use_lcd_text);
+                                      bool can_use_lcd_text,
+                                      bool layers_always_allowed_lcd_text);
 
   template <class LayerType>
   void ExecuteCalculateDrawProperties(LayerType* root_layer) {
     LayerType* page_scale_application_layer = NULL;
-    ExecuteCalculateDrawProperties(
-        root_layer, 1.f, 1.f, page_scale_application_layer, false);
+    ExecuteCalculateDrawProperties(root_layer, 1.f, 1.f,
+                                   page_scale_application_layer, false, false);
   }
 
   template <class LayerType>
   void ExecuteCalculateDrawProperties(LayerType* root_layer,
                                       float device_scale_factor) {
     LayerType* page_scale_application_layer = NULL;
-    ExecuteCalculateDrawProperties(root_layer,
-                                   device_scale_factor,
-                                   1.f,
-                                   page_scale_application_layer,
-                                   false);
+    ExecuteCalculateDrawProperties(root_layer, device_scale_factor, 1.f,
+                                   page_scale_application_layer, false, false);
   }
 
   template <class LayerType>
@@ -99,11 +98,9 @@
                                       float device_scale_factor,
                                       float page_scale_factor,
                                       LayerType* page_scale_application_layer) {
-    ExecuteCalculateDrawProperties(root_layer,
-                                   device_scale_factor,
+    ExecuteCalculateDrawProperties(root_layer, device_scale_factor,
                                    page_scale_factor,
-                                   page_scale_application_layer,
-                                   false);
+                                   page_scale_application_layer, false, false);
   }
 
   RenderSurfaceLayerList* render_surface_layer_list() const {
diff --git a/cc/test/layer_tree_pixel_resource_test.cc b/cc/test/layer_tree_pixel_resource_test.cc
index fa2bbb8..4542d2a 100644
--- a/cc/test/layer_tree_pixel_resource_test.cc
+++ b/cc/test/layer_tree_pixel_resource_test.cc
@@ -25,14 +25,14 @@
     case GL_GPU_RASTER_2D_DRAW:
     case GL_ZERO_COPY_2D_DRAW:
     case GL_ZERO_COPY_RECT_DRAW:
+    case GL_ONE_COPY_2D_STAGING_2D_DRAW:
     case GL_ASYNC_UPLOAD_2D_DRAW:
       return true;
     case GL_ZERO_COPY_EXTERNAL_DRAW:
-    case GL_ONE_COPY_2D_STAGING_2D_DRAW:
     case GL_ONE_COPY_RECT_STAGING_2D_DRAW:
     case GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW:
       // These should all be enabled in practice.
-      // TODO(reveman): one copy not supported in unit tests yet.
+      // TODO(reveman): one copy with rect not supported in unit tests yet.
       // TODO(enne): look into getting texture external oes enabled.
       return false;
   }
diff --git a/cc/test/layer_tree_pixel_test.cc b/cc/test/layer_tree_pixel_test.cc
index ef0ba22..23bfcf2 100644
--- a/cc/test/layer_tree_pixel_test.cc
+++ b/cc/test/layer_tree_pixel_test.cc
@@ -107,7 +107,7 @@
   EXPECT_TRUE(PathService::Get(CCPaths::DIR_TEST_DATA, &test_data_dir));
   base::FilePath ref_file_path = test_data_dir.Append(ref_file_);
 
-  CommandLine* cmd = CommandLine::ForCurrentProcess();
+  base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
   if (cmd->HasSwitch(switches::kCCRebaselinePixeltests))
     EXPECT_TRUE(WritePNGFile(*result_bitmap_, ref_file_path, true));
   EXPECT_TRUE(MatchesPNGFile(*result_bitmap_,
diff --git a/cc/test/layer_tree_test.cc b/cc/test/layer_tree_test.cc
index 89cc554..a22c7af 100644
--- a/cc/test/layer_tree_test.cc
+++ b/cc/test/layer_tree_test.cc
@@ -490,7 +490,7 @@
 
   // Tests should timeout quickly unless --cc-layer-tree-test-no-timeout was
   // specified (for running in a debugger).
-  CommandLine* command_line = CommandLine::ForCurrentProcess();
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(switches::kCCLayerTreeTestNoTimeout))
     timeout_seconds_ = 5;
 }
@@ -524,10 +524,8 @@
     Layer* layer_to_receive_animation) {
   main_task_runner_->PostTask(
       FROM_HERE,
-      base::Bind(&LayerTreeTest::DispatchAddAnimation,
-                 main_thread_weak_ptr_,
-                 base::Unretained(layer_to_receive_animation),
-                 0.000001));
+      base::Bind(&LayerTreeTest::DispatchAddAnimation, main_thread_weak_ptr_,
+                 base::Unretained(layer_to_receive_animation), 0.000004));
 }
 
 void LayerTreeTest::PostAddInstantAnimationToMainThread(
diff --git a/cc/test/pixel_test.cc b/cc/test/pixel_test.cc
index 3a9b45b..28c0dc0 100644
--- a/cc/test/pixel_test.cc
+++ b/cc/test/pixel_test.cc
@@ -114,7 +114,7 @@
   if (!result_bitmap_)
     return false;
 
-  CommandLine* cmd = CommandLine::ForCurrentProcess();
+  base::CommandLine* cmd = base::CommandLine::ForCurrentProcess();
   if (cmd->HasSwitch(switches::kCCRebaselinePixeltests))
     return WritePNGFile(*result_bitmap_, test_data_dir.Append(ref_file), true);
 
diff --git a/cc/test/solid_color_content_layer_client.h b/cc/test/solid_color_content_layer_client.h
index a851b72..7a962cf 100644
--- a/cc/test/solid_color_content_layer_client.h
+++ b/cc/test/solid_color_content_layer_client.h
@@ -16,7 +16,6 @@
   explicit SolidColorContentLayerClient(SkColor color) : color_(color) {}
 
   // ContentLayerClient implementation.
-  void DidChangeLayerCanUseLCDText() override {}
   void PaintContents(
       SkCanvas* canvas,
       const gfx::Rect& rect,
diff --git a/cc/test/test_in_process_context_provider.cc b/cc/test/test_in_process_context_provider.cc
index 34b0493..847bc92 100644
--- a/cc/test/test_in_process_context_provider.cc
+++ b/cc/test/test_in_process_context_provider.cc
@@ -129,6 +129,7 @@
   ContextProvider::Capabilities capabilities;
   capabilities.gpu.image = true;
   capabilities.gpu.texture_rectangle = true;
+  capabilities.gpu.sync_query = true;
 
   return capabilities;
 }
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index f85d4e7..808bf21 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -845,17 +845,12 @@
     // Change this if this information is required.
     int render_surface_layer_list_id = 0;
     LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
-        root_layer,
-        device_viewport_size(),
-        gfx::Transform(),
-        device_scale_factor_,
-        page_scale_factor_,
-        page_scale_layer,
-        GetRendererCapabilities().max_texture_size,
-        settings_.can_use_lcd_text,
+        root_layer, device_viewport_size(), gfx::Transform(),
+        device_scale_factor_, page_scale_factor_, page_scale_layer,
+        GetRendererCapabilities().max_texture_size, settings_.can_use_lcd_text,
+        settings_.layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
-        settings_.layer_transforms_should_scale_layer_contents,
-        &update_list,
+        settings_.layer_transforms_should_scale_layer_contents, &update_list,
         render_surface_layer_list_id);
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc
index 0ff6608..6863850 100644
--- a/cc/trees/layer_tree_host_common.cc
+++ b/cc/trees/layer_tree_host_common.cc
@@ -1269,6 +1269,7 @@
   const LayerType* page_scale_application_layer;
   bool can_adjust_raster_scales;
   bool can_render_to_separate_surface;
+  bool layers_always_allowed_lcd_text;
 };
 
 template<typename LayerType>
@@ -1791,13 +1792,19 @@
   // causes jank.
   bool adjust_text_aa =
       !animating_opacity_to_screen && !animating_transform_to_screen;
-  // To avoid color fringing, LCD text should only be used on opaque layers with
-  // just integral translation.
-  bool layer_can_use_lcd_text =
-      data_from_ancestor.subtree_can_use_lcd_text &&
-      accumulated_draw_opacity == 1.f &&
-      layer_draw_properties.target_space_transform.
-          IsIdentityOrIntegerTranslation();
+  bool layer_can_use_lcd_text = true;
+  bool subtree_can_use_lcd_text = true;
+  if (!globals.layers_always_allowed_lcd_text) {
+    // To avoid color fringing, LCD text should only be used on opaque layers
+    // with just integral translation.
+    subtree_can_use_lcd_text = data_from_ancestor.subtree_can_use_lcd_text &&
+                               accumulated_draw_opacity == 1.f &&
+                               layer_draw_properties.target_space_transform
+                                   .IsIdentityOrIntegerTranslation();
+    // Also disable LCD text locally for non-opaque content.
+    layer_can_use_lcd_text = subtree_can_use_lcd_text &&
+                             layer->contents_opaque();
+  }
 
   gfx::Rect content_rect(layer->content_bounds());
 
@@ -1995,7 +2002,7 @@
     // If the new render surface is drawn translucent or with a non-integral
     // translation then the subtree that gets drawn on this render surface
     // cannot use LCD text.
-    data_for_children.subtree_can_use_lcd_text = layer_can_use_lcd_text;
+    data_for_children.subtree_can_use_lcd_text = subtree_can_use_lcd_text;
 
     render_surface_layer_list->push_back(layer);
   } else {
@@ -2374,6 +2381,8 @@
   globals->can_render_to_separate_surface =
       inputs.can_render_to_separate_surface;
   globals->can_adjust_raster_scales = inputs.can_adjust_raster_scales;
+  globals->layers_always_allowed_lcd_text =
+      inputs.layers_always_allowed_lcd_text;
 
   data_for_recursion->parent_matrix = scaled_device_transform;
   data_for_recursion->full_hierarchy_matrix = identity_matrix;
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h
index 089fe29..349b341 100644
--- a/cc/trees/layer_tree_host_common.h
+++ b/cc/trees/layer_tree_host_common.h
@@ -40,6 +40,7 @@
                         const LayerType* page_scale_application_layer,
                         int max_texture_size,
                         bool can_use_lcd_text,
+                        bool layers_always_allowed_lcd_text,
                         bool can_render_to_separate_surface,
                         bool can_adjust_raster_scales,
                         RenderSurfaceLayerListType* render_surface_layer_list,
@@ -52,6 +53,7 @@
           page_scale_application_layer(page_scale_application_layer),
           max_texture_size(max_texture_size),
           can_use_lcd_text(can_use_lcd_text),
+          layers_always_allowed_lcd_text(layers_always_allowed_lcd_text),
           can_render_to_separate_surface(can_render_to_separate_surface),
           can_adjust_raster_scales(can_adjust_raster_scales),
           render_surface_layer_list(render_surface_layer_list),
@@ -66,6 +68,7 @@
     const LayerType* page_scale_application_layer;
     int max_texture_size;
     bool can_use_lcd_text;
+    bool layers_always_allowed_lcd_text;
     bool can_render_to_separate_surface;
     bool can_adjust_raster_scales;
     RenderSurfaceLayerListType* render_surface_layer_list;
@@ -222,6 +225,7 @@
           NULL,
           std::numeric_limits<int>::max() / 2,
           false,
+          false,
           true,
           false,
           render_surface_layer_list,
@@ -246,6 +250,7 @@
           NULL,
           std::numeric_limits<int>::max() / 2,
           false,
+          false,
           true,
           false,
           render_surface_layer_list,
diff --git a/cc/trees/layer_tree_host_common_perftest.cc b/cc/trees/layer_tree_host_common_perftest.cc
index 12e7a5e..39bcbe6 100644
--- a/cc/trees/layer_tree_host_common_perftest.cc
+++ b/cc/trees/layer_tree_host_common_perftest.cc
@@ -93,19 +93,17 @@
       RenderSurfaceLayerList update_list;
       LayerTreeHostCommon::CalcDrawPropsMainInputs inputs(
           layer_tree_host()->root_layer(),
-          layer_tree_host()->device_viewport_size(),
-          gfx::Transform(),
+          layer_tree_host()->device_viewport_size(), gfx::Transform(),
           layer_tree_host()->device_scale_factor(),
           layer_tree_host()->page_scale_factor(),
-          layer_tree_host()->page_scale_layer(),
-          max_texture_size,
+          layer_tree_host()->page_scale_layer(), max_texture_size,
           layer_tree_host()->settings().can_use_lcd_text,
+          layer_tree_host()->settings().layers_always_allowed_lcd_text,
           can_render_to_separate_surface,
           layer_tree_host()
               ->settings()
               .layer_transforms_should_scale_layer_contents,
-          &update_list,
-          0);
+          &update_list, 0);
       LayerTreeHostCommon::CalculateDrawProperties(&inputs);
 
       timer_.NextLap();
@@ -147,18 +145,15 @@
                                 LayerTreeHostImpl* host_impl) {
     LayerImplList update_list;
     LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
-        active_tree->root_layer(),
-        active_tree->DrawViewportSize(),
-        host_impl->DrawTransform(),
-        active_tree->device_scale_factor(),
+        active_tree->root_layer(), active_tree->DrawViewportSize(),
+        host_impl->DrawTransform(), active_tree->device_scale_factor(),
         active_tree->total_page_scale_factor(),
-        active_tree->InnerViewportContainerLayer(),
-        max_texture_size,
+        active_tree->InnerViewportContainerLayer(), max_texture_size,
         host_impl->settings().can_use_lcd_text,
+        host_impl->settings().layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
         host_impl->settings().layer_transforms_should_scale_layer_contents,
-        &update_list,
-        0);
+        &update_list, 0);
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
   }
 };
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc
index b40f66d..7a282c1 100644
--- a/cc/trees/layer_tree_host_common_unittest.cc
+++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -59,7 +59,6 @@
       SkCanvas* canvas,
       const gfx::Rect& clip,
       ContentLayerClient::GraphicsContextStatus gc_status) override {}
-  void DidChangeLayerCanUseLCDText() override {}
   bool FillsBoundsCompletely() const override { return false; }
 };
 
@@ -5644,13 +5643,14 @@
   ASSERT_EQ(2u, root->render_surface()->layer_list().size());
 }
 
-typedef std::tr1::tuple<bool, bool> LCDTextTestParam;
+using LCDTextTestParam = std::tr1::tuple<bool, bool, bool>;
 class LCDTextTest
     : public LayerTreeHostCommonTestBase,
       public testing::TestWithParam<LCDTextTestParam> {
  protected:
   virtual void SetUp() {
     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();
@@ -5658,6 +5658,10 @@
     child_->AddChild(grand_child_.get());
     root_->AddChild(child_.get());
 
+    root_->SetContentsOpaque(true);
+    child_->SetContentsOpaque(true);
+    grand_child_->SetContentsOpaque(true);
+
     gfx::Transform identity_matrix;
     SetLayerPropertiesForTesting(root_.get(),
                                  identity_matrix,
@@ -5681,13 +5685,14 @@
                                  true,
                                  false);
 
-    child_->SetForceRenderSurface(std::tr1::get<1>(GetParam()));
+    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_;
@@ -5695,108 +5700,131 @@
 };
 
 TEST_P(LCDTextTest, CanUseLCDText) {
+  bool expect_lcd_text = can_use_lcd_text_ || layers_always_allowed_lcd_text_;
+  bool expect_not_lcd_text = layers_always_allowed_lcd_text_;
+
   // Case 1: Identity transform.
   gfx::Transform identity_matrix;
-  ExecuteCalculateDrawProperties(
-      root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
 
   // Case 2: Integral translation.
   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_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
 
   // Case 3: Non-integral translation.
   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_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_FALSE(child_->can_use_lcd_text());
-  EXPECT_FALSE(grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
 
   // Case 4: Rotation.
   gfx::Transform rotation;
   rotation.Rotate(10.0);
   child_->SetTransform(rotation);
-  ExecuteCalculateDrawProperties(
-      root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_FALSE(child_->can_use_lcd_text());
-  EXPECT_FALSE(grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
 
   // Case 5: Scale.
   gfx::Transform scale;
   scale.Scale(2.0, 2.0);
   child_->SetTransform(scale);
-  ExecuteCalculateDrawProperties(
-      root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_FALSE(child_->can_use_lcd_text());
-  EXPECT_FALSE(grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
 
   // Case 6: Skew.
   gfx::Transform skew;
   skew.SkewX(10.0);
   child_->SetTransform(skew);
-  ExecuteCalculateDrawProperties(
-      root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_FALSE(child_->can_use_lcd_text());
-  EXPECT_FALSE(grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
 
   // Case 7: Translucent.
   child_->SetTransform(identity_matrix);
   child_->SetOpacity(0.5f);
-  ExecuteCalculateDrawProperties(
-      root_.get(), 1.f, 1.f, NULL, can_use_lcd_text_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_FALSE(child_->can_use_lcd_text());
-  EXPECT_FALSE(grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_not_lcd_text, grand_child_->can_use_lcd_text());
 
   // 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_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
+
+  // Case 9: Non-opaque content.
+  child_->SetContentsOpaque(false);
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
+
+  // Case 10: Sanity check: restore content opaqueness.
+  child_->SetContentsOpaque(true);
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
 }
 
 TEST_P(LCDTextTest, CanUseLCDTextWithAnimation) {
+  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_);
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+  ExecuteCalculateDrawProperties(root_.get(), 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());
+  EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
 
   // Add opacity animation.
   child_->SetOpacity(0.9f);
   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_.get(), 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.
-  EXPECT_EQ(can_use_lcd_text_, root_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, child_->can_use_lcd_text());
-  EXPECT_EQ(can_use_lcd_text_, grand_child_->can_use_lcd_text());
+  EXPECT_EQ(expect_lcd_text, root_->can_use_lcd_text());
+  EXPECT_EQ(expect_lcd_text, child_->can_use_lcd_text());
+  EXPECT_EQ(expect_lcd_text, grand_child_->can_use_lcd_text());
 }
 
 INSTANTIATE_TEST_CASE_P(LayerTreeHostCommonTest,
                         LCDTextTest,
-                        testing::Combine(testing::Bool(), testing::Bool()));
+                        testing::Combine(testing::Bool(),
+                                         testing::Bool(),
+                                         testing::Bool()));
 
 TEST_F(LayerTreeHostCommonTest, SubtreeHidden_SingleLayer) {
   FakeImplProxy proxy;
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index ffe2ddb..bb1be98 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -2567,7 +2567,18 @@
 
   bool consume_by_top_controls = ShouldTopControlsConsumeScroll(scroll_delta);
 
-  for (LayerImpl* layer_impl = CurrentlyScrollingLayer();
+  // There's an edge case where the outer viewport isn't scrollable when the
+  // scroll starts, however, as the top controls show the outer viewport becomes
+  // scrollable. Therefore, always try scrolling the outer viewport before the
+  // inner.
+  // TODO(bokan): Move the top controls logic out of the loop since the scroll
+  // that causes the outer viewport to become scrollable will still be applied
+  // to the inner viewport.
+  LayerImpl* start_layer = CurrentlyScrollingLayer();
+  if (start_layer == InnerViewportScrollLayer() && OuterViewportScrollLayer())
+      start_layer = OuterViewportScrollLayer();
+
+  for (LayerImpl* layer_impl = start_layer;
        layer_impl;
        layer_impl = layer_impl->parent()) {
     if (!layer_impl->scrollable())
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 0b9d976..51377d2 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -2319,6 +2319,8 @@
       const gfx::Size& outer_viewport_size,
       const gfx::Size& scroll_layer_size) {
     CreateHostImpl(settings_, CreateOutputSurface());
+    host_impl_->SetTopControlsLayoutHeight(
+        settings_.top_controls_height);
 
     scoped_ptr<LayerImpl> root =
         LayerImpl::Create(host_impl_->active_tree(), 1);
@@ -2364,8 +2366,6 @@
         outer_viewport_scroll_layer_id);
 
     host_impl_->SetViewportSize(inner_viewport_size);
-    host_impl_->SetTopControlsLayoutHeight(
-        settings_.top_controls_height);
     LayerImpl* root_clip_ptr = host_impl_->active_tree()->root_layer();
     EXPECT_EQ(inner_viewport_size, root_clip_ptr->bounds());
   }
@@ -2402,6 +2402,81 @@
             inner_viewport_scroll_layer->FixedContainerSizeDelta());
 }
 
+// In this test, the outer viewport is initially unscrollable. We test that a
+// scroll initiated on the inner viewport, causing the top controls to show and
+// thus making the outer viewport scrollable, still scrolls the outer viewport.
+TEST_F(LayerTreeHostImplTopControlsTest,
+    TopControlsOuterViewportBecomesScrollable) {
+  SetupTopControlsAndScrollLayerWithVirtualViewport(
+      gfx::Size(10, 50), gfx::Size(10, 50), gfx::Size(10, 100));
+  DrawFrame();
+
+  LayerImpl *inner_scroll =
+      host_impl_->active_tree()->InnerViewportScrollLayer();
+  LayerImpl *inner_container =
+      host_impl_->active_tree()->InnerViewportContainerLayer();
+  LayerImpl *outer_scroll =
+      host_impl_->active_tree()->OuterViewportScrollLayer();
+  LayerImpl *outer_container =
+      host_impl_->active_tree()->OuterViewportContainerLayer();
+
+  // Need SetDrawsContent so ScrollBegin's hit test finds an actual layer.
+  outer_scroll->SetDrawsContent(true);
+  host_impl_->active_tree()->SetPageScaleFactorAndLimits(2.f, 1.f, 2.f);
+
+  EXPECT_EQ(InputHandler::ScrollStarted,
+            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.
+  // The viewport layers should be resized back to their full sizes.
+  EXPECT_EQ(0.f,
+      host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(0.f, inner_scroll->TotalScrollOffset().y());
+  EXPECT_EQ(100.f, inner_container->BoundsForScrolling().height());
+  EXPECT_EQ(100.f, outer_container->BoundsForScrolling().height());
+
+  // The inner viewport should be scrollable by 50px * page_scale.
+  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, 100.f));
+  EXPECT_EQ(50.f, inner_scroll->TotalScrollOffset().y());
+  EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y());
+  EXPECT_EQ(gfx::ScrollOffset(), outer_scroll->MaxScrollOffset());
+
+  host_impl_->ScrollEnd();
+
+  EXPECT_EQ(InputHandler::ScrollStarted,
+            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));
+
+  // The entire scroll delta should have been used to show the top controls.
+  // The outer viewport should be resized to accomodate and scrolled to the
+  // bottom of the document to keep the viewport in place.
+  EXPECT_EQ(50.f,
+      host_impl_->active_tree()->total_top_controls_content_offset());
+  EXPECT_EQ(50.f, outer_container->BoundsForScrolling().height());
+  EXPECT_EQ(50.f, inner_container->BoundsForScrolling().height());
+  EXPECT_EQ(25.f, outer_scroll->TotalScrollOffset().y());
+  EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y());
+
+  // Now when we continue scrolling, make sure the outer viewport gets scrolled
+  // since it wasn't scrollable when the scroll began.
+  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -20.f));
+  EXPECT_EQ(15.f, outer_scroll->TotalScrollOffset().y());
+  EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y());
+
+  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -30.f));
+  EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y());
+  EXPECT_EQ(25.f, inner_scroll->TotalScrollOffset().y());
+
+  host_impl_->ScrollBy(gfx::Point(), gfx::Vector2dF(0.f, -50.f));
+  host_impl_->ScrollEnd();
+
+  EXPECT_EQ(0.f, outer_scroll->TotalScrollOffset().y());
+  EXPECT_EQ(0.f, inner_scroll->TotalScrollOffset().y());
+}
+
 // Test that the fixed position container delta is appropriately adjusted
 // by the top controls showing/hiding and page scale doesn't affect it.
 TEST_F(LayerTreeHostImplTopControlsTest, FixedContainerDelta) {
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index f4f174c..4d0717d 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -24,8 +24,6 @@
   explicit MaskContentLayerClient(const gfx::Size& bounds) : bounds_(bounds) {}
   ~MaskContentLayerClient() override {}
 
-  void DidChangeLayerCanUseLCDText() override {}
-
   bool FillsBoundsCompletely() const override { return false; }
 
   void PaintContents(
diff --git a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
index d703e22..e7dd149 100644
--- a/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
+++ b/cc/trees/layer_tree_host_pixeltest_on_demand_raster.cc
@@ -59,8 +59,6 @@
   explicit BlueYellowLayerClient(gfx::Rect layer_rect)
       : layer_rect_(layer_rect) {}
 
-  void DidChangeLayerCanUseLCDText() override {}
-
   bool FillsBoundsCompletely() const override { return false; }
 
   void PaintContents(
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index e39a76d..72a5b45 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -1112,7 +1112,6 @@
     if (test_layer_)
       test_layer_->SetOpacity(0.f);
   }
-  void DidChangeLayerCanUseLCDText() override {}
   bool FillsBoundsCompletely() const override { return false; }
 
  private:
@@ -2306,46 +2305,42 @@
 SINGLE_AND_MULTI_THREAD_NOIMPL_TEST_F(
     LayerTreeHostTestShutdownWithOnlySomeResourcesEvicted);
 
-class LayerTreeHostTestLCDNotification : public LayerTreeHostTest {
+class LayerTreeHostTestLCDChange : public LayerTreeHostTest {
  public:
-  class NotificationClient : public ContentLayerClient {
+  class PaintClient : public FakeContentLayerClient {
    public:
-    NotificationClient()
-        : layer_(0), paint_count_(0), lcd_notification_count_(0) {}
+    PaintClient() : paint_count_(0) {}
 
-    void set_layer(Layer* layer) { layer_ = layer; }
     int paint_count() const { return paint_count_; }
-    int lcd_notification_count() const { return lcd_notification_count_; }
 
     void PaintContents(
         SkCanvas* canvas,
         const gfx::Rect& clip,
         ContentLayerClient::GraphicsContextStatus gc_status) override {
+      FakeContentLayerClient::PaintContents(canvas, clip, gc_status);
       ++paint_count_;
     }
-    void DidChangeLayerCanUseLCDText() override {
-      ++lcd_notification_count_;
-      layer_->SetNeedsDisplay();
-    }
+
     bool FillsBoundsCompletely() const override { return false; }
 
    private:
-    Layer* layer_;
     int paint_count_;
-    int lcd_notification_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_);
+    client_.set_fill_with_nonsolid_color(true);
     root_layer->SetIsDrawable(true);
-    root_layer->SetBounds(gfx::Size(1, 1));
+    root_layer->SetBounds(gfx::Size(10, 10));
+    root_layer->SetContentsOpaque(true);
 
     layer_tree_host()->SetRootLayer(root_layer);
-    client_.set_layer(root_layer.get());
 
     // The expecations are based on the assumption that the default
     // LCD settings are:
@@ -2356,49 +2351,76 @@
   }
 
   void BeginTest() override { PostSetNeedsCommitToMainThread(); }
-  void AfterTest() override {}
 
-  void DidCommit() override {
+  void DidCommitAndDrawFrame() override {
     switch (layer_tree_host()->source_frame_number()) {
       case 1:
-        // The first update consists of one LCD notification and one paint.
-        EXPECT_EQ(1, client_.lcd_notification_count());
+        // 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 notification
-        // or paint on the second update.
-        EXPECT_EQ(1, client_.lcd_notification_count());
+        // 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 notification.
+        // Change layer opacity that should trigger lcd change.
         layer_tree_host()->root_layer()->SetOpacity(.5f);
-        // No need to request a commit - setting opacity will do it.
         break;
-      default:
-        // Verify that there is no extra commit due to layer invalidation.
-        EXPECT_EQ(3, layer_tree_host()->source_frame_number());
-        // LCD notification count should have incremented due to
-        // change in layer opacity.
-        EXPECT_EQ(2, client_.lcd_notification_count());
-        // Paint count should be incremented due to invalidation.
-        EXPECT_EQ(2, client_.paint_count());
+      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;
     }
   }
 
+  void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
+                                      const Tile* tile) override {
+    ++num_tiles_rastered_;
+  }
+
+  void DrawLayersOnThread(LayerTreeHostImpl* host_impl) override {
+    switch (host_impl->active_tree()->source_frame_number()) {
+      case 0:
+        // The first draw.
+        EXPECT_EQ(1, num_tiles_rastered_);
+        break;
+      case 1:
+        // Nothing changed on the layer.
+        EXPECT_EQ(1, num_tiles_rastered_);
+        break;
+      case 2:
+        // LCD text was disabled, it should be re-rastered with LCD text off.
+        EXPECT_EQ(2, num_tiles_rastered_);
+        break;
+      case 3:
+        // LCD text was enabled but it's sticky and stays off.
+        EXPECT_EQ(2, num_tiles_rastered_);
+        break;
+    }
+  }
+
+  void AfterTest() override {}
+
  private:
-  NotificationClient client_;
+  PaintClient client_;
+  int num_tiles_rastered_;
 };
 
-SINGLE_AND_MULTI_THREAD_TEST_F(LayerTreeHostTestLCDNotification);
+SINGLE_AND_MULTI_THREAD_IMPL_TEST_F(LayerTreeHostTestLCDChange);
 
 // Verify that the BeginFrame notification is used to initiate rendering.
 class LayerTreeHostTestBeginFrameNotification : public LayerTreeHostTest {
@@ -2569,8 +2591,6 @@
       layer_->SetBounds(gfx::Size(2, 2));
     }
 
-    void DidChangeLayerCanUseLCDText() override {}
-
     bool FillsBoundsCompletely() const override { return false; }
 
    private:
@@ -5387,6 +5407,9 @@
         FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
     layer->SetBounds(gfx::Size(500, 500));
     layer->SetContentsOpaque(true);
+    // Avoid LCD text on the layer so we don't cause extra commits when we
+    // pinch.
+    layer->disable_lcd_text();
     pinch->AddChild(layer);
 
     layer_tree_host()->RegisterViewportLayers(root, pinch, pinch);
@@ -5433,11 +5456,6 @@
         PostNextAfterDraw(host_impl);
         break;
       case 2:
-        // Wait for any activations that need to occur due to starting a pinch,
-        // and drawing with a non-identity transform (for eg. LCD text being
-        // disabled).
-        if (host_impl->pending_tree())
-          break;
         if (quad_scale_delta != 1.f)
           break;
         // Drew at page scale 1.5 after pinching in.
@@ -5582,7 +5600,6 @@
   void SetupTree() override {
     step_ = 1;
     continuous_draws_ = 0;
-    expect_draw_ = false;
     client_.set_fill_with_nonsolid_color(true);
 
     scoped_refptr<Layer> root = Layer::Create();
@@ -5600,6 +5617,9 @@
         FakePictureLayer::CreateWithRecordingSource(&client_, pile.Pass());
     layer->SetBounds(gfx::Size(500, 500));
     layer->SetContentsOpaque(true);
+    // Avoid LCD text on the layer so we don't cause extra commits when we
+    // pinch.
+    layer->disable_lcd_text();
     pinch->AddChild(layer);
 
     layer_tree_host()->RegisterViewportLayers(root, pinch, pinch);
@@ -5662,18 +5682,17 @@
         EXPECT_EQ(1.f, quad_scale_delta);
         break;
       case 5:
-        // TODO(danakj): We may get one more draw because the NotifyReadyToDraw
-        // is asynchronous from the previous draw and happens late.
+        // TODO(danakj): We get more draws before the NotifyReadyToDraw
+        // because it is asynchronous from the previous draw and happens late.
         break;
       case 6:
-        // We may get another draw if we activate due to the pinch (eg LCD text
-        // gets disabled).
-        if (expect_draw_)
-          break;
+        // NotifyReadyToDraw happened. If we were already inside a frame, we may
+        // try to draw once more.
+        break;
+      case 7:
         NOTREACHED() << "No draws should happen once we have a complete frame.";
         break;
     }
-    expect_draw_ = false;
     return draw_result;
   }
 
@@ -5701,8 +5720,13 @@
         }
         break;
       case 4:
-        // TODO(danakj): Now we wait for NotifyReadyToDraw to avoid flakiness
-        // since it happens asynchronously.
+        ++step_;
+        break;
+      case 5:
+        // Waiting for NotifyReadyToDraw.
+        break;
+      case 6:
+        // NotifyReadyToDraw happened.
         ++step_;
         break;
     }
@@ -5710,21 +5734,17 @@
 
   void NotifyReadyToDrawOnThread(LayerTreeHostImpl* host_impl) override {
     if (step_ == 5) {
-      // We should not continue to draw any more. End the test after a timeout
-      // to watch for any extraneous draws.
+      ++step_;
+      // NotifyReadyToDraw has happened, we may draw once more, but should not
+      // get any more draws after that. End the test after a timeout to watch
+      // for any extraneous draws.
       // TODO(brianderson): We could remove this delay and instead wait until
       // the BeginFrameSource decides it doesn't need to send frames anymore,
       // or test that it already doesn't here.
       EndTestAfterDelayMs(16 * 4);
-      ++step_;
-      expect_draw_ = true;
     }
   }
 
-  void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
-    expect_draw_ = true;
-  }
-
   void NotifyTileStateChangedOnThread(LayerTreeHostImpl* host_impl,
                                       const Tile* tile) override {
     // On step_ == 2, we are preventing texture uploads from completing,
@@ -5739,7 +5759,6 @@
   FakeContentLayerClient client_;
   int step_;
   int continuous_draws_;
-  bool expect_draw_;
   base::WaitableEvent playback_allowed_event_;
 };
 
diff --git a/cc/trees/layer_tree_host_unittest_animation.cc b/cc/trees/layer_tree_host_unittest_animation.cc
index 9c346e2..8318192 100644
--- a/cc/trees/layer_tree_host_unittest_animation.cc
+++ b/cc/trees/layer_tree_host_unittest_animation.cc
@@ -8,6 +8,7 @@
 #include "cc/animation/layer_animation_controller.h"
 #include "cc/animation/scroll_offset_animation_curve.h"
 #include "cc/animation/timing_function.h"
+#include "cc/base/time_util.h"
 #include "cc/layers/layer.h"
 #include "cc/layers/layer_impl.h"
 #include "cc/test/animation_test_common.h"
@@ -503,11 +504,11 @@
 
     const FloatAnimationCurve* curve =
         animation->curve()->ToFloatAnimationCurve();
-    float start_opacity = curve->GetValue(0.0);
-    float end_opacity = curve->GetValue(curve->Duration().InSecondsF());
+    float start_opacity = curve->GetValue(base::TimeDelta());
+    float end_opacity = curve->GetValue(curve->Duration());
     float linearly_interpolated_opacity =
         0.25f * end_opacity + 0.75f * start_opacity;
-    double time = curve->Duration().InSecondsF() * 0.25;
+    base::TimeDelta time = TimeUtil::Scale(curve->Duration(), 0.25f);
     // If the linear timing function associated with this animation was not
     // picked up, then the linearly interpolated opacity would be different
     // because of the default ease timing function.
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index 6b2b37f..c005a18 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -490,18 +490,14 @@
 
     ++render_surface_layer_list_id_;
     LayerTreeHostCommon::CalcDrawPropsImplInputs inputs(
-        root_layer(),
-        DrawViewportSize(),
-        layer_tree_host_impl_->DrawTransform(),
-        device_scale_factor(),
-        total_page_scale_factor(),
-        page_scale_layer,
-        resource_provider()->max_texture_size(),
-        settings().can_use_lcd_text,
+        root_layer(), DrawViewportSize(),
+        layer_tree_host_impl_->DrawTransform(), device_scale_factor(),
+        total_page_scale_factor(), page_scale_layer,
+        resource_provider()->max_texture_size(), settings().can_use_lcd_text,
+        settings().layers_always_allowed_lcd_text,
         can_render_to_separate_surface,
         settings().layer_transforms_should_scale_layer_contents,
-        &render_surface_layer_list_,
-        render_surface_layer_list_id_);
+        &render_surface_layer_list_, render_surface_layer_list_id_);
     LayerTreeHostCommon::CalculateDrawProperties(&inputs);
   }
 
diff --git a/cc/trees/layer_tree_settings.cc b/cc/trees/layer_tree_settings.cc
index 48c4133..14c1def 100644
--- a/cc/trees/layer_tree_settings.cc
+++ b/cc/trees/layer_tree_settings.cc
@@ -43,6 +43,7 @@
       timeout_and_draw_when_animation_checkerboards(true),
       maximum_number_of_failed_draws_before_draw_is_forced_(3),
       layer_transforms_should_scale_layer_contents(false),
+      layers_always_allowed_lcd_text(false),
       minimum_contents_scale(0.0625f),
       low_res_contents_scale_factor(0.25f),
       top_controls_height(0.f),
diff --git a/cc/trees/layer_tree_settings.h b/cc/trees/layer_tree_settings.h
index 3097e59..69ac995 100644
--- a/cc/trees/layer_tree_settings.h
+++ b/cc/trees/layer_tree_settings.h
@@ -54,6 +54,7 @@
   bool timeout_and_draw_when_animation_checkerboards;
   int maximum_number_of_failed_draws_before_draw_is_forced_;
   bool layer_transforms_should_scale_layer_contents;
+  bool layers_always_allowed_lcd_text;
   float minimum_contents_scale;
   float low_res_contents_scale_factor;
   float top_controls_height;
diff --git a/gpu/command_buffer/client/gles2_implementation.h b/gpu/command_buffer/client/gles2_implementation.h
index cfe8ed9..4fcfea8 100644
--- a/gpu/command_buffer/client/gles2_implementation.h
+++ b/gpu/command_buffer/client/gles2_implementation.h
@@ -671,10 +671,10 @@
   bool debug_;
 
   // When true, the context is lost when a GL_OUT_OF_MEMORY error occurs.
-  bool lose_context_when_out_of_memory_;
+  const bool lose_context_when_out_of_memory_;
 
   // Whether or not to support client side arrays.
-  bool support_client_side_arrays_;
+  const bool support_client_side_arrays_;
 
   // Used to check for single threaded access.
   int use_count_;
diff --git a/gpu/command_buffer/client/vertex_array_object_manager.h b/gpu/command_buffer/client/vertex_array_object_manager.h
index 8638584..e4c8999 100644
--- a/gpu/command_buffer/client/vertex_array_object_manager.h
+++ b/gpu/command_buffer/client/vertex_array_object_manager.h
@@ -117,7 +117,7 @@
   VertexArrayObject* bound_vertex_array_object_;
   VertexArrayObjectMap vertex_array_objects_;
 
-  bool support_client_side_arrays_;
+  const bool support_client_side_arrays_;
 
   DISALLOW_COPY_AND_ASSIGN(VertexArrayObjectManager);
 };
diff --git a/gpu/command_buffer/service/BUILD.gn b/gpu/command_buffer/service/BUILD.gn
index 1c43029..351e5c9 100644
--- a/gpu/command_buffer/service/BUILD.gn
+++ b/gpu/command_buffer/service/BUILD.gn
@@ -103,6 +103,8 @@
     "shader_translator_cache.cc",
     "stream_texture_manager_in_process_android.h",
     "stream_texture_manager_in_process_android.cc",
+    "sync_point_manager.h",
+    "sync_point_manager.cc",
     "texture_definition.h",
     "texture_definition.cc",
     "texture_manager.h",
diff --git a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
index f98ca2e..ffb9370 100644
--- a/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
+++ b/gpu/command_buffer/service/gles2_cmd_copy_texture_chromium.cc
@@ -21,8 +21,8 @@
   "#define SamplerType sampler2D\n" \
   "#define TextureLookup texture2D\n" SHADER(src)
 #define SHADER_RECTANGLE_ARB(src)     \
-  "#define SamplerType samplerRect\n" \
-  "#define TextureLookup textureRect\n" SHADER(src)
+  "#define SamplerType sampler2DRect\n" \
+  "#define TextureLookup texture2DRect\n" SHADER(src)
 #define SHADER_EXTERNAL_OES(src)                     \
   "#extension GL_OES_EGL_image_external : require\n" \
   "#define SamplerType samplerExternalOES\n"         \
diff --git a/gpu/command_buffer/service/sync_point_manager.cc b/gpu/command_buffer/service/sync_point_manager.cc
new file mode 100644
index 0000000..cd8c490
--- /dev/null
+++ b/gpu/command_buffer/service/sync_point_manager.cc
@@ -0,0 +1,84 @@
+// 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 "gpu/command_buffer/service/sync_point_manager.h"
+
+#include <climits>
+
+#include "base/logging.h"
+#include "base/rand_util.h"
+
+namespace gpu {
+
+static const int kMaxSyncBase = INT_MAX;
+
+SyncPointManager::SyncPointManager()
+    : next_sync_point_(base::RandInt(1, kMaxSyncBase)) {
+  // To reduce the risk that a sync point created in a previous GPU process
+  // will be in flight in the next GPU process, randomize the starting sync
+  // point number. http://crbug.com/373452
+}
+
+SyncPointManager::~SyncPointManager() {
+}
+
+uint32 SyncPointManager::GenerateSyncPoint() {
+  base::AutoLock lock(lock_);
+  uint32 sync_point = next_sync_point_++;
+  // When an integer overflow occurs, don't return 0.
+  if (!sync_point)
+    sync_point = next_sync_point_++;
+
+  // Note: wrapping would take days for a buggy/compromized renderer that would
+  // insert sync points in a loop, but if that were to happen, better explicitly
+  // crash the GPU process than risk worse.
+  // For normal operation (at most a few per frame), it would take ~a year to
+  // wrap.
+  CHECK(sync_point_map_.find(sync_point) == sync_point_map_.end());
+  sync_point_map_.insert(std::make_pair(sync_point, ClosureList()));
+  return sync_point;
+}
+
+void SyncPointManager::RetireSyncPoint(uint32 sync_point) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  ClosureList list;
+  {
+    base::AutoLock lock(lock_);
+    SyncPointMap::iterator it = sync_point_map_.find(sync_point);
+    if (it == sync_point_map_.end()) {
+      LOG(ERROR) << "Attempted to retire sync point that"
+                    " didn't exist or was already retired.";
+      return;
+    }
+    list.swap(it->second);
+    sync_point_map_.erase(it);
+  }
+  for (ClosureList::iterator i = list.begin(); i != list.end(); ++i)
+    i->Run();
+}
+
+void SyncPointManager::AddSyncPointCallback(uint32 sync_point,
+                                            const base::Closure& callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  {
+    base::AutoLock lock(lock_);
+    SyncPointMap::iterator it = sync_point_map_.find(sync_point);
+    if (it != sync_point_map_.end()) {
+      it->second.push_back(callback);
+      return;
+    }
+  }
+  callback.Run();
+}
+
+bool SyncPointManager::IsSyncPointRetired(uint32 sync_point) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  {
+    base::AutoLock lock(lock_);
+    SyncPointMap::iterator it = sync_point_map_.find(sync_point);
+    return it == sync_point_map_.end();
+  }
+}
+
+}  // namespace gpu
diff --git a/gpu/command_buffer/service/sync_point_manager.h b/gpu/command_buffer/service/sync_point_manager.h
new file mode 100644
index 0000000..8cbf8a8
--- /dev/null
+++ b/gpu/command_buffer/service/sync_point_manager.h
@@ -0,0 +1,62 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef GPU_COMMAND_BUFFER_SERVICE_SYNC_POINT_MANAGER_H_
+#define GPU_COMMAND_BUFFER_SERVICE_SYNC_POINT_MANAGER_H_
+
+#include <vector>
+
+#include "base/callback.h"
+#include "base/containers/hash_tables.h"
+#include "base/memory/ref_counted.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/thread_checker.h"
+#include "gpu/gpu_export.h"
+
+namespace gpu {
+
+// This class manages the sync points, which allow cross-channel
+// synchronization.
+class GPU_EXPORT SyncPointManager
+    : public base::RefCountedThreadSafe<SyncPointManager> {
+ public:
+  SyncPointManager();
+
+  // Generates a sync point, returning its ID. This can me called on any thread.
+  // IDs start at a random number. Never return 0.
+  uint32 GenerateSyncPoint();
+
+  // Retires a sync point. This will call all the registered callbacks for this
+  // sync point. This can only be called on the main thread.
+  void RetireSyncPoint(uint32 sync_point);
+
+  // Adds a callback to the sync point. The callback will be called when the
+  // sync point is retired, or immediately (from within that function) if the
+  // sync point was already retired (or not created yet). This can only be
+  // called on the main thread.
+  void AddSyncPointCallback(uint32 sync_point, const base::Closure& callback);
+
+  bool IsSyncPointRetired(uint32 sync_point);
+
+ private:
+  friend class base::RefCountedThreadSafe<SyncPointManager>;
+  typedef std::vector<base::Closure> ClosureList;
+  typedef base::hash_map<uint32, ClosureList> SyncPointMap;
+
+  ~SyncPointManager();
+
+  base::ThreadChecker thread_checker_;
+
+  // Protects the 2 fields below. Note: callbacks shouldn't be called with this
+  // held.
+  base::Lock lock_;
+  SyncPointMap sync_point_map_;
+  uint32 next_sync_point_;
+
+  DISALLOW_COPY_AND_ASSIGN(SyncPointManager);
+};
+
+}  // namespace gpu
+
+#endif  // GPU_COMMAND_BUFFER_SERVICE_SYNC_POINT_MANAGER_H_
diff --git a/gpu/command_buffer_service.gypi b/gpu/command_buffer_service.gypi
index c276d43..358317c 100644
--- a/gpu/command_buffer_service.gypi
+++ b/gpu/command_buffer_service.gypi
@@ -121,6 +121,8 @@
     'command_buffer/service/shader_translator_cache.cc',
     'command_buffer/service/stream_texture_manager_in_process_android.h',
     'command_buffer/service/stream_texture_manager_in_process_android.cc',
+    'command_buffer/service/sync_point_manager.h',
+    'command_buffer/service/sync_point_manager.cc',
     'command_buffer/service/texture_definition.h',
     'command_buffer/service/texture_definition.cc',
     'command_buffer/service/texture_manager.h',
diff --git a/net/base/net_log_event_type_list.h b/net/base/net_log_event_type_list.h
index af7c290..494b762 100644
--- a/net/base/net_log_event_type_list.h
+++ b/net/base/net_log_event_type_list.h
@@ -796,6 +796,14 @@
 //     "headers": <The list of header:value pairs>,
 //   }
 
+EVENT_TYPE(URL_REQUEST_FILTERS_SET)
+// This event is logged when a URLRequestJob sets up the filters, if any
+// filters were added to the job.  It logs the filters added.
+// The following parameters are attached:
+//   {
+//     "filters": <The list of filter names>
+//   }
+
 // ------------------------------------------------------------------------
 // HttpCache
 // ------------------------------------------------------------------------
@@ -2398,3 +2406,11 @@
 // This event is created when SdchDictionaryFetcher starts fetch.  It contains
 // no parameters.
 EVENT_TYPE(SDCH_DICTIONARY_FETCH)
+
+// This event is created if the SdchDictionaryFetcher URLRequest returns
+// no error, but signals an error through bytes_read < 0.
+// It contains the following parameters:
+//   {
+//     "net_error": <error created>
+//   }
+EVENT_TYPE(SDCH_DICTIONARY_FETCH_IMPLIED_ERROR)
diff --git a/net/base/sdch_problem_code_list.h b/net/base/sdch_problem_code_list.h
index 4efc17c..a0d5196 100644
--- a/net/base/sdch_problem_code_list.h
+++ b/net/base/sdch_problem_code_list.h
@@ -55,7 +55,7 @@
 SDCH_PROBLEM_CODE(DICTIONARY_COUNT_EXCEEDED, 35)
 // defunct = 36, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
 // defunct = 37, // DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD used instead.
-SDCH_PROBLEM_CODE(DICTIONARY_FETCH_READ_FAILED, 38)
+// defunct = 38, // No longer paying attention to URLRequest::Read return.
 SDCH_PROBLEM_CODE(DICTIONARY_PREVIOUSLY_SCHEDULED_TO_DOWNLOAD, 39)
 
 // Failsafe hack.
diff --git a/net/filter/filter.cc b/net/filter/filter.cc
index c9a56bd..53d6583 100644
--- a/net/filter/filter.cc
+++ b/net/filter/filter.cc
@@ -64,6 +64,24 @@
       base::Bind(&NetLogSdchResourceProblemCallback, problem));
 }
 
+std::string FilterTypeAsString(Filter::FilterType type_id) {
+  switch (type_id) {
+    case Filter::FILTER_TYPE_DEFLATE:
+      return "FILTER_TYPE_DEFLATE";
+    case Filter::FILTER_TYPE_GZIP:
+      return "FILTER_TYPE_GZIP";
+    case Filter::FILTER_TYPE_GZIP_HELPING_SDCH:
+      return "FILTER_TYPE_GZIP_HELPING_SDCH";
+    case Filter::FILTER_TYPE_SDCH:
+      return "FILTER_TYPE_SDCH";
+    case Filter::FILTER_TYPE_SDCH_POSSIBLE  :
+      return "FILTER_TYPE_SDCH_POSSIBLE  ";
+    case Filter::FILTER_TYPE_UNSUPPORTED:
+      return "FILTER_TYPE_UNSUPPORTED";
+  }
+  return "";
+}
+
 }  // namespace
 
 FilterContext::~FilterContext() {
@@ -340,12 +358,22 @@
   return;
 }
 
-Filter::Filter()
+std::string Filter::OrderedFilterList() const {
+  if (next_filter_) {
+    return FilterTypeAsString(type_id_) + "," +
+        next_filter_->OrderedFilterList();
+  } else {
+    return FilterTypeAsString(type_id_);
+  }
+}
+
+Filter::Filter(FilterType type_id)
     : stream_buffer_(NULL),
       stream_buffer_size_(0),
       next_stream_data_(NULL),
       stream_data_len_(0),
-      last_status_(FILTER_NEED_MORE_DATA) {}
+      last_status_(FILTER_NEED_MORE_DATA),
+      type_id_(type_id) {}
 
 Filter::FilterStatus Filter::CopyOut(char* dest_buffer, int* dest_len) {
   int out_len;
@@ -370,7 +398,7 @@
 
 // static
 Filter* Filter::InitGZipFilter(FilterType type_id, int buffer_size) {
-  scoped_ptr<GZipFilter> gz_filter(new GZipFilter());
+  scoped_ptr<GZipFilter> gz_filter(new GZipFilter(type_id));
   gz_filter->InitBuffer(buffer_size);
   return gz_filter->InitDecoding(type_id) ? gz_filter.release() : NULL;
 }
@@ -379,7 +407,7 @@
 Filter* Filter::InitSdchFilter(FilterType type_id,
                                const FilterContext& filter_context,
                                int buffer_size) {
-  scoped_ptr<SdchFilter> sdch_filter(new SdchFilter(filter_context));
+  scoped_ptr<SdchFilter> sdch_filter(new SdchFilter(type_id, filter_context));
   sdch_filter->InitBuffer(buffer_size);
   return sdch_filter->InitDecoding(type_id) ? sdch_filter.release() : NULL;
 }
diff --git a/net/filter/filter.h b/net/filter/filter.h
index 13489ef..cec8398 100644
--- a/net/filter/filter.h
+++ b/net/filter/filter.h
@@ -225,12 +225,15 @@
   static void FixupEncodingTypes(const FilterContext& filter_context,
                                  std::vector<FilterType>* encoding_types);
 
+  // Returns a string describing the FilterTypes implemented by this filter.
+  std::string OrderedFilterList() const;
+
  protected:
   friend class GZipUnitTest;
   friend class SdchFilterChainingTest;
   FRIEND_TEST_ALL_PREFIXES(FilterTest, ThreeFilterChain);
 
-  Filter();
+  explicit Filter(FilterType type_id);
 
   // Filters the data stored in stream_buffer_ and writes the output into the
   // dest_buffer passed in.
@@ -294,10 +297,14 @@
 
   // An optional filter to process output from this filter.
   scoped_ptr<Filter> next_filter_;
+
   // Remember what status or local filter last returned so we can better handle
   // chained filters.
   FilterStatus last_status_;
 
+  // The filter type this filter was constructed from.
+  FilterType type_id_;
+
   DISALLOW_COPY_AND_ASSIGN(Filter);
 };
 
diff --git a/net/filter/filter_unittest.cc b/net/filter/filter_unittest.cc
index 506284d..5b2446c 100644
--- a/net/filter/filter_unittest.cc
+++ b/net/filter/filter_unittest.cc
@@ -13,7 +13,7 @@
 
 class PassThroughFilter : public Filter {
  public:
-  PassThroughFilter() {}
+  PassThroughFilter() : Filter(FILTER_TYPE_UNSUPPORTED) {}
 
   FilterStatus ReadFilteredData(char* dest_buffer, int* dest_len) override {
     return CopyOut(dest_buffer, dest_len);
diff --git a/net/filter/gzip_filter.cc b/net/filter/gzip_filter.cc
index 36fe01c..6d15ee9 100644
--- a/net/filter/gzip_filter.cc
+++ b/net/filter/gzip_filter.cc
@@ -10,8 +10,9 @@
 
 namespace net {
 
-GZipFilter::GZipFilter()
-    : decoding_status_(DECODING_UNINITIALIZED),
+GZipFilter::GZipFilter(FilterType type)
+    : Filter(type),
+      decoding_status_(DECODING_UNINITIALIZED),
       decoding_mode_(DECODE_MODE_UNKNOWN),
       gzip_header_status_(GZIP_CHECK_HEADER_IN_PROGRESS),
       zlib_header_added_(false),
diff --git a/net/filter/gzip_filter.h b/net/filter/gzip_filter.h
index 597c2e7..42dc320 100644
--- a/net/filter/gzip_filter.h
+++ b/net/filter/gzip_filter.h
@@ -73,7 +73,7 @@
   static const int kGZipFooterSize = 8;
 
   // Only to be instantiated by Filter::Factory.
-  GZipFilter();
+  GZipFilter(FilterType type);
   friend class Filter;
 
   // Parses and verifies the GZip header.
diff --git a/net/filter/sdch_filter.cc b/net/filter/sdch_filter.cc
index d03ff7f..d1eb7f4 100644
--- a/net/filter/sdch_filter.cc
+++ b/net/filter/sdch_filter.cc
@@ -99,8 +99,9 @@
 
 }  // namespace
 
-SdchFilter::SdchFilter(const FilterContext& filter_context)
-    : filter_context_(filter_context),
+SdchFilter::SdchFilter(FilterType type, const FilterContext& filter_context)
+    : Filter(type),
+      filter_context_(filter_context),
       decoding_status_(DECODING_UNINITIALIZED),
       dictionary_hash_(),
       dictionary_hash_is_plausible_(false),
diff --git a/net/filter/sdch_filter.h b/net/filter/sdch_filter.h
index a1a6607..bc7788c 100644
--- a/net/filter/sdch_filter.h
+++ b/net/filter/sdch_filter.h
@@ -54,7 +54,7 @@
   };
 
   // Only to be instantiated by Filter::Factory.
-  explicit SdchFilter(const FilterContext& filter_context);
+  SdchFilter(FilterType type, const FilterContext& filter_context);
   friend class Filter;
 
   // Identify the suggested dictionary, and initialize underlying decompressor.
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc
index 794030d..41b70b1 100644
--- a/net/http/http_server_properties_manager.cc
+++ b/net/http/http_server_properties_manager.cc
@@ -13,6 +13,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
 #include "base/values.h"
+#include "net/base/net_util.h"
 
 namespace net {
 
@@ -419,7 +420,7 @@
       int port = 0;
       if (!port_alternate_protocol_dict->GetIntegerWithoutPathExpansion(
               "port", &port) ||
-          (port > (1 << 16))) {
+          !IsPortValid(port)) {
         DVLOG(1) << "Malformed Alternate-Protocol server: " << server_str;
         detected_corrupted_prefs = true;
         continue;
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h
index 4acf76f..22e2499 100644
--- a/net/http/http_server_properties_manager.h
+++ b/net/http/http_server_properties_manager.h
@@ -7,6 +7,7 @@
 
 #include <string>
 #include <vector>
+
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc
index db58c92..bb8b68c 100644
--- a/net/http/http_server_properties_manager_unittest.cc
+++ b/net/http/http_server_properties_manager_unittest.cc
@@ -241,6 +241,95 @@
   EXPECT_EQ("bar", supports_quic2.address);
 }
 
+TEST_F(HttpServerPropertiesManagerTest, BadCachedHostPortPair) {
+  ExpectCacheUpdate();
+  // The prefs are automaticalls updated in the case corruption is detected.
+  ExpectPrefsUpdate();
+
+  base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
+
+  // Set supports_spdy for www.google.com:65536.
+  server_pref_dict->SetBoolean("supports_spdy", true);
+
+  // Set up alternate_protocol for www.google.com:65536.
+  base::DictionaryValue* alternate_protocol = new base::DictionaryValue;
+  alternate_protocol->SetInteger("port", 80);
+  alternate_protocol->SetString("protocol_str", "npn-spdy/3");
+  server_pref_dict->SetWithoutPathExpansion("alternate_protocol",
+                                            alternate_protocol);
+
+  // Set up SupportsQuic for www.google.com:65536.
+  base::DictionaryValue* supports_quic = new base::DictionaryValue;
+  supports_quic->SetBoolean("used_quic", true);
+  supports_quic->SetString("address", "foo");
+  server_pref_dict->SetWithoutPathExpansion("supports_quic", supports_quic);
+
+  // Set the server preference for www.google.com:65536.
+  base::DictionaryValue* servers_dict = new base::DictionaryValue;
+  servers_dict->SetWithoutPathExpansion("www.google.com:65536",
+                                        server_pref_dict);
+
+  base::DictionaryValue* http_server_properties_dict =
+      new base::DictionaryValue;
+  HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1);
+  http_server_properties_dict->SetWithoutPathExpansion("servers", servers_dict);
+
+  // Set up the pref.
+  pref_service_.SetManagedPref(kTestHttpServerProperties,
+                               http_server_properties_dict);
+
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
+
+  // Verify that nothing is set.
+  EXPECT_FALSE(http_server_props_manager_->SupportsSpdy(
+      net::HostPortPair::FromString("www.google.com:65536")));
+  EXPECT_FALSE(http_server_props_manager_->HasAlternateProtocol(
+      net::HostPortPair::FromString("www.google.com:65536")));
+  net::SupportsQuic supports_quic2 =
+      http_server_props_manager_->GetSupportsQuic(
+          net::HostPortPair::FromString("www.google.com:65536"));
+  EXPECT_FALSE(supports_quic2.used_quic);
+}
+
+TEST_F(HttpServerPropertiesManagerTest, BadCachedAltProtocolPort) {
+  ExpectCacheUpdate();
+  // The prefs are automaticalls updated in the case corruption is detected.
+  ExpectPrefsUpdate();
+
+  base::DictionaryValue* server_pref_dict = new base::DictionaryValue;
+
+  // Set supports_spdy for www.google.com:80.
+  server_pref_dict->SetBoolean("supports_spdy", true);
+
+  // Set up alternate_protocol for www.google.com:80.
+  base::DictionaryValue* alternate_protocol = new base::DictionaryValue;
+  alternate_protocol->SetInteger("port", 65536);
+  alternate_protocol->SetString("protocol_str", "npn-spdy/3");
+  server_pref_dict->SetWithoutPathExpansion("alternate_protocol",
+                                            alternate_protocol);
+
+  // Set the server preference for www.google.com:80.
+  base::DictionaryValue* servers_dict = new base::DictionaryValue;
+  servers_dict->SetWithoutPathExpansion("www.google.com:80", server_pref_dict);
+
+  base::DictionaryValue* http_server_properties_dict =
+      new base::DictionaryValue;
+  HttpServerPropertiesManager::SetVersion(http_server_properties_dict, -1);
+  http_server_properties_dict->SetWithoutPathExpansion("servers", servers_dict);
+
+  // Set up the pref.
+  pref_service_.SetManagedPref(kTestHttpServerProperties,
+                               http_server_properties_dict);
+
+  base::RunLoop().RunUntilIdle();
+  Mock::VerifyAndClearExpectations(http_server_props_manager_.get());
+
+  // Verify AlternateProtocol is not set.
+  EXPECT_FALSE(http_server_props_manager_->HasAlternateProtocol(
+      net::HostPortPair::FromString("www.google.com:80")));
+}
+
 TEST_F(HttpServerPropertiesManagerTest, SupportsSpdy) {
   ExpectPrefsUpdate();
 
diff --git a/net/http/transport_security_state.cc b/net/http/transport_security_state.cc
index baf38bf..6217d57 100644
--- a/net/http/transport_security_state.cc
+++ b/net/http/transport_security_state.cc
@@ -22,6 +22,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
+#include "base/metrics/sparse_histogram.h"
 #include "base/sha1.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
@@ -723,8 +724,8 @@
 
   DCHECK(result.domain_id != DOMAIN_NOT_PINNED);
 
-  UMA_HISTOGRAM_ENUMERATION(
-      "Net.PublicKeyPinFailureDomain", result.domain_id, DOMAIN_NUM_EVENTS);
+  UMA_HISTOGRAM_SPARSE_SLOWLY(
+      "Net.PublicKeyPinFailureDomain", result.domain_id);
 }
 
 // static
diff --git a/net/ocsp/nss_ocsp.cc b/net/ocsp/nss_ocsp.cc
index 61c65ee..18a476d 100644
--- a/net/ocsp/nss_ocsp.cc
+++ b/net/ocsp/nss_ocsp.cc
@@ -23,6 +23,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -297,6 +298,11 @@
   }
 
   void OnResponseStarted(URLRequest* request) override {
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "423948 OCSPRequestSession::OnResponseStarted"));
+
     DCHECK_EQ(request_.get(), request);
     DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_);
 
@@ -311,6 +317,11 @@
   }
 
   void OnReadCompleted(URLRequest* request, int bytes_read) override {
+    // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+    tracked_objects::ScopedTracker tracking_profile(
+        FROM_HERE_WITH_EXPLICIT_FUNCTION(
+            "423948 OCSPRequestSession::OnReadCompleted"));
+
     DCHECK_EQ(request_.get(), request);
     DCHECK_EQ(base::MessageLoopForIO::current(), io_loop_);
 
diff --git a/net/proxy/proxy_script_fetcher_impl.cc b/net/proxy/proxy_script_fetcher_impl.cc
index 0ce507b..4e57121 100644
--- a/net/proxy/proxy_script_fetcher_impl.cc
+++ b/net/proxy/proxy_script_fetcher_impl.cc
@@ -7,6 +7,7 @@
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/message_loop/message_loop.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_util.h"
 #include "net/base/data_url.h"
 #include "net/base/io_buffer.h"
@@ -202,6 +203,11 @@
 }
 
 void ProxyScriptFetcherImpl::OnResponseStarted(URLRequest* request) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "423948 ProxyScriptFetcherImpl::OnResponseStarted"));
+
   DCHECK_EQ(request, cur_request_.get());
 
   if (!request->status().is_success()) {
@@ -237,6 +243,11 @@
 
 void ProxyScriptFetcherImpl::OnReadCompleted(URLRequest* request,
                                              int num_bytes) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "423948 ProxyScriptFetcherImpl::OnReadCompleted"));
+
   DCHECK_EQ(request, cur_request_.get());
   if (ConsumeBytesRead(request, num_bytes)) {
     // Keep reading.
diff --git a/net/url_request/sdch_dictionary_fetcher.cc b/net/url_request/sdch_dictionary_fetcher.cc
index 5ac65ef..9aeed9a 100644
--- a/net/url_request/sdch_dictionary_fetcher.cc
+++ b/net/url_request/sdch_dictionary_fetcher.cc
@@ -9,6 +9,7 @@
 #include "base/auto_reset.h"
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/thread_task_runner_handle.h"
 #include "net/base/load_flags.h"
 #include "net/base/sdch_net_log_params.h"
@@ -81,6 +82,11 @@
 }
 
 void SdchDictionaryFetcher::OnResponseStarted(URLRequest* request) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "423948 SdchDictionaryFetcher::OnResponseStarted"));
+
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(request, current_request_.get());
   DCHECK_EQ(next_state_, STATE_REQUEST_STARTED);
@@ -99,6 +105,11 @@
 
 void SdchDictionaryFetcher::OnReadCompleted(URLRequest* request,
                                             int bytes_read) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "423948 SdchDictionaryFetcher::OnReadCompleted"));
+
   DCHECK(CalledOnValidThread());
   DCHECK_EQ(request, current_request_.get());
   DCHECK_EQ(next_state_, STATE_REQUEST_READING);
@@ -199,33 +210,29 @@
 
   next_state_ = STATE_REQUEST_READING;
   int bytes_read = 0;
-  if (!current_request_->Read(buffer_.get(), kBufferSize, &bytes_read)) {
-    if (current_request_->status().is_io_pending())
-      return ERR_IO_PENDING;
+  current_request_->Read(buffer_.get(), kBufferSize, &bytes_read);
+  if (current_request_->status().is_io_pending())
+    return ERR_IO_PENDING;
 
-    if (current_request_->status().error() == OK) {
-      // This "should never happen", but if it does the result will be
-      // an infinite loop.  It's not clear how to handle a read failure
-      // without a promise to invoke the callback at some point in the future,
-      // so the request is failed.
-      SdchManager::SdchErrorRecovery(SDCH_DICTIONARY_FETCH_READ_FAILED);
-      current_request_->net_log().AddEvent(
-          NetLog::TYPE_SDCH_DICTIONARY_ERROR,
-          base::Bind(&NetLogSdchDictionaryFetchProblemCallback,
-                     SDCH_DICTIONARY_FETCH_READ_FAILED, current_request_->url(),
-                     true));
-      DLOG(FATAL)
-          << "URLRequest::Read() returned false without IO pending or error!";
-      return ERR_FAILED;
-    }
+  if (bytes_read < 0 || !current_request_->status().is_success()) {
+    if (current_request_->status().error() != OK)
+      return current_request_->status().error();
 
-    return current_request_->status().error();
+    // An error with request status of OK should not happen,
+    // but there's enough machinery underneath URLRequest::Read()
+    // that this routine checks for that case.
+    net::Error error =
+        current_request_->status().status() == URLRequestStatus::CANCELED ?
+        ERR_ABORTED : ERR_FAILED;
+    current_request_->net_log().AddEventWithNetErrorCode(
+        NetLog::TYPE_SDCH_DICTIONARY_FETCH_IMPLIED_ERROR, error);
+    return error;
   }
 
-  if (bytes_read != 0)
-    dictionary_.append(buffer_->data(), bytes_read);
-  else
+  if (bytes_read == 0)
     next_state_ = STATE_REQUEST_COMPLETE;
+  else
+    dictionary_.append(buffer_->data(), bytes_read);
 
   return OK;
 }
diff --git a/net/url_request/url_fetcher_core.cc b/net/url_request/url_fetcher_core.cc
index aae47d9..23399f3 100644
--- a/net/url_request/url_fetcher_core.cc
+++ b/net/url_request/url_fetcher_core.cc
@@ -9,6 +9,7 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
@@ -389,6 +390,11 @@
 }
 
 void URLFetcherCore::OnResponseStarted(URLRequest* request) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "423948 URLFetcherCore::OnResponseStarted"));
+
   DCHECK_EQ(request, request_.get());
   DCHECK(network_task_runner_->BelongsToCurrentThread());
   if (request_->status().is_success()) {
@@ -417,6 +423,11 @@
 
 void URLFetcherCore::OnReadCompleted(URLRequest* request,
                                      int bytes_read) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION(
+          "423948 URLFetcherCore::OnReadCompleted"));
+
   DCHECK(request == request_);
   DCHECK(network_task_runner_->BelongsToCurrentThread());
 
diff --git a/net/url_request/url_request_job.cc b/net/url_request/url_request_job.cc
index 3610195..5d32c6f 100644
--- a/net/url_request/url_request_job.cc
+++ b/net/url_request/url_request_job.cc
@@ -11,6 +11,7 @@
 #include "base/profiler/scoped_tracker.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
+#include "base/values.h"
 #include "net/base/auth.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
@@ -21,6 +22,18 @@
 #include "net/http/http_response_headers.h"
 #include "net/url_request/url_request.h"
 
+namespace {
+
+// Callback for TYPE_URL_REQUEST_FILTERS_SET net-internals event.
+base::Value* FiltersSetCallback(net::Filter* filter,
+                                enum net::NetLog::LogLevel /* log_level */) {
+  base::DictionaryValue* event_params = new base::DictionaryValue();
+  event_params->SetString("filters", filter->OrderedFilterList());
+  return event_params;
+}
+
+}  // namespace
+
 namespace net {
 
 URLRequestJob::URLRequestJob(URLRequest* request,
@@ -424,6 +437,10 @@
     request_->GetResponseHeaderByName("content-length", &content_length);
     if (!content_length.empty())
       base::StringToInt64(content_length, &expected_content_size_);
+  } else {
+    request_->net_log().AddEvent(
+        NetLog::TYPE_URL_REQUEST_FILTERS_SET,
+        base::Bind(&FiltersSetCallback, base::Unretained(filter_.get())));
   }
 
   // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
diff --git a/net/websockets/websocket_stream.cc b/net/websockets/websocket_stream.cc
index 005b6c5..c0d0c4c 100644
--- a/net/websockets/websocket_stream.cc
+++ b/net/websockets/websocket_stream.cc
@@ -8,6 +8,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram.h"
 #include "base/metrics/sparse_histogram.h"
+#include "base/profiler/scoped_tracker.h"
 #include "base/time/time.h"
 #include "base/timer/timer.h"
 #include "net/base/load_flags.h"
@@ -222,6 +223,10 @@
 };
 
 void Delegate::OnResponseStarted(URLRequest* request) {
+  // TODO(vadimt): Remove ScopedTracker below once crbug.com/423948 is fixed.
+  tracked_objects::ScopedTracker tracking_profile(
+      FROM_HERE_WITH_EXPLICIT_FUNCTION("423948 Delegate::OnResponseStarted"));
+
   // All error codes, including OK and ABORTED, as with
   // Net.ErrorCodesForMainFrame3
   UMA_HISTOGRAM_SPARSE_SLOWLY("Net.WebSocket.ErrorCodes",
diff --git a/skia/BUILD.gn b/skia/BUILD.gn
index 7daabd4..2751977 100644
--- a/skia/BUILD.gn
+++ b/skia/BUILD.gn
@@ -308,7 +308,6 @@
   sources += gypi_skia_core.sources
   sources += gypi_skia_effects.sources
   sources += gypi_skia_utils.sources
-  sources += gypi_skia_pdf.sources
   sources += gypi_values.skia_library_sources
 
   if (cpu_arch == "arm") {
@@ -343,7 +342,6 @@
   "//third_party/skia/include/utils/SkParsePaint.h",
   "//third_party/skia/include/utils/SkParsePath.h",
   "//third_party/skia/include/utils/SkRandom.h",
-  "//third_party/skia/include/utils/SkWGL.h",
 
   "//third_party/skia/src/utils/SkBitmapHasher.cpp",
   "//third_party/skia/src/utils/SkBitmapHasher.h",
@@ -548,6 +546,7 @@
 
   if (skia_support_pdf) {
     deps += [ "//third_party/sfntly" ]
+    sources += gypi_skia_pdf.sources
   }
 
   if (is_android && !is_debug) {
diff --git a/skia/skia_library.gypi b/skia/skia_library.gypi
index 6879cfc..46259e5 100644
--- a/skia/skia_library.gypi
+++ b/skia/skia_library.gypi
@@ -105,7 +105,6 @@
   '../third_party/skia/include/utils/SkParsePaint.h',
   '../third_party/skia/include/utils/SkParsePath.h',
   '../third_party/skia/include/utils/SkRandom.h',
-  '../third_party/skia/include/utils/SkWGL.h',
 
   '../third_party/skia/src/utils/SkBitmapHasher.cpp',
   '../third_party/skia/src/utils/SkBitmapHasher.h',
@@ -189,7 +188,8 @@
     }],
     ['skia_support_pdf == 0', {
       'sources/': [
-        ['exclude', '../third_party/skia/src/pdf/']
+        ['exclude', '../third_party/skia/src/doc/SkDocument_PDF.cpp'],
+        ['exclude', '../third_party/skia/src/pdf/'],
       ],
     }],
     ['skia_support_pdf == 1', {
diff --git a/sky/viewer/cc/web_content_layer_impl.cc b/sky/viewer/cc/web_content_layer_impl.cc
index 0369b72..261d3a0 100644
--- a/sky/viewer/cc/web_content_layer_impl.cc
+++ b/sky/viewer/cc/web_content_layer_impl.cc
@@ -19,13 +19,12 @@
 namespace sky_viewer_cc {
 
 WebContentLayerImpl::WebContentLayerImpl(blink::WebContentLayerClient* client)
-    : client_(client), ignore_lcd_text_change_(false) {
+    : client_(client) {
   if (WebLayerImpl::UsingPictureLayer())
     layer_ = make_scoped_ptr(new WebLayerImpl(PictureLayer::Create(this)));
   else
     layer_ = make_scoped_ptr(new WebLayerImpl(ContentLayer::Create(this)));
   layer_->layer()->SetIsDrawable(true);
-  can_use_lcd_text_ = layer_->layer()->can_use_lcd_text();
 }
 
 WebContentLayerImpl::~WebContentLayerImpl() {
@@ -55,31 +54,14 @@
     return;
 
   blink::WebFloatRect web_opaque;
+  bool can_use_lcd_text = false;
   client_->paintContents(
-      canvas,
-      clip,
-      can_use_lcd_text_,
-      web_opaque,
+      canvas, clip, can_use_lcd_text, web_opaque,
       graphics_context_status == ContentLayerClient::GRAPHICS_CONTEXT_ENABLED
           ? blink::WebContentLayerClient::GraphicsContextEnabled
           : blink::WebContentLayerClient::GraphicsContextDisabled);
 }
 
-void WebContentLayerImpl::DidChangeLayerCanUseLCDText() {
-  // It is important to make this comparison because the LCD text status
-  // here can get out of sync with that in the layer.
-  if (can_use_lcd_text_ == layer_->layer()->can_use_lcd_text())
-    return;
-
-  // LCD text cannot be enabled once disabled.
-  if (layer_->layer()->can_use_lcd_text() && ignore_lcd_text_change_)
-    return;
-
-  can_use_lcd_text_ = layer_->layer()->can_use_lcd_text();
-  ignore_lcd_text_change_ = true;
-  layer_->invalidate();
-}
-
 bool WebContentLayerImpl::FillsBoundsCompletely() const {
   return false;
 }
diff --git a/sky/viewer/cc/web_content_layer_impl.h b/sky/viewer/cc/web_content_layer_impl.h
index 8957098..d18446f 100644
--- a/sky/viewer/cc/web_content_layer_impl.h
+++ b/sky/viewer/cc/web_content_layer_impl.h
@@ -40,7 +40,6 @@
                              const gfx::Rect& clip,
                              ContentLayerClient::GraphicsContextStatus
                                  graphics_context_status) override;
-  virtual void DidChangeLayerCanUseLCDText() override;
   virtual bool FillsBoundsCompletely() const override;
 
   scoped_ptr<WebLayerImpl> layer_;
@@ -48,8 +47,6 @@
   bool draws_content_;
 
  private:
-  bool can_use_lcd_text_;
-  bool ignore_lcd_text_change_;
 
   DISALLOW_COPY_AND_ASSIGN(WebContentLayerImpl);
 };
diff --git a/sky/viewer/cc/web_filter_animation_curve_impl.cc b/sky/viewer/cc/web_filter_animation_curve_impl.cc
index 6b323b2..560ca16 100644
--- a/sky/viewer/cc/web_filter_animation_curve_impl.cc
+++ b/sky/viewer/cc/web_filter_animation_curve_impl.cc
@@ -32,7 +32,8 @@
       static_cast<const WebFilterOperationsImpl&>(keyframe.value())
           .AsFilterOperations();
   curve_->AddKeyframe(cc::FilterKeyframe::Create(
-      keyframe.time(), filter_operations, CreateTimingFunction(type)));
+      base::TimeDelta::FromSecondsD(keyframe.time()), filter_operations,
+      CreateTimingFunction(type)));
 }
 
 void WebFilterAnimationCurveImpl::add(const WebFilterKeyframe& keyframe,
@@ -44,8 +45,7 @@
       static_cast<const WebFilterOperationsImpl&>(keyframe.value())
           .AsFilterOperations();
   curve_->AddKeyframe(cc::FilterKeyframe::Create(
-      keyframe.time(),
-      filter_operations,
+      base::TimeDelta::FromSecondsD(keyframe.time()), filter_operations,
       cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2).Pass()));
 }
 
diff --git a/sky/viewer/cc/web_float_animation_curve_impl.cc b/sky/viewer/cc/web_float_animation_curve_impl.cc
index 2812471..f39f881 100644
--- a/sky/viewer/cc/web_float_animation_curve_impl.cc
+++ b/sky/viewer/cc/web_float_animation_curve_impl.cc
@@ -31,8 +31,9 @@
 
 void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
                                      TimingFunctionType type) {
-  curve_->AddKeyframe(cc::FloatKeyframe::Create(
-      keyframe.time, keyframe.value, CreateTimingFunction(type)));
+  curve_->AddKeyframe(
+      cc::FloatKeyframe::Create(base::TimeDelta::FromSecondsD(keyframe.time),
+                                keyframe.value, CreateTimingFunction(type)));
 }
 
 void WebFloatAnimationCurveImpl::add(const WebFloatKeyframe& keyframe,
@@ -41,13 +42,12 @@
                                      double x2,
                                      double y2) {
   curve_->AddKeyframe(cc::FloatKeyframe::Create(
-      keyframe.time,
-      keyframe.value,
+      base::TimeDelta::FromSecondsD(keyframe.time), keyframe.value,
       cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2).Pass()));
 }
 
 float WebFloatAnimationCurveImpl::getValue(double time) const {
-  return curve_->GetValue(time);
+  return curve_->GetValue(base::TimeDelta::FromSecondsD(time));
 }
 
 scoped_ptr<cc::AnimationCurve>
diff --git a/sky/viewer/cc/web_transform_animation_curve_impl.cc b/sky/viewer/cc/web_transform_animation_curve_impl.cc
index 11e69ae..0ad02a7 100644
--- a/sky/viewer/cc/web_transform_animation_curve_impl.cc
+++ b/sky/viewer/cc/web_transform_animation_curve_impl.cc
@@ -36,7 +36,8 @@
       static_cast<const WebTransformOperationsImpl&>(keyframe.value())
           .AsTransformOperations();
   curve_->AddKeyframe(cc::TransformKeyframe::Create(
-      keyframe.time(), transform_operations, CreateTimingFunction(type)));
+      base::TimeDelta::FromSecondsD(keyframe.time()), transform_operations,
+      CreateTimingFunction(type)));
 }
 
 void WebTransformAnimationCurveImpl::add(const WebTransformKeyframe& keyframe,
@@ -48,8 +49,7 @@
       static_cast<const WebTransformOperationsImpl&>(keyframe.value())
           .AsTransformOperations();
   curve_->AddKeyframe(cc::TransformKeyframe::Create(
-      keyframe.time(),
-      transform_operations,
+      base::TimeDelta::FromSecondsD(keyframe.time()), transform_operations,
       cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2).Pass()));
 }
 
diff --git a/third_party/zlib/BUILD.gn b/third_party/zlib/BUILD.gn
index d07fd9a..810fbb7 100644
--- a/third_party/zlib/BUILD.gn
+++ b/third_party/zlib/BUILD.gn
@@ -7,9 +7,11 @@
 }
 
 static_library("zlib_x86_simd") {
-  if (!is_win && (cpu_arch == "x86" || cpu_arch == "x64")) {
+  if (!is_ios && (cpu_arch == "x86" || cpu_arch == "x64")) {
     sources = [ "crc_folding.c", "fill_window_sse.c" ]
-    cflags = [ "-msse2", "-msse4.2", "-mpclmul" ]
+    if (!is_win || is_clang) {
+      cflags = [ "-msse4.2", "-mpclmul" ]
+    }
   } else {
     sources = [ "simd_stub.c"]
   }
diff --git a/third_party/zlib/zlib.gyp b/third_party/zlib/zlib.gyp
index 22a48a3..bb478ce 100644
--- a/third_party/zlib/zlib.gyp
+++ b/third_party/zlib/zlib.gyp
@@ -9,15 +9,27 @@
       'type': 'static_library',
       'conditions': [
         ['OS!="ios" and (target_arch=="ia32" or target_arch=="x64")', {
-          'cflags' : ["-msse2", "-msse4.2", "-mpclmul"],
+          'cflags' : ['-msse4.2', '-mpclmul'],
           'xcode_settings' : {
-             'OTHER_CFLAGS' : ["-msse4.2", "-mpclmul"],
+             'OTHER_CFLAGS' : ['-msse4.2', '-mpclmul'],
           },
-          'sources' : [ 'crc_folding.c',
-                        'fill_window_sse.c']
+          'sources' : [
+            'crc_folding.c',
+            'fill_window_sse.c',
+          ],
+          'conditions': [
+            ['OS=="win" and clang==1', {
+              'msvs_settings': {
+                'VCCLCompilerTool': {
+                  'AdditionalOptions': [ '-msse4.2', '-mpclmul' ],
+                },
+              },
+            }],
+          ],
         }, {
           'sources' : [ 'simd_stub.c' ],
-        }], ['OS=="android"', {
+        }],
+        ['OS=="android"', {
           'toolsets': ['target', 'host'],
         }],
       ],
diff --git a/tools/clang/scripts/package.sh b/tools/clang/scripts/package.sh
index afa43bd..f00abb4 100755
--- a/tools/clang/scripts/package.sh
+++ b/tools/clang/scripts/package.sh
@@ -73,6 +73,7 @@
 echo "Starting build" | tee -a buildlog.txt
 
 set -exu
+set -o pipefail
 
 # Do a clobber build.
 rm -rf "${LLVM_BOOTSTRAP_DIR}"
diff --git a/tools/clang/scripts/update.py b/tools/clang/scripts/update.py
index 25aa5a5..041087f 100755
--- a/tools/clang/scripts/update.py
+++ b/tools/clang/scripts/update.py
@@ -10,7 +10,9 @@
 import re
 import shutil
 import subprocess
+import stat
 import sys
+import time
 
 # Do NOT CHANGE this if you don't know what you're doing -- see
 # https://code.google.com/p/chromium/wiki/UpdatingClang
@@ -58,16 +60,16 @@
     f.write(s)
 
 
-def DeleteFiles(dir, pattern):
-  """Delete all files in dir matching pattern."""
-  n = 0
-  regex = re.compile(r'^' + pattern + r'$')
-  for root, _, files in os.walk(dir):
-    for f in files:
-      if regex.match(f):
-        os.remove(os.path.join(root, f))
-        n += 1
-  return n
+def RmTree(dir):
+  """Delete dir."""
+  def ChmodAndRetry(func, path, _):
+    # Subversion can leave read-only files around.
+    if not os.access(path, os.W_OK):
+      os.chmod(path, stat.S_IWUSR)
+      return func(path)
+    raise
+
+  shutil.rmtree(dir, onerror=ChmodAndRetry)
 
 
 def ClobberChromiumBuildFiles():
@@ -75,18 +77,21 @@
   print 'Clobbering Chromium build files...'
   out_dir = os.path.join(CHROMIUM_DIR, 'out')
   if os.path.isdir(out_dir):
-    shutil.rmtree(out_dir)
+    RmTree(out_dir)
     print 'Removed Chromium out dir: %s.' % (out_dir)
 
 
-def RunCommand(command, tries=1):
-  """Run a command, possibly with multiple retries."""
-  for i in range(0, tries):
-    print 'Running %s (try #%d)' % (str(command), i + 1)
-    if subprocess.call(command, shell=True) == 0:
-      return
-    print 'Failed.'
-  sys.exit(1)
+def RunCommand(command, fail_hard=True):
+  """Run command and return success (True) or failure; or if fail_hard is
+     True, exit on failure."""
+
+  print 'Running %s' % (str(command))
+  if subprocess.call(command, shell=True) == 0:
+    return True
+  print 'Failed.'
+  if fail_hard:
+    sys.exit(1)
+  return False
 
 
 def CopyFile(src, dst):
@@ -110,8 +115,17 @@
 def Checkout(name, url, dir):
   """Checkout the SVN module at url into dir. Use name for the log message."""
   print "Checking out %s r%s into '%s'" % (name, LLVM_WIN_REVISION, dir)
-  RunCommand(['svn', 'checkout', '--force',
-              url + '@' + LLVM_WIN_REVISION, dir], tries=2)
+
+  command = ['svn', 'checkout', '--force', url + '@' + LLVM_WIN_REVISION, dir]
+  if RunCommand(command, fail_hard=False):
+    return
+
+  if os.path.isdir(dir):
+    print "Removing %s." % (dir)
+    RmTree(dir)
+
+  print "Retrying."
+  RunCommand(command)
 
 
 def AddCMakeToPath():
diff --git a/tools/valgrind/chrome_tests.py b/tools/valgrind/chrome_tests.py
index 27d554e..8f5432f 100755
--- a/tools/valgrind/chrome_tests.py
+++ b/tools/valgrind/chrome_tests.py
@@ -470,9 +470,6 @@
   def TestUIBaseUnit(self):
     return self.SimpleTest("chrome", "ui_base_unittests")
 
-  def TestUIUnit(self):
-    return self.SimpleTest("chrome", "ui_unittests")
-
   def TestURL(self):
     return self.SimpleTest("chrome", "url_unittests")
 
@@ -715,7 +712,6 @@
     "sync_integration_tests": TestSyncIntegration,
     "sync_integration": TestSyncIntegration,
     "ui_base_unit": TestUIBaseUnit,       "ui_base_unittests": TestUIBaseUnit,
-    "ui_unit": TestUIUnit,       "ui_unittests": TestUIUnit,
     "unit": TestUnit,            "unit_tests": TestUnit,
     "url": TestURL,              "url_unittests": TestURL,
     "views": TestViews,          "views_unittests": TestViews,
diff --git a/ui/compositor/float_animation_curve_adapter.cc b/ui/compositor/float_animation_curve_adapter.cc
index 3b5e155..d40d701 100644
--- a/ui/compositor/float_animation_curve_adapter.cc
+++ b/ui/compositor/float_animation_curve_adapter.cc
@@ -4,6 +4,8 @@
 
 #include "ui/compositor/float_animation_curve_adapter.h"
 
+#include "cc/base/time_util.h"
+
 namespace ui {
 
 FloatAnimationCurveAdapter::FloatAnimationCurveAdapter(
@@ -26,12 +28,12 @@
       tween_type_, initial_value_, target_value_, duration_));
 }
 
-float FloatAnimationCurveAdapter::GetValue(double t) const {
-  if (t >= duration_.InSecondsF())
+float FloatAnimationCurveAdapter::GetValue(base::TimeDelta t) const {
+  if (t >= duration_)
     return target_value_;
-  if (t <= 0.0)
+  if (t <= base::TimeDelta())
     return initial_value_;
-  double progress = t / duration_.InSecondsF();
+  double progress = cc::TimeUtil::Divide(t, duration_);
   return gfx::Tween::FloatValueBetween(
       gfx::Tween::CalculateValue(tween_type_, progress),
       initial_value_,
diff --git a/ui/compositor/float_animation_curve_adapter.h b/ui/compositor/float_animation_curve_adapter.h
index 88d5870..dc665d4 100644
--- a/ui/compositor/float_animation_curve_adapter.h
+++ b/ui/compositor/float_animation_curve_adapter.h
@@ -23,7 +23,7 @@
   // FloatAnimationCurve implementation.
   base::TimeDelta Duration() const override;
   scoped_ptr<cc::AnimationCurve> Clone() const override;
-  float GetValue(double t) const override;
+  float GetValue(base::TimeDelta t) const override;
 
  private:
   gfx::Tween::Type tween_type_;
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 74781d1..eb4628d 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -333,7 +333,6 @@
       SkCanvas* canvas,
       const gfx::Rect& clip,
       ContentLayerClient::GraphicsContextStatus gc_status) override;
-  void DidChangeLayerCanUseLCDText() override {}
   bool FillsBoundsCompletely() const override;
 
   cc::Layer* cc_layer() { return cc_layer_; }
diff --git a/ui/compositor/transform_animation_curve_adapter.cc b/ui/compositor/transform_animation_curve_adapter.cc
index 2c11488..1b67ca2 100644
--- a/ui/compositor/transform_animation_curve_adapter.cc
+++ b/ui/compositor/transform_animation_curve_adapter.cc
@@ -4,6 +4,8 @@
 
 #include "ui/compositor/transform_animation_curve_adapter.h"
 
+#include "cc/base/time_util.h"
+
 namespace ui {
 
 TransformAnimationCurveAdapter::TransformAnimationCurveAdapter(
@@ -32,12 +34,12 @@
 }
 
 gfx::Transform TransformAnimationCurveAdapter::GetValue(
-    double t) const {
-  if (t >= duration_.InSecondsF())
+    base::TimeDelta t) const {
+  if (t >= duration_)
     return target_value_;
-  if (t <= 0.0)
+  if (t <= base::TimeDelta())
     return initial_value_;
-  double progress = t / duration_.InSecondsF();
+  double progress = cc::TimeUtil::Divide(t, duration_);
 
   gfx::DecomposedTransform to_return;
   gfx::BlendDecomposedTransforms(&to_return,
@@ -80,7 +82,8 @@
     : base_curve_(base_curve),
       initial_value_(initial_value),
       duration_(duration) {
-  effective_initial_value_ = base_curve_.GetValue(0.0) * initial_value_;
+  effective_initial_value_ =
+      base_curve_.GetValue(base::TimeDelta()) * initial_value_;
 }
 
 InverseTransformCurveAdapter::~InverseTransformCurveAdapter() {
@@ -95,9 +98,8 @@
       new InverseTransformCurveAdapter(base_curve_, initial_value_, duration_));
 }
 
-gfx::Transform InverseTransformCurveAdapter::GetValue(
-    double t) const {
-  if (t <= 0.0)
+gfx::Transform InverseTransformCurveAdapter::GetValue(base::TimeDelta t) const {
+  if (t <= base::TimeDelta())
     return initial_value_;
 
   gfx::Transform base_transform = base_curve_.GetValue(t);
diff --git a/ui/compositor/transform_animation_curve_adapter.h b/ui/compositor/transform_animation_curve_adapter.h
index c08024d..5bbe6a3 100644
--- a/ui/compositor/transform_animation_curve_adapter.h
+++ b/ui/compositor/transform_animation_curve_adapter.h
@@ -27,7 +27,7 @@
   // TransformAnimationCurve implementation.
   base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
-  gfx::Transform GetValue(double t) const override;
+  gfx::Transform GetValue(base::TimeDelta t) const override;
   bool AnimatedBoundsForBox(const gfx::BoxF& box,
                             gfx::BoxF* bounds) const override;
   bool AffectsScale() const override;
@@ -57,7 +57,7 @@
 
   base::TimeDelta Duration() const override;
   scoped_ptr<AnimationCurve> Clone() const override;
-  gfx::Transform GetValue(double t) const override;
+  gfx::Transform GetValue(base::TimeDelta t) const override;
   bool AnimatedBoundsForBox(const gfx::BoxF& box,
                             gfx::BoxF* bounds) const override;
   bool AffectsScale() const override;