diff --git a/DEPS b/DEPS
index 1011036..985ea54 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '7ea33f5e1ae9eb1fb1e7377d6edf6acdcf71d103',
+  'skia_revision': '5931922997b8904b1243240120014c016064b9fa',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '88d3129d9b98d5cfb94655d622f6505291d87cb4',
+  'v8_revision': 'fcdcfb5615f8af96516156abe920e0dcbf64b565',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/cc/output/shader.cc b/cc/output/shader.cc
index f356c7c8..de1ddd4 100644
--- a/cc/output/shader.cc
+++ b/cc/output/shader.cc
@@ -2105,15 +2105,8 @@
                                    unsigned program,
                                    int* base_uniform_index) {
   static const char* uniforms[] = {
-      "y_texture",
-      "u_texture",
-      "v_texture",
-      "a_texture",
-      "alpha",
-      "cc_matrix",
-      "yuv_adj",
-      "ya_clamp_rect",
-      "uv_clamp_rect",
+      "y_texture",  "u_texture", "v_texture",     "a_texture",     "alpha",
+      "yuv_matrix", "yuv_adj",   "ya_clamp_rect", "uv_clamp_rect",
   };
   int locations[arraysize(uniforms)];
 
diff --git a/chrome/VERSION b/chrome/VERSION
index 3246460..00b5e795 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=49
 MINOR=0
-BUILD=2572
+BUILD=2573
 PATCH=0
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 0b99f9b..189065b 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-7664.0.0
\ No newline at end of file
+7666.0.0
\ No newline at end of file
diff --git a/components/scheduler/base/real_time_domain.cc b/components/scheduler/base/real_time_domain.cc
index 8a57a041..c3b4505 100644
--- a/components/scheduler/base/real_time_domain.cc
+++ b/components/scheduler/base/real_time_domain.cc
@@ -10,29 +10,59 @@
 
 namespace scheduler {
 
-RealTimeDomain::RealTimeDomain(
-    TaskQueueManagerDelegate* task_queue_manager_delegate,
-    base::Closure do_work_closure)
-    : task_queue_manager_delegate_(task_queue_manager_delegate),
-      do_work_closure_(do_work_closure) {
-  DCHECK(task_queue_manager_delegate_);
-}
+RealTimeDomain::RealTimeDomain() : weak_factory_(this) {}
 
 RealTimeDomain::~RealTimeDomain() {}
 
+void RealTimeDomain::OnRegisterWithTaskQueueManager(
+    TaskQueueManagerDelegate* task_queue_manager_delegate,
+    base::Closure do_work_closure) {
+  task_queue_manager_delegate_ = task_queue_manager_delegate;
+  do_work_closure_ = do_work_closure;
+  DCHECK(task_queue_manager_delegate_);
+}
+
 LazyNow RealTimeDomain::CreateLazyNow() {
+  DCHECK(task_queue_manager_delegate_);
   return LazyNow(task_queue_manager_delegate_);
 }
 
-void RealTimeDomain::RequestWakeup(base::TimeDelta delay) {
-  task_queue_manager_delegate_->PostDelayedTask(FROM_HERE, do_work_closure_,
-                                                delay);
+void RealTimeDomain::RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) {
+  PostWrappedDoWork(lazy_now->Now(), lazy_now->Now() + delay);
 }
 
 bool RealTimeDomain::MaybeAdvanceTime() {
+  base::TimeTicks next_run_time;
+  if (!NextScheduledRunTime(&next_run_time))
+    return false;
+
+  DCHECK(task_queue_manager_delegate_);
+  base::TimeTicks now = task_queue_manager_delegate_->NowTicks();
+  if (now >= next_run_time)
+    return true;
+
+  PostWrappedDoWork(now, next_run_time);
   return false;
 }
 
+void RealTimeDomain::PostWrappedDoWork(base::TimeTicks now,
+                                       base::TimeTicks run_time) {
+  DCHECK_GE(run_time, now);
+  DCHECK(task_queue_manager_delegate_);
+  if (pending_wakeups_.insert(run_time).second) {
+    task_queue_manager_delegate_->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&RealTimeDomain::WrappedDoWorkTask,
+                   weak_factory_.GetWeakPtr(), run_time),
+        run_time - now);
+  }
+}
+
+void RealTimeDomain::WrappedDoWorkTask(base::TimeTicks run_time) {
+  pending_wakeups_.erase(run_time);
+  do_work_closure_.Run();
+}
+
 void RealTimeDomain::AsValueIntoInternal(
     base::trace_event::TracedValue* state) const {}
 
diff --git a/components/scheduler/base/real_time_domain.h b/components/scheduler/base/real_time_domain.h
index f4f9ba8..f382fad 100644
--- a/components/scheduler/base/real_time_domain.h
+++ b/components/scheduler/base/real_time_domain.h
@@ -5,7 +5,8 @@
 #ifndef COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
 #define COMPONENTS_SCHEDULER_BASE_REAL_TIME_DOMAIN_H_
 
-#include "base/callback.h"
+#include <set>
+
 #include "base/macros.h"
 #include "components/scheduler/base/time_domain.h"
 #include "components/scheduler/scheduler_export.h"
@@ -15,8 +16,7 @@
 
 class SCHEDULER_EXPORT RealTimeDomain : public TimeDomain {
  public:
-  RealTimeDomain(TaskQueueManagerDelegate* task_queue_manager_delegate,
-                 base::Closure do_work_closure);
+  RealTimeDomain();
 
   // TimeDomain implementation:
   LazyNow CreateLazyNow() override;
@@ -24,13 +24,21 @@
   const char* GetName() const override;
 
  protected:
-  void RequestWakeup(base::TimeDelta delay) override;
+  void OnRegisterWithTaskQueueManager(
+      TaskQueueManagerDelegate* task_queue_manager_delegate,
+      base::Closure do_work_closure) override;
+  void RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) override;
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override;
 
  private:
+  void PostWrappedDoWork(base::TimeTicks now, base::TimeTicks run_time);
+  void WrappedDoWorkTask(base::TimeTicks run_time);
+
   TaskQueueManagerDelegate* task_queue_manager_delegate_;  // NOT OWNED
+  std::set<base::TimeTicks> pending_wakeups_;
   base::Closure do_work_closure_;
+  base::WeakPtrFactory<RealTimeDomain> weak_factory_;
 
   ~RealTimeDomain() override;
 
diff --git a/components/scheduler/base/task_queue_impl.cc b/components/scheduler/base/task_queue_impl.cc
index a09e84d..0ad965b 100644
--- a/components/scheduler/base/task_queue_impl.cc
+++ b/components/scheduler/base/task_queue_impl.cc
@@ -325,10 +325,6 @@
     return;
   if (any_thread().incoming_queue.empty())
     any_thread().time_domain->RegisterAsUpdatableTaskQueue(this);
-  if (any_thread().pump_policy == PumpPolicy::AUTO &&
-      any_thread().incoming_queue.empty()) {
-    any_thread().task_queue_manager->MaybePostDoWorkOnMainRunner();
-  }
   // TODO(alexclarke): consider std::move() when allowed.
   any_thread().incoming_queue.push(pending_task);
   any_thread().incoming_queue.back().set_enqueue_order(
diff --git a/components/scheduler/base/task_queue_manager.cc b/components/scheduler/base/task_queue_manager.cc
index 4a3602e..b9df8756 100644
--- a/components/scheduler/base/task_queue_manager.cc
+++ b/components/scheduler/base/task_queue_manager.cc
@@ -43,8 +43,8 @@
   do_work_closure_ =
       base::Bind(&TaskQueueManager::DoWork, weak_factory_.GetWeakPtr(), false);
 
-  real_time_domain_ =
-      make_scoped_refptr(new RealTimeDomain(delegate.get(), do_work_closure_));
+  // TODO(alexclarke): Change this to be a parameter that's passed in.
+  real_time_domain_ = make_scoped_refptr(new RealTimeDomain());
   RegisterTimeDomain(real_time_domain_);
 }
 
@@ -61,6 +61,8 @@
 void TaskQueueManager::RegisterTimeDomain(
     const scoped_refptr<TimeDomain>& time_domain) {
   time_domains_.insert(time_domain);
+  time_domain->OnRegisterWithTaskQueueManager(delegate_.get(),
+                                              do_work_closure_);
 }
 
 void TaskQueueManager::UnregisterTimeDomain(
diff --git a/components/scheduler/base/task_queue_manager_unittest.cc b/components/scheduler/base/task_queue_manager_unittest.cc
index d5ad8e5..251ac56 100644
--- a/components/scheduler/base/task_queue_manager_unittest.cc
+++ b/components/scheduler/base/task_queue_manager_unittest.cc
@@ -1458,4 +1458,28 @@
   manager_->UnregisterTimeDomain(domain_b);
 }
 
+namespace {
+void ChromiumRunloopInspectionTask(
+    scoped_refptr<cc::OrderedSimpleTaskRunner> test_task_runner) {
+  EXPECT_EQ(1u, test_task_runner->NumPendingTasks());
+}
+}  // namespace
+
+TEST_F(TaskQueueManagerTest, NumberOfPendingTasksOnChromiumRunLoop) {
+  Initialize(1u);
+
+  // NOTE because tasks posted to the chromiumrun loop are not cancellable, we
+  // will end up with a lot more tasks posted if the delayed tasks were posted
+  // in the reverse order.
+  // TODO(alexclarke): Consider talking to the message pump directly.
+  test_task_runner_->SetAutoAdvanceNowToPendingTasks(true);
+  for (int i = 1; i < 100; i++) {
+    runners_[0]->PostDelayedTask(
+        FROM_HERE,
+        base::Bind(&ChromiumRunloopInspectionTask, test_task_runner_),
+        base::TimeDelta::FromMilliseconds(i));
+  }
+  test_task_runner_->RunUntilIdle();
+}
+
 }  // namespace scheduler
diff --git a/components/scheduler/base/time_domain.cc b/components/scheduler/base/time_domain.cc
index 825812e..2abfb52 100644
--- a/components/scheduler/base/time_domain.cc
+++ b/components/scheduler/base/time_domain.cc
@@ -12,7 +12,7 @@
 
 namespace scheduler {
 
-TimeDomain::TimeDomain() : weak_factory_(this) {}
+TimeDomain::TimeDomain() {}
 
 TimeDomain::~TimeDomain() {}
 
@@ -31,7 +31,7 @@
     }
   }
 
-  // |newly_updatable_| might contain |task_queue|, we use
+  // |newly_updatable_| might contain |queue|, we use
   // MoveNewlyUpdatableQueuesIntoUpdatableQueueSet to flush it out.
   MoveNewlyUpdatableQueuesIntoUpdatableQueueSet();
   updatable_queue_set_.erase(queue);
@@ -66,12 +66,12 @@
                                      base::TimeTicks delayed_run_time,
                                      LazyNow* lazy_now) {
   DCHECK(main_thread_checker_.CalledOnValidThread());
-  // Dedupe wakeups.
-  if (delayed_wakeup_multimap_.find(delayed_run_time) ==
-      delayed_wakeup_multimap_.end()) {
+
+  if (delayed_wakeup_multimap_.empty() ||
+      delayed_run_time < delayed_wakeup_multimap_.begin()->first) {
     base::TimeDelta delay =
         std::max(base::TimeDelta(), delayed_run_time - lazy_now->Now());
-    RequestWakeup(delay);
+    RequestWakeup(lazy_now, delay);
   }
   delayed_wakeup_multimap_.insert(std::make_pair(delayed_run_time, queue));
 }
diff --git a/components/scheduler/base/time_domain.h b/components/scheduler/base/time_domain.h
index b01f05d9..476a68e 100644
--- a/components/scheduler/base/time_domain.h
+++ b/components/scheduler/base/time_domain.h
@@ -7,6 +7,7 @@
 
 #include <map>
 
+#include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -20,6 +21,7 @@
 class TaskQueueImpl;
 }  // internal
 class TaskQueueManager;
+class TaskQueueManagerDelegate;
 
 class SCHEDULER_EXPORT TimeDomain : public base::RefCounted<TimeDomain> {
  public:
@@ -79,9 +81,14 @@
   void UpdateWorkQueues(bool should_trigger_wakeup,
                         const internal::TaskQueueImpl::Task* previous_task);
 
+  // Called by the TaskQueueManager when the TimeDomain is registered.
+  virtual void OnRegisterWithTaskQueueManager(
+      TaskQueueManagerDelegate* task_queue_manager_delegate,
+      base::Closure do_work_closure) = 0;
+
   // The implementaion will secedule task processing to run with |delay| with
   // respect to the TimeDomain's time source.
-  virtual void RequestWakeup(base::TimeDelta delay) = 0;
+  virtual void RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) = 0;
 
   // For implementation specific tracing.
   virtual void AsValueIntoInternal(
@@ -109,7 +116,6 @@
   std::set<internal::TaskQueueImpl*> updatable_queue_set_;
 
   base::ThreadChecker main_thread_checker_;
-  base::WeakPtrFactory<TimeDomain> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TimeDomain);
 };
diff --git a/components/scheduler/base/time_domain_unittest.cc b/components/scheduler/base/time_domain_unittest.cc
index 75e5459..d41305a 100644
--- a/components/scheduler/base/time_domain_unittest.cc
+++ b/components/scheduler/base/time_domain_unittest.cc
@@ -13,6 +13,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 
 using testing::_;
+using testing::Mock;
 
 namespace scheduler {
 
@@ -34,10 +35,12 @@
       base::trace_event::TracedValue* state) const override {}
 
   bool MaybeAdvanceTime() override { return false; }
-
   const char* GetName() const override { return "Test"; }
+  void OnRegisterWithTaskQueueManager(
+      TaskQueueManagerDelegate* task_queue_manager_delegate,
+      base::Closure do_work_closure) override {}
 
-  MOCK_METHOD1(RequestWakeup, void(base::TimeDelta delay));
+  MOCK_METHOD2(RequestWakeup, void(LazyNow* lazy_now, base::TimeDelta delay));
 
   void SetNow(base::TimeTicks now) { now_ = now; }
 
@@ -67,7 +70,7 @@
 TEST_F(TimeDomainTest, ScheduleDelayedWork) {
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(10);
   base::TimeTicks delayed_runtime = time_domain_->Now() + delay;
-  EXPECT_CALL(*time_domain_.get(), RequestWakeup(delay));
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay));
   LazyNow lazy_now = time_domain_->CreateLazyNow();
   time_domain_->ScheduleDelayedWork(task_queue_.get(),
                                     time_domain_->Now() + delay, &lazy_now);
@@ -81,13 +84,41 @@
   EXPECT_EQ(task_queue_.get(), next_task_queue);
 }
 
+TEST_F(TimeDomainTest, RequestWakeup_OnlyCalledForEarlierTasks) {
+  base::TimeDelta delay1 = base::TimeDelta::FromMilliseconds(10);
+  base::TimeDelta delay2 = base::TimeDelta::FromMilliseconds(20);
+  base::TimeDelta delay3 = base::TimeDelta::FromMilliseconds(30);
+  base::TimeDelta delay4 = base::TimeDelta::FromMilliseconds(1);
+
+  // RequestWakeup should always be called if there are no other wakeups.
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay1));
+  LazyNow lazy_now = time_domain_->CreateLazyNow();
+  time_domain_->ScheduleDelayedWork(task_queue_.get(),
+                                    time_domain_->Now() + delay1, &lazy_now);
+
+  Mock::VerifyAndClearExpectations(time_domain_.get());
+
+  // RequestWakeup should not be called when scheduling later tasks.
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(0);
+  time_domain_->ScheduleDelayedWork(task_queue_.get(),
+                                    time_domain_->Now() + delay2, &lazy_now);
+  time_domain_->ScheduleDelayedWork(task_queue_.get(),
+                                    time_domain_->Now() + delay3, &lazy_now);
+
+  // RequestWakeup should be called when scheduling earlier tasks.
+  Mock::VerifyAndClearExpectations(time_domain_.get());
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay4));
+  time_domain_->ScheduleDelayedWork(task_queue_.get(),
+                                    time_domain_->Now() + delay4, &lazy_now);
+}
+
 TEST_F(TimeDomainTest, UnregisterQueue) {
   scoped_refptr<internal::TaskQueueImpl> task_queue2_ =
       make_scoped_refptr(new internal::TaskQueueImpl(
           nullptr, time_domain_, TaskQueue::Spec("test_queue2"),
           "test.category", "test.category"));
 
-  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_)).Times(2);
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, _)).Times(1);
   LazyNow lazy_now = time_domain_->CreateLazyNow();
   time_domain_->ScheduleDelayedWork(
       task_queue_.get(),
@@ -132,7 +163,7 @@
   // MoveReadyDelayedTasksToIncomingQueue as expected.
   base::TimeDelta delay = base::TimeDelta::FromMilliseconds(50);
   base::TimeTicks delayed_runtime = time_domain_->Now() + delay;
-  EXPECT_CALL(*time_domain_.get(), RequestWakeup(delay));
+  EXPECT_CALL(*time_domain_.get(), RequestWakeup(_, delay));
   LazyNow lazy_now = time_domain_->CreateLazyNow();
   time_domain_->ScheduleDelayedWork(dummy_queue.get(), delayed_runtime,
                                     &lazy_now);
diff --git a/components/scheduler/base/virtual_time_domain.cc b/components/scheduler/base/virtual_time_domain.cc
index fdd997c..3251039 100644
--- a/components/scheduler/base/virtual_time_domain.cc
+++ b/components/scheduler/base/virtual_time_domain.cc
@@ -15,13 +15,22 @@
 
 VirtualTimeDomain::~VirtualTimeDomain() {}
 
+void VirtualTimeDomain::OnRegisterWithTaskQueueManager(
+    TaskQueueManagerDelegate* task_queue_manager_delegate,
+    base::Closure do_work_closure) {
+  task_queue_manager_delegate_ = task_queue_manager_delegate;
+  do_work_closure_ = do_work_closure;
+  DCHECK(task_queue_manager_delegate_);
+}
+
 LazyNow VirtualTimeDomain::CreateLazyNow() {
   base::AutoLock lock(lock_);
   return LazyNow(now_);
 }
 
-void VirtualTimeDomain::RequestWakeup(base::TimeDelta delay) {
-  // We don't need to do anything here because AdvanceTo triggers delayed tasks.
+void VirtualTimeDomain::RequestWakeup(LazyNow* lazy_now,
+                                      base::TimeDelta delay) {
+  // We don't need to do anything here because AdvanceTo posts a DoWork.
 }
 
 bool VirtualTimeDomain::MaybeAdvanceTime() {
@@ -35,8 +44,7 @@
   base::AutoLock lock(lock_);
   DCHECK_GE(now, now_);
   now_ = now;
-  LazyNow lazy_now(now_);
-  WakeupReadyDelayedQueues(&lazy_now);
+  task_queue_manager_delegate_->PostTask(FROM_HERE, do_work_closure_);
 }
 
 const char* VirtualTimeDomain::GetName() const {
diff --git a/components/scheduler/base/virtual_time_domain.h b/components/scheduler/base/virtual_time_domain.h
index 2e38414..ce1f99a 100644
--- a/components/scheduler/base/virtual_time_domain.h
+++ b/components/scheduler/base/virtual_time_domain.h
@@ -27,7 +27,10 @@
   void AdvanceTo(base::TimeTicks now);
 
  protected:
-  void RequestWakeup(base::TimeDelta delay) override;
+  void OnRegisterWithTaskQueueManager(
+      TaskQueueManagerDelegate* task_queue_manager_delegate,
+      base::Closure do_work_closure) override;
+  void RequestWakeup(LazyNow* lazy_now, base::TimeDelta delay) override;
   void AsValueIntoInternal(
       base::trace_event::TracedValue* state) const override;
 
@@ -35,6 +38,9 @@
   mutable base::Lock lock_;  // Protects |now_|.
   base::TimeTicks now_;
 
+  TaskQueueManagerDelegate* task_queue_manager_delegate_;  // NOT OWNED
+  base::Closure do_work_closure_;
+
   ~VirtualTimeDomain() override;
 
   DISALLOW_COPY_AND_ASSIGN(VirtualTimeDomain);
diff --git a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt
index ef4e662..eb2f272 100644
--- a/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt
+++ b/gpu/GLES2/extensions/CHROMIUM/CHROMIUM_bind_uniform_location.txt
@@ -104,7 +104,8 @@
     to a program object.  Hence it is allowed to bind any name (except a name
     starting with "gl_") to an index, including a name that is never used as a
     uniform in any shader object.  Assigned bindings for uniform variables
-    that do not exist or are not active are ignored.
+    that do not exist or are not active are ignored. Using such bindings
+    behaves as if passed location was -1.
 
     It is possible for an application to bind more than one uniform name to
     the same location.  This is referred to as aliasing.  This will only work
@@ -126,4 +127,7 @@
     7/20/2012    Documented the extension
     9/8/2015     Require program link to fail if two statically used uniforms
                  are bound to the same location.
+    11/6/2015    Require inactive and non-existing, bound uniform locations
+                 to behave like location -1.
+
 
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index 7f13556..4b870d3 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -603,16 +603,6 @@
       'GL_RENDERBUFFER',
     ],
   },
-  'InvalidateFrameBufferTarget': {
-    'type': 'GLenum',
-    'valid': [
-      'GL_FRAMEBUFFER',
-    ],
-    'invalid': [
-      'GL_DRAW_FRAMEBUFFER' ,
-      'GL_READ_FRAMEBUFFER' ,
-    ],
-  },
   'RenderBufferTarget': {
     'type': 'GLenum',
     'valid': [
diff --git a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
index 0fa8726..d6cac7e 100644
--- a/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_impl_autogen.h
@@ -1472,9 +1472,9 @@
                                                 const GLenum* attachments) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInvalidateFramebuffer("
-                     << GLES2Util::GetStringInvalidateFrameBufferTarget(target)
-                     << ", " << count << ", "
-                     << static_cast<const void*>(attachments) << ")");
+                     << GLES2Util::GetStringFrameBufferTarget(target) << ", "
+                     << count << ", " << static_cast<const void*>(attachments)
+                     << ")");
   GPU_CLIENT_LOG_CODE_BLOCK({
     for (GLsizei i = 0; i < count; ++i) {
       GPU_CLIENT_LOG("  " << i << ": " << attachments[0 + i * 1]);
@@ -1497,10 +1497,10 @@
                                                    GLsizei height) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
   GPU_CLIENT_LOG("[" << GetLogPrefix() << "] glInvalidateSubFramebuffer("
-                     << GLES2Util::GetStringInvalidateFrameBufferTarget(target)
-                     << ", " << count << ", "
-                     << static_cast<const void*>(attachments) << ", " << x
-                     << ", " << y << ", " << width << ", " << height << ")");
+                     << GLES2Util::GetStringFrameBufferTarget(target) << ", "
+                     << count << ", " << static_cast<const void*>(attachments)
+                     << ", " << x << ", " << y << ", " << width << ", "
+                     << height << ")");
   GPU_CLIENT_LOG_CODE_BLOCK({
     for (GLsizei i = 0; i < count; ++i) {
       GPU_CLIENT_LOG("  " << i << ": " << attachments[0 + i * 1]);
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index e31f1a8..0457731 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -124,8 +124,8 @@
 GL_APICALL void         GL_APIENTRY glGetVertexAttribIuiv (GLuint index, GLenumVertexAttribute pname, GLuint* params);
 GL_APICALL void         GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenumVertexPointer pname, void** pointer);
 GL_APICALL void         GL_APIENTRY glHint (GLenumHintTarget target, GLenumHintMode mode);
-GL_APICALL void         GL_APIENTRY glInvalidateFramebuffer (GLenumInvalidateFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments);
-GL_APICALL void         GL_APIENTRY glInvalidateSubFramebuffer (GLenumInvalidateFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+GL_APICALL void         GL_APIENTRY glInvalidateFramebuffer (GLenumFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments);
+GL_APICALL void         GL_APIENTRY glInvalidateSubFramebuffer (GLenumFrameBufferTarget target, GLsizeiNotNegative count, const GLenum* attachments, GLint x, GLint y, GLsizei width, GLsizei height);
 GL_APICALL GLboolean    GL_APIENTRY glIsBuffer (GLidBuffer buffer);
 GL_APICALL GLboolean    GL_APIENTRY glIsEnabled (GLenumCapability cap);
 GL_APICALL GLboolean    GL_APIENTRY glIsFramebuffer (GLidFramebuffer framebuffer);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
index e37d8c5d..fc26129 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_autogen.h
@@ -44,7 +44,6 @@
 static std::string GetStringIndexedBufferTarget(uint32_t value);
 static std::string GetStringIndexedGLState(uint32_t value);
 static std::string GetStringInternalFormatParameter(uint32_t value);
-static std::string GetStringInvalidateFrameBufferTarget(uint32_t value);
 static std::string GetStringMapBufferAccess(uint32_t value);
 static std::string GetStringMatrixMode(uint32_t value);
 static std::string GetStringPathCoordType(uint32_t value);
diff --git a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
index 169a8bb..411d7b4 100644
--- a/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
+++ b/gpu/command_buffer/common/gles2_cmd_utils_implementation_autogen.h
@@ -4007,14 +4007,6 @@
                                            arraysize(string_table), value);
 }
 
-std::string GLES2Util::GetStringInvalidateFrameBufferTarget(uint32_t value) {
-  static const EnumToString string_table[] = {
-      {GL_FRAMEBUFFER, "GL_FRAMEBUFFER"},
-  };
-  return GLES2Util::GetQualifiedEnumString(string_table,
-                                           arraysize(string_table), value);
-}
-
 std::string GLES2Util::GetStringMapBufferAccess(uint32_t value) {
   static const EnumToString string_table[] = {
       {GL_MAP_READ_BIT, "GL_MAP_READ_BIT"},
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc
index 20b3fb7..c01034a 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -6814,7 +6814,8 @@
   if (!CheckCurrentProgram(function_name)) {
     return false;
   }
-  return location != -1;
+  return !state_.current_program->IsInactiveUniformLocationByFakeLocation(
+      location);
 }
 
 bool GLES2DecoderImpl::CheckDrawingFeedbackLoops() {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
index 4901ba1..2d37097 100644
--- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
+++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_2.cc
@@ -475,10 +475,6 @@
       .WillOnce(SetArgumentPointee<2>(0));
   EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORMS, _))
       .WillOnce(SetArgumentPointee<2>(0));
-  EXPECT_CALL(
-      *gl_,
-      GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORM_MAX_LENGTH, _))
-      .WillOnce(SetArgumentPointee<2>(0));
 
   Program* program = GetProgram(client_program_id_);
   ASSERT_TRUE(program != NULL);
@@ -589,10 +585,6 @@
       .WillOnce(SetArgumentPointee<2>(0));
   EXPECT_CALL(*gl_, GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORMS, _))
       .WillOnce(SetArgumentPointee<2>(0));
-  EXPECT_CALL(
-      *gl_,
-      GetProgramiv(kServiceProgramId, GL_ACTIVE_UNIFORM_MAX_LENGTH, _))
-      .WillOnce(SetArgumentPointee<2>(0));
 
   cmds::AttachShader attach_cmd;
   attach_cmd.Init(client_program_id_, kClientVertexShaderId);
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
index ac58e82..5194672 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_autogen.h
@@ -44,7 +44,6 @@
 ValueValidator<GLenum> indexed_buffer_target;
 ValueValidator<GLenum> indexed_g_l_state;
 ValueValidator<GLenum> internal_format_parameter;
-ValueValidator<GLenum> invalidate_frame_buffer_target;
 ValueValidator<GLenum> map_buffer_access;
 ValueValidator<GLenum> matrix_mode;
 ValueValidator<GLenum> path_coord_type;
diff --git a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
index 867e1940..981d100 100644
--- a/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
+++ b/gpu/command_buffer/service/gles2_cmd_validation_implementation_autogen.h
@@ -395,10 +395,6 @@
     GL_NUM_SAMPLE_COUNTS, GL_SAMPLES,
 };
 
-static const GLenum valid_invalidate_frame_buffer_target_table[] = {
-    GL_FRAMEBUFFER,
-};
-
 static const GLenum valid_map_buffer_access_table[] = {
     GL_MAP_READ_BIT,
     GL_MAP_WRITE_BIT,
@@ -1025,9 +1021,6 @@
       internal_format_parameter(
           valid_internal_format_parameter_table,
           arraysize(valid_internal_format_parameter_table)),
-      invalidate_frame_buffer_target(
-          valid_invalidate_frame_buffer_target_table,
-          arraysize(valid_invalidate_frame_buffer_target_table)),
       map_buffer_access(valid_map_buffer_access_table,
                         arraysize(valid_map_buffer_access_table)),
       matrix_mode(valid_matrix_mode_table, arraysize(valid_matrix_mode_table)),
diff --git a/gpu/command_buffer/service/program_manager.cc b/gpu/command_buffer/service/program_manager.cc
index 233eb4e..dc60003 100644
--- a/gpu/command_buffer/service/program_manager.cc
+++ b/gpu/command_buffer/service/program_manager.cc
@@ -119,20 +119,22 @@
 Program::UniformInfo::UniformInfo()
     : size(0),
       type(GL_NONE),
+      accepts_api_type(0),
       fake_location_base(0),
-      is_array(false) {
-}
+      is_array(false) {}
 
-Program::UniformInfo::UniformInfo(GLsizei _size,
+Program::UniformInfo::UniformInfo(const std::string& client_name,
+                                  int client_location_base,
                                   GLenum _type,
-                                  int _fake_location_base,
-                                  const std::string& _name)
-    : size(_size),
+                                  bool _is_array,
+                                  const std::vector<GLint>& service_locations)
+    : size(service_locations.size()),
       type(_type),
       accepts_api_type(0),
-      fake_location_base(_fake_location_base),
-      is_array(false),
-      name(_name) {
+      fake_location_base(client_location_base),
+      is_array(_is_array),
+      name(client_name),
+      element_locations(service_locations) {
   switch (type) {
     case GL_INT:
       accepts_api_type = kUniform1i;
@@ -238,8 +240,13 @@
       NOTREACHED() << "Unhandled UniformInfo type " << type;
       break;
   }
-}
+  DCHECK_LT(0, size);
+  DCHECK(is_array || size == 1);
 
+  size_t num_texture_units = IsSampler() ? static_cast<size_t>(size) : 0u;
+  texture_units.clear();
+  texture_units.resize(num_texture_units, 0);
+}
 Program::UniformInfo::~UniformInfo() {}
 
 bool ProgramManager::IsInvalidPrefix(const char* name, size_t length) {
@@ -258,7 +265,6 @@
       valid_(false),
       link_status_(false),
       uniforms_cleared_(false),
-      num_uniforms_(0),
       transform_feedback_buffer_mode_(GL_NONE) {
   manager_->StartTracking(this);
 }
@@ -266,11 +272,11 @@
 void Program::Reset() {
   valid_ = false;
   link_status_ = false;
-  num_uniforms_ = 0;
   max_uniform_name_length_ = 0;
   max_attrib_name_length_ = 0;
   attrib_infos_.clear();
   uniform_infos_.clear();
+  uniform_locations_.clear();
   fragment_input_infos_.clear();
   sampler_indices_.clear();
   attrib_location_to_index_map_.clear();
@@ -322,11 +328,7 @@
     return;
   }
   uniforms_cleared_ = true;
-  for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
-    const UniformInfo& uniform_info = uniform_infos_[ii];
-    if (!uniform_info.IsValid()) {
-      continue;
-    }
+  for (const UniformInfo& uniform_info : uniform_infos_) {
     GLint location = uniform_info.element_locations[0];
     GLsizei size = uniform_info.size;
     uint32 unit_size =
@@ -444,22 +446,6 @@
   }
 }
 
-namespace {
-
-struct UniformData {
-  UniformData() : size(-1), type(GL_NONE), location(0), added(false) {
-  }
-  std::string queried_name;
-  std::string corrected_name;
-  std::string original_name;
-  GLsizei size;
-  GLenum type;
-  GLint location;
-  bool added;
-};
-
-}  // anonymous namespace
-
 void Program::Update() {
   Reset();
   UpdateLogInfo();
@@ -515,88 +501,18 @@
     }
   }
 #endif
-
-  max_len = 0;
-  GLint num_uniforms = 0;
-  glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
-  glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH, &max_len);
-  DCHECK(num_uniforms <= 0 || max_len > 0);
-  name_buffer.reset(new char[max_len]);
-
-  // Reads all the names.
-  std::vector<UniformData> uniform_data;
-  for (GLint ii = 0; ii < num_uniforms; ++ii) {
-    GLsizei length = 0;
-    UniformData data;
-    glGetActiveUniform(
-        service_id_, ii, max_len, &length,
-        &data.size, &data.type, name_buffer.get());
-    DCHECK(length < max_len);
-    DCHECK(length == 0 || name_buffer[length] == '\0');
-    data.queried_name = std::string(name_buffer.get());
-    GetCorrectedUniformData(data.queried_name, &data.corrected_name,
-                            &data.original_name, &data.size, &data.type);
-    uniform_data.push_back(data);
-  }
-
-  // NOTE: We don't care if 2 uniforms are bound to the same location.
-  // One of them will take preference. The spec allows this, same as
-  // BindAttribLocation.
-  //
-  // The reason we don't check is if we were to fail we'd have to
-  // restore the previous program but since we've already linked successfully
-  // at this point the previous program is gone.
-
-  // Assigns the uniforms with bindings.
-  size_t next_available_index = 0;
-  for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
-    UniformData& data = uniform_data[ii];
-    // Force builtin uniforms (gl_DepthRange) to have invalid location.
-    if (ProgramManager::IsInvalidPrefix(data.queried_name.c_str(),
-                                        data.queried_name.size())) {
-      data.location = -1;
-    } else {
-      data.location =
-          glGetUniformLocation(service_id_, data.queried_name.c_str());
-    }
-    // remove "[0]"
-    std::string short_name;
-    int element_index = 0;
-    bool good = GetUniformNameSansElement(data.original_name, &element_index,
-                                          &short_name);
-    DCHECK(good);
-    LocationMap::const_iterator it = bind_uniform_location_map_.find(
-        short_name);
-    if (it != bind_uniform_location_map_.end()) {
-      AddUniformInfo(
-          data.size, data.type, data.location, it->second, data.corrected_name,
-          data.original_name, &next_available_index);
-      data.added = true;
-    }
-  }
-
-  // Assigns the uniforms that were not bound.
-  for (size_t ii = 0; ii < uniform_data.size(); ++ii) {
-    const UniformData& data = uniform_data[ii];
-    if (!data.added) {
-      AddUniformInfo(
-          data.size, data.type, data.location, -1, data.corrected_name,
-          data.original_name, &next_available_index);
-    }
-  }
+  UpdateUniforms();
 
 #if !defined(NDEBUG)
   if (base::CommandLine::ForCurrentProcess()->HasSwitch(
           switches::kEnableGPUServiceLoggingGPU)) {
     DVLOG(1) << "----: uniforms for service_id: " << service_id();
-    for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
-      const UniformInfo& info = uniform_infos_[ii];
-      if (info.IsValid()) {
-        DVLOG(1) << ii << ": loc = " << info.element_locations[0]
-                 << ", size = " << info.size
-                 << ", type = " << GLES2Util::GetStringEnum(info.type)
-                 << ", name = " << info.name;
-      }
+    size_t ii = 0;
+    for (const UniformInfo& info : uniform_infos_) {
+      DVLOG(1) << ii++ << ": loc = " << info.element_locations[0]
+               << ", size = " << info.size
+               << ", type = " << GLES2Util::GetStringEnum(info.type)
+               << ", name = " << info.name;
     }
   }
 #endif
@@ -606,6 +522,144 @@
   valid_ = true;
 }
 
+void Program::UpdateUniforms() {
+  // Reserve each client-bound uniform location. This way unbound uniforms will
+  // not be allocated to locations that user expects bound uniforms to be, even
+  // if the expected uniforms are optimized away by the driver.
+  for (const auto& binding : bind_uniform_location_map_) {
+    if (binding.second < 0)
+      continue;
+    size_t client_location = static_cast<size_t>(binding.second);
+    if (uniform_locations_.size() <= client_location)
+      uniform_locations_.resize(client_location + 1);
+    uniform_locations_[client_location].SetInactive();
+  }
+
+  GLint num_uniforms = 0;
+  glGetProgramiv(service_id_, GL_ACTIVE_UNIFORMS, &num_uniforms);
+  if (num_uniforms <= 0)
+    return;
+
+  uniform_infos_.resize(num_uniforms);
+
+  GLint name_buffer_length = 0;
+  glGetProgramiv(service_id_, GL_ACTIVE_UNIFORM_MAX_LENGTH,
+                 &name_buffer_length);
+  DCHECK(name_buffer_length > 0);
+  scoped_ptr<char[]> name_buffer(new char[name_buffer_length]);
+
+  size_t unused_client_location_cursor = 0;
+
+  for (GLint uniform_index = 0; uniform_index < num_uniforms; ++uniform_index) {
+    GLsizei name_length = 0;
+    GLsizei size = 0;
+    GLenum type = GL_NONE;
+    glGetActiveUniform(service_id_, uniform_index, name_buffer_length,
+                       &name_length, &size, &type, name_buffer.get());
+    DCHECK(name_length < name_buffer_length);
+    DCHECK(name_length == 0 || name_buffer[name_length] == '\0');
+    std::string service_name(name_buffer.get(), name_length);
+
+    GLint service_location = -1;
+    // Force builtin uniforms (gl_DepthRange) to have invalid location.
+    if (!ProgramManager::IsInvalidPrefix(service_name.c_str(),
+                                         service_name.size())) {
+      service_location =
+          glGetUniformLocation(service_id_, service_name.c_str());
+    }
+
+    // Determine the client name of the uniform and whether it is an array
+    // or not.
+    bool is_array = false;
+    std::string client_name;
+    for (size_t i = 0; i < kMaxAttachedShaders && client_name.empty(); ++i) {
+      const auto& shader = attached_shaders_[i];
+      if (!shader)
+        continue;
+      const sh::ShaderVariable* info = nullptr;
+      const sh::Uniform* uniform = shader->GetUniformInfo(service_name);
+      if (uniform &&
+          uniform->findInfoByMappedName(service_name, &info, &client_name)) {
+        DCHECK(!client_name.empty());
+        is_array = info->arraySize > 0;
+        type = info->type;
+        size = std::max(1u, info->arraySize);
+      }
+    }
+    if (client_name.empty()) {
+      // This happens only in cases where we do not have ANGLE or run unit tests
+      // (or ANGLE has a severe bug).
+      client_name = service_name;
+      GLSLArrayName parsed_service_name(service_name);
+      is_array = size > 1 || parsed_service_name.IsArrayName();
+    }
+
+    std::string service_base_name = service_name;
+    std::string client_base_name = client_name;
+    if (is_array) {
+      // Some drivers incorrectly return an uniform name of size-1 array without
+      // "[0]". In this case, we correct the service name by appending "[0]" to
+      // it.
+      GLSLArrayName parsed_service_name(service_name);
+      if (parsed_service_name.IsArrayName()) {
+        service_base_name = parsed_service_name.base_name();
+        GLSLArrayName parsed_client_name(client_name);
+        client_base_name = parsed_client_name.base_name();
+      } else {
+        service_name += "[0]";
+        client_name += "[0]";
+      }
+    }
+
+    // Assign a location for the uniform: use either client-bound
+    // location or automatically assigned to an unused location.
+    size_t client_location_base = 0;
+    LocationMap::const_iterator it =
+        bind_uniform_location_map_.find(client_base_name);
+    if (it != bind_uniform_location_map_.end()) {
+      client_location_base = it->second;
+    } else {
+      while (unused_client_location_cursor < uniform_locations_.size() &&
+             !uniform_locations_[unused_client_location_cursor].IsUnused())
+        unused_client_location_cursor++;
+      if (unused_client_location_cursor == uniform_locations_.size())
+        uniform_locations_.resize(unused_client_location_cursor + 1);
+      client_location_base = unused_client_location_cursor;
+      unused_client_location_cursor++;
+    }
+
+    // Populate the uniform list entry.
+    std::vector<GLint> service_locations;
+    service_locations.resize(size);
+    service_locations[0] = service_location;
+
+    if (size > 1) {
+      for (GLsizei ii = 1; ii < size; ++ii) {
+        std::string element_name(service_base_name + "[" +
+                                 base::IntToString(ii) + "]");
+        service_locations[ii] =
+            glGetUniformLocation(service_id_, element_name.c_str());
+      }
+    }
+
+    UniformInfo& info = uniform_infos_[uniform_index];
+    info = UniformInfo(client_name, client_location_base, type, is_array,
+                       service_locations);
+    if (info.IsSampler()) {
+      sampler_indices_.push_back(uniform_index);
+    }
+
+    // Populate the uniform location list entry.
+    // Before linking, we already validated that no two statically used uniforms
+    // are bound to the same location.
+    DCHECK(!uniform_locations_[client_location_base].IsActive());
+    uniform_locations_[client_location_base].SetActive(&info);
+
+    max_uniform_name_length_ = std::max(max_uniform_name_length_,
+                                        static_cast<GLsizei>(info.name.size()));
+  }
+}
+
 void Program::UpdateFragmentInputs() {
   if (!feature_info().feature_flags().chromium_path_rendering)
     return;
@@ -921,11 +975,7 @@
     const std::string& name) const {
   GLSLArrayName parsed_name(name);
 
-  for (GLuint ii = 0; ii < uniform_infos_.size(); ++ii) {
-    const UniformInfo& info = uniform_infos_[ii];
-    if (!info.IsValid()) {
-      continue;
-    }
+  for (const UniformInfo& info : uniform_infos_) {
     if (info.name == name ||
         (info.is_array &&
          info.name.compare(0, info.name.size() - 3, name) == 0)) {
@@ -935,7 +985,6 @@
       size_t open_pos = info.name.find_last_of('[');
       if (info.name.compare(0, open_pos, parsed_name.base_name()) == 0) {
         int index = parsed_name.element_index();
-        DCHECK(index >= 0);
         if (index < info.size) {
           DCHECK_GT(static_cast<int>(info.element_locations.size()), index);
           if (info.element_locations[index] == -1)
@@ -965,25 +1014,34 @@
         GLint fake_location, GLint* real_location, GLint* array_index) const {
   DCHECK(real_location);
   DCHECK(array_index);
-  if (fake_location < 0) {
-    return NULL;
-  }
+  if (fake_location < 0)
+    return nullptr;
+  size_t location_index =
+      GetUniformLocationIndexFromFakeLocation(fake_location);
+  if (location_index >= uniform_locations_.size())
+    return nullptr;
 
-  GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
-  if (uniform_index >= 0 &&
-      static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
-    const UniformInfo& uniform_info = uniform_infos_[uniform_index];
-    if (!uniform_info.IsValid()) {
-      return NULL;
-    }
-    GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
-    if (element_index < uniform_info.size) {
-      *real_location = uniform_info.element_locations[element_index];
-      *array_index = element_index;
-      return &uniform_info;
-    }
-  }
-  return NULL;
+  if (!uniform_locations_[location_index].IsActive())
+    return nullptr;
+
+  const UniformInfo* info = uniform_locations_[location_index].uniform();
+  size_t element_index = GetArrayElementIndexFromFakeLocation(fake_location);
+  if (static_cast<GLsizei>(element_index) >= info->size)
+    return nullptr;
+  *real_location = info->element_locations[element_index];
+  *array_index = element_index;
+  return info;
+}
+
+bool Program::IsInactiveUniformLocationByFakeLocation(
+    GLint fake_location) const {
+  if (fake_location < 0)
+    return true;
+  size_t location_index =
+      GetUniformLocationIndexFromFakeLocation(fake_location);
+  if (location_index >= uniform_locations_.size())
+    return false;
+  return uniform_locations_[location_index].IsInactive();
 }
 
 const std::string* Program::GetAttribMappedName(
@@ -1063,41 +1121,6 @@
   bind_fragment_input_location_map_[name + "[0]"] = location;
 }
 
-// Note: This is only valid to call right after a program has been linked
-// successfully.
-void Program::GetCorrectedUniformData(
-    const std::string& name,
-    std::string* corrected_name, std::string* original_name,
-    GLsizei* size, GLenum* type) const {
-  DCHECK(corrected_name && original_name && size && type);
-  for (auto shader : attached_shaders_) {
-    if (!shader)
-      continue;
-    const sh::ShaderVariable* info = NULL;
-    const sh::Uniform* uniform = shader->GetUniformInfo(name);
-    bool found = false;
-    if (uniform)
-      found = uniform->findInfoByMappedName(name, &info, original_name);
-    if (found) {
-      const std::string kArraySpec("[0]");
-      if (info->arraySize > 0 &&
-          !base::EndsWith(name, kArraySpec, base::CompareCase::SENSITIVE)) {
-        *corrected_name = name + kArraySpec;
-        *original_name += kArraySpec;
-      } else {
-        *corrected_name = name;
-      }
-      *type = info->type;
-      *size = std::max(1u, info->arraySize);
-      return;
-    }
-  }
-  // TODO(zmo): this path should never be reached unless there is a serious
-  // bug in the driver or in ANGLE translator.
-  *corrected_name = name;
-  *original_name = name;
-}
-
 void Program::GetVertexAttribData(
     const std::string& name, std::string* original_name, GLenum* type) const {
   DCHECK(original_name);
@@ -1181,81 +1204,13 @@
   }
 }
 
-void Program::AddUniformInfo(
-    GLsizei size, GLenum type, GLint location, GLint fake_base_location,
-    const std::string& name, const std::string& original_name,
-    size_t* next_available_index) {
-  DCHECK(next_available_index);
-  const char* kArraySpec = "[0]";
-  size_t uniform_index =
-      fake_base_location >= 0 ? fake_base_location : *next_available_index;
-  if (uniform_infos_.size() < uniform_index + 1) {
-    uniform_infos_.resize(uniform_index + 1);
-  }
-
-  // Before linking, we already validated that no two statically used uniforms
-  // are bound to the same location.
-  DCHECK(!uniform_infos_[uniform_index].IsValid());
-
-  uniform_infos_[uniform_index] = UniformInfo(
-      size, type, uniform_index, original_name);
-  ++num_uniforms_;
-
-  UniformInfo& info = uniform_infos_[uniform_index];
-  info.element_locations.resize(size);
-  info.element_locations[0] = location;
-  DCHECK_LE(0, size);
-  size_t num_texture_units = info.IsSampler() ? static_cast<size_t>(size) : 0u;
-  info.texture_units.clear();
-  info.texture_units.resize(num_texture_units, 0);
-
-  if (size > 1) {
-    // Go through the array element locations looking for a match.
-    // We can skip the first element because it's the same as the
-    // the location without the array operators.
-    size_t array_pos = name.rfind(kArraySpec);
-    std::string base_name = name;
-    if (name.size() > 3) {
-      if (array_pos != name.size() - 3) {
-        info.name = name + kArraySpec;
-      } else {
-        base_name = name.substr(0, name.size() - 3);
-      }
-    }
-    for (GLsizei ii = 1; ii < info.size; ++ii) {
-      std::string element_name(base_name + "[" + base::IntToString(ii) + "]");
-      info.element_locations[ii] =
-          glGetUniformLocation(service_id_, element_name.c_str());
-    }
-  }
-
-  info.is_array =
-     (size > 1 ||
-      (info.name.size() > 3 &&
-       info.name.rfind(kArraySpec) == info.name.size() - 3));
-
-  if (info.IsSampler()) {
-    sampler_indices_.push_back(info.fake_location_base);
-  }
-  max_uniform_name_length_ =
-      std::max(max_uniform_name_length_,
-               static_cast<GLsizei>(info.name.size()));
-
-  while (*next_available_index < uniform_infos_.size() &&
-         uniform_infos_[*next_available_index].IsValid()) {
-    *next_available_index = *next_available_index + 1;
-  }
-}
-
 const Program::UniformInfo*
     Program::GetUniformInfo(
         GLint index) const {
   if (static_cast<size_t>(index) >= uniform_infos_.size()) {
     return NULL;
   }
-
-  const UniformInfo& info = uniform_infos_[index];
-  return info.IsValid() ? &info : NULL;
+  return &uniform_infos_[index];
 }
 
 bool Program::SetSamplers(
@@ -1264,27 +1219,29 @@
   if (fake_location < 0) {
     return true;
   }
-  GLint uniform_index = GetUniformInfoIndexFromFakeLocation(fake_location);
-  if (uniform_index >= 0 &&
-      static_cast<size_t>(uniform_index) < uniform_infos_.size()) {
-    UniformInfo& info = uniform_infos_[uniform_index];
-    if (!info.IsValid()) {
-      return false;
-    }
-    GLint element_index = GetArrayElementIndexFromFakeLocation(fake_location);
-    if (element_index < info.size) {
-      count = std::min(info.size - element_index, count);
-      if (info.IsSampler() && count > 0) {
-        for (GLsizei ii = 0; ii < count; ++ii) {
-          if (value[ii] < 0 || value[ii] >= num_texture_units) {
-            return false;
-          }
-        }
-        std::copy(value, value + count,
-                  info.texture_units.begin() + element_index);
-        return true;
+  size_t location_index =
+      GetUniformLocationIndexFromFakeLocation(fake_location);
+  if (location_index >= uniform_infos_.size())
+    return false;
+
+  if (!uniform_locations_[location_index].IsActive())
+    return false;
+
+  UniformInfo* info = uniform_locations_[location_index].uniform();
+
+  size_t element_index = GetArrayElementIndexFromFakeLocation(fake_location);
+  if (static_cast<GLsizei>(element_index) >= info->size)
+    return true;
+  count = std::min(info->size - static_cast<GLsizei>(element_index), count);
+  if (info->IsSampler() && count > 0) {
+    for (GLsizei ii = 0; ii < count; ++ii) {
+      if (value[ii] < 0 || value[ii] >= num_texture_units) {
+        return false;
       }
     }
+    std::copy(value, value + count,
+              info->texture_units.begin() + element_index);
+    return true;
   }
   return true;
 }
@@ -1299,7 +1256,7 @@
       *params = max_attrib_name_length_ + 1;
       break;
     case GL_ACTIVE_UNIFORMS:
-      *params = num_uniforms_;
+      *params = uniform_infos_.size();
       break;
     case GL_ACTIVE_UNIFORM_MAX_LENGTH:
       // Notice +1 to accomodate NULL terminator.
@@ -1661,15 +1618,12 @@
     total_string_size += info.name.size();
   }
 
-  for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
-    const UniformInfo& info = uniform_infos_[ii];
-    if (info.IsValid()) {
-      num_locations += info.element_locations.size();
-      total_string_size += info.name.size();
-    }
+  for (const UniformInfo& info : uniform_infos_) {
+    num_locations += info.element_locations.size();
+    total_string_size += info.name.size();
   }
 
-  uint32 num_inputs = attrib_infos_.size() + num_uniforms_;
+  uint32 num_inputs = attrib_infos_.size() + uniform_infos_.size();
   uint32 input_size = num_inputs * sizeof(ProgramInput);
   uint32 location_size = num_locations * sizeof(int32);
   uint32 size = sizeof(ProgramInfoHeader) +
@@ -1691,7 +1645,7 @@
 
   header->link_status = link_status_;
   header->num_attribs = attrib_infos_.size();
-  header->num_uniforms = num_uniforms_;
+  header->num_uniforms = uniform_infos_.size();
 
   for (size_t ii = 0; ii < attrib_infos_.size(); ++ii) {
     const VertexAttrib& info = attrib_infos_[ii];
@@ -1706,26 +1660,26 @@
     ++inputs;
   }
 
-  for (size_t ii = 0; ii < uniform_infos_.size(); ++ii) {
-    const UniformInfo& info = uniform_infos_[ii];
-    if (info.IsValid()) {
-      inputs->size = info.size;
-      inputs->type = info.type;
-      inputs->location_offset = ComputeOffset(header, locations);
-      inputs->name_offset = ComputeOffset(header, strings);
-      inputs->name_length = info.name.size();
-      DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
-      for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
-        if (info.element_locations[jj] == -1)
-          *locations++ = -1;
-        else
-          *locations++ = ProgramManager::MakeFakeLocation(ii, jj);
-      }
-      memcpy(strings, info.name.c_str(), info.name.size());
-      strings += info.name.size();
-      ++inputs;
+  for (const UniformInfo& info : uniform_infos_) {
+    inputs->size = info.size;
+    inputs->type = info.type;
+    inputs->location_offset = ComputeOffset(header, locations);
+    inputs->name_offset = ComputeOffset(header, strings);
+    inputs->name_length = info.name.size();
+    DCHECK(static_cast<size_t>(info.size) == info.element_locations.size());
+    for (size_t jj = 0; jj < info.element_locations.size(); ++jj) {
+      if (info.element_locations[jj] == -1)
+        *locations++ = -1;
+      else
+        *locations++ =
+            ProgramManager::MakeFakeLocation(info.fake_location_base, jj);
     }
+    memcpy(strings, info.name.c_str(), info.name.size());
+    strings += info.name.size();
+    ++inputs;
   }
+  // NOTE: currently we do not pass inactive uniform binding locations
+  // through the program info call.
 
   // NOTE: currently we do not pass fragment input infos through the program
   // info call, because they are not exposed through any getter function.
diff --git a/gpu/command_buffer/service/program_manager.h b/gpu/command_buffer/service/program_manager.h
index 737c849..daecf4d 100644
--- a/gpu/command_buffer/service/program_manager.h
+++ b/gpu/command_buffer/service/program_manager.h
@@ -73,15 +73,12 @@
 
   struct UniformInfo {
     UniformInfo();
-    UniformInfo(
-        GLsizei _size, GLenum _type, GLint _fake_location_base,
-        const std::string& _name);
+    UniformInfo(const std::string& client_name,
+                GLint client_location_base,
+                GLenum _type,
+                bool _is_array,
+                const std::vector<GLint>& service_locations);
     ~UniformInfo();
-
-    bool IsValid() const {
-      return size != 0;
-    }
-
     bool IsSampler() const {
       return type == GL_SAMPLER_2D || type == GL_SAMPLER_2D_RECT_ARB ||
              type == GL_SAMPLER_CUBE || type == GL_SAMPLER_EXTERNAL_OES;
@@ -110,7 +107,37 @@
     std::string name;
   };
 
+  class UniformLocationEntry {
+   public:
+    UniformLocationEntry() : uniform_(nullptr), inactive_(false) {}
+    bool IsUnused() const { return !uniform_ && !inactive_; }
+    bool IsInactive() const { return inactive_; }
+    bool IsActive() const { return uniform_ != nullptr; }
+    void SetInactive() {
+      uniform_ = nullptr;
+      inactive_ = true;
+    }
+    void SetActive(UniformInfo* uniform) {
+      DCHECK(uniform);
+      uniform_ = uniform;
+      inactive_ = false;
+    }
+    const UniformInfo* uniform() const {
+      DCHECK(IsActive());
+      return uniform_;
+    }
+    UniformInfo* uniform() {
+      DCHECK(IsActive());
+      return uniform_;
+    }
+
+   private:
+    UniformInfo* uniform_;  // Pointer to uniform_info_ vector entry.
+    bool inactive_;
+  };
+
   typedef std::vector<UniformInfo> UniformInfoVector;
+  typedef std::vector<UniformLocationEntry> UniformLocationVector;
   typedef std::vector<VertexAttrib> AttribInfoVector;
   typedef std::vector<FragmentInputInfo> FragmentInputInfoVector;
   typedef std::vector<int> SamplerIndices;
@@ -172,6 +199,10 @@
   const UniformInfo* GetUniformInfoByFakeLocation(
       GLint fake_location, GLint* real_location, GLint* array_index) const;
 
+  // Returns true if |fake_location| is a location for an inactive uniform,
+  // -1 for bound, non-existing uniform.
+  bool IsInactiveUniformLocationByFakeLocation(GLint fake_location) const;
+
   // Gets all the program info.
   void GetProgramInfo(
       ProgramManager* manager, CommonDecoder::Bucket* bucket) const;
@@ -333,6 +364,7 @@
 
   // Updates the program info after a successful link.
   void Update();
+  void UpdateUniforms();
   void UpdateFragmentInputs();
 
   // Process the program log, replacing the hashed names with original names.
@@ -367,33 +399,20 @@
   // Returns false upon failure.
   bool ExecuteTransformFeedbackVaryingsCall();
 
-  void AddUniformInfo(
-      GLsizei size, GLenum type, GLint location, GLint fake_base_location,
-      const std::string& name, const std::string& original_name,
-      size_t* next_available_index);
-
-  // Query uniform data returned by ANGLE translator by the mapped name.
-  // Some drivers incorrectly return an uniform name of size-1 array without
-  // "[0]". In this case, we correct the name by appending "[0]" to it.
-  void GetCorrectedUniformData(
-      const std::string& name,
-      std::string* corrected_name, std::string* original_name,
-      GLsizei* size, GLenum* type) const;
-
   // Query VertexAttrib data returned by ANGLE translator by the mapped name.
   void GetVertexAttribData(
       const std::string& name, std::string* original_name, GLenum* type) const;
 
   void DetachShaders(ShaderManager* manager);
 
-  static inline GLint GetUniformInfoIndexFromFakeLocation(
+  static inline size_t GetUniformLocationIndexFromFakeLocation(
       GLint fake_location) {
-    return fake_location & 0xFFFF;
+    return static_cast<size_t>(fake_location & 0xFFFF);
   }
 
-  static inline GLint GetArrayElementIndexFromFakeLocation(
+  static inline size_t GetArrayElementIndexFromFakeLocation(
       GLint fake_location) {
-    return (fake_location >> 16) & 0xFFFF;
+    return static_cast<size_t>((fake_location >> 16) & 0xFFFF);
   }
 
   const FeatureInfo& feature_info() const;
@@ -414,6 +433,7 @@
 
   // Uniform info by index.
   UniformInfoVector uniform_infos_;
+  UniformLocationVector uniform_locations_;
 
   // The indices of the uniforms that are samplers.
   SamplerIndices sampler_indices_;
@@ -439,10 +459,6 @@
   // True if the uniforms have been cleared.
   bool uniforms_cleared_;
 
-  // This is different than uniform_infos_.size() because
-  // that is a sparce array.
-  GLint num_uniforms_;
-
   // Log info
   scoped_ptr<std::string> log_info_;
 
diff --git a/gpu/command_buffer/service/test_helper.cc b/gpu/command_buffer/service/test_helper.cc
index c9beda9..2c8fc25 100644
--- a/gpu/command_buffer/service/test_helper.cc
+++ b/gpu/command_buffer/service/test_helper.cc
@@ -735,53 +735,43 @@
       .WillOnce(SetArgumentPointee<2>(num_uniforms))
       .RetiresOnSaturation();
 
-  size_t max_uniform_len = 0;
-  for (size_t ii = 0; ii < num_uniforms; ++ii) {
-    size_t len = strlen(uniforms[ii].name) + 1;
-    max_uniform_len = std::max(max_uniform_len, len);
-  }
-  EXPECT_CALL(*gl,
-      GetProgramiv(service_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, _))
-      .WillOnce(SetArgumentPointee<2>(max_uniform_len))
-      .RetiresOnSaturation();
-  for (size_t ii = 0; ii < num_uniforms; ++ii) {
-    const UniformInfo& info = uniforms[ii];
-    EXPECT_CALL(*gl,
-        GetActiveUniform(service_id, ii,
-                         max_uniform_len, _, _, _, _))
-        .WillOnce(DoAll(
-            SetArgumentPointee<3>(strlen(info.name)),
-            SetArgumentPointee<4>(info.size),
-            SetArgumentPointee<5>(info.type),
-            SetArrayArgument<6>(info.name,
-                                info.name + strlen(info.name) + 1)))
+  if (num_uniforms > 0) {
+    size_t max_uniform_len = 0;
+    for (size_t ii = 0; ii < num_uniforms; ++ii) {
+      size_t len = strlen(uniforms[ii].name) + 1;
+      max_uniform_len = std::max(max_uniform_len, len);
+    }
+    EXPECT_CALL(*gl, GetProgramiv(service_id, GL_ACTIVE_UNIFORM_MAX_LENGTH, _))
+        .WillOnce(SetArgumentPointee<2>(max_uniform_len))
         .RetiresOnSaturation();
-  }
-
-  for (int pass = 0; pass < 2; ++pass) {
     for (size_t ii = 0; ii < num_uniforms; ++ii) {
       const UniformInfo& info = uniforms[ii];
-      if (pass == 0 && info.real_location != -1) {
+      EXPECT_CALL(*gl,
+                  GetActiveUniform(service_id, ii, max_uniform_len, _, _, _, _))
+          .WillOnce(DoAll(SetArgumentPointee<3>(strlen(info.name)),
+                          SetArgumentPointee<4>(info.size),
+                          SetArgumentPointee<5>(info.type),
+                          SetArrayArgument<6>(
+                              info.name, info.name + strlen(info.name) + 1)))
+          .RetiresOnSaturation();
+
+      if (info.real_location != -1) {
         EXPECT_CALL(*gl, GetUniformLocation(service_id, StrEq(info.name)))
             .WillOnce(Return(info.real_location))
             .RetiresOnSaturation();
       }
-      if ((pass == 0 && info.desired_location >= 0) ||
-          (pass == 1 && info.desired_location < 0)) {
-        if (info.size > 1) {
-          std::string base_name = info.name;
-          size_t array_pos = base_name.rfind("[0]");
-          if (base_name.size() > 3 && array_pos == base_name.size() - 3) {
-            base_name = base_name.substr(0, base_name.size() - 3);
-          }
-          for (GLsizei jj = 1; jj < info.size; ++jj) {
-            std::string element_name(
-                std::string(base_name) + "[" + base::IntToString(jj) + "]");
-            EXPECT_CALL(*gl, GetUniformLocation(
-                service_id, StrEq(element_name)))
-                .WillOnce(Return(info.real_location + jj * 2))
-                .RetiresOnSaturation();
-          }
+      if (info.size > 1) {
+        std::string base_name = info.name;
+        size_t array_pos = base_name.rfind("[0]");
+        if (base_name.size() > 3 && array_pos == base_name.size() - 3) {
+          base_name = base_name.substr(0, base_name.size() - 3);
+        }
+        for (GLsizei jj = 1; jj < info.size; ++jj) {
+          std::string element_name(std::string(base_name) + "[" +
+                                   base::IntToString(jj) + "]");
+          EXPECT_CALL(*gl, GetUniformLocation(service_id, StrEq(element_name)))
+              .WillOnce(Return(info.real_location + jj * 2))
+              .RetiresOnSaturation();
         }
       }
     }
diff --git a/gpu/command_buffer/tests/gl_bind_uniform_location_unittest.cc b/gpu/command_buffer/tests/gl_bind_uniform_location_unittest.cc
index d688c69..5c19cf0 100644
--- a/gpu/command_buffer/tests/gl_bind_uniform_location_unittest.cc
+++ b/gpu/command_buffer/tests/gl_bind_uniform_location_unittest.cc
@@ -268,6 +268,98 @@
 
 }
 
+TEST_P(BindUniformLocationTest, UnusedUniformUpdate) {
+  ASSERT_TRUE(GLTestHelper::HasExtension("GL_CHROMIUM_bind_uniform_location"));
+
+  // clang-format off
+  static const char* kVertexShaderString = SHADER(
+      attribute vec4 a_position;
+      void main() {
+        gl_Position = a_position;
+      }
+  );
+  static const char* kFragmentShaderString = SHADER(
+      precision mediump float;
+      uniform vec4 u_colorA;
+      uniform float u_colorU;
+      uniform vec4 u_colorC;
+      void main() {
+        gl_FragColor = u_colorA + u_colorC;
+      }
+  );
+  // clang-format on
+  const GLint kColorULocation = 1;
+  const GLint kNonexistingLocation = 5;
+  const GLint kUnboundLocation = 6;
+
+  GLuint vertex_shader =
+      GLTestHelper::LoadShader(GL_VERTEX_SHADER, kVertexShaderString);
+  GLuint fragment_shader =
+      GLTestHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShaderString);
+  GLuint program = glCreateProgram();
+  glBindUniformLocationCHROMIUM(program, kColorULocation, "u_colorU");
+  // The non-existing uniform should behave like existing, but optimized away
+  // uniform.
+  glBindUniformLocationCHROMIUM(program, kNonexistingLocation, "nonexisting");
+  // Let A and C be assigned automatic locations.
+  glAttachShader(program, vertex_shader);
+  glAttachShader(program, fragment_shader);
+  glLinkProgram(program);
+  GLint linked = 0;
+  glGetProgramiv(program, GL_LINK_STATUS, &linked);
+  EXPECT_EQ(1, linked);
+  glUseProgram(program);
+
+  // No errors on bound locations, since caller does not know
+  // if the driver optimizes them away or not.
+  glUniform1f(kColorULocation, 0.25f);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+  // No errors on bound locations of names that do not exist
+  // in the shader. Otherwise it would be inconsistent wrt the
+  // optimization case.
+  glUniform1f(kNonexistingLocation, 0.25f);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+  // The above are equal to updating -1.
+  glUniform1f(-1, 0.25f);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+  // No errors when updating with other type either.
+  // The type can not be known with the non-existing case.
+  glUniform2f(kColorULocation, 0.25f, 0.25f);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  glUniform2f(kNonexistingLocation, 0.25f, 0.25f);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+  glUniform2f(-1, 0.25f, 0.25f);
+  EXPECT_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+  // Ensure that driver or ANGLE has optimized the variable
+  // away and the test tests what it is supposed to.
+  EXPECT_EQ(-1, glGetUniformLocation(program, "u_colorU"));
+
+  // The bound location gets marked as used and the driver
+  // does not allocate other variables to that location.
+  EXPECT_NE(kColorULocation, glGetUniformLocation(program, "u_colorA"));
+  EXPECT_NE(kColorULocation, glGetUniformLocation(program, "u_colorC"));
+  EXPECT_NE(kNonexistingLocation, glGetUniformLocation(program, "u_colorA"));
+  EXPECT_NE(kNonexistingLocation, glGetUniformLocation(program, "u_colorC"));
+
+  // Unintuitive: while specifying value works, getting the value does not.
+  GLfloat get_result = 0.0f;
+  glGetUniformfv(program, kColorULocation, &get_result);
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+  glGetUniformfv(program, kNonexistingLocation, &get_result);
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+  glGetUniformfv(program, -1, &get_result);
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+
+  // Updating an unbound, non-existing location still causes
+  // an error.
+  glUniform1f(kUnboundLocation, 0.25f);
+  EXPECT_EQ(static_cast<GLenum>(GL_INVALID_OPERATION), glGetError());
+}
+
 INSTANTIATE_TEST_CASE_P(WithAndWithoutShaderNameMapping,
                         BindUniformLocationTest,
                         ::testing::Bool());
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc
index 3d42d10..9a6380d 100644
--- a/ios/chrome/browser/application_context_impl.cc
+++ b/ios/chrome/browser/application_context_impl.cc
@@ -87,7 +87,7 @@
     variations_service->OnAppEnterForeground();
 
   std::vector<ios::ChromeBrowserState*> loaded_browser_state =
-      GetChromeBrowserStateManager()->GetLoadedChromeBrowserStates();
+      GetChromeBrowserStateManager()->GetLoadedBrowserStates();
   for (ios::ChromeBrowserState* browser_state : loaded_browser_state) {
     browser_state->SetExitType(ios::ChromeBrowserState::EXIT_CRASHED);
   }
@@ -97,7 +97,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   // Mark all the ChromeBrowserStates as clean and persist history.
   std::vector<ios::ChromeBrowserState*> loaded_browser_state =
-      GetChromeBrowserStateManager()->GetLoadedChromeBrowserStates();
+      GetChromeBrowserStateManager()->GetLoadedBrowserStates();
   for (ios::ChromeBrowserState* browser_state : loaded_browser_state) {
     if (history::HistoryService* history_service =
             ios::HistoryServiceFactory::GetForBrowserStateIfExists(
diff --git a/ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.cc b/ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.cc
index 4ee19343..a6c5bb0 100644
--- a/ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.cc
+++ b/ios/chrome/browser/signin/ios_chrome_signin_status_metrics_provider_delegate.cc
@@ -74,5 +74,5 @@
 IOSChromeSigninStatusMetricsProviderDelegate::GetLoadedChromeBrowserStates() {
   return GetApplicationContext()
       ->GetChromeBrowserStateManager()
-      ->GetLoadedChromeBrowserStates();
+      ->GetLoadedBrowserStates();
 }
diff --git a/ios/chrome/browser/sync/glue/sync_start_util.cc b/ios/chrome/browser/sync/glue/sync_start_util.cc
index 93753bf..22123a3 100644
--- a/ios/chrome/browser/sync/glue/sync_start_util.cc
+++ b/ios/chrome/browser/sync/glue/sync_start_util.cc
@@ -28,7 +28,7 @@
   }
 
   ios::ChromeBrowserState* browser_state =
-      browser_state_manager->GetChromeBrowserState(browser_state_path);
+      browser_state_manager->GetBrowserState(browser_state_path);
   if (!browser_state) {
     DVLOG(2) << "ChromeBrowserState not found, can't start sync.";
     return;
diff --git a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h
index 3e548da..e5c28c3 100644
--- a/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h
+++ b/ios/public/provider/chrome/browser/browser_state/chrome_browser_state_manager.h
@@ -32,14 +32,13 @@
 
   // Returns the ChromeBrowserState associated with |path|, creating one if
   // necessary.
-  virtual ChromeBrowserState* GetChromeBrowserState(
-      const base::FilePath& path) = 0;
+  virtual ChromeBrowserState* GetBrowserState(const base::FilePath& path) = 0;
 
   // Returns the BrowserStateInfoCache associated with this manager.
   virtual BrowserStateInfoCache* GetBrowserStateInfoCache() = 0;
 
   // Returns the list of loaded ChromeBrowserStates.
-  virtual std::vector<ChromeBrowserState*> GetLoadedChromeBrowserStates() = 0;
+  virtual std::vector<ChromeBrowserState*> GetLoadedBrowserStates() = 0;
 
  protected:
   ChromeBrowserStateManager() {}
diff --git a/net/base/chunked_upload_data_stream.cc b/net/base/chunked_upload_data_stream.cc
index 6ba40c5..52cf4856 100644
--- a/net/base/chunked_upload_data_stream.cc
+++ b/net/base/chunked_upload_data_stream.cc
@@ -28,7 +28,8 @@
   DCHECK(data_len > 0 || is_done);
   if (data_len > 0) {
     DCHECK(data);
-    upload_data_.push_back(new std::vector<char>(data, data + data_len));
+    upload_data_.push_back(
+        make_scoped_ptr(new std::vector<char>(data, data + data_len)));
   }
   all_data_appended_ = is_done;
 
@@ -74,7 +75,7 @@
   // Copy as much data as possible from |upload_data_| to |buf|.
   int bytes_read = 0;
   while (read_index_ < upload_data_.size() && bytes_read < buf_len) {
-    std::vector<char>* data = upload_data_[read_index_];
+    std::vector<char>* data = upload_data_[read_index_].get();
     size_t bytes_to_read =
         std::min(static_cast<size_t>(buf_len - bytes_read),
                  data->size() - read_offset_);
diff --git a/net/base/chunked_upload_data_stream.h b/net/base/chunked_upload_data_stream.h
index b79108ca..6f7d284 100644
--- a/net/base/chunked_upload_data_stream.h
+++ b/net/base/chunked_upload_data_stream.h
@@ -9,7 +9,6 @@
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_vector.h"
 #include "net/base/completion_callback.h"
 #include "net/base/net_export.h"
 #include "net/base/upload_data_stream.h"
@@ -48,7 +47,7 @@
   // True once all data has been appended to the stream.
   bool all_data_appended_;
 
-  ScopedVector<std::vector<char>> upload_data_;
+  std::vector<scoped_ptr<std::vector<char>>> upload_data_;
 
   // Buffer to write the next read's data to. Only set when a call to
   // ReadInternal reads no data.
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 2a7e469c..adb4705 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -333,6 +333,7 @@
 void HttpNetworkSession::GetNpnProtos(NextProtoVector* npn_protos) const {
   if (HttpStreamFactory::spdy_enabled() && params_.enable_npn) {
     *npn_protos = next_protos_;
+    DisableHTTP2(npn_protos);
   } else {
     npn_protos->clear();
   }
diff --git a/net/http/http_network_transaction.h b/net/http/http_network_transaction.h
index 32dd905..6f8b203 100644
--- a/net/http/http_network_transaction.h
+++ b/net/http/http_network_transaction.h
@@ -116,8 +116,6 @@
 
   FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest,
                            ResetStateForRestart);
-  FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest, EnableNPN);
-  FRIEND_TEST_ALL_PREFIXES(HttpNetworkTransactionTest, DisableNPN);
   FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest,
                            WindowUpdateReceived);
   FRIEND_TEST_ALL_PREFIXES(SpdyNetworkTransactionTest,
diff --git a/net/http/http_network_transaction_unittest.cc b/net/http/http_network_transaction_unittest.cc
index b33d9ba..54c689b 100644
--- a/net/http/http_network_transaction_unittest.cc
+++ b/net/http/http_network_transaction_unittest.cc
@@ -81,7 +81,6 @@
 #include "net/ssl/ssl_private_key.h"
 #include "net/test/cert_test_util.h"
 #include "net/websockets/websocket_handshake_stream_base.h"
-#include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
 #include "url/gurl.h"
@@ -15467,29 +15466,4 @@
             trans->GetTotalReceivedBytes());
 }
 
-TEST_P(HttpNetworkTransactionTest, EnableNPN) {
-  session_deps_.next_protos = NextProtosDefaults();
-  session_deps_.enable_npn = true;
-
-  scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
-  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
-
-  EXPECT_THAT(trans.server_ssl_config_.alpn_protos,
-              testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
-  EXPECT_THAT(trans.server_ssl_config_.npn_protos,
-              testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
-}
-
-TEST_P(HttpNetworkTransactionTest, DisableNPN) {
-  session_deps_.next_protos = NextProtosDefaults();
-  session_deps_.enable_npn = false;
-
-  scoped_ptr<HttpNetworkSession> session(CreateSession(&session_deps_));
-  HttpNetworkTransaction trans(DEFAULT_PRIORITY, session.get());
-
-  EXPECT_THAT(trans.server_ssl_config_.alpn_protos,
-              testing::ElementsAre(kProtoHTTP2, kProtoSPDY31, kProtoHTTP11));
-  EXPECT_TRUE(trans.server_ssl_config_.npn_protos.empty());
-}
-
 }  // namespace net
diff --git a/net/log/net_log_unittest.cc b/net/log/net_log_unittest.cc
index 0046b46..fd2a2925 100644
--- a/net/log/net_log_unittest.cc
+++ b/net/log/net_log_unittest.cc
@@ -5,7 +5,6 @@
 #include "net/log/net_log.h"
 
 #include "base/bind.h"
-#include "base/memory/scoped_vector.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/simple_thread.h"
 #include "base/values.h"
@@ -128,17 +127,19 @@
   }
 
   void OnAddEntry(const NetLog::Entry& entry) override {
-    base::Value* value = entry.ToValue();
-    base::DictionaryValue* dict = NULL;
-    ASSERT_TRUE(value->GetAsDictionary(&dict));
-    values_.push_back(dict);
+    scoped_ptr<base::DictionaryValue> dict =
+        base::DictionaryValue::From(make_scoped_ptr(entry.ToValue()));
+    ASSERT_TRUE(dict);
+    values_.push_back(std::move(dict));
   }
 
   size_t GetNumValues() const { return values_.size(); }
-  base::DictionaryValue* GetValue(size_t index) const { return values_[index]; }
+  base::DictionaryValue* GetValue(size_t index) const {
+    return values_[index].get();
+  }
 
  private:
-  ScopedVector<base::DictionaryValue> values_;
+  std::vector<scoped_ptr<base::DictionaryValue>> values_;
 };
 
 void AddEvent(NetLog* net_log) {
diff --git a/net/socket/client_socket_pool_base_unittest.cc b/net/socket/client_socket_pool_base_unittest.cc
index 6b58813..133f7b1 100644
--- a/net/socket/client_socket_pool_base_unittest.cc
+++ b/net/socket/client_socket_pool_base_unittest.cc
@@ -726,7 +726,9 @@
 
   TestSocketRequest* request(int i) { return test_base_.request(i); }
   size_t requests_size() const { return test_base_.requests_size(); }
-  ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
+  std::vector<scoped_ptr<TestSocketRequest>>* requests() {
+    return test_base_.requests();
+  }
   size_t completion_count() const { return test_base_.completion_count(); }
 
   TestNetLog net_log_;
diff --git a/net/socket/socket_test_util.cc b/net/socket/socket_test_util.cc
index c2230d7..93fcf3d 100644
--- a/net/socket/socket_test_util.cc
+++ b/net/socket/socket_test_util.cc
@@ -1785,19 +1785,18 @@
     return kIndexOutOfBounds;
 
   for (size_t i = 0; i < request_order_.size(); i++)
-    if (requests_[index] == request_order_[i])
+    if (requests_[index].get() == request_order_[i])
       return i + 1;
 
   return kRequestNotFound;
 }
 
 bool ClientSocketPoolTest::ReleaseOneConnection(KeepAlive keep_alive) {
-  ScopedVector<TestSocketRequest>::iterator i;
-  for (i = requests_.begin(); i != requests_.end(); ++i) {
-    if ((*i)->handle()->is_initialized()) {
+  for (scoped_ptr<TestSocketRequest>& it : requests_) {
+    if (it->handle()->is_initialized()) {
       if (keep_alive == NO_KEEP_ALIVE)
-        (*i)->handle()->socket()->Disconnect();
-      (*i)->handle()->Reset();
+        it->handle()->socket()->Disconnect();
+      it->handle()->Reset();
       base::RunLoop().RunUntilIdle();
       return true;
     }
@@ -1902,16 +1901,15 @@
       client_socket_factory_->CreateTransportClientSocket(
           AddressList(), net_log.net_log(), NetLog::Source());
   MockConnectJob* job = new MockConnectJob(socket.Pass(), handle, callback);
-  job_list_.push_back(job);
+  job_list_.push_back(make_scoped_ptr(job));
   handle->set_pool_id(1);
   return job->Connect();
 }
 
 void MockTransportClientSocketPool::CancelRequest(const std::string& group_name,
                                                   ClientSocketHandle* handle) {
-  std::vector<MockConnectJob*>::iterator i;
-  for (i = job_list_.begin(); i != job_list_.end(); ++i) {
-    if ((*i)->CancelHandle(handle)) {
+  for (scoped_ptr<MockConnectJob>& it : job_list_) {
+    if (it->CancelHandle(handle)) {
       cancel_count_++;
       break;
     }
diff --git a/net/socket/socket_test_util.h b/net/socket/socket_test_util.h
index 92089b1..430b5225 100644
--- a/net/socket/socket_test_util.h
+++ b/net/socket/socket_test_util.h
@@ -1029,9 +1029,9 @@
       RequestPriority priority,
       const scoped_refptr<typename PoolType::SocketParams>& socket_params) {
     DCHECK(socket_pool);
-    TestSocketRequest* request =
-        new TestSocketRequest(&request_order_, &completion_count_);
-    requests_.push_back(request);
+    TestSocketRequest* request(
+        new TestSocketRequest(&request_order_, &completion_count_));
+    requests_.push_back(make_scoped_ptr(request));
     int rv = request->handle()->Init(group_name,
                                      socket_params,
                                      priority,
@@ -1058,14 +1058,14 @@
 
   // Note that this uses 0-based indices, while GetOrderOfRequest takes and
   // returns 0-based indices.
-  TestSocketRequest* request(int i) { return requests_[i]; }
+  TestSocketRequest* request(int i) { return requests_[i].get(); }
 
   size_t requests_size() const { return requests_.size(); }
-  ScopedVector<TestSocketRequest>* requests() { return &requests_; }
+  std::vector<scoped_ptr<TestSocketRequest>>* requests() { return &requests_; }
   size_t completion_count() const { return completion_count_; }
 
  private:
-  ScopedVector<TestSocketRequest> requests_;
+  std::vector<scoped_ptr<TestSocketRequest>> requests_;
   std::vector<TestSocketRequest*> request_order_;
   size_t completion_count_;
 
@@ -1133,7 +1133,7 @@
 
  private:
   ClientSocketFactory* client_socket_factory_;
-  ScopedVector<MockConnectJob> job_list_;
+  std::vector<scoped_ptr<MockConnectJob>> job_list_;
   RequestPriority last_request_priority_;
   int release_count_;
   int cancel_count_;
diff --git a/net/socket/socks_client_socket_pool_unittest.cc b/net/socket/socks_client_socket_pool_unittest.cc
index e841c83..587f1fa 100644
--- a/net/socket/socks_client_socket_pool_unittest.cc
+++ b/net/socket/socks_client_socket_pool_unittest.cc
@@ -109,7 +109,9 @@
     return test_base_.GetOrderOfRequest(index);
   }
 
-  ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
+  std::vector<scoped_ptr<TestSocketRequest>>* requests() {
+    return test_base_.requests();
+  }
 
   MockClientSocketFactory transport_client_socket_factory_;
   MockTransportClientSocketPool transport_socket_pool_;
diff --git a/net/socket/transport_client_socket_pool_unittest.cc b/net/socket/transport_client_socket_pool_unittest.cc
index 1a00d46..5224e4ca 100644
--- a/net/socket/transport_client_socket_pool_unittest.cc
+++ b/net/socket/transport_client_socket_pool_unittest.cc
@@ -86,7 +86,9 @@
     test_base_.ReleaseAllConnections(keep_alive);
   }
 
-  ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
+  std::vector<scoped_ptr<TestSocketRequest>>* requests() {
+    return test_base_.requests();
+  }
   size_t completion_count() const { return test_base_.completion_count(); }
 
   bool connect_backup_jobs_enabled_;
diff --git a/net/socket/websocket_transport_client_socket_pool_unittest.cc b/net/socket/websocket_transport_client_socket_pool_unittest.cc
index 477fdb3..96aa84a9 100644
--- a/net/socket/websocket_transport_client_socket_pool_unittest.cc
+++ b/net/socket/websocket_transport_client_socket_pool_unittest.cc
@@ -102,7 +102,9 @@
 
   TestSocketRequest* request(int i) { return test_base_.request(i); }
 
-  ScopedVector<TestSocketRequest>* requests() { return test_base_.requests(); }
+  std::vector<scoped_ptr<TestSocketRequest>>* requests() {
+    return test_base_.requests();
+  }
   size_t completion_count() const { return test_base_.completion_count(); }
 
   TestNetLog net_log_;
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 637f6dbc..551ad6d 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -178,8 +178,8 @@
 
   while (!pending_recv_data_.empty()) {
     // Take ownership of the first element of |pending_recv_data_|.
-    scoped_ptr<SpdyBuffer> buffer(pending_recv_data_.front());
-    pending_recv_data_.weak_erase(pending_recv_data_.begin());
+    scoped_ptr<SpdyBuffer> buffer = std::move(pending_recv_data_.at(0));
+    pending_recv_data_.erase(pending_recv_data_.begin());
 
     bool eof = (buffer == NULL);
 
@@ -484,7 +484,7 @@
     // It should be valid for this to happen in the server push case.
     // We'll return received data when delegate gets attached to the stream.
     if (buffer) {
-      pending_recv_data_.push_back(buffer.Pass());
+      pending_recv_data_.push_back(std::move(buffer));
     } else {
       pending_recv_data_.push_back(NULL);
       // Note: we leave the stream open in the session until the stream
diff --git a/net/spdy/spdy_stream.h b/net/spdy/spdy_stream.h
index 011363ab..faf06e3 100644
--- a/net/spdy/spdy_stream.h
+++ b/net/spdy/spdy_stream.h
@@ -14,7 +14,6 @@
 #include "base/basictypes.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_ptr.h"
-#include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "net/base/io_buffer.h"
 #include "net/base/net_export.h"
@@ -547,7 +546,7 @@
   // after the data is fully read. Specifically, data received before the
   // delegate is attached must be buffered and later replayed. A remote FIN
   // is represented by a final, zero-length buffer.
-  ScopedVector<SpdyBuffer> pending_recv_data_;
+  std::vector<scoped_ptr<SpdyBuffer>> pending_recv_data_;
 
   // The time at which the request was made that resulted in this response.
   // For cached responses, this time could be "far" in the past.
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index b1fcbee..27b8117 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -383,7 +383,6 @@
       enable_compression(false),
       enable_ping(false),
       enable_user_alternate_protocol_ports(false),
-      enable_npn(true),
       protocol(protocol),
       session_max_recv_window_size(
           SpdySession::GetDefaultInitialWindowSize(protocol)),
@@ -442,7 +441,6 @@
   params.enable_spdy_ping_based_connection_checking = session_deps->enable_ping;
   params.enable_user_alternate_protocol_ports =
       session_deps->enable_user_alternate_protocol_ports;
-  params.enable_npn = session_deps->enable_npn;
   params.spdy_default_protocol = session_deps->protocol;
   params.spdy_session_max_recv_window_size =
       session_deps->session_max_recv_window_size;
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index 5316e31..33c8b33 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -197,7 +197,6 @@
   bool enable_compression;
   bool enable_ping;
   bool enable_user_alternate_protocol_ports;
-  bool enable_npn;
   NextProto protocol;
   size_t session_max_recv_window_size;
   size_t stream_max_recv_window_size;
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt
index b314b212..3f93757 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing-expected.txt
@@ -69,6 +69,10 @@
 PASS getComputedStyle(flexitem).flex is "1.75 2 3px"
 PASS flexitem.style.flex is "1 2 3px"
 PASS getComputedStyle(flexitem).flex is "1 2 3px"
+PASS flexitem.style.flex is "4 3 calc(20px + 40%)"
+PASS getComputedStyle(flexitem).flex is "4 3 calc(20px + 40%)"
+PASS flexitem.style.flex is "1 2 calc(10px + 50%)"
+PASS getComputedStyle(flexitem).flex is "1 2 calc(10px + 50%)"
 PASS flexitem.style.flex is "0 0 auto"
 PASS getComputedStyle(flexitem).flex is "0 0 auto"
 PASS flexitem.style.flex is "0 1 auto"
diff --git a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html
index ddf5fca..3ddb4c78 100644
--- a/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html
+++ b/third_party/WebKit/LayoutTests/css3/flexbox/flex-property-parsing.html
@@ -149,6 +149,14 @@
 shouldBeEqualToString('flexitem.style.flex', '1 2 3px');
 shouldBeEqualToString('getComputedStyle(flexitem).flex', '1 2 3px');
 
+flexitem.style.flex = 'calc(20px + 40%) 4 3';
+shouldBeEqualToString('flexitem.style.flex', '4 3 calc(20px + 40%)');
+shouldBeEqualToString('getComputedStyle(flexitem).flex', '4 3 calc(20px + 40%)');
+
+flexitem.style.flex = '1 2 calc(10px + 50%)';
+shouldBeEqualToString('flexitem.style.flex', '1 2 calc(10px + 50%)');
+shouldBeEqualToString('getComputedStyle(flexitem).flex', '1 2 calc(10px + 50%)');
+
 flexitem.style.flex = 'auto 0 0';
 shouldBeEqualToString('flexitem.style.flex', '0 0 auto');
 shouldBeEqualToString('getComputedStyle(flexitem).flex', '0 0 auto');
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate-expected.txt b/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate-expected.txt
index d078f79..24a3e3a 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate-expected.txt
@@ -20,6 +20,8 @@
 PASS candidate.candidate is "bar"
 PASS candidate.sdpMid is "foo"
 PASS candidate.sdpMLineIndex is 0
+PASS candidate.candidate is "null"
+PASS candidate.sdpMid is "null"
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate.html b/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate.html
index 235f670..be05c73 100644
--- a/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate.html
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/RTCIceCandidate.html
@@ -38,6 +38,10 @@
 shouldBeEqualToString('candidate.sdpMid', 'foo');
 shouldBe('candidate.sdpMLineIndex', '0');
 
+candidate.candidate = null;
+candidate.sdpMid = null;
+shouldBeEqualToString('candidate.candidate', 'null');
+shouldBeEqualToString('candidate.sdpMid', 'null');
 
 window.successfullyParsed = true;
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-one-line-in-inner-expected.txt b/third_party/WebKit/LayoutTests/fast/multicol/nested-one-line-in-inner-expected.txt
new file mode 100644
index 0000000..b41178a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-one-line-in-inner-expected.txt
@@ -0,0 +1,5 @@
+Test that an inner multicol with only one line makes the outer multicol tall enough to contain it.
+
+There should be a blue square below.
+
+ PASS
diff --git a/third_party/WebKit/LayoutTests/fast/multicol/nested-one-line-in-inner.html b/third_party/WebKit/LayoutTests/fast/multicol/nested-one-line-in-inner.html
new file mode 100644
index 0000000..498fc19
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/multicol/nested-one-line-in-inner.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<script src="../../resources/check-layout.js"></script>
+<p>Test that an inner multicol with only one line makes the outer multicol tall enough to contain it.</p>
+<p>There should be a blue square below.</p>
+<div id="outer" style="-webkit-columns:4; line-height:80px;" data-expected-height="80">
+    <div style="-webkit-columns:4;" data-expected-height="80">
+        <div style="display:inline-block; vertical-align:top; width:80px; height:80px; background:blue;"></div>
+    </div>
+</div>
+<script>
+    checkLayout("#outer");
+</script>
diff --git a/third_party/WebKit/LayoutTests/nfc/idl-NFC.html b/third_party/WebKit/LayoutTests/nfc/idl-NFC.html
index d098e0f5..1ca2eebe 100644
--- a/third_party/WebKit/LayoutTests/nfc/idl-NFC.html
+++ b/third_party/WebKit/LayoutTests/nfc/idl-NFC.html
@@ -7,5 +7,14 @@
                 'the constructor should not be callable with "new"');
   assert_throws(null, function() { NFC(); },
                 'the constructor should not be callable');
+
+  // Test that navigator.nfc.push exists
+  assert_true('push' in navigator.nfc);
+  // Test that navigator.nfc.cancelPush exists
+  assert_true('cancelPush' in navigator.nfc);
+  // Test that navigator.nfc.watch exists
+  assert_true('watch' in navigator.nfc);
+  // Test that navigator.nfc.cancelWatch exists
+  assert_true('cancelWatch' in navigator.nfc);
 }, 'NFC IDL test');
 </script>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index 77c6b6e..33715ca 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3419,8 +3419,11 @@
     getter type
     method constructor
 interface NFC
+    method cancelPush
+    method cancelWatch
     method constructor
-    method requestAdapter
+    method push
+    method watch
 interface NamedNodeMap
     getter length
     method constructor
diff --git a/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp b/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp
index d364936..f22770b3 100644
--- a/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSPrimitiveValue.cpp
@@ -556,6 +556,7 @@
     case CSSPrimitiveValue::UnitType::Inches:
     case CSSPrimitiveValue::UnitType::Points:
     case CSSPrimitiveValue::UnitType::Picas:
+    case CSSPrimitiveValue::UnitType::UserUnits:
         lengthType = UnitTypePixels;
         return true;
     case CSSPrimitiveValue::UnitType::Ems:
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
index 6b4eaaf..b3b7bb3 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.cpp
@@ -184,7 +184,7 @@
 
     bool consumeNumberRaw(double& result)
     {
-        if (!m_calcValue)
+        if (!m_calcValue || m_calcValue->category() != CalcNumber)
             return false;
         m_sourceRange = m_range;
         result = m_calcValue->doubleValue();
@@ -280,10 +280,13 @@
         case CSSPrimitiveValue::UnitType::Points:
         case CSSPrimitiveValue::UnitType::Picas:
         case CSSPrimitiveValue::UnitType::UserUnits:
+            break;
         case CSSPrimitiveValue::UnitType::ViewportWidth:
         case CSSPrimitiveValue::UnitType::ViewportHeight:
         case CSSPrimitiveValue::UnitType::ViewportMin:
         case CSSPrimitiveValue::UnitType::ViewportMax:
+            if (cssParserMode == SVGAttributeMode)
+                return nullptr;
             break;
         default:
             return nullptr;
@@ -301,6 +304,8 @@
             unitType = CSSPrimitiveValue::UnitType::UserUnits;
         return cssValuePool().createValue(range.consumeIncludingWhitespace().numericValue(), unitType);
     }
+    if (cssParserMode == SVGAttributeMode)
+        return nullptr;
     CalcParser calcParser(range, valueRange);
     if (calcParser.value() && calcParser.value()->category() == CalcLength)
         return calcParser.consumeValue();
@@ -1850,6 +1855,22 @@
     return consumeLengthOrPercent(range, cssParserMode, ValueRangeNonNegative);
 }
 
+static PassRefPtrWillBeRawPtr<CSSValue> consumeStrokeDasharray(CSSParserTokenRange& range)
+{
+    CSSValueID id = range.peek().id();
+    if (id == CSSValueNone)
+        return consumeIdent(range);
+
+    RefPtrWillBeRawPtr<CSSValueList> dashes = CSSValueList::createCommaSeparated();
+    do {
+        RefPtrWillBeRawPtr<CSSPrimitiveValue> dash = consumeLengthOrPercent(range, SVGAttributeMode, ValueRangeNonNegative, UnitlessQuirk::Allow);
+        if (!dash || (consumeCommaIncludingWhitespace(range) && range.atEnd()))
+            return nullptr;
+        dashes->append(dash.release());
+    } while (!range.atEnd());
+    return dashes.release();
+}
+
 PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSingleValue(CSSPropertyID unresolvedProperty)
 {
     CSSPropertyID property = resolveCSSPropertyID(unresolvedProperty);
@@ -2025,6 +2046,8 @@
     case CSSPropertyFlexGrow:
     case CSSPropertyFlexShrink:
         return consumeNumber(m_range, ValueRangeNonNegative);
+    case CSSPropertyStrokeDasharray:
+        return consumeStrokeDasharray(m_range);
     default:
         return nullptr;
     }
diff --git a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
index 774a41e..a642fd9 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
+++ b/third_party/WebKit/Source/core/css/parser/CSSPropertyParser.h
@@ -199,7 +199,6 @@
     PassRefPtrWillBeRawPtr<CSSValueList> consumeFontFaceSrc();
 
     bool parseSVGValue(CSSPropertyID propId, bool important);
-    PassRefPtrWillBeRawPtr<CSSValue> parseSVGStrokeDasharray();
 
     // CSS3 Parsing Routines (for properties specific to CSS3)
     bool parseBorderImageShorthand(CSSPropertyID, bool important);
diff --git a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
index 9079aee..fcecfbd8 100644
--- a/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
+++ b/third_party/WebKit/Source/core/css/parser/LegacyCSSPropertyParser.cpp
@@ -1153,6 +1153,7 @@
     case CSSPropertyFlexGrow:
     case CSSPropertyFlexShrink:
     case CSSPropertyFlexFlow:
+    case CSSPropertyStrokeDasharray:
         validPrimitive = false;
         break;
 
@@ -5441,12 +5442,6 @@
     case CSSPropertyRy:
         validPrimitive = validUnit(value, FLength | FPercent, SVGAttributeMode);
         break;
-    case CSSPropertyStrokeDasharray: // none | <dasharray> | inherit
-        if (id == CSSValueNone)
-            validPrimitive = true;
-        else
-            parsedValue = parseSVGStrokeDasharray();
-        break;
 
     default:
         // If you crash here, it's because you added a css property and are not handling it
@@ -5481,30 +5476,4 @@
     return true;
 }
 
-PassRefPtrWillBeRawPtr<CSSValue> CSSPropertyParser::parseSVGStrokeDasharray()
-{
-    RefPtrWillBeRawPtr<CSSValueList> ret = CSSValueList::createCommaSeparated();
-    CSSParserValue* value = m_valueList->current();
-    bool validPrimitive = true;
-    while (value) {
-        validPrimitive = validUnit(value, FLength | FPercent | FNonNeg, SVGAttributeMode);
-        if (!validPrimitive)
-            break;
-        if (value->id)
-            ret->append(CSSPrimitiveValue::createIdentifier(value->id));
-        else if (value->unit() >= CSSPrimitiveValue::UnitType::Number && value->unit() <= CSSPrimitiveValue::UnitType::Kilohertz)
-            ret->append(CSSPrimitiveValue::create(value->fValue, value->unit()));
-        else if (value->unit() == CSSPrimitiveValue::UnitType::Rems || value->unit() == CSSPrimitiveValue::UnitType::Chs)
-            ret->append(CSSPrimitiveValue::create(value->fValue, value->unit()));
-        value = m_valueList->next();
-        bool commaConsumed = consumeComma(m_valueList);
-        value = m_valueList->current();
-        if (commaConsumed && !value)
-            return nullptr;
-    }
-    if (!validPrimitive)
-        return nullptr;
-    return ret.release();
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp b/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp
index 60009f4..3b6f8aae 100644
--- a/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp
@@ -38,9 +38,27 @@
 
 namespace blink {
 
+BaseChooserOnlyDateAndTimeInputType::BaseChooserOnlyDateAndTimeInputType(HTMLInputElement& element)
+    : BaseDateAndTimeInputType(element)
+{
+#if ENABLE(OILPAN)
+    ThreadState::current()->registerPreFinalizer(this);
+#endif
+}
+
 BaseChooserOnlyDateAndTimeInputType::~BaseChooserOnlyDateAndTimeInputType()
 {
+#if !ENABLE(OILPAN)
     closeDateTimeChooser();
+#endif
+    ASSERT(!m_dateTimeChooser);
+}
+
+DEFINE_TRACE(BaseChooserOnlyDateAndTimeInputType)
+{
+    visitor->trace(m_dateTimeChooser);
+    BaseDateAndTimeInputType::trace(visitor);
+    DateTimeChooserClient::trace(visitor);
 }
 
 void BaseChooserOnlyDateAndTimeInputType::handleDOMActivateEvent(Event*)
diff --git a/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.h b/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.h
index ce37c913..492e76f 100644
--- a/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.h
@@ -31,14 +31,19 @@
 #include "core/html/forms/BaseDateAndTimeInputType.h"
 #include "core/html/forms/DateTimeChooser.h"
 #include "core/html/forms/DateTimeChooserClient.h"
+#include "platform/heap/Handle.h"
 
 namespace blink {
 
 class BaseChooserOnlyDateAndTimeInputType : public BaseDateAndTimeInputType, public DateTimeChooserClient {
+    WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(BaseChooserOnlyDateAndTimeInputType);
+    WILL_BE_USING_PRE_FINALIZER(BaseChooserOnlyDateAndTimeInputType, closeDateTimeChooser);
 protected:
-    BaseChooserOnlyDateAndTimeInputType(HTMLInputElement& element) : BaseDateAndTimeInputType(element) { }
+    BaseChooserOnlyDateAndTimeInputType(HTMLInputElement&);
     ~BaseChooserOnlyDateAndTimeInputType() override;
 
+    DECLARE_VIRTUAL_TRACE();
+
 private:
     void closeDateTimeChooser();
 
@@ -59,9 +64,10 @@
     void didChooseValue(double) override;
     void didEndChooser() override;
 
-    RefPtr<DateTimeChooser> m_dateTimeChooser;
+    RefPtrWillBeMember<DateTimeChooser> m_dateTimeChooser;
 };
 
-}
-#endif
-#endif
+} // namespace blink
+
+#endif // ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#endif // BaseChooserOnlyDateAndTimeInputType_h
diff --git a/third_party/WebKit/Source/core/html/forms/DateInputType.h b/third_party/WebKit/Source/core/html/forms/DateInputType.h
index 38002ce..6229b6ad 100644
--- a/third_party/WebKit/Source/core/html/forms/DateInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/DateInputType.h
@@ -47,7 +47,8 @@
     static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&);
 
 private:
-    DateInputType(HTMLInputElement&);
+    explicit DateInputType(HTMLInputElement&);
+
     void countUsage() override;
     const AtomicString& formControlType() const override;
     StepRange createStepRange(AnyStepHandling) const override;
diff --git a/third_party/WebKit/Source/core/html/forms/DateTimeChooserClient.h b/third_party/WebKit/Source/core/html/forms/DateTimeChooserClient.h
index dc9a846..9f8c1e9 100644
--- a/third_party/WebKit/Source/core/html/forms/DateTimeChooserClient.h
+++ b/third_party/WebKit/Source/core/html/forms/DateTimeChooserClient.h
@@ -31,15 +31,17 @@
 #ifndef DateTimeChooserClient_h
 #define DateTimeChooserClient_h
 
-#include "wtf/text/WTFString.h"
+#include "platform/heap/Handle.h"
+#include "wtf/Forward.h"
 
 namespace blink {
 
 class Element;
 
-class DateTimeChooserClient {
+class DateTimeChooserClient : public WillBeGarbageCollectedMixin {
 public:
     virtual ~DateTimeChooserClient();
+    DEFINE_INLINE_VIRTUAL_TRACE() { }
 
     virtual Element& ownerElement() const = 0;
     // Called when user picked a value.
diff --git a/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h b/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h
index 538882f..d0db7d7 100644
--- a/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/DateTimeLocalInputType.h
@@ -49,7 +49,8 @@
     static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&);
 
 private:
-    DateTimeLocalInputType(HTMLInputElement& element) : BaseDateTimeLocalInputType(element) { }
+    explicit DateTimeLocalInputType(HTMLInputElement& element) : BaseDateTimeLocalInputType(element) { }
+
     void countUsage() override;
     const AtomicString& formControlType() const override;
     double valueAsDate() const override;
diff --git a/third_party/WebKit/Source/core/html/forms/MonthInputType.h b/third_party/WebKit/Source/core/html/forms/MonthInputType.h
index 3b1af1c..b491730 100644
--- a/third_party/WebKit/Source/core/html/forms/MonthInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/MonthInputType.h
@@ -47,7 +47,8 @@
     static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&);
 
 private:
-    MonthInputType(HTMLInputElement& element) : BaseMonthInputType(element) { }
+    explicit MonthInputType(HTMLInputElement& element) : BaseMonthInputType(element) { }
+
     void countUsage() override;
     const AtomicString& formControlType() const override;
     double valueAsDate() const override;
diff --git a/third_party/WebKit/Source/core/html/forms/TimeInputType.h b/third_party/WebKit/Source/core/html/forms/TimeInputType.h
index 25192ddb..85ac111 100644
--- a/third_party/WebKit/Source/core/html/forms/TimeInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/TimeInputType.h
@@ -47,7 +47,8 @@
     static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&);
 
 private:
-    TimeInputType(HTMLInputElement&);
+    explicit TimeInputType(HTMLInputElement&);
+
     void countUsage() override;
     const AtomicString& formControlType() const override;
     Decimal defaultValueForStepUp() const override;
@@ -56,8 +57,8 @@
     bool setMillisecondToDateComponents(double, DateComponents*) const override;
     void warnIfValueIsInvalid(const String&) const override;
     String localizeValue(const String&) const override;
-#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
 
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
     // BaseMultipleFieldsDateAndTimeInputType functions
     String formatDateTimeFieldsState(const DateTimeFieldsState&) const override;
     void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const override;
diff --git a/third_party/WebKit/Source/core/html/forms/WeekInputType.h b/third_party/WebKit/Source/core/html/forms/WeekInputType.h
index 32511ac1..98acfcb 100644
--- a/third_party/WebKit/Source/core/html/forms/WeekInputType.h
+++ b/third_party/WebKit/Source/core/html/forms/WeekInputType.h
@@ -47,7 +47,8 @@
     static PassRefPtrWillBeRawPtr<InputType> create(HTMLInputElement&);
 
 private:
-    WeekInputType(HTMLInputElement& element) : BaseWeekInputType(element) { }
+    explicit WeekInputType(HTMLInputElement& element) : BaseWeekInputType(element) { }
+
     void countUsage() override;
     const AtomicString& formControlType() const override;
     StepRange createStepRange(AnyStepHandling) const override;
diff --git a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
index 9d60f71..22b03e5 100644
--- a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.cpp
@@ -187,8 +187,9 @@
     visitor->trace(m_pickerIndicatorOwner);
     visitor->trace(m_chooser);
     HTMLDivElement::trace(visitor);
+    DateTimeChooserClient::trace(visitor);
 }
 
-}
+} // namespace blink
 
-#endif
+#endif // ENABLE(INPUT_MULTIPLE_FIELDS_UI)
diff --git a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
index fe14ee6..7ce6bfe 100644
--- a/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
+++ b/third_party/WebKit/Source/core/html/shadow/PickerIndicatorElement.h
@@ -41,6 +41,7 @@
 class HTMLInputElement;
 
 class PickerIndicatorElement final : public HTMLDivElement, public DateTimeChooserClient {
+    WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(PickerIndicatorElement);
 public:
     // PickerIndicatorOwner implementer must call removePickerIndicatorOwner when
     // it doesn't handle event, e.g. at destruction.
diff --git a/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp b/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
index 989f2d8..3de1e264 100644
--- a/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
+++ b/third_party/WebKit/Source/core/layout/ColumnBalancer.cpp
@@ -92,8 +92,7 @@
 {
     unsigned index = contentRunIndexWithTallestColumns();
     LayoutUnit startOffset = index > 0 ? m_contentRuns[index - 1].breakOffset() : group().logicalTopInFlowThread();
-    LayoutUnit logicalHeightEstimate = m_contentRuns[index].columnLogicalHeight(startOffset);
-    return std::max(logicalHeightEstimate, m_minimumColumnLogicalHeight);
+    return m_contentRuns[index].columnLogicalHeight(startOffset);
 }
 
 void InitialColumnHeightFinder::examineBoxAfterEntering(const LayoutBox& box)
@@ -113,8 +112,13 @@
         LayoutUnit unsplittableLogicalHeight = box.logicalHeight();
         if (box.isFloating())
             unsplittableLogicalHeight += box.marginBefore() + box.marginAfter();
-        if (m_minimumColumnLogicalHeight < unsplittableLogicalHeight)
-            m_minimumColumnLogicalHeight = unsplittableLogicalHeight;
+        m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, unsplittableLogicalHeight);
+    } else if (box.isLayoutBlockFlow()) {
+        if (LayoutMultiColumnFlowThread* innerFlowThread = toLayoutBlockFlow(box).multiColumnFlowThread()) {
+            LayoutUnit offsetInInnerFlowThread = flowThreadOffset() - innerFlowThread->blockOffsetInEnclosingFlowThread();
+            LayoutUnit innerUnbreakableHeight = innerFlowThread->tallestUnbreakableLogicalHeight(offsetInInnerFlowThread);
+            m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, innerUnbreakableHeight);
+        }
     }
 }
 
@@ -138,8 +142,7 @@
     LayoutUnit lineTop = line.lineTopWithLeading();
     LayoutUnit lineTopInFlowThread = flowThreadOffset() + lineTop;
     LayoutUnit minimumLogialHeight = columnLogicalHeightRequirementForLine(line.block().styleRef(), line);
-    if (m_minimumColumnLogicalHeight < minimumLogialHeight)
-        m_minimumColumnLogicalHeight = minimumLogialHeight;
+    m_tallestUnbreakableLogicalHeight = std::max(m_tallestUnbreakableLogicalHeight, minimumLogialHeight);
     ASSERT(isFirstAfterBreak(lineTopInFlowThread) || !line.paginationStrut());
     if (isFirstAfterBreak(lineTopInFlowThread))
         recordStrutBeforeOffset(lineTopInFlowThread, line.paginationStrut());
diff --git a/third_party/WebKit/Source/core/layout/ColumnBalancer.h b/third_party/WebKit/Source/core/layout/ColumnBalancer.h
index 161f5a0..9bf1dacc 100644
--- a/third_party/WebKit/Source/core/layout/ColumnBalancer.h
+++ b/third_party/WebKit/Source/core/layout/ColumnBalancer.h
@@ -62,16 +62,17 @@
 // of this class, named MinimumSpaceShortageFinder.
 class InitialColumnHeightFinder final : public ColumnBalancer {
 public:
-    static LayoutUnit initialMinimalBalancedHeight(const MultiColumnFragmentainerGroup& group)
-    {
-        return InitialColumnHeightFinder(group).initialMinimalBalancedHeight();
-    }
-
-private:
     InitialColumnHeightFinder(const MultiColumnFragmentainerGroup&);
 
     LayoutUnit initialMinimalBalancedHeight() const;
 
+    // Height of the tallest piece of unbreakable content. This is the minimum column logical height
+    // required to avoid fragmentation where it shouldn't occur (inside unbreakable content, between
+    // orphans and widows, etc.). This will be used as a hint to the column balancer to help set a
+    // good initial column height.
+    LayoutUnit tallestUnbreakableLogicalHeight() const { return m_tallestUnbreakableLogicalHeight; }
+
+private:
     void examineBoxAfterEntering(const LayoutBox&);
     void examineBoxBeforeLeaving(const LayoutBox&);
     void examineLine(const RootInlineBox&);
@@ -139,7 +140,7 @@
     // [1] http://www.w3.org/TR/css3-break/#parallel-flows
     Vector<LayoutUnit, 32> m_shortestStruts;
 
-    LayoutUnit m_minimumColumnLogicalHeight;
+    LayoutUnit m_tallestUnbreakableLogicalHeight;
 };
 
 // If we have previously used InitialColumnHeightFinder to estimate an initial column height, and
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index bd4bf8a..1286c81 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -716,9 +716,7 @@
             // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
             // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
             // and pushes to the next page anyway, so not too concerned about it.
-            paginationStrut += logicalTop;
-            if (isFloating())
-                paginationStrut += marginBefore(); // Floats' margins do not collapse with page or column boundaries.
+            paginationStrut += logicalTop + marginBeforeIfFloating();
             setPaginationStrutPropagatedFromChild(paginationStrut);
             if (childBlockFlow)
                 childBlockFlow->setPaginationStrutPropagatedFromChild(LayoutUnit());
@@ -762,14 +760,6 @@
     return wantsStrutOnBlock && block.allowsPaginationStrut();
 }
 
-static LayoutUnit calculateStrutForPropagation(const LayoutBlockFlow& blockFlow, LayoutUnit lineLogicalOffset)
-{
-    LayoutUnit paginationStrut = std::max<LayoutUnit>(LayoutUnit(), lineLogicalOffset);
-    if (blockFlow.isFloating())
-        paginationStrut += blockFlow.marginBefore(); // Floats' margins do not collapse with page or column boundaries.
-    return paginationStrut;
-}
-
 void LayoutBlockFlow::adjustLinePositionForPagination(RootInlineBox& lineBox, LayoutUnit& delta)
 {
     // TODO(mstensho): Pay attention to line overflow. It should be painted in the same column as
@@ -813,7 +803,8 @@
             // content-less portions (struts) at the beginning of a block before a break, if it can
             // be avoided. After all, that's the reason for setting struts on blocks and not lines
             // in the first place.
-            setPaginationStrutPropagatedFromChild(calculateStrutForPropagation(*this, remainingLogicalHeight + logicalOffset));
+            LayoutUnit strut = remainingLogicalHeight + logicalOffset + marginBeforeIfFloating();
+            setPaginationStrutPropagatedFromChild(strut);
         } else {
             logicalOffset += remainingLogicalHeight;
             delta += remainingLogicalHeight;
@@ -828,15 +819,15 @@
         // case it's a float) margin, we may want to set a strut on the block, so that everything
         // ends up in the next column or page. Setting a strut on the block is also important when
         // it comes to satisfying orphan requirements.
-        if (shouldSetStrutOnBlock(*this, lineBox, logicalOffset, lineIndex, remainingLogicalHeight))
-            setPaginationStrutPropagatedFromChild(calculateStrutForPropagation(*this, logicalOffset));
+        if (shouldSetStrutOnBlock(*this, lineBox, logicalOffset, lineIndex, remainingLogicalHeight)) {
+            LayoutUnit strut = logicalOffset + marginBeforeIfFloating();
+            setPaginationStrutPropagatedFromChild(strut);
+        }
     } else if (lineBox == firstRootBox() && allowsPaginationStrut()) {
         // This is the first line in the block. The block may still start in the previous column or
         // page, and if that's the case, attempt to pull it over to where this line is, so that we
         // don't split the top border, padding, or (in case it's a float) margin.
-        LayoutUnit totalLogicalOffset = logicalOffset;
-        if (isFloating())
-            totalLogicalOffset += marginBefore(); // Floats' margins do not collapse with page or column boundaries.
+        LayoutUnit totalLogicalOffset = logicalOffset + marginBeforeIfFloating();
         LayoutUnit strut = remainingLogicalHeight + totalLogicalOffset - pageLogicalHeight;
         if (strut > 0) {
             // The block starts in a previous column or page. Set a strut on the block if there's
@@ -2932,6 +2923,7 @@
 
 void LayoutBlockFlow::setPaginationStrutPropagatedFromChild(LayoutUnit strut)
 {
+    strut = std::max(strut, LayoutUnit());
     if (!m_rareData) {
         if (!strut)
             return;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
index cb05410..ca222c0 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -516,6 +516,10 @@
     LayoutUnit collapsedMarginBefore() const final { return maxPositiveMarginBefore() - maxNegativeMarginBefore(); }
     LayoutUnit collapsedMarginAfter() const final { return maxPositiveMarginAfter() - maxNegativeMarginAfter(); }
 
+    // Floats' margins do not collapse with page or column boundaries, and we therefore need to
+    // treat them specially in some cases.
+    LayoutUnit marginBeforeIfFloating() const { return isFloating() ? marginBefore() : LayoutUnit(); }
+
     LayoutUnit collapseMargins(LayoutBox& child, MarginInfo&, bool childIsSelfCollapsing, bool childDiscardMarginBefore, bool childDiscardMarginAfter);
     LayoutUnit clearFloatsIfNeeded(LayoutBox& child, MarginInfo&, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos, bool childIsSelfCollapsing, bool childDiscardMargin);
     LayoutUnit estimateLogicalTopPosition(LayoutBox& child, const MarginInfo&, LayoutUnit& estimateWithoutPagination);
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
index 5e2ad6f..fc7e68b 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.cpp
@@ -262,6 +262,13 @@
     destroy();
 }
 
+LayoutUnit LayoutMultiColumnFlowThread::tallestUnbreakableLogicalHeight(LayoutUnit offsetInFlowThread) const
+{
+    if (LayoutMultiColumnSet* multicolSet = columnSetAtBlockOffset(offsetInFlowThread))
+        return multicolSet->tallestUnbreakableLogicalHeight();
+    return LayoutUnit();
+}
+
 LayoutSize LayoutMultiColumnFlowThread::columnOffset(const LayoutPoint& point) const
 {
     if (!hasValidColumnSetInfo())
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h
index 057fec7..42acf66 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnFlowThread.h
@@ -162,6 +162,8 @@
     void setColumnHeightAvailable(LayoutUnit available) { m_columnHeightAvailable = available; }
     bool progressionIsInline() const { return m_progressionIsInline; }
 
+    LayoutUnit tallestUnbreakableLogicalHeight(LayoutUnit offsetInFlowThread) const;
+
     LayoutSize columnOffset(const LayoutPoint&) const final;
 
     // Do we need to set a new width and lay out?
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
index 378540b..0b9ed3a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.cpp
@@ -216,6 +216,8 @@
 
 bool LayoutMultiColumnSet::recalculateColumnHeight(BalancedColumnHeightCalculation calculationMode)
 {
+    if (calculationMode == GuessFromFlowThreadPortion)
+        m_tallestUnbreakableLogicalHeight = LayoutUnit();
     bool changed = false;
     for (auto& group : m_fragmentainerGroups)
         changed = group.recalculateColumnHeight(calculationMode) || changed;
diff --git a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.h b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.h
index c5884e9..a167878 100644
--- a/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.h
+++ b/third_party/WebKit/Source/core/layout/LayoutMultiColumnSet.h
@@ -82,6 +82,8 @@
     LayoutUnit pageLogicalHeightForOffset(LayoutUnit) const;
     LayoutUnit pageRemainingLogicalHeightForOffset(LayoutUnit, PageBoundaryRule) const;
     bool isPageLogicalHeightKnown() const;
+    LayoutUnit tallestUnbreakableLogicalHeight() const { return m_tallestUnbreakableLogicalHeight; }
+    void propagateTallestUnbreakableLogicalHeight(LayoutUnit value) { m_tallestUnbreakableLogicalHeight = std::max(value, m_tallestUnbreakableLogicalHeight); }
 
     LayoutFlowThread* flowThread() const { return m_flowThread; }
 
@@ -168,6 +170,14 @@
 
     MultiColumnFragmentainerGroupList m_fragmentainerGroups;
     LayoutFlowThread* m_flowThread;
+
+    // Height of the tallest piece of unbreakable content. This is the minimum column logical height
+    // required to avoid fragmentation where it shouldn't occur (inside unbreakable content, between
+    // orphans and widows, etc.). We only store this so that outer fragmentation contexts (if any)
+    // can query this when calculating their own minimum. Note that we don't store this value in
+    // every fragmentainer group (but rather here, in the column set), since we only need the
+    // largest one among them.
+    LayoutUnit m_tallestUnbreakableLogicalHeight;
 };
 
 DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutMultiColumnSet, isLayoutMultiColumnSet());
diff --git a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
index 09c64a88..431cc2d 100644
--- a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
+++ b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.cpp
@@ -68,13 +68,25 @@
     // balance the preceding rows, and that could potentially lead to an insane number of layout
     // passes as well.
     if (isLastGroup() && m_columnSet.heightIsAuto()) {
-        LayoutUnit newColumnHeight = calculateColumnHeight(calculationMode);
+        LayoutUnit newColumnHeight;
+        if (calculationMode == GuessFromFlowThreadPortion) {
+            // Initial balancing: Start with the lowest imaginable column height. Also calculate the
+            // height of the tallest piece of unbreakable content. Columns should never get any
+            // shorter than that (unless constrained by max-height). Propagate this to our
+            // containing column set, in case there is an outer multicol container that also needs
+            // to balance. After having calculated the initial column height, the multicol container
+            // needs another layout pass with the column height that we just calculated.
+            InitialColumnHeightFinder initialHeightFinder(*this);
+            LayoutUnit tallestUnbreakableLogicalHeight = initialHeightFinder.tallestUnbreakableLogicalHeight();
+            m_columnSet.propagateTallestUnbreakableLogicalHeight(tallestUnbreakableLogicalHeight);
+            newColumnHeight = std::max(initialHeightFinder.initialMinimalBalancedHeight(), tallestUnbreakableLogicalHeight);
+        } else {
+            // Rebalancing: After having laid out again, we'll need to rebalance if the height
+            // wasn't enough and we're allowed to stretch it, and then re-lay out. There are further
+            // details on the column balancing machinery in ColumnBalancer and its derivates.
+            newColumnHeight = rebalanceColumnHeightIfNeeded();
+        }
         setAndConstrainColumnHeight(newColumnHeight);
-        // After having calculated an initial column height, the multicol container typically needs at
-        // least one more layout pass with a new column height, but if a height was specified, we only
-        // need to do this if we think that we need less space than specified. Conversely, if we
-        // determined that the columns need to be as tall as the specified height of the container, we
-        // have already laid it out correctly, and there's no need for another pass.
     } else {
         // The position of the column set may have changed, in which case height available for
         // columns may have changed as well.
@@ -331,16 +343,8 @@
         m_columnHeight = m_maxColumnHeight;
 }
 
-LayoutUnit MultiColumnFragmentainerGroup::calculateColumnHeight(BalancedColumnHeightCalculation calculationMode) const
+LayoutUnit MultiColumnFragmentainerGroup::rebalanceColumnHeightIfNeeded() const
 {
-    if (calculationMode == GuessFromFlowThreadPortion) {
-        // Initial balancing. Start with the lowest imaginable column height. We use the tallest
-        // content run (after having "inserted" implicit breaks), and find its start offset (by
-        // looking at the previous run's end offset, or, if there's no previous run, the set's start
-        // offset in the flow thread).
-        return InitialColumnHeightFinder::initialMinimalBalancedHeight(*this);
-    }
-
     if (actualColumnCount() <= m_columnSet.usedColumnCount()) {
         // With the current column height, the content fits without creating overflowing columns. We're done.
         return m_columnHeight;
diff --git a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
index 4f53c50e..e0e1f49 100644
--- a/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
+++ b/third_party/WebKit/Source/core/layout/MultiColumnFragmentainerGroup.h
@@ -84,7 +84,7 @@
     LayoutUnit calculateMaxColumnHeight() const;
     void setAndConstrainColumnHeight(LayoutUnit);
 
-    LayoutUnit calculateColumnHeight(BalancedColumnHeightCalculation) const;
+    LayoutUnit rebalanceColumnHeightIfNeeded() const;
 
     LayoutRect columnRectAt(unsigned columnIndex) const;
     LayoutUnit logicalTopInFlowThreadAt(unsigned columnIndex) const { return m_logicalTopInFlowThread + columnIndex * m_columnHeight; }
diff --git a/third_party/WebKit/Source/modules/mediastream/RTCIceCandidate.idl b/third_party/WebKit/Source/modules/mediastream/RTCIceCandidate.idl
index d6ce94d..d3bce54a 100644
--- a/third_party/WebKit/Source/modules/mediastream/RTCIceCandidate.idl
+++ b/third_party/WebKit/Source/modules/mediastream/RTCIceCandidate.idl
@@ -33,8 +33,8 @@
     Constructor(RTCIceCandidateInit candidateInitDict),
     RaisesException=Constructor
 ] interface RTCIceCandidate {
-    [TreatNullAs=NullString] attribute DOMString candidate;
-    [TreatNullAs=NullString] attribute DOMString sdpMid;
+    attribute DOMString candidate;
+    attribute DOMString sdpMid;
     attribute unsigned short sdpMLineIndex;
     serializer = {attribute};
 };
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi
index f80fbaa..fe95788 100644
--- a/third_party/WebKit/Source/modules/modules.gypi
+++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -144,6 +144,7 @@
       'navigatorconnect/ServicePortConnectEvent.idl',
       'navigatorconnect/ServicePortCollection.idl',
       'netinfo/NetworkInformation.idl',
+      'nfc/MessageCallback.idl',
       'nfc/NFC.idl',
       'notifications/Notification.idl',
       'notifications/NotificationEvent.idl',
@@ -471,6 +472,7 @@
       'navigatorconnect/ServicePortConnectOptions.idl',
       'navigatorconnect/ServicePortConnectResponse.idl',
       'navigatorconnect/ServicePortMatchOptions.idl',
+      'nfc/NFCMessage.idl',
       'nfc/NFCPushOptions.idl',
       'nfc/NFCRecord.idl',
       'nfc/NFCWatchOptions.idl',
@@ -608,6 +610,8 @@
       '<(blink_modules_output_dir)/navigatorconnect/ServicePortConnectResponse.h',
       '<(blink_modules_output_dir)/navigatorconnect/ServicePortMatchOptions.cpp',
       '<(blink_modules_output_dir)/navigatorconnect/ServicePortMatchOptions.h',
+      '<(blink_modules_output_dir)/nfc/NFCMessage.cpp',
+      '<(blink_modules_output_dir)/nfc/NFCMessage.h',
       '<(blink_modules_output_dir)/nfc/NFCPushOptions.cpp',
       '<(blink_modules_output_dir)/nfc/NFCPushOptions.h',
       '<(blink_modules_output_dir)/nfc/NFCRecord.cpp',
diff --git a/third_party/WebKit/Source/modules/nfc/MessageCallback.h b/third_party/WebKit/Source/modules/nfc/MessageCallback.h
new file mode 100644
index 0000000..84d4279
--- /dev/null
+++ b/third_party/WebKit/Source/modules/nfc/MessageCallback.h
@@ -0,0 +1,23 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MessageCallback_h
+#define MessageCallback_h
+
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class NFCMessage;
+
+class MessageCallback : public GarbageCollectedFinalized<MessageCallback> {
+public:
+    virtual ~MessageCallback() { }
+    DEFINE_INLINE_VIRTUAL_TRACE() { }
+    virtual void handleMessage(const NFCMessage&) = 0;
+};
+
+} // namespace blink
+
+#endif // MessageCallback_h
diff --git a/third_party/WebKit/Source/modules/nfc/MessageCallback.idl b/third_party/WebKit/Source/modules/nfc/MessageCallback.idl
new file mode 100644
index 0000000..edbffe5
--- /dev/null
+++ b/third_party/WebKit/Source/modules/nfc/MessageCallback.idl
@@ -0,0 +1,9 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/web-nfc/#idl-def-messagecallback
+
+callback interface MessageCallback {
+    void handleMessage(NFCMessage message);
+};
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.cpp b/third_party/WebKit/Source/modules/nfc/NFC.cpp
index ffd1cf7..1f935e5 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.cpp
+++ b/third_party/WebKit/Source/modules/nfc/NFC.cpp
@@ -8,6 +8,8 @@
 #include "bindings/core/v8/ScriptPromiseResolver.h"
 #include "core/dom/DOMException.h"
 #include "core/dom/ExceptionCode.h"
+#include "modules/nfc/NFCMessage.h"
+#include "modules/nfc/NFCPushOptions.h"
 
 namespace blink {
 
@@ -23,13 +25,33 @@
     return nfc;
 }
 
-NFC::~NFC()
+ScriptPromise NFC::push(ScriptState* scriptState, const NFCPushMessage& records, const NFCPushOptions& options)
 {
+    // TODO(shalamov): To be implemented.
+    return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
 }
 
-ScriptPromise NFC::requestAdapter(ScriptState* scriptState)
+ScriptPromise NFC::cancelPush(ScriptState* scriptState, const String& target)
 {
-    // TODO(riju): To be implemented.
+    // TODO(shalamov): To be implemented.
+    return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+}
+
+ScriptPromise NFC::watch(ScriptState* scriptState, MessageCallback* callback, const NFCWatchOptions& options)
+{
+    // TODO(shalamov): To be implemented.
+    return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+}
+
+ScriptPromise NFC::cancelWatch(ScriptState* scriptState, long id)
+{
+    // TODO(shalamov): To be implemented.
+    return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
+}
+
+ScriptPromise NFC::cancelWatch(ScriptState* scriptState)
+{
+    // TODO(shalamov): To be implemented.
     return ScriptPromise::rejectWithDOMException(scriptState, DOMException::create(NotSupportedError));
 }
 
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.h b/third_party/WebKit/Source/modules/nfc/NFC.h
index ffb5845f..50b9b47e 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.h
+++ b/third_party/WebKit/Source/modules/nfc/NFC.h
@@ -7,11 +7,17 @@
 
 #include "bindings/core/v8/ScriptPromise.h"
 #include "bindings/core/v8/ScriptWrappable.h"
+#include "bindings/modules/v8/UnionTypesModules.h"
 #include "core/frame/LocalFrameLifecycleObserver.h"
 #include "core/page/PageLifecycleObserver.h"
 
 namespace blink {
 
+class MessageCallback;
+class NFCPushOptions;
+using NFCPushMessage = StringOrArrayBufferOrNFCMessage;
+class NFCWatchOptions;
+
 class NFC final
     : public GarbageCollectedFinalized<NFC>
     , public ScriptWrappable
@@ -22,19 +28,29 @@
 
 public:
     static NFC* create(LocalFrame*);
-#if ENABLE(OILPAN)
-    ~NFC();
-#else
-    ~NFC() override;
+#if !ENABLE(OILPAN)
+    ~NFC() override = default;
 #endif
 
-    // Get an adapter object providing NFC functionality.
-    ScriptPromise requestAdapter(ScriptState*);
+    // Pushes NFCPushMessage asynchronously to NFC tag / peer.
+    ScriptPromise push(ScriptState*, const NFCPushMessage&, const NFCPushOptions&);
+
+    // Cancels ongoing push operation.
+    ScriptPromise cancelPush(ScriptState*, const String&);
+
+    // Starts watching for NFC messages that match NFCWatchOptions criteria.
+    ScriptPromise watch(ScriptState*, MessageCallback*, const NFCWatchOptions&);
+
+    // Cancels watch operation with id.
+    ScriptPromise cancelWatch(ScriptState*, long id);
+
+    // Cancels all watch operations.
+    ScriptPromise cancelWatch(ScriptState*);
 
     // Implementation of LocalFrameLifecycleObserver.
     void willDetachFrameHost() override;
 
-    // Implementation of PageLifecycleObserver
+    // Implementation of PageLifecycleObserver.
     void pageVisibilityChanged() override;
 
     // Interface required by garbage collection.
diff --git a/third_party/WebKit/Source/modules/nfc/NFC.idl b/third_party/WebKit/Source/modules/nfc/NFC.idl
index cc38e16f..bb0f5209 100644
--- a/third_party/WebKit/Source/modules/nfc/NFC.idl
+++ b/third_party/WebKit/Source/modules/nfc/NFC.idl
@@ -2,11 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/web-nfc/#idl-def-NFC
+// https://w3c.github.io/web-nfc/#the-nfc-interface
+
+typedef (DOMString or ArrayBuffer or NFCMessage) NFCPushMessage;
 
 [
   GarbageCollected,
   RuntimeEnabled=WebNFC,
 ] interface NFC {
-   [CallWith=ScriptState] Promise<NFCAdapter> requestAdapter ();
+    [CallWith=ScriptState] Promise<void> push (NFCPushMessage message, optional NFCPushOptions options);
+    [CallWith=ScriptState] Promise<void> cancelPush (optional NFCPushTarget target = "any");
+    [CallWith=ScriptState] Promise<long> watch (MessageCallback callback, optional NFCWatchOptions options);
+    [CallWith=ScriptState] Promise<void> cancelWatch (optional long id);
 };
diff --git a/third_party/WebKit/Source/modules/nfc/NFCMessage.idl b/third_party/WebKit/Source/modules/nfc/NFCMessage.idl
new file mode 100644
index 0000000..5cea9c70
--- /dev/null
+++ b/third_party/WebKit/Source/modules/nfc/NFCMessage.idl
@@ -0,0 +1,10 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// https://w3c.github.io/web-nfc/#the-nfcmessage-dictionary
+
+dictionary NFCMessage {
+    sequence<NFCRecord> data;
+    USVString url;
+};
diff --git a/third_party/WebKit/Source/modules/nfc/NFCPushOptions.idl b/third_party/WebKit/Source/modules/nfc/NFCPushOptions.idl
index 2fe24e81..c7c78fb5 100644
--- a/third_party/WebKit/Source/modules/nfc/NFCPushOptions.idl
+++ b/third_party/WebKit/Source/modules/nfc/NFCPushOptions.idl
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/web-nfc/index.html#the-nfcpushoptions-dictionary
+// https://w3c.github.io/web-nfc/#the-nfcpushoptions-dictionary
 
-enum NFCPushTarget { "tag", "peer" };
+enum NFCPushTarget { "tag", "peer", "any" };
 
 dictionary NFCPushOptions {
-    NFCPushTarget target;
-    unsigned long timeout;
+    NFCPushTarget target = "any";
+    unrestricted double timeout; // in ms
+    boolean ignoreRead = true;
 };
diff --git a/third_party/WebKit/Source/modules/nfc/NFCRecord.idl b/third_party/WebKit/Source/modules/nfc/NFCRecord.idl
index a20ccbb..48bfd24 100644
--- a/third_party/WebKit/Source/modules/nfc/NFCRecord.idl
+++ b/third_party/WebKit/Source/modules/nfc/NFCRecord.idl
@@ -2,17 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/web-nfc/index.html#the-nfcrecord-dictionary
+// https://w3c.github.io/web-nfc/#the-nfcrecord-dictionary
 
 enum NFCRecordType { "empty", "text", "url", "json", "opaque" };
 
-// typedef (DOMString or unrestricted double or object or ArrayBuffer) NFCRecordData;
+// TODO(shalamov): This is blocked by https://crbug.com/524424
+// typedef (DOMString or unrestricted double or ArrayBuffer or Dictionary) NFCRecordData;
+typedef any NFCRecordData;
 
 dictionary NFCRecord {
-    NFCRecordType kind;
-    USVString type;
-    // NFCRecordData data;
-    // Use ´any´ as Blink IDL compiler complains that Object is not supported as
-    // union member. Tracked in https://crbug.com/537133 .
-    any data;
+    NFCRecordType recordType;
+    USVString mediaType;
+    NFCRecordData data;
 };
diff --git a/third_party/WebKit/Source/modules/nfc/NFCWatchOptions.idl b/third_party/WebKit/Source/modules/nfc/NFCWatchOptions.idl
index 971497a..8a4722de 100644
--- a/third_party/WebKit/Source/modules/nfc/NFCWatchOptions.idl
+++ b/third_party/WebKit/Source/modules/nfc/NFCWatchOptions.idl
@@ -2,15 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// https://w3c.github.io/web-nfc/#idl-def-nfcwatchoptions
+// https://w3c.github.io/web-nfc/#the-nfcwatchoptions-dictionary
 
 enum NFCWatchMode { "web-nfc-only", "any" };
 
-[
-   RuntimeEnabled=WebNFC,
-] dictionary NFCWatchOptions {
-    USVString    url = "";
-    USVString    kind = "";
-    USVString    type = "";
+dictionary NFCWatchOptions {
+    USVString url = "";
+    NFCRecordType? recordType;
+    USVString mediaType = "";
     NFCWatchMode mode = "web-nfc-only";
 };
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
index e8d9ee84..daff13f 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.cpp
@@ -393,20 +393,93 @@
     }
 }
 
-void WebGL2RenderingContextBase::invalidateFramebuffer(GLenum target, Vector<GLenum>& attachments)
+bool WebGL2RenderingContextBase::checkAndTranslateAttachments(const char* functionName, GLenum target, const Vector<GLenum>& attachments, Vector<GLenum>& translatedAttachments)
 {
-    if (isContextLost())
-        return;
+    GLsizei size = attachments.size();
+    translatedAttachments.resize(size);
 
-    webContext()->invalidateFramebuffer(target, attachments.size(), attachments.data());
+    WebGLFramebuffer* framebufferBinding = getFramebufferBinding(target);
+    ASSERT(framebufferBinding || drawingBuffer());
+    if (!framebufferBinding) {
+        // For the default framebuffer
+        // Translate GL_COLOR/GL_DEPTH/GL_STENCIL, because the default framebuffer of WebGL is not fb 0, it is an internal fbo
+        for (GLsizei i = 0; i < size; ++i) {
+            switch (attachments[i]) {
+            case GL_COLOR:
+                translatedAttachments[i] = GL_COLOR_ATTACHMENT0;
+                break;
+            case GL_DEPTH:
+                translatedAttachments[i] = GL_DEPTH_ATTACHMENT;
+                break;
+            case GL_STENCIL:
+                translatedAttachments[i] = GL_STENCIL_ATTACHMENT;
+                break;
+            default:
+                synthesizeGLError(GL_INVALID_ENUM, functionName, "invalid attachment");
+                return false;
+            }
+        }
+    } else {
+        // For the FBO
+        for (GLsizei i = 0; i < size; ++i) {
+            switch (attachments[i]) {
+            case GL_COLOR_ATTACHMENT0:
+            case GL_DEPTH_ATTACHMENT:
+            case GL_STENCIL_ATTACHMENT:
+            case GL_DEPTH_STENCIL_ATTACHMENT:
+                translatedAttachments[i] = attachments[i];
+                break;
+            default:
+                if (attachments[i] > GL_COLOR_ATTACHMENT0
+                    && attachments[i] < static_cast<GLenum>(GL_COLOR_ATTACHMENT0 + maxColorAttachments())) {
+                    translatedAttachments[i] = attachments[i];
+                    break;
+                }
+                synthesizeGLError(GL_INVALID_OPERATION, functionName, "invalid attachment");
+                return false;
+            }
+        }
+    }
+    return true;
 }
 
-void WebGL2RenderingContextBase::invalidateSubFramebuffer(GLenum target, Vector<GLenum>& attachments, GLint x, GLint y, GLsizei width, GLsizei height)
+void WebGL2RenderingContextBase::invalidateFramebuffer(GLenum target, const Vector<GLenum>& attachments)
 {
     if (isContextLost())
         return;
 
-    webContext()->invalidateSubFramebuffer(target, attachments.size(), attachments.data(), x, y, width, height);
+    if (!validateFramebufferTarget(target)) {
+        synthesizeGLError(GL_INVALID_ENUM, "invalidateFramebuffer", "invalid target");
+        return;
+    }
+
+    Vector<GLenum> translatedAttachments;
+    if (!checkAndTranslateAttachments("invalidateFramebuffer", target, attachments, translatedAttachments))
+        return;
+
+    webContext()->invalidateFramebuffer(target, translatedAttachments.size(), translatedAttachments.data());
+}
+
+void WebGL2RenderingContextBase::invalidateSubFramebuffer(GLenum target, const Vector<GLenum>& attachments, GLint x, GLint y, GLsizei width, GLsizei height)
+{
+    if (isContextLost())
+        return;
+
+    if (!validateFramebufferTarget(target)) {
+        synthesizeGLError(GL_INVALID_ENUM, "invalidateFramebuffer", "invalid target");
+        return;
+    }
+
+    if (width < 0 || height < 0) {
+        synthesizeGLError(GL_INVALID_VALUE, "invalidateSubFramebuffer", "invalid width or height");
+        return;
+    }
+
+    Vector<GLenum> translatedAttachments;
+    if (!checkAndTranslateAttachments("invalidateSubFramebuffer", target, attachments, translatedAttachments))
+        return;
+
+    webContext()->invalidateSubFramebuffer(target, translatedAttachments.size(), translatedAttachments.data(), x, y, width, height);
 }
 
 void WebGL2RenderingContextBase::readBuffer(GLenum mode)
diff --git a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
index 3ab1aad..726ceb2 100644
--- a/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
+++ b/third_party/WebKit/Source/modules/webgl/WebGL2RenderingContextBase.h
@@ -36,8 +36,8 @@
     void blitFramebuffer(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum);
     void framebufferTextureLayer(ScriptState*, GLenum, GLenum, WebGLTexture*, GLint, GLint);
     ScriptValue getInternalformatParameter(ScriptState*, GLenum, GLenum, GLenum);
-    void invalidateFramebuffer(GLenum, Vector<GLenum>&);
-    void invalidateSubFramebuffer(GLenum, Vector<GLenum>&, GLint, GLint, GLsizei, GLsizei);
+    void invalidateFramebuffer(GLenum, const Vector<GLenum>&);
+    void invalidateSubFramebuffer(GLenum, const Vector<GLenum>&, GLint, GLint, GLsizei, GLsizei);
     void readBuffer(GLenum);
 
     /* Renderbuffer objects */
@@ -213,6 +213,8 @@
     void vertexAttribIivImpl(const char*, GLuint, const GLint*, GLsizei);
     void vertexAttribIuivImpl(const char*, GLuint, const GLuint*, GLsizei);
 
+    bool checkAndTranslateAttachments(const char* functionName, GLenum, const Vector<GLenum>&, Vector<GLenum>&);
+
     /* WebGLRenderingContextBase overrides */
     unsigned getMaxWebGLLocationLength() const override { return 1024; };
     bool validateCapability(const char* functionName, GLenum) override;
diff --git a/third_party/WebKit/Source/platform/heap/HeapTest.cpp b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
index 071b252..d75c36d 100644
--- a/third_party/WebKit/Source/platform/heap/HeapTest.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapTest.cpp
@@ -4596,6 +4596,25 @@
     Member<IntWrapper> m_obj;
 };
 
+class DerivedMultipleMixins : public MultipleMixins {
+public:
+    DerivedMultipleMixins() : m_obj(IntWrapper::create(103)) { }
+
+    DEFINE_INLINE_VIRTUAL_TRACE()
+    {
+        s_traceCalled++;
+        visitor->trace(m_obj);
+        MultipleMixins::trace(visitor);
+    }
+
+    static int s_traceCalled;
+
+private:
+    Member<IntWrapper> m_obj;
+};
+
+int DerivedMultipleMixins::s_traceCalled = 0;
+
 static const bool s_isMixinTrue = IsGarbageCollectedMixin<MultipleMixins>::value;
 static const bool s_isMixinFalse = IsGarbageCollectedMixin<IntWrapper>::value;
 
@@ -4621,6 +4640,29 @@
     EXPECT_EQ(3, IntWrapper::s_destructorCalls);
 }
 
+TEST(HeapTest, DerivedMultipleMixins)
+{
+    clearOutOldGarbage();
+    IntWrapper::s_destructorCalls = 0;
+    DerivedMultipleMixins::s_traceCalled = 0;
+
+    DerivedMultipleMixins* obj = new DerivedMultipleMixins();
+    {
+        Persistent<MixinA> a = obj;
+        preciselyCollectGarbage();
+        EXPECT_EQ(0, IntWrapper::s_destructorCalls);
+        EXPECT_EQ(1, DerivedMultipleMixins::s_traceCalled);
+    }
+    {
+        Persistent<MixinB> b = obj;
+        preciselyCollectGarbage();
+        EXPECT_EQ(0, IntWrapper::s_destructorCalls);
+        EXPECT_EQ(2, DerivedMultipleMixins::s_traceCalled);
+    }
+    preciselyCollectGarbage();
+    EXPECT_EQ(4, IntWrapper::s_destructorCalls);
+}
+
 class GCParkingThreadTester {
 public:
     static void test()
diff --git a/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp b/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
index 0d93ced..7bb8523 100644
--- a/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
+++ b/third_party/WebKit/Source/web/DateTimeChooserImpl.cpp
@@ -70,6 +70,7 @@
 DEFINE_TRACE(DateTimeChooserImpl)
 {
     visitor->trace(m_chromeClient);
+    visitor->trace(m_client);
     DateTimeChooser::trace(visitor);
 }
 
@@ -204,7 +205,7 @@
 void DateTimeChooserImpl::didClosePopup()
 {
     ASSERT(m_client);
-    m_popup = 0;
+    m_popup = nullptr;
     m_client->didEndChooser();
 }
 
diff --git a/third_party/WebKit/Source/web/DateTimeChooserImpl.h b/third_party/WebKit/Source/web/DateTimeChooserImpl.h
index 368afa6..d7b9d9b 100644
--- a/third_party/WebKit/Source/web/DateTimeChooserImpl.h
+++ b/third_party/WebKit/Source/web/DateTimeChooserImpl.h
@@ -65,7 +65,7 @@
     void didClosePopup() override;
 
     RawPtrWillBeMember<ChromeClientImpl> m_chromeClient;
-    DateTimeChooserClient* m_client;
+    RawPtrWillBeMember<DateTimeChooserClient> m_client;
     PagePopup* m_popup;
     DateTimeChooserParameters m_parameters;
     OwnPtr<Locale> m_locale;
diff --git a/third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp b/third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp
index b609d71b..bb72787 100644
--- a/third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp
+++ b/third_party/WebKit/Source/web/ExternalDateTimeChooser.cpp
@@ -63,23 +63,29 @@
         delete this;
     }
 
-    RefPtr<ExternalDateTimeChooser> m_chooser;
+    RefPtrWillBePersistent<ExternalDateTimeChooser> m_chooser;
 };
 
 ExternalDateTimeChooser::~ExternalDateTimeChooser()
 {
 }
 
+DEFINE_TRACE(ExternalDateTimeChooser)
+{
+    visitor->trace(m_client);
+    DateTimeChooser::trace(visitor);
+}
+
 ExternalDateTimeChooser::ExternalDateTimeChooser(DateTimeChooserClient* client)
     : m_client(client)
 {
     ASSERT(client);
 }
 
-PassRefPtr<ExternalDateTimeChooser> ExternalDateTimeChooser::create(ChromeClientImpl* chromeClient, WebViewClient* webViewClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
+PassRefPtrWillBeRawPtr<ExternalDateTimeChooser> ExternalDateTimeChooser::create(ChromeClientImpl* chromeClient, WebViewClient* webViewClient, DateTimeChooserClient* client, const DateTimeChooserParameters& parameters)
 {
     ASSERT(chromeClient);
-    RefPtr<ExternalDateTimeChooser> chooser = adoptRef(new ExternalDateTimeChooser(client));
+    RefPtrWillBeRawPtr<ExternalDateTimeChooser> chooser = adoptRefWillBeNoop(new ExternalDateTimeChooser(client));
     if (!chooser->openDateTimeChooser(chromeClient, webViewClient, parameters))
         chooser.clear();
     return chooser.release();
@@ -162,13 +168,13 @@
 void ExternalDateTimeChooser::endChooser()
 {
     DateTimeChooserClient* client = m_client;
-    m_client = 0;
+    m_client = nullptr;
     client->didEndChooser();
 }
 
 AXObject* ExternalDateTimeChooser::rootAXObject()
 {
-    return 0;
+    return nullptr;
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/web/ExternalDateTimeChooser.h b/third_party/WebKit/Source/web/ExternalDateTimeChooser.h
index faa89f73..fcaaf1d 100644
--- a/third_party/WebKit/Source/web/ExternalDateTimeChooser.h
+++ b/third_party/WebKit/Source/web/ExternalDateTimeChooser.h
@@ -40,6 +40,7 @@
 public:
     static PassRefPtrWillBeRawPtr<ExternalDateTimeChooser> create(ChromeClientImpl*, WebViewClient*, DateTimeChooserClient*, const DateTimeChooserParameters&);
     ~ExternalDateTimeChooser() override;
+    DECLARE_VIRTUAL_TRACE();
 
     // The following functions are for DateTimeChooserCompletion.
     void didChooseValue(const WebString&);
@@ -54,7 +55,7 @@
     void endChooser() override;
     AXObject* rootAXObject() override;
 
-    DateTimeChooserClient* m_client;
+    RawPtrWillBeMember<DateTimeChooserClient> m_client;
 };
 
 }
diff --git a/ui/gfx/image/image_skia.h b/ui/gfx/image/image_skia.h
index 941ebc9f..7bf5e58f 100644
--- a/ui/gfx/image/image_skia.h
+++ b/ui/gfx/image/image_skia.h
@@ -33,6 +33,11 @@
 // Functions that mutate the image should operate on the gfx::ImageSkiaRep
 // returned from ImageSkia::GetRepresentation, not on ImageSkia.
 //
+// NOTE: This class should *not* be used to store multiple logical sizes of an
+// image (e.g., small, medium and large versions of an icon); use an ImageFamily
+// for that. An ImageSkia represents an image of a single logical size, with
+// potentially many different densities for high-DPI displays.
+//
 // ImageSkia is cheap to copy and intentionally supports copy semantics.
 class GFX_EXPORT ImageSkia {
  public: