Import Cobalt 21.master.0.267865
diff --git a/src/base/containers/flat_map_unittest.cc b/src/base/containers/flat_map_unittest.cc
index a8457c2..8299914 100644
--- a/src/base/containers/flat_map_unittest.cc
+++ b/src/base/containers/flat_map_unittest.cc
@@ -20,7 +20,7 @@
 
 namespace base {
 
-// At least PS4 compiler does not allow this test at compiler time.
+// Non-conforming compilers do not allow this test at compiler time.
 #ifndef STARBOARD
 TEST(FlatMap, IncompleteType) {
   struct A {
diff --git a/src/base/feature_list.h b/src/base/feature_list.h
index 17bc922..5dcd336 100644
--- a/src/base/feature_list.h
+++ b/src/base/feature_list.h
@@ -38,7 +38,7 @@
   // It is strongly recommended to use CamelCase style for feature names, e.g.
   // "MyGreatFeature".
 #ifdef STARBOARD
-  // At least PS4 compiler does not allow copy assignment operator on Feature
+  // Non-conforming compilers do not allow copy assignment operator on Feature
   // because of const variables.
   const char* name;
 
diff --git a/src/base/logging.h b/src/base/logging.h
index ba07729..5363975 100644
--- a/src/base/logging.h
+++ b/src/base/logging.h
@@ -349,7 +349,7 @@
 #endif  // defined(__clang_analyzer__)
 
 #ifdef STARBOARD
-// Roku defined some macros that have the same names.
+// Some platforms define macros that have the same names.
 #undef LOG_INFO
 #undef LOG_WARNING
 #endif
diff --git a/src/base/trace_event/memory_usage_estimator_unittest.cc b/src/base/trace_event/memory_usage_estimator_unittest.cc
index cf9b4c5..0f3451b 100644
--- a/src/base/trace_event/memory_usage_estimator_unittest.cc
+++ b/src/base/trace_event/memory_usage_estimator_unittest.cc
@@ -260,7 +260,7 @@
                     std::list<int>::const_reverse_iterator>(),
                 "");
 #ifndef STARBOARD
-  // At least PS4 compiler does not even compile with int as iterator.
+  // TODO: Non-conforming compilers do not compile with int as iterator.
   STATIC_ASSERT(!internal::IsStandardContainerComplexIterator<int>(), "");
 #endif
   STATIC_ASSERT(!internal::IsStandardContainerComplexIterator<abstract*>(), "");
diff --git a/src/build/build_config.h b/src/build/build_config.h
index d7a522a..7506ad9 100644
--- a/src/build/build_config.h
+++ b/src/build/build_config.h
@@ -139,10 +139,6 @@
 #define ARCH_CPU_X86_64 1
 #define ARCH_CPU_64_BITS 1
 #define ARCH_CPU_LITTLE_ENDIAN 1
-#elif defined(__LB_PS3__) || defined(__LB_WIIU__) || defined(__LB_XB360__)
-#define ARCH_CPU_32_BITS 1
-#define ARCH_CPU_BIG_ENDIAN 1
-#define ARCH_CPU_PPC_FAMILY 1
 #elif defined(_M_IX86) || defined(__i386__)
 #define ARCH_CPU_X86_FAMILY 1
 #define ARCH_CPU_X86 1
diff --git a/src/cobalt/base/accessibility_text_to_speech_settings_changed_event.h b/src/cobalt/base/accessibility_text_to_speech_settings_changed_event.h
new file mode 100644
index 0000000..255c315
--- /dev/null
+++ b/src/cobalt/base/accessibility_text_to_speech_settings_changed_event.h
@@ -0,0 +1,31 @@
+// Copyright 2020 The Cobalt Authors. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#ifndef COBALT_BASE_ACCESSIBILITY_TEXT_TO_SPEECH_SETTINGS_CHANGED_EVENT_H_
+#define COBALT_BASE_ACCESSIBILITY_TEXT_TO_SPEECH_SETTINGS_CHANGED_EVENT_H_
+
+#include "cobalt/base/event.h"
+
+namespace base {
+
+class AccessibilityTextToSpeechSettingsChangedEvent : public Event {
+ public:
+  AccessibilityTextToSpeechSettingsChangedEvent() {}
+
+  BASE_EVENT_SUBCLASS(AccessibilityTextToSpeechSettingsChangedEvent);
+};
+
+}  // namespace base
+
+#endif  // COBALT_BASE_ACCESSIBILITY_TEXT_TO_SPEECH_SETTINGS_CHANGED_EVENT_H_
diff --git a/src/cobalt/base/base.gyp b/src/cobalt/base/base.gyp
index b8e5f75..4e4962b 100644
--- a/src/cobalt/base/base.gyp
+++ b/src/cobalt/base/base.gyp
@@ -25,7 +25,9 @@
          'defines': ["COBALT_ENABLE_VERSION_COMPATIBILITY_VALIDATIONS=1"],
       },
       'sources': [
-        'accessibility_changed_event.h',
+        'accessibility_caption_settings_changed_event.h',
+        'accessibility_settings_changed_event.h',
+        'accessibility_text_to_speech_settings_changed_event.h',
         'address_sanitizer.h',
         'camera_transform.h',
         'circular_buffer_shell.cc',
diff --git a/src/cobalt/base/wrap_main_starboard.h b/src/cobalt/base/wrap_main_starboard.h
index 2a68bae..03c1f36 100644
--- a/src/cobalt/base/wrap_main_starboard.h
+++ b/src/cobalt/base/wrap_main_starboard.h
@@ -139,6 +139,9 @@
 #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
     case kSbEventTypeAccessibilityCaptionSettingsChanged:
 #endif  // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
+#if SB_API_VERSION >= 12
+    case kSbEventTypeAccessiblityTextToSpeechSettingsChanged:
+#endif  // SB_API_VERSION >= 12
       event_function(event);
       break;
   }
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index ecd4985..8ceff23 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -37,6 +37,7 @@
 #include "build/build_config.h"
 #include "cobalt/base/accessibility_caption_settings_changed_event.h"
 #include "cobalt/base/accessibility_settings_changed_event.h"
+#include "cobalt/base/accessibility_text_to_speech_settings_changed_event.h"
 #include "cobalt/base/application_event.h"
 #include "cobalt/base/cobalt_paths.h"
 #include "cobalt/base/deep_link_event.h"
@@ -988,6 +989,13 @@
     }
     case kSbEventTypeAccessiblitySettingsChanged:
       DispatchEventInternal(new base::AccessibilitySettingsChangedEvent());
+#if SB_API_VERSION < 12
+      // Also dispatch the newer text-to-speech settings changed event since
+      // the specific kSbEventTypeAccessiblityTextToSpeechSettingsChanged
+      // event is not available in this starboard version.
+      DispatchEventInternal(
+          new base::AccessibilityTextToSpeechSettingsChangedEvent());
+#endif
       break;
 #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
     case kSbEventTypeAccessibilityCaptionSettingsChanged:
@@ -995,6 +1003,12 @@
           new base::AccessibilityCaptionSettingsChangedEvent());
       break;
 #endif  // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
+#if SB_API_VERSION >= 12
+    case kSbEventTypeAccessiblityTextToSpeechSettingsChanged:
+      DispatchEventInternal(
+          new base::AccessibilityTextToSpeechSettingsChangedEvent());
+      break;
+#endif
     // Explicitly list unhandled cases here so that the compiler can give a
     // warning when a value is added, but not handled.
     case kSbEventTypeInput:
@@ -1135,6 +1149,9 @@
 #if SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
     case kSbEventTypeAccessibilityCaptionSettingsChanged:
 #endif  // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
+#if SB_API_VERSION >= 12
+    case kSbEventTypeAccessiblityTextToSpeechSettingsChanged:
+#endif  // SB_API_VERSION >= 12
 #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD)
     case kSbEventTypeOnScreenKeyboardBlurred:
     case kSbEventTypeOnScreenKeyboardFocused:
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index 7a96893..5741ef3 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-267507
\ No newline at end of file
+267865
\ No newline at end of file
diff --git a/src/cobalt/build/copy_icu_data.gypi b/src/cobalt/build/copy_icu_data.gypi
index 1b3c39c..88af6c9 100644
--- a/src/cobalt/build/copy_icu_data.gypi
+++ b/src/cobalt/build/copy_icu_data.gypi
@@ -30,12 +30,6 @@
           'use_icu_dat_file%': 0,
         },
 
-        'conditions': [
-          ['target_arch in ["ps3"]', {
-            'little_endian%': 0,
-          }],
-        ],
-
         'little_endian%': '<(little_endian)',
         'use_icu_dat_file%': '<(use_icu_dat_file)',
       },
diff --git a/src/cobalt/build/copy_web_data.gypi b/src/cobalt/build/copy_web_data.gypi
index 3be2335..f849b7b 100644
--- a/src/cobalt/build/copy_web_data.gypi
+++ b/src/cobalt/build/copy_web_data.gypi
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # This file is meant to be included into an action to copy web data files into
-# the content directory, e.g. out/PS3_Debug/content/data/web.
+# the content directory, e.g. out/stub_debug/content/data/web.
 #
 # To use this, create a gyp target with the following form:
 # {
diff --git a/src/cobalt/dom/lottie_player.cc b/src/cobalt/dom/lottie_player.cc
index 6c218e3..5b3fc1e 100644
--- a/src/cobalt/dom/lottie_player.cc
+++ b/src/cobalt/dom/lottie_player.cc
@@ -39,7 +39,9 @@
 LottiePlayer::LottiePlayer(Document* document)
     : HTMLElement(document, base::Token(kTagName)),
       autoplaying_(true),
-      ALLOW_THIS_IN_INITIALIZER_LIST(event_queue_(this)) {}
+      ALLOW_THIS_IN_INITIALIZER_LIST(event_queue_(this)) {
+  SetAnimationEventCallbacks();
+}
 
 std::string LottiePlayer::src() const {
   return GetAttribute("src").value_or("");
@@ -140,7 +142,6 @@
     properties_.SeekPercent(frame_percent);
   }
 
-  autoplaying_ = false;
   UpdateLottieObjects();
 }
 
@@ -173,17 +174,12 @@
 
 void LottiePlayer::TogglePlay() {
   // https://github.com/LottieFiles/lottie-player#toggleplay--void
-  UpdatePlaybackStateForAutoplay();
   properties_.TogglePlay();
 
-  autoplaying_ = false;
   UpdateLottieObjects();
 }
 
-LottieAnimation::LottieProperties LottiePlayer::GetUpdatedProperties() {
-  UpdatePlaybackStateForAutoplay();
-  SetAnimationEventCallbacks();
-
+LottieAnimation::LottieProperties LottiePlayer::GetProperties() const {
   return properties_;
 }
 
@@ -307,6 +303,9 @@
   // then a "ready" event to indicate the DOM element is ready.
   ScheduleEvent(base::Tokens::load());
   ScheduleEvent(base::Tokens::ready());
+  // If the animation is autoplaying and autoplay is true, then the animation
+  // playback state needs to be set to LottieAnimation::LottieState::kPlaying.
+  UpdatePlaybackStateIfAutoplaying();
 }
 
 void LottiePlayer::OnLoadingError() {
@@ -349,29 +348,16 @@
 }
 
 void LottiePlayer::UpdateState(LottieAnimation::LottieState state) {
-  autoplaying_ = false;
   if (properties_.UpdateState(state)) {
     UpdateLottieObjects();
-
-    if (state == LottieAnimation::LottieState::kPlaying) {
-      ScheduleEvent(base::Tokens::play());
-    } else if (state == LottieAnimation::LottieState::kPaused) {
-      ScheduleEvent(base::Tokens::pause());
-    } else if (state == LottieAnimation::LottieState::kStopped) {
-      ScheduleEvent(base::Tokens::stop());
-    }
   }
 }
 
-void LottiePlayer::UpdatePlaybackStateForAutoplay() {
-  // The state may not have be initialized properly if the animation is
-  // autoplaying.
-  if (autoplaying_) {
-    LottieAnimation::LottieState state =
-        autoplay() ? LottieAnimation::LottieState::kPlaying
-                   : LottieAnimation::LottieState::kStopped;
-    properties_.UpdateState(state);
+void LottiePlayer::UpdatePlaybackStateIfAutoplaying() {
+  if (autoplaying_ && autoplay()) {
+    properties_.UpdateState(LottieAnimation::LottieState::kPlaying);
   }
+  autoplaying_ = false;
 }
 
 void LottiePlayer::SetCount(int count) {
@@ -405,6 +391,18 @@
 }
 
 void LottiePlayer::SetAnimationEventCallbacks() {
+  properties_.onplay_callback = base::Bind(
+      base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
+      base::Unretained(base::MessageLoop::current()->task_runner().get()),
+      FROM_HERE, base::Bind(&LottiePlayer::OnPlay, base::AsWeakPtr(this)));
+  properties_.onpause_callback = base::Bind(
+      base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
+      base::Unretained(base::MessageLoop::current()->task_runner().get()),
+      FROM_HERE, base::Bind(&LottiePlayer::OnPause, base::AsWeakPtr(this)));
+  properties_.onstop_callback = base::Bind(
+      base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
+      base::Unretained(base::MessageLoop::current()->task_runner().get()),
+      FROM_HERE, base::Bind(&LottiePlayer::OnStop, base::AsWeakPtr(this)));
   properties_.oncomplete_callback = base::Bind(
       base::IgnoreResult(&base::SingleThreadTaskRunner::PostTask),
       base::Unretained(base::MessageLoop::current()->task_runner().get()),
@@ -415,6 +413,12 @@
       FROM_HERE, base::Bind(&LottiePlayer::OnLoop, base::AsWeakPtr(this)));
 }
 
+void LottiePlayer::OnPlay() { ScheduleEvent(base::Tokens::play()); }
+
+void LottiePlayer::OnPause() { ScheduleEvent(base::Tokens::pause()); }
+
+void LottiePlayer::OnStop() { ScheduleEvent(base::Tokens::stop()); }
+
 void LottiePlayer::OnComplete() { ScheduleEvent(base::Tokens::complete()); }
 
 void LottiePlayer::OnLoop() { ScheduleEvent(base::Tokens::loop()); }
diff --git a/src/cobalt/dom/lottie_player.h b/src/cobalt/dom/lottie_player.h
index 226d16f..d246964 100644
--- a/src/cobalt/dom/lottie_player.h
+++ b/src/cobalt/dom/lottie_player.h
@@ -83,7 +83,7 @@
     return cached_image_;
   }
 
-  LottieAnimation::LottieProperties GetUpdatedProperties();
+  LottieAnimation::LottieProperties GetProperties() const;
 
   DEFINE_WRAPPABLE_TYPE(LottiePlayer);
 
@@ -113,7 +113,7 @@
           scoped_prevent_gc);
 
   void UpdateState(LottieAnimation::LottieState state);
-  void UpdatePlaybackStateForAutoplay();
+  void UpdatePlaybackStateIfAutoplaying();
   void SetCount(int count);
   void SetMode(std::string mode);
   void SetMode(LottieAnimation::LottieMode mode);
@@ -122,6 +122,9 @@
   void ScheduleEvent(base::Token event_name);
   void SetAnimationEventCallbacks();
 
+  void OnPlay();
+  void OnPause();
+  void OnStop();
   void OnComplete();
   void OnLoop();
 
diff --git a/src/cobalt/h5vcc/h5vcc_accessibility.cc b/src/cobalt/h5vcc/h5vcc_accessibility.cc
index 40e5395..0a800c2 100644
--- a/src/cobalt/h5vcc/h5vcc_accessibility.cc
+++ b/src/cobalt/h5vcc/h5vcc_accessibility.cc
@@ -17,6 +17,7 @@
 #include "base/command_line.h"
 #include "base/message_loop/message_loop.h"
 #include "cobalt/base/accessibility_settings_changed_event.h"
+#include "cobalt/base/accessibility_text_to_speech_settings_changed_event.h"
 #include "cobalt/browser/switches.h"
 #include "starboard/accessibility.h"
 #include "starboard/memory.h"
@@ -47,12 +48,18 @@
   event_dispatcher_->AddEventCallback(
       base::AccessibilitySettingsChangedEvent::TypeId(),
       on_application_event_callback_);
+  event_dispatcher_->AddEventCallback(
+      base::AccessibilityTextToSpeechSettingsChangedEvent::TypeId(),
+      on_application_event_callback_);
 }
 
 H5vccAccessibility::~H5vccAccessibility() {
   event_dispatcher_->RemoveEventCallback(
       base::AccessibilitySettingsChangedEvent::TypeId(),
       on_application_event_callback_);
+  event_dispatcher_->RemoveEventCallback(
+      base::AccessibilityTextToSpeechSettingsChangedEvent::TypeId(),
+      on_application_event_callback_);
 }
 
 bool H5vccAccessibility::built_in_screen_reader() const { return false; }
@@ -90,6 +97,13 @@
          settings.is_text_to_speech_enabled;
 }
 
+void H5vccAccessibility::AddTextToSpeechListener(
+    const H5vccAccessibilityCallbackHolder& holder) {
+  DCHECK_EQ(base::MessageLoop::current()->task_runner(), task_runner_);
+  text_to_speech_listener_.reset(
+      new H5vccAccessibilityCallbackReference(this, holder));
+}
+
 void H5vccAccessibility::AddHighContrastTextListener(
     const H5vccAccessibilityCallbackHolder& holder) {
   DCHECK_EQ(base::MessageLoop::current()->task_runner(), task_runner_);
@@ -102,14 +116,20 @@
   DCHECK_NE(base::MessageLoop::current()->task_runner(), task_runner_);
   task_runner_->PostTask(
       FROM_HERE, base::Bind(&H5vccAccessibility::InternalOnApplicationEvent,
-                            base::Unretained(this)));
+                            base::Unretained(this),
+                            event->GetTypeId()));
 }
 
-void H5vccAccessibility::InternalOnApplicationEvent() {
+void H5vccAccessibility::InternalOnApplicationEvent(base::TypeId type) {
   DCHECK_EQ(base::MessageLoop::current()->task_runner(), task_runner_);
-  if (high_contrast_text_listener_) {
+  if (type == base::AccessibilitySettingsChangedEvent::TypeId() &&
+      high_contrast_text_listener_) {
     high_contrast_text_listener_->value().Run();
   }
+  if (type == base::AccessibilityTextToSpeechSettingsChangedEvent::TypeId() &&
+      text_to_speech_listener_) {
+    text_to_speech_listener_->value().Run();
+  }
 }
 
 }  // namespace h5vcc
diff --git a/src/cobalt/h5vcc/h5vcc_accessibility.h b/src/cobalt/h5vcc/h5vcc_accessibility.h
index c9c5077..bb74c88 100644
--- a/src/cobalt/h5vcc/h5vcc_accessibility.h
+++ b/src/cobalt/h5vcc/h5vcc_accessibility.h
@@ -42,6 +42,8 @@
   void OnApplicationEvent(const base::Event* event);
 
   bool text_to_speech() const;
+  void AddTextToSpeechListener(
+      const H5vccAccessibilityCallbackHolder& holder);
 
   bool built_in_screen_reader() const;
   void set_built_in_screen_reader(bool value);
@@ -52,7 +54,7 @@
   typedef H5vccAccessibilityCallbackHolder::Reference
       H5vccAccessibilityCallbackReference;
 
-  void InternalOnApplicationEvent();
+  void InternalOnApplicationEvent(base::TypeId type);
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
@@ -60,6 +62,8 @@
   base::EventDispatcher* event_dispatcher_;
   std::unique_ptr<H5vccAccessibilityCallbackReference>
       high_contrast_text_listener_;
+  std::unique_ptr<H5vccAccessibilityCallbackReference>
+      text_to_speech_listener_;
 
   DISALLOW_COPY_AND_ASSIGN(H5vccAccessibility);
 };
diff --git a/src/cobalt/h5vcc/h5vcc_accessibility.idl b/src/cobalt/h5vcc/h5vcc_accessibility.idl
index d4aa26d..857d7e6 100644
--- a/src/cobalt/h5vcc/h5vcc_accessibility.idl
+++ b/src/cobalt/h5vcc/h5vcc_accessibility.idl
@@ -22,6 +22,11 @@
   // option is enabled.
   readonly attribute boolean textToSpeech;
 
+  // This callback is invoked when text-to-speech settings have changed. It
+  // may also be invoked if other accessibility settings (ones not related to
+  // text-to-speech) have changed.
+  void addTextToSpeechListener(H5vccAccessibilityCallback callback);
+
   // True if the built-in screen reader is enabled.
   // Setting it to false disables the built-in screen reader.
   attribute boolean builtInScreenReader;
diff --git a/src/cobalt/layout/box_generator.cc b/src/cobalt/layout/box_generator.cc
index a1c8282..b2b1d6b 100644
--- a/src/cobalt/layout/box_generator.cc
+++ b/src/cobalt/layout/box_generator.cc
@@ -444,7 +444,7 @@
       base::nullopt, base::nullopt, context_,
       ReplacedBox::ReplacedBoxMode::kLottie,
       math::Size() /* only relevant to punch out video */,
-      lottie_player->GetUpdatedProperties());
+      lottie_player->GetProperties());
   lottie_player->computed_style()->display()->Accept(&replaced_box_generator);
 
   scoped_refptr<ReplacedBox> replaced_box =
diff --git a/src/cobalt/math/matrix3_unittest.cc b/src/cobalt/math/matrix3_unittest.cc
index cf11475..d78d59b 100644
--- a/src/cobalt/math/matrix3_unittest.cc
+++ b/src/cobalt/math/matrix3_unittest.cc
@@ -131,7 +131,7 @@
 
   // The below three EXPECT_NEARs are changed from
   //   EXPECT_EQ(Vector3dF(8.0f, -1.0f, -1.0f), eigenvals);
-  // because the test fails on PS3.
+  // because the test fails on some platforms.
   //   Value of: eigenvals.y()
   //   Actual: -0.99999952
   //   Expected: -1.0f
diff --git a/src/cobalt/render_tree/lottie_animation.h b/src/cobalt/render_tree/lottie_animation.h
index 5f50944..8b1a771 100644
--- a/src/cobalt/render_tree/lottie_animation.h
+++ b/src/cobalt/render_tree/lottie_animation.h
@@ -49,10 +49,19 @@
 
     // Return true if |state| is updated to a new & valid LottieState.
     bool UpdateState(LottieState new_state) {
-      // It is not possible to pause a stopped animation.
-      if (new_state == LottieState::kPaused && state == LottieState::kStopped) {
-        return false;
+      // Regardless of whether the state actually changes, per the web spec, we
+      // need to dispatch an event signaling that a particular playback state
+      // was requested.
+      if (new_state == LottieState::kPlaying && !onplay_callback.is_null()) {
+        onplay_callback.Run();
+      } else if (new_state == LottieState::kPaused &&
+                 !onpause_callback.is_null()) {
+        onpause_callback.Run();
+      } else if (new_state == LottieState::kStopped &&
+                 !onstop_callback.is_null()) {
+        onstop_callback.Run();
       }
+
       if (new_state == state) {
         return false;
       }
@@ -155,9 +164,9 @@
 
     void TogglePlay() {
       if (state == LottieState::kPlaying) {
-        state = LottieState::kPaused;
+        UpdateState(LottieState::kPaused);
       } else {
-        state = LottieState::kPlaying;
+        UpdateState(LottieState::kPlaying);
       }
     }
 
@@ -184,6 +193,9 @@
     // animation.
     size_t seek_counter = 0;
 
+    base::Closure onplay_callback;
+    base::Closure onpause_callback;
+    base::Closure onstop_callback;
     base::Closure oncomplete_callback;
     base::Closure onloop_callback;
   };
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 3365ed6..90ee177 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -2239,7 +2239,7 @@
 TEST_F(PixelTest, OpacityOnRectAndEllipseMaskedImage) {
   // The opacity in this test will result in the rect and ellipse being rendered
   // to an offscreen surface.  The ellipse masking shaders may make use of
-  // |gl_FragCoord|, which can return a flipped y value for at least the PS3
+  // |gl_FragCoord|, which can return a flipped y value on some platforms
   // when rendering to a texture.  This test ensures that this is handled.
   scoped_refptr<Image> image =
       CreateColoredCheckersImage(GetResourceProvider(), output_surface_size());
diff --git a/src/cobalt/storage/storage_manager.cc b/src/cobalt/storage/storage_manager.cc
index 352c392..8feb2e0 100644
--- a/src/cobalt/storage/storage_manager.cc
+++ b/src/cobalt/storage/storage_manager.cc
@@ -177,8 +177,8 @@
     }
   }
 
-  // Legacy Steel save data may contain multiple files (e.g. db-journal as well
-  // as db), so use the first one that looks like a valid database file.
+  // Very old legacy save data may contain multiple files (e.g. db-journal as
+  // well as db), so use the first one that looks like a valid database file.
 
   if (has_upgrade_data) {
     const char* buffer = reinterpret_cast<char*>(&raw_bytes[0]);
diff --git a/src/cobalt/storage/storage_manager.h b/src/cobalt/storage/storage_manager.h
index 5db579c..cf8ec90 100644
--- a/src/cobalt/storage/storage_manager.h
+++ b/src/cobalt/storage/storage_manager.h
@@ -43,7 +43,7 @@
 class StorageManager {
  public:
   // Support for "upgrade" of legacy save data that may have been generated by
-  // a platform other than Steel/Cobalt. If save data in the upgrade format is
+  // a platform other than Cobalt. If save data in the upgrade format is
   // detected, the |OnUpgrade| method will be called on |upgrade_handler_|.
   class UpgradeHandler {
    public:
diff --git a/src/cobalt/storage/store_upgrade/upgrade.cc b/src/cobalt/storage/store_upgrade/upgrade.cc
index 26c455c..302d7b5 100644
--- a/src/cobalt/storage/store_upgrade/upgrade.cc
+++ b/src/cobalt/storage/store_upgrade/upgrade.cc
@@ -179,8 +179,8 @@
     filenames.push_back(kDefaultSaveFile);
   }
 
-  // Legacy Steel save data may contain multiple files (e.g. db-journal as well
-  // as db), so use the first one that looks like a valid database file.
+  // Very old legacy save data may contain multiple files (e.g. db-journal as
+  // well as db), so use the first one that looks like a valid database file.
   const std::string& save_name = GetFirstValidDatabaseFile(filenames);
   bool ok = connection->Open(base::FilePath(save_name));
   if (!ok) {
diff --git a/src/cobalt/tools/gyp_to_gn.py b/src/cobalt/tools/gyp_to_gn.py
index 0fa1e1d..23f4a59 100755
--- a/src/cobalt/tools/gyp_to_gn.py
+++ b/src/cobalt/tools/gyp_to_gn.py
@@ -63,24 +63,24 @@
   true/false):
 
   >>> g = GYPCondToGNNodeVisitor()
-  >>> g.visit(ast.parse('arm_neon and target_arch=="xb1"', mode='eval'))
-  '(arm_use_neon && target_cpu == "xb1")'
-  >>> g.visit(ast.parse('use_system_libjpeg and target_arch=="xb1"',
+  >>> g.visit(ast.parse('arm_neon and target_arch=="raspi-2"', mode='eval'))
+  '(arm_use_neon && target_cpu == "raspi-2")'
+  >>> g.visit(ast.parse('use_system_libjpeg and target_arch=="raspi-2"',
   ...                   mode='eval'))
-  '(use_system_libjpeg && target_cpu == "xb1")'
+  '(use_system_libjpeg && target_cpu == "raspi-2")'
   >>> g.visit(ast.parse('arm_neon == 1', mode='eval'))
   'arm_use_neon == true'
   >>> g.visit(ast.parse('1', mode='eval'))
   'true'
   >>> g.visit(ast.parse('0', mode='eval'))
   'false'
-  >>> g.visit(ast.parse('arm_neon != 0 and target_arch != "xb1" and
+  >>> g.visit(ast.parse('arm_neon != 0 and target_arch != "raspi-2" and
   use_system_libjpeg or enable_doom_melon', mode='eval'))
-  '((arm_use_neon != false && target_cpu != "xb1" && use_system_libjpeg) ||
+  '((arm_use_neon != false && target_cpu != "raspi-2" && use_system_libjpeg) ||
   enable_doom_melon)'
-  >>> g.visit(ast.parse('arm_neon != 0 and target_arch != "xb1" or
+  >>> g.visit(ast.parse('arm_neon != 0 and target_arch != "raspi-2" or
   use_system_libjpeg and enable_doom_melon', mode='eval'))
-  '((arm_use_neon != false && target_cpu != "xb1") || (use_system_libjpeg &&
+  '((arm_use_neon != false && target_cpu != "raspi-2") || (use_system_libjpeg &&
   enable_doom_melon))'
   """
 
diff --git a/src/content/browser/speech/endpointer/energy_endpointer.cc b/src/content/browser/speech/endpointer/energy_endpointer.cc
index fc1d871..eb0b565 100644
--- a/src/content/browser/speech/endpointer/energy_endpointer.cc
+++ b/src/content/browser/speech/endpointer/energy_endpointer.cc
@@ -1,10 +1,6 @@
 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-//
-// To know more about the algorithm used and the original code which this is
-// based of, see
-// https://wiki.corp.google.com/twiki/bin/view/Main/ChromeGoogleCodeXRef
 
 #include "content/browser/speech/endpointer/energy_endpointer.h"
 
diff --git a/src/nb/nb_test.gyp b/src/nb/nb_test.gyp
index 1707887..5520709 100644
--- a/src/nb/nb_test.gyp
+++ b/src/nb/nb_test.gyp
@@ -18,7 +18,7 @@
       'target_name': 'nb_test',
       'type': '<(gtest_target_type)',
       'conditions': [
-        ['OS=="starboard" or (OS=="lb_shell" and target_arch == "ps3")', {
+        ['OS=="starboard"', {
           'sources': [
             'analytics/memory_tracker_helpers_test.cc',
             'analytics/memory_tracker_impl_test.cc',
diff --git a/src/nb/ref_counted.h b/src/nb/ref_counted.h
index ab24980..ba14980 100644
--- a/src/nb/ref_counted.h
+++ b/src/nb/ref_counted.h
@@ -238,13 +238,6 @@
     SB_DCHECK(ptr_ != NULL);
     return ptr_;
   }
-// The compiler requires an explicit * operator here.
-#if defined(__LB_PS3__)
-  T& operator*() const {
-    SB_DCHECK(ptr_ != NULL);
-    return *ptr_;
-  }
-#endif
 
   scoped_refptr<T>& operator=(T* p) {
     // AddRef first so that self assignment should work
diff --git a/src/nb/testdata/mem_history_cobalt.txt b/src/nb/testdata/mem_history_cobalt.txt
index 7e7814b..a47c0d3 100644
--- a/src/nb/testdata/mem_history_cobalt.txt
+++ b/src/nb/testdata/mem_history_cobalt.txt
@@ -1,4 +1,4 @@
-# cobalt PS3
+# cobalt
 c0000000 65536 65536
 c0020000 8847360 65536
 c08a0000 8847360 65536
diff --git a/src/net/METADATA b/src/net/METADATA
index 0ed2294..ee25224 100644
--- a/src/net/METADATA
+++ b/src/net/METADATA
@@ -1,5 +1,3 @@
-# Format: google3/devtools/metadata/metadata.proto (go/google3metadata)
-
 name: "net"
 description:
   "Subtree at net."
diff --git a/src/starboard/CHANGELOG.md b/src/starboard/CHANGELOG.md
index c535b8b..5575e52 100644
--- a/src/starboard/CHANGELOG.md
+++ b/src/starboard/CHANGELOG.md
@@ -242,6 +242,13 @@
 The Platform Services API should be used
 instead. See cobalt/doc/platform_services.md.
 
+### Add event for text-to-speech settings changes.
+
+If the platform supports text-to-speech settings, it must use the new
+kSbEventTypeAccessiblityTextToSpeechSettingsChanged event to inform the app
+when those settings change. For older starboard versions, use
+kSbEventTypeAccessiblitySettingsChanged instead.
+
 ## Version 11
 
 ### Add arguments to `SbMediaIsVideoSupported`.
diff --git a/src/starboard/build/convert_i18n_data.gypi b/src/starboard/build/convert_i18n_data.gypi
index 695d49b..6ae88fe 100644
--- a/src/starboard/build/convert_i18n_data.gypi
+++ b/src/starboard/build/convert_i18n_data.gypi
@@ -14,7 +14,7 @@
 
 # This file is meant to be included into an action to convert a set of XLB files
 # into files of a simpler format (e.g. CSV) in the product directory, e.g.
-# e.g. out/ps4_debug/content/data/i18n.
+# e.g. out/stub_debug/content/data/i18n.
 #
 # To use this, define the variable xlb_files and include this file.
 #  'variables': {
diff --git a/src/starboard/client_porting/poem/strnlen_poem.h b/src/starboard/client_porting/poem/strnlen_poem.h
index f714990..664d503 100644
--- a/src/starboard/client_porting/poem/strnlen_poem.h
+++ b/src/starboard/client_porting/poem/strnlen_poem.h
@@ -13,7 +13,7 @@
 // limitations under the License.
 
 // A poem (POsix EMulation) implementation for strnlen. Usually declared in
-// <string.h>, but may be missing on some platforms (e.g. PS3).
+// <string.h>, but may be missing on some platforms.
 
 #ifndef STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
 #define STARBOARD_CLIENT_PORTING_POEM_STRNLEN_POEM_H_
diff --git a/src/starboard/event.h b/src/starboard/event.h
index feca155..0a18f26 100644
--- a/src/starboard/event.h
+++ b/src/starboard/event.h
@@ -359,7 +359,12 @@
   // The platform's accessibility settings have changed. The application should
   // query the accessibility settings using the appropriate APIs to get the
   // new settings. Note this excludes captions settings changes, which
-  // causes kSbEventTypeAccessibilityCaptionSettingsChanged to fire.
+  // causes kSbEventTypeAccessibilityCaptionSettingsChanged to fire. If the
+  // starboard version has kSbEventTypeAccessiblityTextToSpeechSettingsChanged,
+  // then that event should be used to signal text-to-speech settings changes
+  // instead; platforms using older starboard versions should use
+  // kSbEventTypeAccessiblitySettingsChanged for text-to-speech settings
+  // changes.
   kSbEventTypeAccessiblitySettingsChanged,
 
   // An optional event that platforms may send to indicate that the application
@@ -430,6 +435,11 @@
   // has changed.
   kSbEventTypeAccessibilityCaptionSettingsChanged,
 #endif  // SB_API_VERSION >= 12 || SB_HAS(CAPTIONS)
+
+#if SB_API_VERSION >= 12
+  // The platform's text-to-speech settings have changed.
+  kSbEventTypeAccessiblityTextToSpeechSettingsChanged,
+#endif  // SB_API_VERSION >= 12
 } SbEventType;
 
 // Structure representing a Starboard event and its data.
diff --git a/src/starboard/shared/msvc/uwp/msvc_toolchain.py b/src/starboard/shared/msvc/uwp/msvc_toolchain.py
deleted file mode 100644
index 83007e6..0000000
--- a/src/starboard/shared/msvc/uwp/msvc_toolchain.py
+++ /dev/null
@@ -1,937 +0,0 @@
-# Copyright 2017 The Cobalt Authors. All Rights Reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-"""This module implements starboard's abstract toolchain for MSVC UWP."""
-
-from difflib import get_close_matches
-import os
-import re
-import subprocess
-import sys
-
-_COBALT_SRC = os.path.abspath(os.path.join(*([__file__] + 5 * [os.pardir])))
-sys.path.append(os.path.join(_COBALT_SRC, 'starboard', 'tools'))
-
-import gyp.MSVSVersion  # pylint: disable=g-import-not-at-top
-# This tool_chain is starboard/build/toolchain.py
-from starboard.tools.toolchain_deprecated import CompilerSettings
-from starboard.tools.toolchain_deprecated import PrecompiledHeader
-from starboard.tools.toolchain_deprecated import Toolchain
-
-def _LanguageMatchesForPch(source_ext, pch_source_ext):
-  c_exts = ('.c',)
-  cc_exts = ('.cc', '.cxx', '.cpp')
-  return ((source_ext in c_exts and pch_source_ext in c_exts) or
-          (source_ext in cc_exts and pch_source_ext in cc_exts))
-
-
-class MSVCPrecompiledHeader(PrecompiledHeader):
-  """MSVC implementation of PrecompiledHeader interface."""
-
-  def __init__(self, **kwargs):
-    self.settings = kwargs['settings']
-    self.config = kwargs['config']
-    gyp_path_to_ninja = kwargs['gyp_path_to_ninja']
-    gyp_path_to_unique_output = kwargs['gyp_path_to_unique_output']
-    obj_ext = kwargs['obj_ext']
-    pch_source = self.settings.msvs_precompiled_source[self.config]
-    self.pch_source = gyp_path_to_ninja(pch_source)
-    filename, _ = os.path.splitext(pch_source)
-    self.output_obj = gyp_path_to_unique_output(filename + obj_ext).lower()
-
-  def GetFlagsModifications(self, input_flags, output, implicit, command,
-                            cflags_c, cflags_cc, expand_special):
-    """Get the modified cflags and implicit dependencies."""
-    if self.settings.UsesComponentExtensions(self.config):
-      # No-op if component extensions are used.
-      return [], output, []
-
-    if input_flags == self.pch_source:
-      pch_output = ['/Yc' + self._PchHeader()]
-      if command == 'cxx':
-        return ([('cflags_cc', map(expand_special, cflags_cc + pch_output))],
-                self.output_obj, [])
-      elif command == 'cc':
-        return ([('cflags_c', map(expand_special, cflags_c + pch_output))],
-                self.output_obj, [])
-    return [], output, implicit
-
-  def GetInclude(self):
-    pass
-
-  def GetPchBuildCommands(self):
-    """Not used on Windows as there are no additional build steps required
-    (instead, existing steps are modified in GetFlagsModifications below)."""
-    return []
-
-  def _PchHeader(self):
-    """Get the header that will appear in an #include line for all source
-    files."""
-    return os.path.split(self.settings.msvs_precompiled_header[self.config])[1]
-
-  def GetObjDependencies(self, sources, output):
-    """Given a list of sources files and the corresponding object files,
-    returns a list of the pch files that should be depended upon. The
-    additional wrapping in the return value is for interface compatability
-    with make.py on Mac, and xcode_emulation.py."""
-    if not self._PchHeader():
-      return []
-    pch_ext = os.path.splitext(self.pch_source)[1]
-    for source in sources:
-      if _LanguageMatchesForPch(os.path.splitext(source)[1], pch_ext):
-        return [(None, None, self.output_obj)]
-    return []
-
-
-vs_version = None
-
-
-def GetVSVersion(generator_flags):
-  global vs_version
-  if not vs_version:
-    vs_version = gyp.MSVSVersion.SelectVisualStudioVersion(
-        generator_flags.get('msvs_version', 'auto'))
-  return vs_version
-
-
-def _GenericRetrieve(root, default, path):
-  """Given a list of dictionary keys |path| and a tree of dicts |root|, find
-  value at path, or return |default| if any of the path doesn't exist."""
-  if not root:
-    return default
-  if not path:
-    return root
-  return _GenericRetrieve(root.get(path[0]), default, path[1:])
-
-
-def _AddPrefix(element, prefix):
-  """Add |prefix| to |element| or each subelement if element is iterable."""
-  if element is None:
-    return element
-  # Note, not Iterable because we don't want to handle strings like that.
-  if isinstance(element, list) or isinstance(element, tuple):
-    return [prefix + e for e in element]
-  else:
-    return prefix + element
-
-
-def _CallMap(map, element):
-  e = map(element)
-  if e is None:
-    raise Exception('Invalid element %s' % element)
-  return e
-
-
-def _DoRemapping(element, map):
-  """If |element| then remap it through |map|. If |element| is iterable then
-  each item will be remapped. Any elements not found will be removed."""
-  if map is not None and element is not None:
-    if not callable(map):
-      map = map.get  # Assume it's a dict, otherwise a callable to do the remap.
-    if isinstance(element, list) or isinstance(element, tuple):
-      element = [_CallMap(map, elem) for elem in element]
-    else:
-      element = _CallMap(map, element)
-
-  return element
-
-
-def _AppendOrReturn(append, element):
-  """If |append| is None, simply return |element|. If |append| is not None,
-  then add |element| to it, adding each item in |element| if it's a list or
-  tuple."""
-  if append is not None and element is not None:
-    if isinstance(element, list) or isinstance(element, tuple):
-      append.extend(element)
-    else:
-      append.append(element)
-  else:
-    return element
-
-
-class MsvsSettings(CompilerSettings):
-  """A class that understands the gyp 'msvs_...' values (especially the
-  msvs_settings field). They largely correpond to the VS2008 IDE DOM. This
-  class helps map those settings to command line options."""
-
-  def __init__(self, spec, generator_flags):
-    self.spec = spec
-    self.vs_version = GetVSVersion(generator_flags)
-    # Try to find an installation location for the Windows DDK by checking
-    # the WDK_DIR environment variable, may be None.
-    self.wdk_dir = os.environ.get('WDK_DIR')
-
-    supported_fields = [
-        ('msvs_configuration_attributes', dict),
-        ('msvs_settings', dict),
-        ('msvs_system_include_dirs', list),
-        ('msvs_disabled_warnings', list),
-        ('msvs_precompiled_header', str),
-        ('msvs_precompiled_source', str),
-        ('msvs_configuration_platform', str),
-        ('msvs_target_platform', str),
-    ]
-    validators = {
-        'msvs_settings': self._SettingsValidator,
-    }
-    configs = spec['configurations']
-    for field, default in supported_fields:
-      setattr(self, field, {})
-      for configname, config in configs.iteritems():
-        getattr(self, field)[configname] = config.get(field, default())
-        if field in validators:
-          validators[field](configname)
-
-    self.msvs_cygwin_dirs = spec.get('msvs_cygwin_dirs', ['.'])
-
-  def GetVSMacroEnv(self, base_to_build=None, config=None):
-    """Get a dict of variables mapping internal VS macro names to their gyp
-    equivalents."""
-    vs_path = self.vs_version.Path()
-    # Absolute paths in cygwin the path will start with /cygdrive/c/
-    # The MS compiler tools need
-    # TODO: this is getting generated from the vs install path
-    # need to pass this in, or fix earlier in generation
-    if sys.platform == 'cygwin':
-      vs_path = cygpath.to_nt(vs_path)
-
-    target_platform = 'Win32' if self.GetArch(config) == 'x86' else 'x64'
-
-    try:
-      vc_install_dir = os.path.join(vs_path, 'VC') + '\\'
-    except TypeError as te:
-      raise IOError('Error while constructing path, is vs_path (' + \
-                    str(vs_path) + ') missing?')
-
-    replacements = {
-        '$(VSInstallDir)': vs_path,
-        '$(VCInstallDir)': vc_install_dir,
-        '$(OutDir)\\': base_to_build + '\\' if base_to_build else '',
-        '$(IntDir)': '$!INTERMEDIATE_DIR',
-        '$(InputPath)': '${source}',
-        '$(InputName)': '${root}',
-        '$(ProjectName)': self.spec['target_name'],
-        '$(PlatformName)': target_platform,
-        '$(ProjectDir)\\': '',
-    }
-
-    replacements['$(WDK_DIR)'] = self.wdk_dir if self.wdk_dir else ''
-    return replacements
-
-  def ConvertVSMacros(self, s, base_to_build=None, config=None):
-    """Convert from VS macro names to something equivalent."""
-    env = self.GetVSMacroEnv(base_to_build, config=config)
-    return ToolchainImpl().ExpandEnvVars(s, env)
-
-  def ProcessLibraries(self, libraries):
-    """Strip -l from library if it's specified with that."""
-    return [lib[2:] if lib.startswith('-l') else lib for lib in libraries]
-
-  def _GetAndMunge(self, field, path, default, prefix, append, map):
-    """Retrieve a value from |field| at |path| or return |default|. If
-    |append| is specified, and the item is found, it will be appended to that
-    object instead of returned. If |map| is specified, results will be
-    remapped through |map| before being returned or appended."""
-    result = _GenericRetrieve(field, default, path)
-    result = _DoRemapping(result, map)
-    result = _AddPrefix(result, prefix)
-    return _AppendOrReturn(append, result)
-
-  class _GetWrapper(object):
-
-    def __init__(self, parent, field, base_path, append=None):
-      self.parent = parent
-      self.field = field
-      self.base_path = [base_path]
-      self.append = append
-
-    def __call__(self, name, map=None, prefix='', default=None):
-      return self.parent._GetAndMunge(
-          self.field,
-          self.base_path + [name],
-          default=default,
-          prefix=prefix,
-          append=self.append,
-          map=map)
-
-  def GetArch(self, config):
-    """Get architecture based on msvs_configuration_platform and
-    msvs_target_platform. Returns either 'x86' or 'x64'."""
-    configuration_platform = self.msvs_configuration_platform.get(config, '')
-    platform = self.msvs_target_platform.get(config, '')
-    if not platform:  # If no specific override, use the configuration's.
-      platform = configuration_platform
-    # Map from platform to architecture.
-    return {'Win32': 'x86', 'x64': 'x64'}.get(platform, 'x86')
-
-  def _TargetConfig(self, config):
-    """Returns the target-specific configuration."""
-    # On Cobalt, we're not using any suffix on config names like Win_Debug_x64.
-    # Cobalt on Windows is x64 only.
-    return config
-
-  def _Setting(self,
-               path,
-               config,
-               default=None,
-               prefix='',
-               append=None,
-               map=None):
-    """_GetAndMunge for msvs_settings."""
-    return self._GetAndMunge(self.msvs_settings[config], path, default, prefix,
-                             append, map)
-
-  def _SettingsValidator(self, configname):
-    """Validate msvs_settings."""
-    valid_fields = [
-        'VCCLCompilerTool',
-        'VCLinkerTool',
-        'VCLibrarianTool',
-        'VCMIDLTool',
-        'VCResourceCompilerTool',
-        'VCManifestTool',
-    ]
-    for field in self.msvs_settings[configname]:
-      if field not in valid_fields:
-        message = ('Invalid msvs_settings field: "%s", '
-                   'config: "%s"' % (field, configname))
-        close_match = get_close_matches(field, valid_fields, 1)
-        if close_match:
-          message += '\nDid you mean %s?' % tuple(close_match)
-        raise Exception(message)
-
-  def _ConfigAttrib(self,
-                    path,
-                    config,
-                    default=None,
-                    prefix='',
-                    append=None,
-                    map=None):
-    """_GetAndMunge for msvs_configuration_attributes."""
-    return self._GetAndMunge(self.msvs_configuration_attributes[config], path,
-                             default, prefix, append, map)
-
-  def ProcessIncludeDirs(self, include_dirs, config):
-    """Updates include_dirs to expand VS specific paths, and adds the system
-    include dirs used for platform SDK and similar."""
-    config = self._TargetConfig(config)
-    includes = include_dirs + self.msvs_system_include_dirs[config]
-    includes.extend(
-        self._Setting(
-            ('VCCLCompilerTool', 'AdditionalIncludeDirectories'),
-            config,
-            default=[]))
-    return [self.ConvertVSMacros(p, config=config) for p in includes]
-
-  def GetDefines(self, config):
-    """Returns the set of defines that are injected to the defines list based
-    on other VS settings."""
-    config = self._TargetConfig(config)
-    defines = []
-    if self._ConfigAttrib(['CharacterSet'], config) == '1':
-      defines.extend(('_UNICODE', 'UNICODE'))
-    if self._ConfigAttrib(['CharacterSet'], config) == '2':
-      defines.append('_MBCS')
-    defines.extend(
-        self._Setting(
-            ('VCCLCompilerTool', 'PreprocessorDefinitions'), config,
-            default=[]))
-    return defines
-
-  def GetOutputName(self, config, expand_special):
-    """Gets the explicitly overridden output name for a target or returns None
-    if it's not overridden."""
-    config = self._TargetConfig(config)
-    type = self.spec['type']
-    root = 'VCLibrarianTool' if type == 'static_library' else 'VCLinkerTool'
-    # TODO: Handle OutputDirectory without OutputFile.
-    output_file = self._Setting((root, 'OutputFile'), config)
-    if output_file:
-      output_file = expand_special(
-          self.ConvertVSMacros(output_file, config=config))
-    return output_file
-
-  def GetPDBName(self, config, expand_special):
-    """Gets the explicitly overridden pdb name for a target or returns None
-    if it's not overridden."""
-    config = self._TargetConfig(config)
-    output_file = self._Setting(('VCLinkerTool', 'ProgramDatabaseFile'), config)
-    if output_file:
-      output_file = expand_special(
-          self.ConvertVSMacros(output_file, config=config))
-    return output_file
-
-  def GetCflags(self, config):
-    """Returns the flags that need to be added to .c and .cc compilations."""
-    config = self._TargetConfig(config)
-    cflags = []
-    cflags.extend(['/wd' + w for w in self.msvs_disabled_warnings[config]])
-    cl = self._GetWrapper(
-        self, self.msvs_settings[config], 'VCCLCompilerTool', append=cflags)
-    cl('Optimization',
-       map={'0': 'd',
-            '1': '1',
-            '2': '2',
-            '3': 'x'},
-       prefix='/O')
-    cl('InlineFunctionExpansion', prefix='/Ob')
-    cl('OmitFramePointers', map={'false': '-', 'true': ''}, prefix='/Oy')
-    cl('FavorSizeOrSpeed', map={'1': 't', '2': 's'}, prefix='/O')
-    cl('WholeProgramOptimization', map={'true': '/GL'})
-    cl('WarningLevel', prefix='/W')
-    cl('WarnAsError', map={'false': '', 'true': '/WX'})
-    cl('DebugInformationFormat',
-       map={'1': '7',
-            '3': 'i',
-            '4': 'I'},
-       prefix='/Z')
-    cl('RuntimeTypeInfo', map={'true': '/GR', 'false': '/GR-'})
-    cl('EnableFunctionLevelLinking', map={'true': '/Gy', 'false': '/Gy-'})
-    cl('MinimalRebuild', map={'true': '/Gm', 'false': '/Gm-'})
-    cl('BufferSecurityCheck', map={'true': '/GS', 'false': '/GS-'})
-    cl('BasicRuntimeChecks', map={'1': 's', '2': 'u', '3': '1'}, prefix='/RTC')
-    cl('RuntimeLibrary',
-       map={'0': 'T',
-            '1': 'Td',
-            '2': 'D',
-            '3': 'Dd'},
-       prefix='/M')
-    cl('ExceptionHandling', map={'1': 'sc', '2': 'a'}, prefix='/EH')
-    cl('EnablePREfast', map={'true': '/analyze'})
-    cl('AdditionalOptions', prefix='')
-    cflags.extend([
-        '/FI' + f
-        for f in self._Setting(
-            ('VCCLCompilerTool', 'ForcedIncludeFiles'), config, default=[])
-    ])
-    cflags.extend([
-        '/Zc:' + f
-        for f in self._Setting(
-            ('VCCLCompilerTool', 'Conformance'), config, default=[])
-    ])
-
-    # ninja handles parallelism by itself, don't have the compiler do it too.
-    cflags = filter(lambda x: not x.startswith('/MP'), cflags)
-    return cflags
-
-  def GetCflagsObjectiveC(self):
-    pass
-
-  def GetCflagsObjectiveCC(self):
-    pass
-
-  def _GetPchFlags(self, config, extension):
-    """Get the flags to be added to the cflags for precompiled header support.
-    """
-    config = self._TargetConfig(config)
-    # The PCH is only built once by a particular source file. Usage of PCH must
-    # only be for the same language (i.e. C vs. C++), so only include the pch
-    # flags when the language matches.
-    if self.msvs_precompiled_header[config]:
-      source_ext = os.path.splitext(self.msvs_precompiled_source[config])[1]
-      if _LanguageMatchesForPch(source_ext, extension):
-        pch = os.path.split(self.msvs_precompiled_header[config])[1]
-        return ['/Yu' + pch, '/FI' + pch, '/Fp${pchprefix}.' + pch + '.pch']
-    return []
-
-  def UsesComponentExtensions(self, config):
-    return self._Setting(
-        ('VCCLCompilerTool', 'ComponentExtensions'), config, default=[])
-
-  def GetCflagsC(self, config):
-    """Returns the flags that need to be added to .c compilations."""
-    config = self._TargetConfig(config)
-    return self._GetPchFlags(config, '.c')
-
-  def GetCflagsCC(self, config):
-    """Returns the flags that need to be added to .cc compilations."""
-    config = self._TargetConfig(config)
-    ccflags = []
-    cl = self._GetWrapper(
-        self, self.msvs_settings[config], 'VCCLCompilerTool', append=ccflags)
-    cl('ComponentExtensions', map={'true': '/ZW'})
-
-    if self.UsesComponentExtensions(config):
-      # Disable PCH for libs compiled with /ZW, even if it was requested.
-      # Causes a fatal compiler error.
-      return ['/TP'] + ccflags
-    else:
-      return ['/TP'] + self._GetPchFlags(config, '.cc') + ccflags
-
-  def _GetAdditionalLibraryDirectories(self, root, config, gyp_path_to_ninja):
-    """Get and normalize the list of paths in AdditionalLibraryDirectories
-    setting."""
-    config = self._TargetConfig(config)
-    libpaths = self._Setting(
-        (root, 'AdditionalLibraryDirectories'), config, default=[])
-    libpaths = [
-        os.path.normpath(
-            gyp_path_to_ninja(self.ConvertVSMacros(p, config=config)))
-        for p in libpaths
-    ]
-    return ['/LIBPATH:"' + p + '"' for p in libpaths]
-
-  def GetLibFlags(self, config, gyp_path_to_ninja):
-    """Returns the flags that need to be added to lib commands."""
-    config = self._TargetConfig(config)
-    libflags = []
-    lib = self._GetWrapper(
-        self, self.msvs_settings[config], 'VCLibrarianTool', append=libflags)
-    libflags.extend(
-        self._GetAdditionalLibraryDirectories('VCLibrarianTool', config,
-                                              gyp_path_to_ninja))
-    lib('AdditionalOptions')
-    return libflags
-
-  def _GetDefFileAsLdflags(self, spec, ldflags, gyp_path_to_ninja):
-    """.def files get implicitly converted to a ModuleDefinitionFile for the
-    linker in the VS generator. Emulate that behaviour here."""
-    def_file = ''
-    if spec['type'] in ('shared_library', 'loadable_module', 'executable'):
-      def_files = [s for s in spec.get('sources', []) if s.endswith('.def')]
-      if len(def_files) == 1:
-        ldflags.append('/DEF:"%s"' % gyp_path_to_ninja(def_files[0]))
-      elif len(def_files) > 1:
-        raise Exception('Multiple .def files')
-
-  def GetLdFlags(self, config, **kwargs):
-    """Returns the flags that need to be added to link commands, and the
-    manifest files."""
-
-    gyp_path_to_ninja = kwargs['gyp_path_to_ninja']
-    expand_special = kwargs['expand_special']
-    manifest_name = kwargs['manifest_name']
-    is_executable = kwargs['is_executable']
-
-    config = self._TargetConfig(config)
-    ldflags = []
-    ld = self._GetWrapper(
-        self, self.msvs_settings[config], 'VCLinkerTool', append=ldflags)
-    self._GetDefFileAsLdflags(self.spec, ldflags, gyp_path_to_ninja)
-    ld('GenerateDebugInformation', map={'true': '/DEBUG'})
-    ld('TargetMachine', map={'1': 'X86', '17': 'X64'}, prefix='/MACHINE:')
-    ldflags.extend(
-        self._GetAdditionalLibraryDirectories('VCLinkerTool', config,
-                                              gyp_path_to_ninja))
-    ld('DelayLoadDLLs', prefix='/DELAYLOAD:')
-    out = self.GetOutputName(config, expand_special)
-    if out:
-      ldflags.append('/OUT:' + out)
-    pdb = self.GetPDBName(config, expand_special)
-    if pdb:
-      ldflags.append('/PDB:' + pdb)
-    ld('AdditionalOptions', prefix='')
-    ld('SubSystem', map={'1': 'CONSOLE', '2': 'WINDOWS'}, prefix='/SUBSYSTEM:')
-    ld('LinkIncremental', map={'1': ':NO', '2': ''}, prefix='/INCREMENTAL')
-    ld('FixedBaseAddress', map={'1': ':NO', '2': ''}, prefix='/FIXED')
-    ld('RandomizedBaseAddress',
-       map={'1': ':NO',
-            '2': ''},
-       prefix='/DYNAMICBASE')
-    ld('DataExecutionPrevention', map={'1': ':NO', '2': ''}, prefix='/NXCOMPAT')
-    ld('OptimizeReferences', map={'1': 'NOREF', '2': 'REF'}, prefix='/OPT:')
-    ld('EnableCOMDATFolding', map={'1': 'NOICF', '2': 'ICF'}, prefix='/OPT:')
-    ld('LinkTimeCodeGeneration', map={'1': '/LTCG'})
-    ld('IgnoreDefaultLibraryNames', prefix='/NODEFAULTLIB:')
-    ld('ResourceOnlyDLL', map={'true': '/NOENTRY'})
-    ld('EntryPointSymbol', prefix='/ENTRY:')
-    ld('Profile', map={'true': '/PROFILE'})
-    # TODO: This should sort of be somewhere else (not really a flag).
-    ld('AdditionalDependencies', prefix='')
-
-    # If the base address is not specifically controlled, DYNAMICBASE should
-    # be on by default.
-    base_flags = filter(lambda x: 'DYNAMICBASE' in x or x == '/FIXED',
-                        ldflags)
-    if not base_flags:
-      ldflags.append('/DYNAMICBASE')
-
-    # If the NXCOMPAT flag has not been specified, default to on. Despite the
-    # documentation that says this only defaults to on when the subsystem is
-    # Vista or greater (which applies to the linker), the IDE defaults it on
-    # unless it's explicitly off.
-    if not filter(lambda x: 'NXCOMPAT' in x, ldflags):
-      ldflags.append('/NXCOMPAT')
-
-    have_def_file = filter(lambda x: x.startswith('/DEF:'), ldflags)
-    manifest_flags, intermediate_manifest_file = self._GetLdManifestFlags(
-        config, manifest_name, is_executable and not have_def_file)
-    ldflags.extend(manifest_flags)
-    manifest_files = self._GetAdditionalManifestFiles(config, gyp_path_to_ninja)
-    manifest_files.append(intermediate_manifest_file)
-
-    return ldflags, manifest_files
-
-  def _GetLdManifestFlags(self, config, name, allow_isolation):
-    """Returns the set of flags that need to be added to the link to generate
-    a default manifest, as well as the name of the generated file."""
-    output_name = name + '.intermediate.manifest'
-    # Manifests are off for UWP. If needed by another target,
-    # please find a way to configure them per target.
-    flags = [
-        '/MANIFEST:NO',
-    ]
-    return flags, output_name
-
-  def _GetAdditionalManifestFiles(self, config, gyp_path_to_ninja):
-    """Gets additional manifest files that are added to the default one
-    generated by the linker."""
-    files = self._Setting(
-        ('VCManifestTool', 'AdditionalManifestFiles'), config, default=[])
-    if (self._Setting(('VCManifestTool', 'EmbedManifest'), config,
-                      default='') == 'true'):
-      print 'gyp/msvs_emulation.py: "EmbedManifest: true" not yet supported.'
-    if isinstance(files, str):
-      files = files.split(';')
-    return [
-        os.path.normpath(
-            gyp_path_to_ninja(self.ConvertVSMacros(f, config=config)))
-        for f in files
-    ]
-
-  def IsUseLibraryDependencyInputs(self, config):
-    """Returns whether the target should be linked via Use Library Dependency
-    Inputs (using component .objs of a given .lib)."""
-    config = self._TargetConfig(config)
-    uldi = self._Setting(('VCLinkerTool', 'UseLibraryDependencyInputs'), config)
-    return uldi == 'true'
-
-  def GetRcFlags(self, config, gyp_to_ninja_path):
-    """Returns the flags that need to be added to invocations of the resource
-    compiler."""
-    config = self._TargetConfig(config)
-    rcflags = []
-    rc = self._GetWrapper(
-        self,
-        self.msvs_settings[config],
-        'VCResourceCompilerTool',
-        append=rcflags)
-    rc('AdditionalIncludeDirectories', map=gyp_to_ninja_path, prefix='/I')
-    rcflags.append('/I' + gyp_to_ninja_path('.'))
-    rc('PreprocessorDefinitions', prefix='/d')
-    # /l arg must be in hex without leading '0x'
-    rc('Culture', prefix='/l', map=lambda x: hex(int(x))[2:])
-    return rcflags
-
-  def BuildCygwinBashCommandLine(self, args, path_to_base):
-    """Build a command line that runs args via cygwin bash. We assume that all
-    incoming paths are in Windows normpath'd form, so they need to be
-    converted to posix style for the part of the command line that's passed to
-    bash. We also have to do some Visual Studio macro emulation here because
-    various rules use magic VS names for things. Also note that rules that
-    contain ninja variables cannot be fixed here (for example ${source}), so
-    the outer generator needs to make sure that the paths that are written out
-    are in posix style, if the command line will be used here."""
-    cygwin_dir = os.path.normpath(
-        os.path.join(path_to_base, self.msvs_cygwin_dirs[0]))
-    cd = ('cd %s' % path_to_base).replace('\\', '/')
-    args = [a.replace('\\', '/').replace('"', '\\"') for a in args]
-    args = ["'%s'" % a.replace("'", "'\\''") for a in args]
-    bash_cmd = ' '.join(args)
-    cmd = ('call "%s\\setup_env.bat" && set CYGWIN=nontsec && ' % cygwin_dir +
-           'bash -c "%s ; %s"' % (cd, bash_cmd))
-    return cmd
-
-  def IsRuleRunUnderCygwin(self, rule):
-    """Determine if an action should be run under cygwin. If the variable is
-    unset, or set to 1 we use cygwin."""
-    return int(
-        rule.get('msvs_cygwin_shell', self.spec.get('msvs_cygwin_shell',
-                                                    1))) != 0
-
-  def _HasExplicitRuleForExtension(self, spec, extension):
-    """Determine if there's an explicit rule for a particular extension."""
-    for rule in spec.get('rules', []):
-      if rule['extension'] == extension:
-        return True
-    return False
-
-  def HasExplicitIdlRules(self, spec):
-    """Determine if there's an explicit rule for idl files. When there isn't we
-    need to generate implicit rules to build MIDL .idl files."""
-    return self._HasExplicitRuleForExtension(spec, 'idl')
-
-  def HasExplicitAsmRules(self, spec):
-    """Determine if there's an explicit rule for asm files. When there isn't we
-    need to generate implicit rules to assemble .asm files."""
-    return self._HasExplicitRuleForExtension(spec, 'asm')
-
-  def GetIdlBuildData(self, source, config):
-    """Determine the implicit outputs for an idl file. Returns output
-    directory, outputs, and variables and flags that are required."""
-    config = self._TargetConfig(config)
-    midl_get = self._GetWrapper(self, self.msvs_settings[config], 'VCMIDLTool')
-
-    def midl(name, default=None):
-      return self.ConvertVSMacros(
-          midl_get(name, default=default), config=config)
-
-    # TODO: remove references to xb1 below.
-    if config.startswith('xb1'):
-      tlb = ''
-      header = midl('HeaderFileName', default='${root}.h')
-      dlldata = ''
-      iid = ''
-      proxy = ''
-      outdir = midl('OutputDirectory', default='')
-    else:
-      tlb = midl('TypeLibraryName', default='${root}.tlb')
-      header = midl('HeaderFileName', default='${root}.h')
-      dlldata = midl('DLLDataFileName', default='dlldata.c')
-      iid = midl('InterfaceIdentifierFileName', default='${root}_i.c')
-      proxy = midl('ProxyFileName', default='${root}_p.c')
-      # Note that .tlb is not included in the outputs as it is not always
-      # generated depending on the content of the input idl file.
-      outdir = midl('OutputDirectory', default='')
-    if config.startswith('xb1'):
-      output = [header]
-    else:
-      output = [header, dlldata, iid, proxy]
-    variables = [('tlb', tlb), ('h', header), ('dlldata', dlldata),
-                 ('iid', iid), ('proxy', proxy)]
-    if config.startswith('xb1'):
-      metadata_dir = '"%s%s"' % ('C:\\Program Files (x86)\\Windows Kits\\10\\',
-                                 'UnionMetadata')
-      flags = [
-          '/env', 'x64', '/W1', '/char', 'signed', '/enum_class',
-          '/metadata_dir', metadata_dir, '/notlb', '/winrt'
-      ]
-    else:
-      # TODO: Are there configuration settings to set these flags?
-      flags = ['/char', 'signed', '/env', 'win32', '/Oicf']
-    return outdir, output, variables, flags
-
-
-def _ExtractImportantEnvironment(output_of_set):
-  """Extracts environment variables required for the toolchain to run from
-  a textual dump output by the cmd.exe 'set' command."""
-  envvars_to_save = (
-      'durangoxdk',
-      'goma_.*',  # TODO: This is ugly, but needed for goma.
-      'include',
-      'lib',
-      'libpath',
-      'path',
-      'pathext',
-      'systemroot',
-      'temp',
-      'tmp',
-      'xedk',
-      'cell_.*',
-      'sn_.*',
-      'sce_.*',)
-  env = {}
-  for line in output_of_set.splitlines():
-    for envvar in envvars_to_save:
-      if re.match(envvar + '=', line.lower()):
-        var, setting = line.split('=', 1)
-        if envvar == 'path':
-          # Our own rules (for running gyp-win-tool) and other actions in
-          # Chromium rely on python being in the path. Add the path to this
-          # python here so that if it's not in the path when ninja is run
-          # later, python will still be found.
-          setting = os.path.dirname(sys.executable) + ';' + setting
-        env[var.upper()] = setting
-        break
-  for required in ('SYSTEMROOT', 'TEMP', 'TMP'):
-    if required not in env:
-      raise Exception('Environment variable "%s" '
-                      'required to be set to valid path' % required)
-  return env
-
-
-def _FormatAsEnvironmentBlock(envvar_dict):
-  """Format as an 'environment block' directly suitable for CreateProcess.
-  Briefly this is a list of key=value\0, terminated by an additional \0. See
-  CreateProcess documentation for more details."""
-  block = ''
-  nul = '\0'
-  for key, value in envvar_dict.iteritems():
-    block += key + '=' + value + nul
-  block += nul
-  return block
-
-
-class MSVCUWPToolchain(Toolchain):
-
-  def __init__(self):
-    self.compiler_settings = None
-
-  def _escape(self, string):
-    """Escape a string such that it can be embedded into a Ninja file without
-    further interpretation."""
-    assert '\n' not in string, 'Ninja syntax does not allow newlines'
-    # We only have one special metacharacter: '$'.
-    return string.replace('$', '$$')
-
-  def Define(self, d):
-    # cl.exe replaces literal # characters with = in preprocesor definitions for
-    # some reason. Octal-encode to work around that.
-    d = d.replace('#', '\\%03o' % ord('#'))
-    return '/D' + self.QuoteForRspFile(self._escape(d))
-
-  def EncodeRspFileList(self, args):
-    """Process a list of arguments using QuoteForRspFile."""
-    # Note that the first argument is assumed to be the command. Don't add
-    # quotes around it because then built-ins like 'echo', etc. won't work.
-    # Take care to normpath only the path in the case of 'call ../x.bat' because
-    # otherwise the whole thing is incorrectly interpreted as a path and not
-    # normalized correctly.
-    if not args:
-      return ''
-    if args[0].startswith('call '):
-      call, program = args[0].split(' ', 1)
-      program = call + ' ' + os.path.normpath(program)
-    else:
-      program = os.path.normpath(args[0])
-    return program + ' ' + ' '.join(
-        self.QuoteForRspFile(arg) for arg in args[1:])
-
-  def ExpandEnvVars(self, string, expansions):
-    """Expand $(Variable) per expansions dict. See MsvsSettings.GetVSMacroEnv
-    for the canonical way to retrieve a suitable dict."""
-    if '$' in string:
-      for old, new in expansions.iteritems():
-        assert '$(' not in new, new
-        string = string.replace(old, new)
-    return string
-
-  def ExpandRuleVariables(self, path, root, dirname, source, ext, name):
-    path = self.compiler_settings.ConvertVSMacros(path, config=self.config_name)
-    path = path.replace(generator_default_variables['RULE_INPUT_ROOT'], root)
-    path = path.replace(generator_default_variables['RULE_INPUT_DIRNAME'],
-                        dirname)
-    path = path.replace(generator_default_variables['RULE_INPUT_PATH'], source)
-    path = path.replace(generator_default_variables['RULE_INPUT_EXT'], ext)
-    path = path.replace(generator_default_variables['RULE_INPUT_NAME'], name)
-    return path
-
-  def GenerateEnvironmentFiles(self, toplevel_build_dir, generator_flags,
-                               open_out):
-    """It's not sufficient to have the absolute path to the compiler, linker,
-
-    etc. on Windows, as those tools rely on .dlls being in the PATH. Different
-    architectures require a different compiler binary, and different supporting
-    environment variables (INCLUDE, LIB, LIBPATH). So, we extract the
-    environment
-    here, wrap all invocations of compiler tools (cl, link, lib, rc, midl, etc.)
-    via win_tool.py which sets up the environment, and then we do not prefix the
-    compiler with an absolute path, instead preferring something like "cl.exe"
-    in
-    the rule which will then run whichever the environment setup has put in the
-    path.
-    """
-    arch = 'x64'
-
-    # Get the dos environment via set:
-    # Use cmd /c to execute under native windows command
-    args = 'set'
-
-    popen = subprocess.Popen(
-        args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
-    variables, _ = popen.communicate()
-    env = _ExtractImportantEnvironment(variables)
-    env_block = _FormatAsEnvironmentBlock(env)
-    f = open_out(os.path.join(toplevel_build_dir, 'environment.' + arch), 'wb')
-    f.write(env_block)
-    f.close()
-
-  def GetCompilerSettings(self):
-    return self.compiler_settings
-
-  def GetPrecompiledHeader(self, **kwargs):
-    return MSVCPrecompiledHeader(**kwargs)
-
-  def InitCompilerSettings(self, spec, **kwargs):
-    self.compiler_settings = MsvsSettings(spec, kwargs['generator_flags'])
-
-  def SetAdditionalGypVariables(self, default_variables, **kwargs):
-    """Calculate additional variables for use in the build (called by gyp)."""
-    default_variables.setdefault('OS', 'win')
-    default_variables['EXECUTABLE_SUFFIX'] = '.exe'
-    default_variables['STATIC_LIB_PREFIX'] = ''
-    default_variables['STATIC_LIB_SUFFIX'] = '.lib'
-    default_variables['SHARED_LIB_PREFIX'] = ''
-    default_variables['SHARED_LIB_SUFFIX'] = '.dll'
-    generator_flags = {}
-
-    # Copy additional generator configuration data from VS, which is shared
-    # by the Windows Ninja generator.
-    import gyp.generator.msvs as msvs_generator
-    generator_additional_non_configuration_keys = getattr(
-        msvs_generator, 'generator_additional_non_configuration_keys', [])
-    generator_additional_path_sections = getattr(
-        msvs_generator, 'generator_additional_path_sections', [])
-
-    # Set a variable so conditions can be based on msvs_version.
-    msvs_version = gyp.msvs_emulation.GetVSVersion(generator_flags)
-    default_variables['MSVS_VERSION'] = msvs_version.ShortName()
-
-    # To determine processor word size on Windows, in addition to checking
-    # PROCESSOR_ARCHITECTURE (which reflects the word size of the current
-    # process), it is also necessary to check PROCESSOR_ARCHITEW6432 (which
-    # contains the actual word size of the system when running thru WOW64).
-    if ('64' in os.environ.get('PROCESSOR_ARCHITECTURE', '') or
-        '64' in os.environ.get('PROCESSOR_ARCHITEW6432', '')):
-      default_variables['MSVS_OS_BITS'] = 64
-    else:
-      default_variables['MSVS_OS_BITS'] = 32
-    return
-
-  def VerifyMissingSources(self, sources, **kwargs):
-    """Emulate behavior of msvs_error_on_missing_sources present in the msvs
-
-    generator: Check that all regular source files, i.e. not created at run
-    time,
-    exist on disk. Missing files cause needless recompilation when building via
-    VS, and we want this check to match for people/bots that build using ninja,
-    so they're not surprised when the VS build fails.
-    """
-    build_dir = kwargs['build_dir']
-    generator_flags = kwargs['generator_flags']
-    gyp_path_to_ninja = kwargs['gyp_path_to_ninja']
-    if int(generator_flags.get('msvs_error_on_missing_sources', 0)):
-      no_specials = filter(lambda x: '$' not in x, sources)
-      relative = [
-          os.path.join(build_dir, gyp_path_to_ninja(s)) for s in no_specials
-      ]
-      missing = filter(lambda x: not os.path.exists(x), relative)
-      if missing:
-        # They'll look like out\Release\..\..\stuff\things.cc, so normalize the
-        # path for a slightly less crazy looking output.
-        cleaned_up = [os.path.normpath(x) for x in missing]
-        raise Exception('Missing input files:\n%s' % '\n'.join(cleaned_up))
-
-  def QuoteForRspFile(self, arg):
-    """Quote a command line argument so that it appears as one argument when
-    processed via cmd.exe and parsed by CommandLineToArgvW (as is typical for
-    Windows programs)."""
-    # See http://goo.gl/cuFbX and http://goo.gl/dhPnp including the comment
-    # threads. This is actually the quoting rules for CommandLineToArgvW, not
-    # for the shell, because the shell doesn't do anything in Windows. This
-    # works more or less because most programs (including the compiler, etc.)
-    # use that function to handle command line arguments.
-
-    # For a literal quote, CommandLineToArgvW requires 2n+1 backslashes
-    # preceding it, and results in n backslashes + the quote. So we substitute
-    # in 2* what we match, +1 more, plus the quote.
-    windows_quoter_regex = re.compile(r'(\\*)"')
-    arg = windows_quoter_regex.sub(lambda mo: 2 * mo.group(1) + '\\"', arg)
-
-    # %'s also need to be doubled otherwise they're interpreted as batch
-    # positional arguments. Also make sure to escape the % so that they're
-    # passed literally through escaping so they can be singled to just the
-    # original %. Otherwise, trying to pass the literal representation that
-    # looks like an environment variable to the shell (e.g. %PATH%) would fail.
-    arg = arg.replace('%', '%%')
-
-    # These commands are used in rsp files, so no escaping for the shell (via ^)
-    # is necessary.
-
-    # Finally, wrap the whole thing in quotes so that the above quote rule
-    # applies and whitespace isn't a word break.
-    return '"' + arg + '"'
-
-
-def ToolchainImpl():
-  return MSVCUWPToolchain()
diff --git a/src/starboard/shared/pthread/thread_context_internal.cc b/src/starboard/shared/pthread/thread_context_internal.cc
index 2bf4701..e17c5b5 100644
--- a/src/starboard/shared/pthread/thread_context_internal.cc
+++ b/src/starboard/shared/pthread/thread_context_internal.cc
@@ -34,8 +34,6 @@
 SbThreadContextPrivate::SbThreadContextPrivate(ucontext_t* ucontext) {
   mcontext_t& mcontext = ucontext->uc_mcontext;
 
-// TODO: Remove redundant #if checks when
-//       SB_MINIMUM_API_VERSION >= 12.
 #if SB_IS_ARCH_X64
   // 64-bit X86 (aka X64)
   ip_ = reinterpret_cast<void*>(mcontext.gregs[REG_RIP]);
diff --git a/src/starboard/shared/starboard/player/file_cache_reader.cc b/src/starboard/shared/starboard/player/file_cache_reader.cc
index b43f62a..e79fc25 100644
--- a/src/starboard/shared/starboard/player/file_cache_reader.cc
+++ b/src/starboard/shared/starboard/player/file_cache_reader.cc
@@ -25,15 +25,11 @@
 namespace player {
 
 FileCacheReader::FileCacheReader(const char* filename, int file_cache_size)
-    : file_(filename, kSbFileOpenOnly | kSbFileRead),
-      max_file_cache_size_(
-          std::min(file_cache_size, static_cast<int>(file_.GetSize()))) {
-  SB_CHECK(file_.IsValid());
-  file_cache_.resize(max_file_cache_size_);
-  file_cache_offset_ = max_file_cache_size_;
-}
+    : filename_(filename), default_file_cache_size_(file_cache_size) {}
 
 int FileCacheReader::Read(void* out_buffer, int bytes_to_read) {
+  EnsureFileOpened();
+
   int total_bytes_read = 0;
 
   while (bytes_to_read > 0 && file_cache_.size() != 0) {
@@ -48,6 +44,24 @@
   return total_bytes_read;
 }
 
+int64_t FileCacheReader::GetSize() {
+  EnsureFileOpened();
+  return file_->GetSize();
+}
+
+void FileCacheReader::EnsureFileOpened() {
+  if (file_) {
+    return;
+  }
+  file_.reset(new ScopedFile(filename_.c_str(), kSbFileOpenOnly | kSbFileRead));
+  SB_CHECK(file_->IsValid());
+
+  max_file_cache_size_ =
+      std::min(default_file_cache_size_, static_cast<int>(file_->GetSize()));
+  file_cache_.resize(max_file_cache_size_);
+  file_cache_offset_ = max_file_cache_size_;
+}
+
 int FileCacheReader::ReadFromCache(void* out_buffer, int bytes_to_read) {
   SB_CHECK(file_cache_offset_ <= file_cache_.size());
   bytes_to_read = std::min(
@@ -63,7 +77,7 @@
     return;
   }
   file_cache_offset_ = 0;
-  int bytes_read = file_.ReadAll(file_cache_.data(), file_cache_.size());
+  int bytes_read = file_->ReadAll(file_cache_.data(), file_cache_.size());
   SB_CHECK(bytes_read >= 0);
   if (bytes_read < static_cast<int>(file_cache_.size())) {
     file_cache_.resize(bytes_read);
diff --git a/src/starboard/shared/starboard/player/file_cache_reader.h b/src/starboard/shared/starboard/player/file_cache_reader.h
index 58768df..c9e2a08 100644
--- a/src/starboard/shared/starboard/player/file_cache_reader.h
+++ b/src/starboard/shared/starboard/player/file_cache_reader.h
@@ -15,8 +15,10 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_FILE_CACHE_READER_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_FILE_CACHE_READER_H_
 
+#include <string>
 #include <vector>
 
+#include "starboard/common/scoped_ptr.h"
 #include "starboard/file.h"
 
 namespace starboard {
@@ -29,10 +31,12 @@
   FileCacheReader(const char* filename, int file_cache_size);
 
   int Read(void* out_buffer, int bytes_to_read);
-
-  int64_t GetSize() const { return file_.GetSize(); }
+  int64_t GetSize();
 
  private:
+  // This function CHECK() if file is successfully opened.
+  void EnsureFileOpened();
+
   // Reads from the currently cached file contents, into the output buffer.
   // Returns the final number of bytes read out from the cache.
   int ReadFromCache(void* out_buffer, int bytes_to_read);
@@ -41,10 +45,13 @@
   // is emptied out.
   void RefillCacheIfEmpty();
 
-  ScopedFile file_;
+  const std::string filename_;
+  const int default_file_cache_size_;
+
+  scoped_ptr<ScopedFile> file_;
 
   // Maximum size of the buffered file.
-  const int max_file_cache_size_;
+  int max_file_cache_size_ = 0;
 
   // Position marker in the buffer that we have finished reading.
   int file_cache_offset_ = 0;
diff --git a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
index 9da268a..76366c6a 100644
--- a/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/adaptive_audio_decoder_test.cc
@@ -51,10 +51,12 @@
 
 const SbTimeMonotonic kWaitForNextEventTimeOut = 5 * kSbTimeSecond;
 
-scoped_refptr<InputBuffer> GetAudioInputBuffer(const VideoDmpReader& dmp_reader,
+scoped_refptr<InputBuffer> GetAudioInputBuffer(VideoDmpReader* dmp_reader,
                                                size_t index) {
+  SB_DCHECK(dmp_reader);
+
   auto player_sample_info =
-      dmp_reader.GetPlayerSampleInfo(kSbMediaTypeAudio, index);
+      dmp_reader->GetPlayerSampleInfo(kSbMediaTypeAudio, index);
 #if SB_API_VERSION >= 11
   return new InputBuffer(StubDeallocateSampleFunc, NULL, NULL,
                          player_sample_info);
@@ -87,7 +89,6 @@
   return GetTestInputDirectory() + kSbFileSepChar + filename;
 }
 
-// TODO: Avoid reading same dmp file repeatly.
 class AdaptiveAudioDecoderTest
     : public ::testing::TestWithParam<std::tuple<vector<const char*>, bool>> {
  protected:
@@ -98,7 +99,8 @@
         using_stub_decoder_(std::get<1>(GetParam())) {
     for (auto filename : test_filenames_) {
       dmp_readers_.emplace_back(
-          new VideoDmpReader(ResolveTestFileName(filename).c_str()));
+          new VideoDmpReader(ResolveTestFileName(filename).c_str(),
+                             VideoDmpReader::kEnableReadOnDemand));
     }
 
     auto accumulate_operation = [](string accumulated, const char* str) {
@@ -132,9 +134,11 @@
         std::bind(&AdaptiveAudioDecoderTest::OnError, this));
   }
 
-  void WriteSingleInput(const VideoDmpReader& dmp_reader, size_t buffer_index) {
+  void WriteSingleInput(VideoDmpReader* dmp_reader, size_t buffer_index) {
+    SB_DCHECK(dmp_reader);
+
     ASSERT_TRUE(can_accept_more_input_);
-    ASSERT_LT(buffer_index, dmp_reader.number_of_audio_buffers());
+    ASSERT_LT(buffer_index, dmp_reader->number_of_audio_buffers());
 
     can_accept_more_input_ = false;
     audio_decoder_->Decode(
@@ -142,11 +146,13 @@
         std::bind(&AdaptiveAudioDecoderTest::OnConsumed, this));
   }
 
-  void WriteMultipleInputs(const VideoDmpReader& dmp_reader,
+  void WriteMultipleInputs(VideoDmpReader* dmp_reader,
                            size_t buffer_start_index,
                            size_t number_of_inputs_to_write) {
+    SB_DCHECK(dmp_reader);
+
     ASSERT_LT(buffer_start_index + number_of_inputs_to_write,
-              dmp_reader.number_of_audio_buffers());
+              dmp_reader->number_of_audio_buffers());
 
     while (number_of_inputs_to_write > 0) {
       ASSERT_NO_FATAL_FAILURE(WaitAndProcessUntilAcceptInput());
@@ -300,13 +306,14 @@
   for (auto& dmp_reader : dmp_readers_) {
     SB_DCHECK(dmp_reader);
     ASSERT_NO_FATAL_FAILURE(
-        WriteMultipleInputs(*dmp_reader, buffer_index, kBuffersToWrite));
-    auto input_buffer = GetAudioInputBuffer(*dmp_reader, buffer_index);
+        WriteMultipleInputs(dmp_reader.get(), buffer_index, kBuffersToWrite));
+    auto input_buffer = GetAudioInputBuffer(dmp_reader.get(), buffer_index);
     SbTime input_timestamp = input_buffer->timestamp();
     buffer_index += kBuffersToWrite;
     // Use next buffer here, need to make sure dmp file has enough buffers.
     SB_DCHECK(dmp_reader->number_of_audio_buffers() > buffer_index);
-    auto next_input_buffer = GetAudioInputBuffer(*dmp_reader, buffer_index);
+    auto next_input_buffer =
+        GetAudioInputBuffer(dmp_reader.get(), buffer_index);
     SbTime next_timestamp = next_input_buffer->timestamp();
     playing_duration += next_timestamp - input_timestamp;
   }
@@ -333,13 +340,14 @@
   for (auto& dmp_reader : dmp_readers_) {
     SB_DCHECK(dmp_reader);
     ASSERT_NO_FATAL_FAILURE(
-        WriteMultipleInputs(*dmp_reader, buffer_index, kBuffersToWrite));
-    auto input_buffer = GetAudioInputBuffer(*dmp_reader, buffer_index);
+        WriteMultipleInputs(dmp_reader.get(), buffer_index, kBuffersToWrite));
+    auto input_buffer = GetAudioInputBuffer(dmp_reader.get(), buffer_index);
     SbTime input_timestamp = input_buffer->timestamp();
     buffer_index += kBuffersToWrite;
     // Use next buffer here, need to make sure dmp file has enough buffers.
     SB_DCHECK(dmp_reader->number_of_audio_buffers() > buffer_index);
-    auto next_input_buffer = GetAudioInputBuffer(*dmp_reader, buffer_index);
+    auto next_input_buffer =
+        GetAudioInputBuffer(dmp_reader.get(), buffer_index);
     SbTime next_timestamp = next_input_buffer->timestamp();
     playing_duration += next_timestamp - input_timestamp;
   }
diff --git a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
index b2e1392..c1494b8 100644
--- a/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/audio_decoder_test.cc
@@ -56,7 +56,8 @@
   AudioDecoderTest()
       : test_filename_(std::get<0>(GetParam())),
         using_stub_decoder_(std::get<1>(GetParam())),
-        dmp_reader_(ResolveTestFileName(test_filename_).c_str()) {
+        dmp_reader_(ResolveTestFileName(test_filename_).c_str(),
+                    VideoDmpReader::kEnableReadOnDemand) {
     SB_LOG(INFO) << "Testing " << test_filename_
                  << (using_stub_decoder_ ? " with stub audio decoder." : ".");
   }
@@ -296,7 +297,7 @@
     }
   }
 
-  scoped_refptr<InputBuffer> GetAudioInputBuffer(size_t index) const {
+  scoped_refptr<InputBuffer> GetAudioInputBuffer(size_t index) {
     auto player_sample_info =
         dmp_reader_.GetPlayerSampleInfo(kSbMediaTypeAudio, index);
 #if SB_API_VERSION >= 11
diff --git a/src/starboard/shared/starboard/player/filter/testing/test_util.cc b/src/starboard/shared/starboard/player/filter/testing/test_util.cc
index 1207ea7..830d175 100644
--- a/src/starboard/shared/starboard/player/filter/testing/test_util.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/test_util.cc
@@ -101,7 +101,8 @@
   }
 
   for (auto filename : kFilenames) {
-    VideoDmpReader dmp_reader(ResolveTestFileName(filename).c_str());
+    VideoDmpReader dmp_reader(ResolveTestFileName(filename).c_str(),
+                              VideoDmpReader::kEnableReadOnDemand);
     SB_DCHECK(dmp_reader.number_of_audio_buffers() > 0);
     if (SbMediaIsAudioSupported(dmp_reader.audio_codec(),
 #if SB_API_VERSION >= 12
@@ -140,7 +141,8 @@
   }
 
   for (auto filename : kFilenames) {
-    VideoDmpReader dmp_reader(ResolveTestFileName(filename).c_str());
+    VideoDmpReader dmp_reader(ResolveTestFileName(filename).c_str(),
+                              VideoDmpReader::kEnableReadOnDemand);
     SB_DCHECK(dmp_reader.number_of_video_buffers() > 0);
 
     for (auto output_mode : kOutputModes) {
diff --git a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.cc b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.cc
index f680f11..46dd43c 100644
--- a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.cc
+++ b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.cc
@@ -67,7 +67,8 @@
       test_filename_(test_filename),
       output_mode_(output_mode),
       using_stub_decoder_(using_stub_decoder),
-      dmp_reader_(ResolveTestFileName(test_filename).c_str()) {
+      dmp_reader_(ResolveTestFileName(test_filename).c_str(),
+                  VideoDmpReader::kEnableReadOnDemand) {
   SB_DCHECK(job_queue_);
   SB_DCHECK(fake_graphics_context_provider_);
   SB_LOG(INFO) << "Testing " << test_filename_ << ", output mode "
@@ -358,7 +359,7 @@
 }
 
 scoped_refptr<InputBuffer> VideoDecoderTestFixture::GetVideoInputBuffer(
-    size_t index) const {
+    size_t index) {
   auto video_sample_info =
       dmp_reader_.GetPlayerSampleInfo(kSbMediaTypeVideo, index);
 #if SB_API_VERSION >= 11
diff --git a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h
index 1ffaab3..1450b58 100644
--- a/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h
+++ b/src/starboard/shared/starboard/player/filter/testing/video_decoder_test_fixture.h
@@ -125,7 +125,7 @@
 
   void ResetDecoderAndClearPendingEvents();
 
-  scoped_refptr<InputBuffer> GetVideoInputBuffer(size_t index) const;
+  scoped_refptr<InputBuffer> GetVideoInputBuffer(size_t index);
 
   void UseInvalidDataForInput(size_t index, uint8_t byte_to_fill) {
     invalid_inputs_[index] = byte_to_fill;
diff --git a/src/starboard/shared/starboard/player/video_dmp_common.h b/src/starboard/shared/starboard/player/video_dmp_common.h
index 1353c6b..d7ebd4e 100644
--- a/src/starboard/shared/starboard/player/video_dmp_common.h
+++ b/src/starboard/shared/starboard/player/video_dmp_common.h
@@ -78,7 +78,11 @@
         stored_audio_specific_config(that.stored_audio_specific_config) {
     audio_specific_config = stored_audio_specific_config.data();
   }
-  void operator=(const SbMediaAudioSampleInfoWithConfig& that) = delete;
+  void operator=(const SbMediaAudioSampleInfoWithConfig& that) {
+    SbMemoryCopy(this, &that, sizeof(SbMediaAudioSampleInfo));
+    stored_audio_specific_config = that.stored_audio_specific_config;
+    audio_specific_config = stored_audio_specific_config.data();
+  }
 
   std::vector<uint8_t> stored_audio_specific_config;
 };
@@ -109,14 +113,21 @@
     }
 #endif  // SB_API_VERSION < 11
   }
-  void operator=(const SbMediaVideoSampleInfoWithOptionalColorMetadata& that) =
-      delete;
+  void operator=(const SbMediaVideoSampleInfoWithOptionalColorMetadata& that) {
+    SbMemoryCopy(this, &that, sizeof(SbMediaVideoSampleInfo));
+#if SB_API_VERSION < 11
+    stored_color_metadata = that.stored_color_metadata;
+    if (color_metadata) {
+      color_metadata = &stored_color_metadata;
+    }
+#endif  // SB_API_VERSION < 11
+  }
 
   SbMediaColorMetadata stored_color_metadata;
 };
 
 const uint32_t kByteOrderMark = 0x76543210;
-const uint32_t kSupportWriterVersion = 0x00001000;
+const uint32_t kSupportedWriterVersion = 0x00001000;
 
 void Read(const ReadCB& read_cb, void* buffer, size_t size);
 
diff --git a/src/starboard/shared/starboard/player/video_dmp_reader.cc b/src/starboard/shared/starboard/player/video_dmp_reader.cc
index 8a9a96a..cf5b54e 100644
--- a/src/starboard/shared/starboard/player/video_dmp_reader.cc
+++ b/src/starboard/shared/starboard/player/video_dmp_reader.cc
@@ -17,8 +17,6 @@
 #include <algorithm>
 #include <functional>
 
-#include "starboard/shared/starboard/player/file_cache_reader.h"
-
 namespace starboard {
 namespace shared {
 namespace starboard {
@@ -93,19 +91,59 @@
 using std::placeholders::_1;
 using std::placeholders::_2;
 
-VideoDmpReader::VideoDmpReader(const char* filename)
-    : reverse_byte_order_(false) {
-  FileCacheReader reader(filename, 1024 * 1024);
-  int64_t file_size = reader.GetSize();
-  SB_CHECK(file_size >= 0);
-  read_cb_ = std::bind(&FileCacheReader::Read, &reader, _1, _2);
+bool VideoDmpReader::Registry::GetDmpInfo(const char* filename,
+                                          DmpInfo* dmp_info) const {
+  SB_DCHECK(filename);
+  SB_DCHECK(dmp_info);
+
+  ScopedLock scoped_lock(mutex_);
+  auto iter = dmp_infos_.find(filename);
+  if (iter == dmp_infos_.end()) {
+    return false;
+  }
+  *dmp_info = iter->second;
+  return true;
+}
+
+void VideoDmpReader::Registry::Register(const char* filename,
+                                        const DmpInfo& dmp_info) {
+  SB_DCHECK(filename);
+
+  ScopedLock scoped_lock(mutex_);
+  SB_DCHECK(dmp_infos_.find(filename) == dmp_infos_.end());
+  dmp_infos_[filename] = dmp_info;
+}
+
+VideoDmpReader::VideoDmpReader(
+    const char* filename,
+    ReadOnDemandOptions read_on_demand_options /*= kDisableReadOnDemand*/)
+    : file_reader_(filename, 1024 * 1024),
+      read_cb_(std::bind(&FileCacheReader::Read, &file_reader_, _1, _2)),
+      allow_read_on_demand_(read_on_demand_options == kEnableReadOnDemand) {
+  bool already_cached = GetRegistry()->GetDmpInfo(filename, &dmp_info_);
+
+  if (already_cached && allow_read_on_demand_) {
+    // This is necessary as the current implementation assumes that the address
+    // of any access units are never changed during the life time of the object,
+    // and keep using it without explicit reference.
+    audio_access_units_.reserve(dmp_info_.audio_access_units_size);
+    video_access_units_.reserve(dmp_info_.video_access_units_size);
+    return;
+  }
+
   Parse();
+
+  if (!already_cached) {
+    GetRegistry()->Register(filename, dmp_info_);
+  }
 }
 
 VideoDmpReader::~VideoDmpReader() {}
 
 SbPlayerSampleInfo VideoDmpReader::GetPlayerSampleInfo(SbMediaType type,
-                                                       size_t index) const {
+                                                       size_t index) {
+  EnsureSampleLoaded(type, index);
+
   switch (type) {
     case kSbMediaTypeAudio: {
       SB_DCHECK(index < audio_access_units_.size());
@@ -122,71 +160,91 @@
   return SbPlayerSampleInfo();
 }
 
-const SbMediaAudioSampleInfo& VideoDmpReader::GetAudioSampleInfo(
-    size_t index) const {
+const SbMediaAudioSampleInfo& VideoDmpReader::GetAudioSampleInfo(size_t index) {
+  EnsureSampleLoaded(kSbMediaTypeAudio, index);
+
   SB_DCHECK(index < audio_access_units_.size());
   const AudioAccessUnit& au = audio_access_units_[index];
   return au.audio_sample_info();
 }
 
-void VideoDmpReader::Parse() {
+void VideoDmpReader::ParseHeader(uint32_t* dmp_writer_version) {
+  SB_DCHECK(dmp_writer_version);
+  SB_DCHECK(!reverse_byte_order_.has_engaged());
+
+  int64_t file_size = file_reader_.GetSize();
+  SB_CHECK(file_size >= 0);
+
   reverse_byte_order_ = false;
   uint32_t byte_order_mark;
-  Read(read_cb_, reverse_byte_order_, &byte_order_mark);
+  Read(read_cb_, reverse_byte_order_.value(), &byte_order_mark);
   if (byte_order_mark != kByteOrderMark) {
     std::reverse(reinterpret_cast<uint8_t*>(&byte_order_mark),
                  reinterpret_cast<uint8_t*>(&byte_order_mark + 1));
-    SB_DCHECK(byte_order_mark == kByteOrderMark);
-    if (byte_order_mark != kByteOrderMark) {
-      SB_LOG(ERROR) << "Invalid BOM" << byte_order_mark;
-      return;
-    }
+    SB_CHECK(byte_order_mark == kByteOrderMark);
     reverse_byte_order_ = true;
   }
-  uint32_t dmp_writer_version;
-  Read(read_cb_, reverse_byte_order_, &dmp_writer_version);
-  if (dmp_writer_version != kSupportWriterVersion) {
+
+  Read(read_cb_, reverse_byte_order_.value(), dmp_writer_version);
+}
+
+bool VideoDmpReader::ParseOneRecord() {
+  uint32_t type;
+  int bytes_read = read_cb_(&type, sizeof(type));
+  if (bytes_read != sizeof(type)) {
+    // Read an invalid number of bytes (corrupt file), or we read zero bytes
+    // (end of file).  Return false to signal the end of reading.
+    return false;
+  }
+  if (reverse_byte_order_.value()) {
+    std::reverse(reinterpret_cast<uint8_t*>(&type),
+                 reinterpret_cast<uint8_t*>(&type + 1));
+  }
+  switch (type) {
+    case kRecordTypeAudioConfig:
+      Read(read_cb_, reverse_byte_order_.value(), &dmp_info_.audio_codec);
+      if (dmp_info_.audio_codec != kSbMediaAudioCodecNone) {
+        Read(read_cb_, reverse_byte_order_.value(),
+             &dmp_info_.audio_sample_info);
+      }
+      break;
+    case kRecordTypeVideoConfig:
+      Read(read_cb_, reverse_byte_order_.value(), &dmp_info_.video_codec);
+      break;
+    case kRecordTypeAudioAccessUnit:
+      audio_access_units_.push_back(ReadAudioAccessUnit());
+      break;
+    case kRecordTypeVideoAccessUnit:
+      video_access_units_.push_back(ReadVideoAccessUnit());
+      break;
+    default:
+      SB_NOTREACHED() << type;
+      return false;
+  }
+
+  return true;
+}
+
+void VideoDmpReader::Parse() {
+  SB_DCHECK(!reverse_byte_order_.has_engaged());
+
+  uint32_t dmp_writer_version = 0;
+  ParseHeader(&dmp_writer_version);
+  if (dmp_writer_version != kSupportedWriterVersion) {
     SB_LOG(ERROR) << "Unsupported input dmp file(" << dmp_writer_version
                   << "). Please regenerate dmp files with"
                   << " right dmp writer. Currently support version "
-                  << kSupportWriterVersion << ".";
+                  << kSupportedWriterVersion << ".";
     return;
   }
-  for (;;) {
-    uint32_t type;
-    int bytes_read = read_cb_(&type, sizeof(type));
-    if (bytes_read != sizeof(type)) {
-      // Read an invalid number of bytes (corrupt file), or we read zero bytes
-      // (end of file).
-      break;
-    }
-    if (reverse_byte_order_) {
-      std::reverse(reinterpret_cast<uint8_t*>(&type),
-                   reinterpret_cast<uint8_t*>(&type + 1));
-    }
-    switch (type) {
-      case kRecordTypeAudioConfig:
-        Read(read_cb_, reverse_byte_order_, &audio_codec_);
-        if (audio_codec_ != kSbMediaAudioCodecNone) {
-          Read(read_cb_, reverse_byte_order_, &audio_sample_info_);
-        }
-        break;
-      case kRecordTypeVideoConfig:
-        Read(read_cb_, reverse_byte_order_, &video_codec_);
-        break;
-      case kRecordTypeAudioAccessUnit:
-        audio_access_units_.push_back(ReadAudioAccessUnit());
-        break;
-      case kRecordTypeVideoAccessUnit:
-        video_access_units_.push_back(ReadVideoAccessUnit());
-        break;
-      default:
-        SB_NOTREACHED() << type;
-        break;
-    }
+
+  while (ParseOneRecord()) {
   }
-  audio_bitrate_ = CalculateAverageBitrate(audio_access_units_);
-  video_bitrate_ = CalculateAverageBitrate(video_access_units_);
+
+  dmp_info_.audio_access_units_size = audio_access_units_.size();
+  dmp_info_.audio_bitrate = CalculateAverageBitrate(audio_access_units_);
+  dmp_info_.video_access_units_size = video_access_units_.size();
+  dmp_info_.video_bitrate = CalculateAverageBitrate(video_access_units_);
 
   // Guestimate the video fps.
   if (video_access_units_.size() > 1) {
@@ -199,29 +257,48 @@
       }
     }
     SB_DCHECK(first_timestamp < second_timestamp);
-    video_fps_ = kSbTimeSecond / (second_timestamp - first_timestamp);
+    dmp_info_.video_fps = kSbTimeSecond / (second_timestamp - first_timestamp);
+  }
+}
+
+void VideoDmpReader::EnsureSampleLoaded(SbMediaType type, size_t index) {
+  if (!reverse_byte_order_.has_engaged()) {
+    uint32_t dmp_writer_version = 0;
+    ParseHeader(&dmp_writer_version);
+    SB_DCHECK(dmp_writer_version == kSupportedWriterVersion);
+  }
+
+  if (type == kSbMediaTypeAudio) {
+    while (index >= audio_access_units_.size() && ParseOneRecord()) {
+    }
+    SB_CHECK(index < audio_access_units_.size());
+  } else {
+    SB_DCHECK(type == kSbMediaTypeVideo);
+    while (index >= video_access_units_.size() && ParseOneRecord()) {
+    }
+    SB_CHECK(index < video_access_units_.size());
   }
 }
 
 VideoDmpReader::AudioAccessUnit VideoDmpReader::ReadAudioAccessUnit() {
   SbTime timestamp;
-  Read(read_cb_, reverse_byte_order_, &timestamp);
+  Read(read_cb_, reverse_byte_order_.value(), &timestamp);
 
   bool drm_sample_info_present;
-  Read(read_cb_, reverse_byte_order_, &drm_sample_info_present);
+  Read(read_cb_, reverse_byte_order_.value(), &drm_sample_info_present);
 
   SbDrmSampleInfoWithSubSampleMapping drm_sample_info;
   if (drm_sample_info_present) {
-    Read(read_cb_, reverse_byte_order_, &drm_sample_info);
+    Read(read_cb_, reverse_byte_order_.value(), &drm_sample_info);
   }
 
   uint32_t size;
-  Read(read_cb_, reverse_byte_order_, &size);
+  Read(read_cb_, reverse_byte_order_.value(), &size);
   std::vector<uint8_t> data(size);
   Read(read_cb_, data.data(), size);
 
   SbMediaAudioSampleInfoWithConfig audio_sample_info;
-  Read(read_cb_, reverse_byte_order_, &audio_sample_info);
+  Read(read_cb_, reverse_byte_order_.value(), &audio_sample_info);
 
   return AudioAccessUnit(timestamp,
                          drm_sample_info_present ? &drm_sample_info : NULL,
@@ -230,29 +307,35 @@
 
 VideoDmpReader::VideoAccessUnit VideoDmpReader::ReadVideoAccessUnit() {
   SbTime timestamp;
-  Read(read_cb_, reverse_byte_order_, &timestamp);
+  Read(read_cb_, reverse_byte_order_.value(), &timestamp);
 
   bool drm_sample_info_present;
-  Read(read_cb_, reverse_byte_order_, &drm_sample_info_present);
+  Read(read_cb_, reverse_byte_order_.value(), &drm_sample_info_present);
 
   SbDrmSampleInfoWithSubSampleMapping drm_sample_info;
   if (drm_sample_info_present) {
-    Read(read_cb_, reverse_byte_order_, &drm_sample_info);
+    Read(read_cb_, reverse_byte_order_.value(), &drm_sample_info);
   }
 
   uint32_t size;
-  Read(read_cb_, reverse_byte_order_, &size);
+  Read(read_cb_, reverse_byte_order_.value(), &size);
   std::vector<uint8_t> data(size);
   Read(read_cb_, data.data(), size);
 
   SbMediaVideoSampleInfoWithOptionalColorMetadata video_sample_info;
-  Read(read_cb_, reverse_byte_order_, &video_sample_info);
+  Read(read_cb_, reverse_byte_order_.value(), &video_sample_info);
 
   return VideoAccessUnit(timestamp,
                          drm_sample_info_present ? &drm_sample_info : NULL,
                          std::move(data), video_sample_info);
 }
 
+// static
+VideoDmpReader::Registry* VideoDmpReader::GetRegistry() {
+  static Registry s_registry;
+  return &s_registry;
+}
+
 }  // namespace video_dmp
 }  // namespace player
 }  // namespace starboard
diff --git a/src/starboard/shared/starboard/player/video_dmp_reader.h b/src/starboard/shared/starboard/player/video_dmp_reader.h
index 7333b8f..218384d 100644
--- a/src/starboard/shared/starboard/player/video_dmp_reader.h
+++ b/src/starboard/shared/starboard/player/video_dmp_reader.h
@@ -15,14 +15,18 @@
 #ifndef STARBOARD_SHARED_STARBOARD_PLAYER_VIDEO_DMP_READER_H_
 #define STARBOARD_SHARED_STARBOARD_PLAYER_VIDEO_DMP_READER_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
 #include "starboard/common/log.h"
+#include "starboard/common/mutex.h"
+#include "starboard/common/optional.h"
 #include "starboard/common/ref_counted.h"
 #include "starboard/media.h"
 #include "starboard/player.h"
 #include "starboard/shared/internal_only.h"
+#include "starboard/shared/starboard/player/file_cache_reader.h"
 #include "starboard/shared/starboard/player/video_dmp_common.h"
 
 namespace starboard {
@@ -33,6 +37,11 @@
 
 class VideoDmpReader {
  public:
+  enum ReadOnDemandOptions {
+    kDisableReadOnDemand,
+    kEnableReadOnDemand,
+  };
+
   class AccessUnit {
    public:
     AccessUnit(SbTime timestamp,
@@ -90,45 +99,73 @@
     SbMediaVideoSampleInfoWithOptionalColorMetadata video_sample_info_;
   };
 
-  explicit VideoDmpReader(const char* filename);
+  explicit VideoDmpReader(
+      const char* filename,
+      ReadOnDemandOptions read_on_demand_options = kDisableReadOnDemand);
   ~VideoDmpReader();
 
-  SbMediaAudioCodec audio_codec() const { return audio_codec_; }
+  SbMediaAudioCodec audio_codec() const { return dmp_info_.audio_codec; }
   const SbMediaAudioSampleInfo& audio_sample_info() const {
-    return audio_sample_info_;
+    return dmp_info_.audio_sample_info;
   }
-  int64_t audio_bitrate() const { return audio_bitrate_; }
+  int64_t audio_bitrate() const { return dmp_info_.audio_bitrate; }
 
-  SbMediaVideoCodec video_codec() const { return video_codec_; }
-  int64_t video_bitrate() const { return video_bitrate_; }
-  int video_fps() const { return video_fps_; }
+  SbMediaVideoCodec video_codec() const { return dmp_info_.video_codec; }
+  int64_t video_bitrate() const { return dmp_info_.video_bitrate; }
+  int video_fps() const { return dmp_info_.video_fps; }
 
-  size_t number_of_audio_buffers() const { return audio_access_units_.size(); }
+  size_t number_of_audio_buffers() const {
+    return dmp_info_.audio_access_units_size;
+  }
+  size_t number_of_video_buffers() const {
+    return dmp_info_.video_access_units_size;
+  }
 
-  size_t number_of_video_buffers() const { return video_access_units_.size(); }
-
-  SbPlayerSampleInfo GetPlayerSampleInfo(SbMediaType type, size_t index) const;
-  const SbMediaAudioSampleInfo& GetAudioSampleInfo(size_t index) const;
+  SbPlayerSampleInfo GetPlayerSampleInfo(SbMediaType type, size_t index);
+  const SbMediaAudioSampleInfo& GetAudioSampleInfo(size_t index);
 
  private:
+  struct DmpInfo {
+    SbMediaAudioCodec audio_codec = kSbMediaAudioCodecNone;
+    SbMediaAudioSampleInfoWithConfig audio_sample_info;
+    size_t audio_access_units_size = 0;
+    int64_t audio_bitrate = 0;
+
+    SbMediaVideoCodec video_codec = kSbMediaVideoCodecNone;
+    size_t video_access_units_size = 0;
+    int64_t video_bitrate = 0;
+    int video_fps = 0;
+  };
+
+  class Registry {
+   public:
+    bool GetDmpInfo(const char* filename, DmpInfo* dmp_info) const;
+    void Register(const char* filename, const DmpInfo& dmp_info);
+
+   private:
+    Mutex mutex_;
+    std::map<std::string, DmpInfo> dmp_infos_;
+  };
+
   VideoDmpReader(const VideoDmpReader&) = delete;
   VideoDmpReader& operator=(const VideoDmpReader&) = delete;
 
+  void ParseHeader(uint32_t* dmp_writer_version);
+  bool ParseOneRecord();
   void Parse();
+  void EnsureSampleLoaded(SbMediaType type, size_t index);
+
   AudioAccessUnit ReadAudioAccessUnit();
   VideoAccessUnit ReadVideoAccessUnit();
+  static Registry* GetRegistry();
 
+  const bool allow_read_on_demand_;
+
+  FileCacheReader file_reader_;
   ReadCB read_cb_;
+  DmpInfo dmp_info_;
 
-  bool reverse_byte_order_;
-
-  SbMediaAudioCodec audio_codec_ = kSbMediaAudioCodecNone;
-  SbMediaAudioSampleInfoWithConfig audio_sample_info_;
-  int64_t audio_bitrate_ = 0;
-
-  SbMediaVideoCodec video_codec_ = kSbMediaVideoCodecNone;
-  int64_t video_bitrate_ = 0;
-  int video_fps_ = 0;
+  optional<bool> reverse_byte_order_;
 
   std::vector<AudioAccessUnit> audio_access_units_;
   std::vector<VideoAccessUnit> video_access_units_;
diff --git a/src/starboard/shared/starboard/player/video_dmp_writer.cc b/src/starboard/shared/starboard/player/video_dmp_writer.cc
index 9e2a884..78ed1b5 100644
--- a/src/starboard/shared/starboard/player/video_dmp_writer.cc
+++ b/src/starboard/shared/starboard/player/video_dmp_writer.cc
@@ -88,7 +88,7 @@
   write_cb_ = std::bind(&VideoDmpWriter::WriteToFile, this, _1, _2);
 
   Write(write_cb_, kByteOrderMark);
-  Write(write_cb_, kSupportWriterVersion);
+  Write(write_cb_, kSupportedWriterVersion);
 }
 
 VideoDmpWriter::~VideoDmpWriter() {
diff --git a/src/third_party/libpng/pngusr.h b/src/third_party/libpng/pngusr.h
index a582b88..50d3fd9 100644
--- a/src/third_party/libpng/pngusr.h
+++ b/src/third_party/libpng/pngusr.h
@@ -51,9 +51,7 @@
 #endif
 #undef PNG_NO_READ_FILLER
 #define PNG_NO_READ_SWAP
-#if !defined(__LB_PS3__)
 #define PNG_NO_READ_SWAP_ALPHA
-#endif
 #define PNG_NO_READ_INVERT_ALPHA
 #define PNG_NO_READ_RGB_TO_GRAY
 #define PNG_NO_READ_bKGD
diff --git a/src/third_party/libvpx/build/make/configure.sh b/src/third_party/libvpx/build/make/configure.sh
old mode 100644
new mode 100755
index c738504..a8140e5
--- a/src/third_party/libvpx/build/make/configure.sh
+++ b/src/third_party/libvpx/build/make/configure.sh
@@ -263,8 +263,6 @@
 source_path=${0%/*}
 enable_feature source_path_used
 if [ -z "$source_path" ] || [ "$source_path" = "." ]; then
-  # rjogrady: Hack for Cygwin / PS4 interaction.
-  # PS4 compiler doesn't understand cygdrive.
   #source_path="`pwd`"
   source_path='.'
   disable_feature source_path_used
diff --git a/src/third_party/libvpx/vpx_mem/vpx_mem.c b/src/third_party/libvpx/vpx_mem/vpx_mem.c
index 8161061..b261fc0 100644
--- a/src/third_party/libvpx/vpx_mem/vpx_mem.c
+++ b/src/third_party/libvpx/vpx_mem/vpx_mem.c
@@ -16,13 +16,6 @@
 #include "include/vpx_mem_intrnl.h"
 #include "vpx/vpx_integer.h"
 
-#if defined(__ORBIS__)
-// TODO(rjogrady): Only for test apps.
-// Allow system malloc() to grab up to 512MB.
-//size_t sceLibcHeapSize = SCE_LIBC_HEAP_SIZE_EXTENDED_ALLOC_NO_LIMIT;
-//unsigned int sceLibcHeapExtendedAlloc = 1;
-#endif
-
 void *vpx_memalign(size_t align, size_t size) {
   void *addr,
        * x = NULL;
diff --git a/src/third_party/modp_b64/modp_b64.gyp b/src/third_party/modp_b64/modp_b64.gyp
index c5485f5..baed111 100644
--- a/src/third_party/modp_b64/modp_b64.gyp
+++ b/src/third_party/modp_b64/modp_b64.gyp
@@ -16,13 +16,6 @@
       'include_dirs': [
         '../..',
       ],
-      'conditions': [
-        ['OS!="starboard" and (target_arch=="ps3" or target_arch=="wiiu" or target_arch=="xb360")', {
-          'defines': [
-            'WORDS_BIGENDIAN'
-          ]
-        }]
-      ]
     },
   ],
 }
diff --git a/src/third_party/musl/musl.gyp b/src/third_party/musl/musl.gyp
index 9a2a24e..2647e2b 100644
--- a/src/third_party/musl/musl.gyp
+++ b/src/third_party/musl/musl.gyp
@@ -40,7 +40,6 @@
        }
     }],
     # Not yet supported:
-    # target_arch == ps3
     # target_arch == win
   ],
   'targets': [
diff --git a/src/third_party/zlib/zlib.gyp b/src/third_party/zlib/zlib.gyp
index ca7b411..a122c83 100644
--- a/src/third_party/zlib/zlib.gyp
+++ b/src/third_party/zlib/zlib.gyp
@@ -463,7 +463,7 @@
             ],
           },
         }],
-        ['OS in ["mac", "ios", "android"] or os_bsd==1 or target_arch in ["ps3", "wiiu"]', {
+        ['OS in ["mac", "ios", "android"] or os_bsd==1', {
           # Mac, Android and the BSDs don't have fopen64, ftello64, or
           # fseeko64. We use fopen, ftell, and fseek instead on these
           # systems.