Import Cobalt 10.58719
diff --git a/src/cobalt/audio/audio_node.cc b/src/cobalt/audio/audio_node.cc
index 1f561ee..387ef83 100644
--- a/src/cobalt/audio/audio_node.cc
+++ b/src/cobalt/audio/audio_node.cc
@@ -34,6 +34,10 @@
   RemoveAllOutputs();
 }
 
+scoped_refptr<AudioContext> AudioNode::context() const {
+  return audio_context_;
+}
+
 void AudioNode::set_channel_count(uint32 channel_count,
                                   script::ExceptionState* exception_state) {
   AudioLock::AutoLock lock(audio_lock());
diff --git a/src/cobalt/audio/audio_node.h b/src/cobalt/audio/audio_node.h
index b956d30..5e5f8e3 100644
--- a/src/cobalt/audio/audio_node.h
+++ b/src/cobalt/audio/audio_node.h
@@ -62,7 +62,7 @@
   // Web API: AudioNode
   //
   // The AudioContext which owns this AudioNode.
-  AudioContext* context() const { return audio_context_; }
+  scoped_refptr<AudioContext> context() const;
 
   // The number of inputs feeding into the AudioNode. For source nodes, this
   // will be 0.
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 765245a..5c3231b 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -34,6 +34,8 @@
 #include "cobalt/base/localized_strings.h"
 #include "cobalt/base/user_log.h"
 #include "cobalt/browser/memory_settings/auto_mem.h"
+#include "cobalt/browser/memory_settings/checker.h"
+#include "cobalt/browser/memory_settings/pretty_print.h"
 #include "cobalt/browser/memory_tracker/tool.h"
 #include "cobalt/browser/switches.h"
 #include "cobalt/loader/image/image_decoder.h"
@@ -328,7 +330,8 @@
 void ApplyAutoMemSettings(const memory_settings::AutoMem& auto_mem,
                           BrowserModule::Options* options) {
   std::stringstream ss;
-  ss << "\n\n" << auto_mem.ToPrettyPrintString() << "\n\n";
+  const bool enable_color = SbLogIsTty();
+  ss << "\n\n" << auto_mem.ToPrettyPrintString(enable_color) << "\n\n";
   SB_LOG(INFO) << ss.str();
 
   options->web_module_options.image_cache_capacity =
@@ -419,9 +422,13 @@
     options.web_module_options.javascript_options.disable_jit = true;
   }
 
-  memory_settings::AutoMem auto_mem(window_size, *command_line,
-                                    memory_settings::GetDefaultBuildSettings());
-  ApplyAutoMemSettings(auto_mem, &options);
+  auto_mem_.reset(
+      new memory_settings::AutoMem(
+          window_size,
+          *command_line,
+          memory_settings::GetDefaultBuildSettings()));
+
+  ApplyAutoMemSettings(*auto_mem_, &options);
 
 #if defined(ENABLE_DEBUG_COMMAND_LINE_SWITCHES)
   if (command_line->HasSwitch(browser::switches::kNullSavegame)) {
@@ -807,45 +814,25 @@
 
 void Application::UpdatePeriodicStats() {
   TRACE_EVENT0("cobalt::browser", "Application::UpdatePeriodicStats()");
-#if defined(__LB_SHELL__)
-  bool memory_stats_updated = false;
-#if !defined(__LB_SHELL__FOR_RELEASE__)
-  if (LB::Memory::IsCountEnabled()) {
-    memory_stats_updated = true;
-
-    LB::Memory::Info memory_info;
-    lb_memory_get_info(&memory_info);
-
-    available_memory_ = memory_info.free_memory;
-    c_val_stats_.free_cpu_memory =
-        static_cast<size_t>(memory_info.free_memory);
-    c_val_stats_.used_cpu_memory =
-        static_cast<size_t>(memory_info.application_memory);
-    c_val_stats_.exe_memory = static_cast<size_t>(memory_info.executable_size);
-  }
-#endif  // defined(__LB_SHELL__FOR_RELEASE__)
-  // If the memory stats have not been updated yet, then simply use the
-  // unallocated memory as the available memory.
-  if (!memory_stats_updated) {
-    available_memory_ = lb_get_unallocated_memory();
-    c_val_stats_.free_cpu_memory = static_cast<size_t>(available_memory_);
-    c_val_stats_.used_cpu_memory =
-        lb_get_total_system_memory() - lb_get_unallocated_memory();
-  }
-#elif defined(OS_STARBOARD)
   int64_t used_cpu_memory = SbSystemGetUsedCPUMemory();
+  base::optional<int64_t> used_gpu_memory;
+  if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) {
+    used_gpu_memory = SbSystemGetUsedGPUMemory();
+  }
+
   available_memory_ =
       static_cast<ssize_t>(SbSystemGetTotalCPUMemory() - used_cpu_memory);
   c_val_stats_.free_cpu_memory = available_memory_;
   c_val_stats_.used_cpu_memory = used_cpu_memory;
 
-  if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) {
-    int64_t used_gpu_memory = SbSystemGetUsedGPUMemory();
+  if (used_gpu_memory) {
     *c_val_stats_.free_gpu_memory =
-        SbSystemGetTotalGPUMemory() - used_gpu_memory;
-    *c_val_stats_.used_gpu_memory = used_gpu_memory;
+        SbSystemGetTotalGPUMemory() - *used_gpu_memory;
+    *c_val_stats_.used_gpu_memory = *used_gpu_memory;
   }
-#endif
+
+  memory_settings_checker_.RunChecks(
+      *auto_mem_, used_cpu_memory, used_gpu_memory);
 }
 
 }  // namespace browser
diff --git a/src/cobalt/browser/application.h b/src/cobalt/browser/application.h
index 6c1ac47..47da7ec 100644
--- a/src/cobalt/browser/application.h
+++ b/src/cobalt/browser/application.h
@@ -22,6 +22,8 @@
 #include "cobalt/account/account_manager.h"
 #include "cobalt/base/event_dispatcher.h"
 #include "cobalt/browser/browser_module.h"
+#include "cobalt/browser/memory_settings/auto_mem.h"
+#include "cobalt/browser/memory_settings/checker.h"
 #include "cobalt/browser/memory_tracker/tool.h"
 #include "cobalt/system_window/system_window.h"
 
@@ -173,6 +175,13 @@
   base::Timer lite_stats_update_timer_;
 
   scoped_ptr<memory_tracker::Tool> memory_tracker_tool_;
+
+  // Memory configuration tool.
+  scoped_ptr<memory_settings::AutoMem> auto_mem_;
+
+  // Fires memory warning once when memory exceeds specified max cpu/gpu
+  // memory.
+  memory_settings::Checker memory_settings_checker_;
 };
 
 // Factory method for creating an application.  It should be implemented
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp
index 61b714e..fb7ef5e 100644
--- a/src/cobalt/browser/browser.gyp
+++ b/src/cobalt/browser/browser.gyp
@@ -35,7 +35,13 @@
         'memory_settings/build_settings.h',
         'memory_settings/calculations.cc',
         'memory_settings/calculations.h',
+        'memory_settings/checker.cc',
+        'memory_settings/checker.h',
         'memory_settings/constants.h',
+        'memory_settings/constrainer.cc',
+        'memory_settings/constrainer.h',
+        'memory_settings/scaling_function.cc',
+        'memory_settings/scaling_function.h',
         'memory_settings/memory_settings.cc',
         'memory_settings/memory_settings.h',
         'memory_settings/pretty_print.cc',
@@ -213,6 +219,7 @@
         'storage_upgrade_handler_test.cc',
         'memory_settings/auto_mem_test.cc',
         'memory_settings/calculations_test.cc',
+        'memory_settings/constrainer_test.cc',
         'memory_settings/pretty_print_test.cc',
         'memory_settings/memory_settings_test.cc',
         'memory_settings/table_printer_test.cc',
diff --git a/src/cobalt/browser/memory_settings/auto_mem.cc b/src/cobalt/browser/memory_settings/auto_mem.cc
index 5743645..582c49e 100644
--- a/src/cobalt/browser/memory_settings/auto_mem.cc
+++ b/src/cobalt/browser/memory_settings/auto_mem.cc
@@ -21,14 +21,17 @@
 #include <vector>
 
 #include "base/optional.h"
+#include "base/stl_util.h"
 #include "base/string_number_conversions.h"
 #include "base/string_split.h"
 #include "base/stringprintf.h"
 #include "cobalt/browser/memory_settings/build_settings.h"
 #include "cobalt/browser/memory_settings/calculations.h"
 #include "cobalt/browser/memory_settings/constants.h"
+#include "cobalt/browser/memory_settings/constrainer.h"
 #include "cobalt/browser/memory_settings/memory_settings.h"
 #include "cobalt/browser/memory_settings/pretty_print.h"
+#include "cobalt/browser/memory_settings/scaling_function.h"
 #include "cobalt/browser/switches.h"
 #include "nb/lexical_cast.h"
 
@@ -48,15 +51,13 @@
   return is_autoset;
 }
 
-// Creates the specified memory setting type and binds it to (1) command line
-// or else (2) build setting or else (3) an auto_set value.
 template <typename MemorySettingType, typename ValueType>
-scoped_ptr<MemorySettingType> CreateMemorySetting(
-    const char* setting_name,
+void SetMemorySetting(
     const CommandLine& cmd_line,  // Optional.
     const base::optional<ValueType>& build_setting,
-    const ValueType& autoset_value) {
-  scoped_ptr<MemorySettingType> output(new MemorySettingType(setting_name));
+    const ValueType& autoset_value,
+    MemorySettingType* setting) {
+  const std::string setting_name = setting->name();
 
   // True when the command line explicitly requests the variable to be autoset.
   bool force_autoset = false;
@@ -68,19 +69,31 @@
     std::string value = cmd_line.GetSwitchValueNative(setting_name);
     if (StringValueSignalsAutoset(value)) {
       force_autoset = true;
-    } else if (output->TryParseValue(MemorySetting::kCmdLine, value)) {
-      return output.Pass();
+    } else if (setting->TryParseValue(MemorySetting::kCmdLine, value)) {
+      return;
     }
   }
 
   // 2) Is there a build setting? Then set to build_setting, unless the command
   //    line specifies that it should be autoset.
   if (build_setting && !force_autoset) {
-    output->set_value(MemorySetting::kBuildSetting, *build_setting);
+    setting->set_value(MemorySetting::kBuildSetting, *build_setting);
   } else {
     // 3) Otherwise bind to the autoset_value.
-    output->set_value(MemorySetting::kAutoSet, autoset_value);
+    setting->set_value(MemorySetting::kAutoSet, autoset_value);
   }
+}
+
+// Creates the specified memory setting type and binds it to (1) command line
+// or else (2) build setting or else (3) an auto_set value.
+template <typename MemorySettingType, typename ValueType>
+scoped_ptr<MemorySettingType> CreateMemorySetting(
+    const char* setting_name,
+    const CommandLine& cmd_line,  // Optional.
+    const base::optional<ValueType>& build_setting,
+    const ValueType& autoset_value) {
+  scoped_ptr<MemorySettingType> output(new MemorySettingType(setting_name));
+  SetMemorySetting(cmd_line, build_setting, autoset_value, output.get());
   return output.Pass();
 }
 
@@ -187,7 +200,7 @@
                                         const BuildSettings& build_settings) {
   scoped_ptr<IntSetting> cpu_setting =
       CreateSystemMemorySetting(
-          switches::kMaxCobaltGpuUsage,
+          switches::kMaxCobaltCpuUsage,
           MemorySetting::kCPU,
           command_line,
           build_settings.max_cpu_in_bytes,
@@ -197,11 +210,158 @@
   return cpu_setting.Pass();
 }
 
+void CheckConstrainingValues(const MemorySetting& memory_setting) {
+  const size_t kNumTestPoints = 10;
+
+  std::vector<double> values;
+  for (size_t i = 0; i < kNumTestPoints; ++i) {
+    const double requested_constraining_value =
+        static_cast<double>(i) / static_cast<double>(kNumTestPoints - 1);
+
+    const double actual_constraining_value =
+        memory_setting.ComputeAbsoluteMemoryScale(
+            requested_constraining_value);
+
+    values.push_back(actual_constraining_value);
+  }
+
+  DCHECK(base::STLIsSorted(values))
+      << "Constrainer in " << memory_setting.name() << " does not produce "
+         "monotonically decreasing values as input goes from 1.0 -> 0.0";
+}
+
 }  // namespace
 
 AutoMem::AutoMem(const math::Size& ui_resolution,
                  const CommandLine& command_line,
                  const BuildSettings& build_settings) {
+  ConstructSettings(ui_resolution, command_line, build_settings);
+  std::vector<MemorySetting*> memory_settings = AllMemorySettingsMutable();
+  ConstrainToMemoryLimits(max_cpu_bytes_->value(),
+                          max_gpu_bytes_->optional_value(),
+                          &memory_settings,
+                          &error_msgs_);
+}
+
+AutoMem::~AutoMem() {}
+
+const IntSetting* AutoMem::misc_cobalt_cpu_size_in_bytes() const {
+  return misc_cobalt_cpu_size_in_bytes_.get();
+}
+
+const IntSetting* AutoMem::misc_cobalt_gpu_size_in_bytes() const {
+  return misc_cobalt_gpu_size_in_bytes_.get();
+}
+
+const IntSetting* AutoMem::remote_typeface_cache_size_in_bytes() const {
+  return remote_typeface_cache_size_in_bytes_.get();
+}
+
+const IntSetting* AutoMem::image_cache_size_in_bytes() const {
+  return image_cache_size_in_bytes_.get();
+}
+
+const IntSetting* AutoMem::javascript_gc_threshold_in_bytes() const {
+  return javascript_gc_threshold_in_bytes_.get();
+}
+
+const DimensionSetting* AutoMem::skia_atlas_texture_dimensions() const {
+  return skia_atlas_texture_dimensions_.get();
+}
+
+const IntSetting* AutoMem::skia_cache_size_in_bytes() const {
+  return skia_cache_size_in_bytes_.get();
+}
+
+const IntSetting* AutoMem::software_surface_cache_size_in_bytes() const {
+  return software_surface_cache_size_in_bytes_.get();
+}
+
+const IntSetting* AutoMem::max_cpu_bytes() const {
+  return max_cpu_bytes_.get();
+}
+
+const IntSetting* AutoMem::max_gpu_bytes() const {
+  return max_gpu_bytes_.get();
+}
+
+std::vector<const MemorySetting*> AutoMem::AllMemorySettings() const {
+  AutoMem* this_unconst = const_cast<AutoMem*>(this);
+  std::vector<MemorySetting*> all_settings_mutable =
+      this_unconst->AllMemorySettingsMutable();
+
+  std::vector<const MemorySetting*> all_settings;
+  all_settings.assign(all_settings_mutable.begin(),
+                      all_settings_mutable.end());
+  return all_settings;
+}
+
+// Make sure that this is the same as AllMemorySettings().
+std::vector<MemorySetting*> AutoMem::AllMemorySettingsMutable() {
+  std::vector<MemorySetting*> all_settings;
+  // Keep these in alphabetical order.
+  all_settings.push_back(image_cache_size_in_bytes_.get());
+  all_settings.push_back(javascript_gc_threshold_in_bytes_.get());
+  all_settings.push_back(misc_cobalt_cpu_size_in_bytes_.get());
+  all_settings.push_back(misc_cobalt_gpu_size_in_bytes_.get());
+  all_settings.push_back(remote_typeface_cache_size_in_bytes_.get());
+  all_settings.push_back(skia_atlas_texture_dimensions_.get());
+  all_settings.push_back(skia_cache_size_in_bytes_.get());
+  all_settings.push_back(software_surface_cache_size_in_bytes_.get());
+  return all_settings;
+}
+
+std::string AutoMem::ToPrettyPrintString(bool use_color_ascii) const {
+  std::stringstream ss;
+
+  ss << "AutoMem:\n\n";
+  std::vector<const MemorySetting*> all_settings = AllMemorySettings();
+  ss << GeneratePrettyPrintTable(use_color_ascii, all_settings) << "\n";
+
+  int64_t cpu_consumption =
+      SumMemoryConsumption(MemorySetting::kCPU, all_settings);
+  int64_t gpu_consumption =
+      SumMemoryConsumption(MemorySetting::kGPU, all_settings);
+
+  ss << GenerateMemoryTable(use_color_ascii,
+                            *max_cpu_bytes_, *max_gpu_bytes_,
+                            cpu_consumption, gpu_consumption);
+
+  // Copy strings and optionally add more.
+  std::vector<std::string> error_msgs = error_msgs_;
+
+  if (max_cpu_bytes_->value() <= 0) {
+    error_msgs.push_back("ERROR - max_cobalt_cpu_usage WAS 0 BYTES.");
+  } else if (cpu_consumption > max_cpu_bytes_->value()) {
+    error_msgs.push_back("ERROR - CPU CONSUMED WAS MORE THAN AVAILABLE.");
+  }
+
+  if (max_gpu_bytes_->value() <= 0) {
+    error_msgs.push_back("ERROR - max_cobalt_gpu_usage WAS 0 BYTES.");
+  } else if (gpu_consumption > max_gpu_bytes_->value()) {
+    error_msgs.push_back("ERROR - GPU CONSUMED WAS MORE THAN AVAILABLE.");
+  }
+
+  // Stringify error messages.
+  if (!error_msgs.empty()) {
+    std::stringstream ss_error;
+    ss_error << "AutoMem had errors:\n";
+    for (size_t i = 0; i < error_msgs.size(); ++i) {
+      ss_error << "   " << error_msgs[i] << "\n";
+    }
+    ss_error << "\nPlease see cobalt/docs/memory_tuning.md "
+                "for more information.";
+    ss << MakeBorder(ss_error.str(), '*');
+  }
+
+  std::string output_str = ss.str();
+  return output_str;
+}
+
+void AutoMem::ConstructSettings(
+    const math::Size& ui_resolution,
+    const CommandLine& command_line,
+    const BuildSettings& build_settings) {
   max_cpu_bytes_ = CreateCpuSetting(command_line, build_settings);
   max_gpu_bytes_ = CreateGpuSetting(command_line, build_settings);
 
@@ -213,20 +373,35 @@
       CalculateImageCacheSize(ui_resolution));
   EnsureValuePositive(image_cache_size_in_bytes_.get());
   image_cache_size_in_bytes_->set_memory_type(MemorySetting::kGPU);
+  // ImageCache releases memory linearly until a progress value of 75%, then
+  // it will not reduce memory any more. It will also clamp at 100% and won't
+  // be increased beyond that.
+  image_cache_size_in_bytes_->set_memory_scaling_function(
+      MakeLinearMemoryScaler(.75, 1.0));
 
   // Set javascript gc threshold
-  javascript_gc_threshold_in_bytes_ = CreateMemorySetting<IntSetting, int64_t>(
-      switches::kJavaScriptGcThresholdInBytes,
+  JavaScriptGcThresholdSetting* js_setting = new JavaScriptGcThresholdSetting;
+  SetMemorySetting<IntSetting, int64_t>(
       command_line,
       build_settings.javascript_garbage_collection_threshold_in_bytes,
-      kDefaultJsGarbageCollectionThresholdSize);
-  EnsureValuePositive(javascript_gc_threshold_in_bytes_.get());
+      kDefaultJsGarbageCollectionThresholdSize,
+      js_setting);
+  EnsureValuePositive(js_setting);
+  js_setting->PostInit();
+  javascript_gc_threshold_in_bytes_.reset(js_setting);
 
   // Set the misc cobalt size to a specific size.
   misc_cobalt_cpu_size_in_bytes_.reset(
       new IntSetting("misc_cobalt_cpu_size_in_bytes"));
   misc_cobalt_cpu_size_in_bytes_->set_value(
-      MemorySetting::kAutoSet, kMiscCobaltSizeInBytes);
+      MemorySetting::kAutoSet, kMiscCobaltCpuSizeInBytes);
+
+  // Set the misc cobalt size to a specific size.
+  misc_cobalt_gpu_size_in_bytes_.reset(
+      new IntSetting("misc_cobalt_gpu_size_in_bytes"));
+  misc_cobalt_gpu_size_in_bytes_->set_memory_type(MemorySetting::kGPU);
+  misc_cobalt_gpu_size_in_bytes_->set_value(
+      MemorySetting::kAutoSet, CalculateMiscCobaltGpuSize(ui_resolution));
 
   // Set remote_type_face_cache size.
   remote_typeface_cache_size_in_bytes_ =
@@ -237,13 +412,14 @@
         kDefaultRemoteTypeFaceCacheSize);
   EnsureValuePositive(remote_typeface_cache_size_in_bytes_.get());
 
-  // Set skia_atlas_texture_dimensions
-  skia_atlas_texture_dimensions_ =
-      CreateMemorySetting<DimensionSetting, TextureDimensions>(
-          switches::kSkiaTextureAtlasDimensions,
-          command_line,
-          build_settings.skia_texture_atlas_dimensions,
-          CalculateSkiaGlyphAtlasTextureSize(ui_resolution));
+  // Skia atlas texture dimensions.
+  skia_atlas_texture_dimensions_.reset(new SkiaGlyphAtlasTextureSetting());
+  SetMemorySetting(command_line,
+                   build_settings.skia_texture_atlas_dimensions,
+                   CalculateSkiaGlyphAtlasTextureSize(ui_resolution),
+                   skia_atlas_texture_dimensions_.get());
+  EnsureValuePositive(skia_atlas_texture_dimensions_.get());
+
   // Not available for non-blitter platforms.
   if (build_settings.has_blitter) {
     skia_atlas_texture_dimensions_->set_memory_type(
@@ -283,78 +459,14 @@
         MemorySetting::kNotApplicable);
   }
   EnsureValuePositive(software_surface_cache_size_in_bytes_.get());
-}
 
-AutoMem::~AutoMem() {}
-
-const IntSetting* AutoMem::misc_engine_cpu_size_in_bytes() const {
-  return misc_cobalt_cpu_size_in_bytes_.get();
-}
-
-const IntSetting* AutoMem::remote_typeface_cache_size_in_bytes() const {
-  return remote_typeface_cache_size_in_bytes_.get();
-}
-
-const IntSetting* AutoMem::image_cache_size_in_bytes() const {
-  return image_cache_size_in_bytes_.get();
-}
-
-const IntSetting* AutoMem::javascript_gc_threshold_in_bytes() const {
-  return javascript_gc_threshold_in_bytes_.get();
-}
-
-const DimensionSetting* AutoMem::skia_atlas_texture_dimensions() const {
-  return skia_atlas_texture_dimensions_.get();
-}
-
-const IntSetting* AutoMem::skia_cache_size_in_bytes() const {
-  return skia_cache_size_in_bytes_.get();
-}
-
-const IntSetting* AutoMem::software_surface_cache_size_in_bytes() const {
-  return software_surface_cache_size_in_bytes_.get();
-}
-
-std::vector<const MemorySetting*> AutoMem::AllMemorySettings() const {
-  AutoMem* this_unconst = const_cast<AutoMem*>(this);
-  std::vector<MemorySetting*> all_settings_mutable =
-      this_unconst->AllMemorySettingsMutable();
-
-  std::vector<const MemorySetting*> all_settings;
-  all_settings.assign(all_settings_mutable.begin(),
-                      all_settings_mutable.end());
-  return all_settings;
-}
-
-// Make sure that this is the same as AllMemorySettings().
-std::vector<MemorySetting*> AutoMem::AllMemorySettingsMutable() {
-  std::vector<MemorySetting*> all_settings;
-  // Keep these in alphabetical order.
-  all_settings.push_back(image_cache_size_in_bytes_.get());
-  all_settings.push_back(javascript_gc_threshold_in_bytes_.get());
-  all_settings.push_back(misc_cobalt_cpu_size_in_bytes_.get());
-  all_settings.push_back(remote_typeface_cache_size_in_bytes_.get());
-  all_settings.push_back(skia_atlas_texture_dimensions_.get());
-  all_settings.push_back(skia_cache_size_in_bytes_.get());
-  all_settings.push_back(software_surface_cache_size_in_bytes_.get());
-  return all_settings;
-}
-
-std::string AutoMem::ToPrettyPrintString() const {
-  std::stringstream ss;
-  std::vector<const MemorySetting*> all_settings = AllMemorySettings();
-  ss << GeneratePrettyPrintTable(all_settings) << "\n";
-
-  int64_t cpu_consumption =
-      SumMemoryConsumption(MemorySetting::kCPU, all_settings);
-  int64_t gpu_consumption =
-      SumMemoryConsumption(MemorySetting::kGPU, all_settings);
-
-  ss << GenerateMemoryTable(*max_cpu_bytes_, *max_gpu_bytes_,
-                            cpu_consumption, gpu_consumption);
-
-  std::string output_str = ss.str();
-  return output_str;
+  // Final stage: Check that all constraining functions are monotonically
+  // increasing.
+  const std::vector<const MemorySetting*> all_memory_settings =
+      AllMemorySettings();
+  for (size_t i = 0; i < all_memory_settings.size(); ++i) {
+    CheckConstrainingValues(*all_memory_settings[i]);
+  }
 }
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/auto_mem.h b/src/cobalt/browser/memory_settings/auto_mem.h
index ad3e143..c018aec 100644
--- a/src/cobalt/browser/memory_settings/auto_mem.h
+++ b/src/cobalt/browser/memory_settings/auto_mem.h
@@ -27,6 +27,7 @@
 #include "cobalt/browser/memory_settings/build_settings.h"
 #include "cobalt/browser/memory_settings/memory_settings.h"
 #include "cobalt/math/size.h"
+#include "testing/gtest/include/gtest/gtest_prod.h"
 
 namespace cobalt {
 namespace browser {
@@ -44,25 +45,39 @@
 
   const IntSetting* image_cache_size_in_bytes() const;
   const IntSetting* javascript_gc_threshold_in_bytes() const;
-  const IntSetting* misc_engine_cpu_size_in_bytes() const;
+  // This setting represents all others cpu-memory consuming systems within
+  // the engine. This value has been hard coded.
+  const IntSetting* misc_cobalt_cpu_size_in_bytes() const;
+  const IntSetting* misc_cobalt_gpu_size_in_bytes() const;
   const IntSetting* remote_typeface_cache_size_in_bytes() const;
   const DimensionSetting* skia_atlas_texture_dimensions() const;
   const IntSetting* skia_cache_size_in_bytes() const;
   const IntSetting* software_surface_cache_size_in_bytes() const;
 
-  // AllMemorySettings - does not include cpu & gpu max memory.
-  std::vector<const MemorySetting*> AllMemorySettings() const;
-  std::vector<MemorySetting*> AllMemorySettingsMutable();
+  // max_cpu/gpu_bytes represents the maximum amount of memory that should
+  // be consumed by the engine. These values can be set by the command line
+  // or else they are set automatically.
+  const IntSetting* max_cpu_bytes() const;
+  const IntSetting* max_gpu_bytes() const;
 
   // Generates a string table of the memory settings and available memory for
   // cpu and gpu. This is used during startup to display memory configuration
   // information.
-  std::string ToPrettyPrintString() const;
+  std::string ToPrettyPrintString(bool use_color_ascii) const;
 
  private:
+  void ConstructSettings(const math::Size& ui_resolution,
+                         const CommandLine& command_line,
+                         const BuildSettings& build_settings);
+
+  // AllMemorySettings - does not include cpu & gpu max memory.
+  std::vector<const MemorySetting*> AllMemorySettings() const;
+  std::vector<MemorySetting*> AllMemorySettingsMutable();
+
   scoped_ptr<IntSetting> image_cache_size_in_bytes_;
   scoped_ptr<IntSetting> javascript_gc_threshold_in_bytes_;
   scoped_ptr<IntSetting> misc_cobalt_cpu_size_in_bytes_;
+  scoped_ptr<IntSetting> misc_cobalt_gpu_size_in_bytes_;
   scoped_ptr<IntSetting> remote_typeface_cache_size_in_bytes_;
   scoped_ptr<DimensionSetting> skia_atlas_texture_dimensions_;
   scoped_ptr<IntSetting> skia_cache_size_in_bytes_;
@@ -71,6 +86,11 @@
   // These settings are used for constraining the memory.
   scoped_ptr<IntSetting> max_cpu_bytes_;
   scoped_ptr<IntSetting> max_gpu_bytes_;
+  std::vector<std::string> error_msgs_;
+
+  FRIEND_TEST(AutoMem, AllMemorySettingsAreOrderedByName);
+  FRIEND_TEST(AutoMem, ConstrainedCPUEnvironment);
+  FRIEND_TEST(AutoMem, ConstrainedGPUEnvironment);
 };
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/auto_mem_test.cc b/src/cobalt/browser/memory_settings/auto_mem_test.cc
index b5a2ba5..5a17825 100644
--- a/src/cobalt/browser/memory_settings/auto_mem_test.cc
+++ b/src/cobalt/browser/memory_settings/auto_mem_test.cc
@@ -121,7 +121,7 @@
 
 // Tests that skia atlas texture will be bind to the built in value, iff it has
 // been set.
-TEST(AutoMem, SkiaAtlasTextureAtlasSize) {
+TEST(AutoMem, SkiaGlyphAtlasTextureSize) {
   CommandLine empty_command_line(CommandLine::NO_PROGRAM);
   BuildSettings builtin_settings;
   BuildSettings builtin_settings_with_default;
@@ -209,6 +209,37 @@
   }
 }
 
+// Tests the expectation that constraining the CPU memory to 130MB will result
+// in AutoMem reducing the the memory footprint.
+TEST(AutoMem, ConstrainedCPUEnvironment) {
+  CommandLine empty_command_line(CommandLine::NO_PROGRAM);
+  BuildSettings builtin_settings;
+  builtin_settings.max_cpu_in_bytes = 130 * 1024 * 1024;
+
+  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+
+  std::vector<const MemorySetting*> settings = auto_mem.AllMemorySettings();
+
+  const int64_t cpu_memory_consumption =
+      SumMemoryConsumption(MemorySetting::kCPU, settings);
+
+  EXPECT_LE(cpu_memory_consumption, 130 * 1024 * 1024);
+}
+
+// Tests the expectation that constraining the CPU memory to 40MB will result
+// in AutoMem reducing the the memory footprint.
+TEST(AutoMem, ConstrainedGPUEnvironment) {
+  CommandLine empty_command_line(CommandLine::NO_PROGRAM);
+  BuildSettings builtin_settings;
+  builtin_settings.max_gpu_in_bytes = 57 * 1024 * 1024;
+  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+
+  std::vector<const MemorySetting*> settings = auto_mem.AllMemorySettings();
+  const int64_t gpu_memory_consumption =
+      SumMemoryConsumption(MemorySetting::kGPU, settings);
+  EXPECT_LE(gpu_memory_consumption, 57 * 1024 * 1024);
+}
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/calculations.cc b/src/cobalt/browser/memory_settings/calculations.cc
index 7da7d3e..8474f65 100644
--- a/src/cobalt/browser/memory_settings/calculations.cc
+++ b/src/cobalt/browser/memory_settings/calculations.cc
@@ -20,6 +20,7 @@
 
 #include "cobalt/browser/memory_settings/build_settings.h"
 #include "cobalt/browser/memory_settings/constants.h"
+#include "cobalt/math/clamp.h"
 #include "cobalt/math/size.h"
 
 namespace cobalt {
@@ -27,11 +28,6 @@
 namespace memory_settings {
 namespace {
 
-template <typename T>
-T ClampValue(const T& input, const T& minimum, const T& maximum) {
-  return std::max<T>(minimum, std::min<T>(maximum, input));
-}
-
 double DisplayScaleTo1080p(const math::Size& dimensions) {
   static const double kNumReferencePixels = 1920. * 1080.;
   const double num_pixels = static_cast<double>(dimensions.width()) *
@@ -39,8 +35,8 @@
   return num_pixels / kNumReferencePixels;
 }
 
-// LinearRemap is a type of linear interpolation which maps a value from
-// one number line to a corresponding value on another number line.
+// LinearRemap maps a value from one number line to a corresponding value on
+// another number line.
 // Example:
 //  LinearRemap linear_remap(0, 1, 5, 10);
 //  EXPECT_EQ(5.0f, linear_remap.Map(0));
@@ -49,7 +45,9 @@
 class LinearRemap {
  public:
   LinearRemap(double amin, double amax, double bmin, double bmax)
-      : amin_(amin), amax_(amax), bmin_(bmin), bmax_(bmax) {}
+      : amin_(amin), amax_(amax), bmin_(bmin), bmax_(bmax) {
+    DCHECK_NE(amax_, amin_);
+  }
 
   // Maps the value from the number line [amin,amax] to [bmin,bmax]. For
   // example:
@@ -58,8 +56,8 @@
   //   Map((amax+amin)/2) -> (bmax+bmin)/2.
   double Map(double value) const {
     value -= amin_;
-    value /= (amax_ - amin_);
     value *= (bmax_ - bmin_);
+    value /= (amax_ - amin_);
     value += bmin_;
     return value;
   }
@@ -93,8 +91,8 @@
   static const int64_t kReferenceSize1080p = 32 * 1024 * 1024;
   double output_bytes = kReferenceSize1080p * display_scale;
 
-  return ClampValue<int64_t>(static_cast<int64_t>(output_bytes),
-                             kMinImageCacheSize, kMaxImageCacheSize);
+  return math::Clamp<int64_t>(static_cast<int64_t>(output_bytes),
+                              kMinImageCacheSize, kMaxImageCacheSize);
 }
 
 TextureDimensions CalculateSkiaGlyphAtlasTextureSize(
@@ -130,7 +128,7 @@
   // LinearRemap defines a mapping function which will map the number
   // of ui_resolution pixels to the number of surface texture cache such:
   // 720p (1280x720)   => maps to => 4MB &
-  // 1080p (1920x1200) => maps to => 9MB
+  // 1080p (1920x1080) => maps to => 9MB
   LinearRemap remap(1280 * 720, 1920 * 1080, 4 * 1024 * 1024, 9 * 1024 * 1024);
 
   int64_t surface_cache_size_in_bytes =
@@ -146,6 +144,16 @@
   return std::max<int64_t>(output, kMinSkiaCacheSize);
 }
 
+int64_t CalculateMiscCobaltGpuSize(const math::Size& ui_resolution) {
+  // LinearRemap defines a mapping function which will map the number
+  // of ui_resolution pixels to the misc memory of the GPU. This mapping
+  // is linear such that:
+  // 1080p (1920x1080) => maps to => 24MB
+  LinearRemap remap(0, 1920 * 1080, 0, 24 * 1024 * 1024);
+
+  return static_cast<int64_t>(remap.Map(ui_resolution.GetArea()));
+}
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/calculations.h b/src/cobalt/browser/memory_settings/calculations.h
index cbb3afb..bc4a65a 100644
--- a/src/cobalt/browser/memory_settings/calculations.h
+++ b/src/cobalt/browser/memory_settings/calculations.h
@@ -33,7 +33,7 @@
 // The return ranges from [kMinImageCacheSize, kMaxImageCacheSize].
 int64_t CalculateImageCacheSize(const math::Size& dimensions);
 
-// Calculates the SkiaAtlasTextureSize.
+// Calculates the SkiaAtlasGlyphTextureSize.
 // When the ui resolution is 1920x1080, then the returned atlas texture size
 // will be 8192x4096. The texture will scale up and down, by powers of two,
 // in relation to the input ui_resolution. The returned value will be clamped
@@ -53,6 +53,10 @@
 // to be 4MB @ 1080p and scales accordingly.
 int64_t CalculateSkiaCacheSize(const math::Size& ui_resolution);
 
+// Calculates the GPU usage of the app to un-accounted systems. Scales linearly
+// with ui_resolution.
+int64_t CalculateMiscCobaltGpuSize(const math::Size& ui_resolution);
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/calculations_test.cc b/src/cobalt/browser/memory_settings/calculations_test.cc
index 1d82f58..3b7f62c 100644
--- a/src/cobalt/browser/memory_settings/calculations_test.cc
+++ b/src/cobalt/browser/memory_settings/calculations_test.cc
@@ -110,7 +110,7 @@
   EXPECT_EQ(kMaxImageCacheSize, CalculateImageCacheSize(GetDimensions(k8k)));
 }
 
-// Tests the expectation that CalculateSkiaAtlasTextureSize() is a pure
+// Tests the expectation that CalculateSkiaGlyphAtlasTextureSize() is a pure
 // function (side effect free) and will produce expected results.
 TEST(MemoryCalculations, CalculateSkiaGlyphAtlasTextureSize) {
   math::Size ui_dimensions;
@@ -156,6 +156,12 @@
             CalculateSoftwareSurfaceCacheSizeInBytes(ui_resolution));
 }
 
+TEST(MemoryCalculations, CalculateMiscCobaltGpuSize) {
+  math::Size ui_resolution = GetDimensions(k1080p);
+  EXPECT_EQ(24 * 1024 * 1024,
+            CalculateMiscCobaltGpuSize(ui_resolution));
+}
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/checker.cc b/src/cobalt/browser/memory_settings/checker.cc
new file mode 100644
index 0000000..a5ef859
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/checker.cc
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2017 Google Inc. 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.
+ */
+
+#include "cobalt/browser/memory_settings/checker.h"
+
+#include <algorithm>
+#include <sstream>
+#include <string>
+
+#include "cobalt/browser/memory_settings/pretty_print.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+namespace {
+
+std::string GenerateErrorMessage(const std::string& memory_type,
+                                 const IntSetting& max_memory_setting,
+                                 int64_t current_memory_usage) {
+  std::string max_memory_str = ToMegabyteString(max_memory_setting.value(), 2);
+  std::string used_memory_str = ToMegabyteString(current_memory_usage, 2);
+  std::string source_str = StringifySourceType(max_memory_setting);
+
+  std::stringstream ss;
+  ss << memory_type << " MEMORY USAGE EXCEEDED!\n"
+     << "  Max Available: " << max_memory_str << "\n"
+     << "  Used:          " << used_memory_str << "\n"
+     << "  Source:        " << source_str << "\n\n"
+     << "  Please see cobalt/doc/memory_tuning.md for more information";
+
+  return MakeBorder(ss.str(), '*');
+}
+
+void DoCheck(const char* memory_type_str,
+             int64_t curr_memory_consumption,
+             const IntSetting& max_memory_limit,
+             bool* fired_once_flag) {
+  if (*fired_once_flag || (max_memory_limit.value() > 0)) {
+    return;
+  }
+  const int64_t max_memory_value = max_memory_limit.value();
+
+  if (curr_memory_consumption > max_memory_value) {
+    std::string error_msg = GenerateErrorMessage(memory_type_str,
+                                                 max_memory_limit,
+                                                 curr_memory_consumption);
+    LOG(ERROR) << error_msg;
+    *fired_once_flag = true;
+  }
+}
+
+}  // namespace.
+
+Checker::Checker() : cpu_memory_warning_fired_(false),
+                     gpu_memory_warning_fired_(false) {
+}
+
+void Checker::RunChecks(const AutoMem& auto_mem,
+                        int64_t curr_cpu_memory_usage,
+                        base::optional<int64_t> curr_gpu_memory_usage) {
+  DoCheck("CPU",
+          curr_cpu_memory_usage,
+          *auto_mem.max_cpu_bytes(),
+          &cpu_memory_warning_fired_);
+
+  if (curr_gpu_memory_usage) {
+    DoCheck("GPU",
+            *curr_gpu_memory_usage,
+            *auto_mem.max_gpu_bytes(),
+            &gpu_memory_warning_fired_);
+  }
+}
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/checker.h b/src/cobalt/browser/memory_settings/checker.h
new file mode 100644
index 0000000..f749621
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/checker.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2017 Google Inc. 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_BROWSER_MEMORY_SETTINGS_CHECKER_H_
+#define COBALT_BROWSER_MEMORY_SETTINGS_CHECKER_H_
+
+#include <string>
+
+#include "base/optional.h"
+#include "cobalt/browser/memory_settings/auto_mem.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+// This class is responsible for holding the logic necessary to check
+// whether the memory limit has been exceeded. If so then a error
+// message is fired once.
+class Checker {
+ public:
+  Checker();
+  void RunChecks(const AutoMem& auto_mem,
+                 int64_t curr_cpu_memory_usage,
+                 base::optional<int64_t> curr_gpu_memory_usage);
+
+ private:
+  bool cpu_memory_warning_fired_;
+  bool gpu_memory_warning_fired_;
+};
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
+
+#endif  // COBALT_BROWSER_MEMORY_SETTINGS_CHECKER_H_
diff --git a/src/cobalt/browser/memory_settings/constants.h b/src/cobalt/browser/memory_settings/constants.h
index 9f397eb..aa1bdc8 100644
--- a/src/cobalt/browser/memory_settings/constants.h
+++ b/src/cobalt/browser/memory_settings/constants.h
@@ -23,8 +23,9 @@
 
 // These internal values are exposed for testing.
 enum MemorySizes {
-  // Size of the engine, minus all caches.
-  kMiscCobaltSizeInBytes = 32 * 1024 * 1024,
+  // Size of the engine + unaccounted caches.
+  // This was experimentally selected.
+  kMiscCobaltCpuSizeInBytes = 119 * 1024 * 1024,
 
   kMinImageCacheSize = 20 * 1024 * 1024,  // 20mb.
   kMaxImageCacheSize = 64 * 1024 * 1024,  // 64mb
@@ -33,7 +34,7 @@
   kMinSkiaGlyphTextureAtlasHeight = 2048,
   kSkiaGlyphAtlasTextureBytesPerPixel = 2,
   kDefaultRemoteTypeFaceCacheSize = 4 * 1024 * 1024,  // 4mb.
-  kDefaultJsGarbageCollectionThresholdSize = 1 * 1024 * 1024,  // 1mb
+  kDefaultJsGarbageCollectionThresholdSize = 8 * 1024 * 1024,  // 8mb
 
   kMinSkiaCacheSize = 4 * 1024 * 1024,  // 4mb.
 };
diff --git a/src/cobalt/browser/memory_settings/constrainer.cc b/src/cobalt/browser/memory_settings/constrainer.cc
new file mode 100644
index 0000000..f4a9e54
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/constrainer.cc
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2017 Google Inc. 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.
+ */
+
+#include "cobalt/browser/memory_settings/constrainer.h"
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include "cobalt/browser/memory_settings/memory_settings.h"
+#include "starboard/configuration.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+namespace {
+
+// Any memory setting that matches the MemoryType and is an AutoSet type is
+// passed to the output.
+std::vector<MemorySetting*> FilterSettings(
+    MemorySetting::MemoryType memory_type,
+    const std::vector<MemorySetting*>& settings) {
+  std::vector<MemorySetting*> output;
+  for (size_t i = 0; i < settings.size(); ++i) {
+    MemorySetting* setting = settings[i];
+    if (setting->memory_type() == memory_type) {
+      output.push_back(setting);
+    }
+  }
+  return output;
+}
+
+// Sums the memory consumption at the given global_constraining_value. The
+// settings variable is read buy not modified (despite the non-const
+// declaration). If constrained_values_out is non-null, then the computed
+// constraining values are stored in this vector.
+// Returns: The amount of memory in bytes that the memory settings vector will
+//          consume at the given global_constraining_factor.
+int64_t SumMemoryConsumption(
+    double global_constraining_factor,
+    const std::vector<MemorySetting*>& memory_settings,
+    std::vector<double>* constrained_values_out) {
+
+  if (constrained_values_out) {
+    constrained_values_out->clear();
+  }
+
+  int64_t sum = 0;
+
+  // Iterates through the MemorySettings and determines the total memory
+  // consumption at the current global_constraining_value.
+  for (size_t i = 0; i < memory_settings.size(); ++i) {
+    const MemorySetting* setting = memory_settings[i];
+
+    const int64_t requested_consumption = setting->MemoryConsumption();
+    double local_constraining_value = 1.0;
+    if (setting->source_type() == MemorySetting::kAutoSet) {
+      local_constraining_value =
+          setting->ComputeAbsoluteMemoryScale(global_constraining_factor);
+    }
+
+    const int64_t new_consumption_value =
+        static_cast<int64_t>(local_constraining_value * requested_consumption);
+
+    if (constrained_values_out) {
+      constrained_values_out->push_back(local_constraining_value);
+    }
+
+    sum += new_consumption_value;
+  }
+
+  return sum;
+}
+
+void CheckMemoryChange(const std::string& setting_name,
+                       int64_t old_memory_consumption,
+                       int64_t new_memory_consumption,
+                       double constraining_value) {
+  // Represents 1% allowed difference.
+  static const double kErrorThreshold = 0.01;
+
+  const double actual_constraining_value =
+      static_cast<double>(new_memory_consumption) /
+      static_cast<double>(old_memory_consumption);
+
+  double diff = constraining_value - actual_constraining_value;
+  if (diff < 0.0) {
+    diff = -diff;
+  }
+
+  DCHECK_LE(diff, kErrorThreshold)
+      << "MemorySetting " << setting_name << " did not change it's memory by "
+      << "the expected value.\n"
+      << "  Expected Change: " << (constraining_value * 100) << "%\n"
+      << "  Actual Change: " << (diff * 100) << "%\n"
+      << "  Original memory consumption (bytes): " << old_memory_consumption
+      << "  New memory consumption (bytes):      " << new_memory_consumption
+      << "\n";
+}
+
+void ConstrainToMemoryLimit(int64_t memory_limit,
+                            std::vector<MemorySetting*>* memory_settings) {
+  if (memory_settings->empty()) {
+    return;
+  }
+
+  // If the memory consumed is already under the memory limit then no further
+  // work needs to be done.
+  if (SumMemoryConsumption(1.0, *memory_settings, NULL) <= memory_limit) {
+    return;
+  }
+
+  // Iterate by small steps the constraining value from 1.0 (100%) toward
+  // 0.0.
+  static const double kStep = 0.0001;  // .01% change per iteration.
+  std::vector<double> constrained_sizes;
+  // 1-1 mapping.
+  constrained_sizes.resize(memory_settings->size());
+  for (double global_constraining_factor = 1.0;
+       global_constraining_factor >= 0.0;
+       global_constraining_factor -= kStep) {
+    global_constraining_factor = std::max(0.0, global_constraining_factor);
+    const int64_t new_global_memory_consumption =
+        SumMemoryConsumption(global_constraining_factor, *memory_settings,
+                             &constrained_sizes);
+
+    const bool finished =
+        (global_constraining_factor == 0.0) ||
+        (new_global_memory_consumption <= memory_limit);
+
+    if (finished) {
+      break;
+    }
+  }
+  DCHECK_EQ(memory_settings->size(), constrained_sizes.size());
+  for (size_t i = 0; i < memory_settings->size(); ++i) {
+    const double local_constraining_factor = constrained_sizes[i];
+    MemorySetting* setting = memory_settings->at(i);
+    if (local_constraining_factor != 1.0) {
+      const int64_t old_memory_consumption = setting->MemoryConsumption();
+      DCHECK_EQ(setting->source_type(), MemorySetting::kAutoSet);
+      setting->ScaleMemory(local_constraining_factor);
+      const int64_t new_memory_consumption = setting->MemoryConsumption();
+
+      // If the memory doesn't actually change as predicted by the constraining
+      // value then this check will catch it here.
+      CheckMemoryChange(setting->name(),
+                        old_memory_consumption, new_memory_consumption,
+                        local_constraining_factor);
+    }
+  }
+}
+
+}  // namespace.
+
+void ConstrainToMemoryLimits(
+    const int64_t& max_cpu_memory,
+    const base::optional<int64_t>& max_gpu_memory,
+    std::vector<MemorySetting*>* memory_settings,
+    std::vector<std::string>* error_msgs) {
+
+  // Some platforms may just return 0 for the max_cpu memory, in this case
+  // we don't want to constrain the memory.
+  if (max_cpu_memory > 0) {
+    std::vector<MemorySetting*> cpu_memory_settings =
+        FilterSettings(MemorySetting::kCPU, *memory_settings);
+    ConstrainToMemoryLimit(max_cpu_memory, &cpu_memory_settings);
+  } else {
+    error_msgs->push_back(
+        "ERROR - COULD NOT CONSTRAIN CPU MEMORY "
+        "BECAUSE max_cobalt_cpu_usage WAS 0.");
+  }
+
+  // Some platforms may just return 0 for the max_gpu memory, in this case
+  // we don't want to constrain the memory.
+  if (max_gpu_memory) {
+    if (*max_gpu_memory > 0) {
+      std::vector<MemorySetting*> gpu_memory_settings =
+          FilterSettings(MemorySetting::kGPU, *memory_settings);
+      ConstrainToMemoryLimit(*max_gpu_memory, &gpu_memory_settings);
+    } else {
+      error_msgs->push_back(
+          "ERROR - COULD NOT CONSTRAIN GPU MEMORY "
+          "BECAUSE max_cobalt_gpu_usage WAS 0.");
+    }
+  }
+}
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/constrainer.h b/src/cobalt/browser/memory_settings/constrainer.h
new file mode 100644
index 0000000..3c22193
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/constrainer.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2017 Google Inc. 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_BROWSER_MEMORY_SETTINGS_CONSTRAINER_H_
+#define COBALT_BROWSER_MEMORY_SETTINGS_CONSTRAINER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/optional.h"
+#include "cobalt/browser/memory_settings/memory_settings.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+// Constrains the memory in the memmory_settings vector so that the target is
+// such that the sum of memory consumption is below max_cpu_memory and
+// max_gpu_memory.
+//
+// How the memory settings will reduce their memory usage is dependent on
+// the ConstrainerFunction they contain. It's possible that the memory
+// settings won't be able to match the target memory.
+//
+// The output variable error_msgs will be populated with any error messages
+// that result from this function call.
+void ConstrainToMemoryLimits(
+    const int64_t& max_cpu_memory,
+    const base::optional<int64_t>& max_gpu_memory,
+    std::vector<MemorySetting*>* memory_settings,
+    std::vector<std::string>* error_msgs);
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
+
+#endif  // COBALT_BROWSER_MEMORY_SETTINGS_CONSTRAINER_H_
diff --git a/src/cobalt/browser/memory_settings/constrainer_test.cc b/src/cobalt/browser/memory_settings/constrainer_test.cc
new file mode 100644
index 0000000..7a5e3d5
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/constrainer_test.cc
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2017 Google Inc. 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.
+ */
+
+#include "base/bind.h"
+#include "base/callback.h"
+#include "cobalt/browser/memory_settings/constrainer.h"
+#include "cobalt/browser/memory_settings/memory_settings.h"
+#include "cobalt/browser/memory_settings/test_common.h"
+#include "starboard/configuration.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+namespace {
+const int64_t kOneMegabyte = 1 * 1024 * 1024;
+const int64_t kTwoMegabytes = 2 * 1024 * 1024;
+const int64_t kFiveMegabytes = 5 * 1024 * 1024;
+const base::optional<int64_t> kNoGpuMemory;
+
+ScalingFunction MakeLinearConstrainer() {
+  // Linearly scale, but clamp between 0 and 1.
+  return MakeLinearMemoryScaler(0.0, 1.0);
+}
+
+}  // namespace.
+
+// Tests the expectation that given one IntSetting which occupies 2MB of
+// the available memory, and max_cpu_setting of 1MB, that
+// ConstrainToMemoryLimits() function will reduce the memory setting
+// down 1MB.
+TEST(ConstrainToMemoryLimits, ConstrainCpuMemoryWithOneSetting) {
+  IntSetting int_setting("dummy_cpu_setting");
+  int_setting.set_memory_type(MemorySetting::kCPU);
+  int_setting.set_value(MemorySetting::kAutoSet, kTwoMegabytes);
+
+  ScalingFunction constrainer(MakeLinearConstrainer());
+
+  int_setting.set_memory_scaling_function(constrainer);
+
+  std::vector<MemorySetting*> settings;
+  settings.push_back(&int_setting);
+
+  std::vector<std::string> error_msgs;
+
+  // Will reduce the memory usage of the IntSetting.
+  ConstrainToMemoryLimits(kOneMegabyte, kNoGpuMemory, &settings, &error_msgs);
+  EXPECT_EQ(kOneMegabyte, int_setting.MemoryConsumption());
+  EXPECT_TRUE(error_msgs.empty());
+}
+
+// Tests the expectation that given two IntSettings, one that was AutoSet and
+// one that was set by the command line and one set by the build system, that
+// only the AutoSet IntSetting will be constrained.
+TEST(ConstrainToMemoryLimits, ConstrainerIgnoresNonAutosetVariables) {
+  IntSetting int_setting_autoset("autoset_cpu_setting");
+  int_setting_autoset.set_memory_type(MemorySetting::kCPU);
+  int_setting_autoset.set_value(MemorySetting::kAutoSet, kTwoMegabytes);
+  int_setting_autoset.set_memory_scaling_function(MakeLinearConstrainer());
+
+  IntSetting int_setting_cmdline("cmdline_cpu_setting");
+  int_setting_cmdline.set_memory_type(MemorySetting::kCPU);
+  int_setting_cmdline.set_value(MemorySetting::kCmdLine, kTwoMegabytes);
+  int_setting_cmdline.set_memory_scaling_function(MakeLinearConstrainer());
+
+  IntSetting int_setting_builtin("builtin_cpu_setting");
+  int_setting_builtin.set_memory_type(MemorySetting::kCPU);
+  int_setting_builtin.set_value(MemorySetting::kBuildSetting, kTwoMegabytes);
+  int_setting_builtin.set_memory_scaling_function(MakeLinearConstrainer());
+
+  std::vector<MemorySetting*> settings;
+  settings.push_back(&int_setting_autoset);
+  settings.push_back(&int_setting_cmdline);
+  settings.push_back(&int_setting_builtin);
+
+  std::vector<std::string> error_msgs;
+
+  // Right now we need to shave off 1MB, but this can only come from the
+  // MemorySetting that was autoset.
+  ConstrainToMemoryLimits(kFiveMegabytes, kNoGpuMemory, &settings,
+                          &error_msgs);
+
+  EXPECT_EQ(kOneMegabyte, int_setting_autoset.MemoryConsumption());
+  EXPECT_EQ(kTwoMegabytes, int_setting_cmdline.MemoryConsumption());
+  EXPECT_EQ(kTwoMegabytes, int_setting_builtin.MemoryConsumption());
+
+  EXPECT_TRUE(error_msgs.empty());
+}
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/memory_settings.cc b/src/cobalt/browser/memory_settings/memory_settings.cc
index b71735b..5da12a6 100644
--- a/src/cobalt/browser/memory_settings/memory_settings.cc
+++ b/src/cobalt/browser/memory_settings/memory_settings.cc
@@ -20,6 +20,7 @@
 #include <string>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/compiler_specific.h"
 #include "base/logging.h"
 #include "base/string_number_conversions.h"
@@ -28,6 +29,7 @@
 #include "cobalt/browser/memory_settings/build_settings.h"
 #include "cobalt/browser/memory_settings/constants.h"
 #include "cobalt/browser/switches.h"
+#include "cobalt/math/linear_interpolator.h"
 #include "nb/lexical_cast.h"
 
 namespace cobalt {
@@ -43,8 +45,12 @@
   int value_;
   bool error_;  // true if there was a parse error.
 };
+
 // Parses a string like "1234x5678" to vector of parsed int values.
-std::vector<ParsedIntValue> ParseDimensions(const std::string& value_str) {
+std::vector<ParsedIntValue> ParseDimensions(const std::string& input) {
+  std::string value_str = input;
+  std::transform(value_str.begin(), value_str.end(),
+                 value_str.begin(), ::tolower);
   std::vector<ParsedIntValue> output;
 
   std::vector<std::string> lengths;
@@ -58,8 +64,57 @@
   return output;
 }
 
+bool StringEndsWith(const std::string& value, const std::string& ending) {
+  if (ending.size() > value.size()) {
+    return false;
+  }
+  // Reverse search through the back of the string.
+  return std::equal(ending.rbegin(), ending.rend(), value.rbegin());
+}
+
+// Handles bytes: "12435"
+// Handles kilobytes: "128KB"
+// Handles megabytes: "64MB"
+// Handles gigabytes: "1GB"
+// Handles fractional units for kilo/mega/gigabytes
+int64_t ParseMemoryValue(const std::string& value, bool* parse_ok) {
+  // nb::lexical_cast<> will parse out the number but it will ignore the
+  // unit part, such as "kb" or "mb".
+  double numerical_value = nb::lexical_cast<double>(value, parse_ok);
+  if (!(*parse_ok)) {
+    return static_cast<int64_t>(numerical_value);
+  }
+
+  // Lowercasing the string makes the units easier to detect.
+  std::string value_lower_case = value;
+  std::transform(value_lower_case.begin(), value_lower_case.end(),
+                 value_lower_case.begin(),
+                 ::tolower);
+
+  if (StringEndsWith(value_lower_case, "kb")) {
+    numerical_value *= 1024;  // convert kb -> bytes.
+  } else if (StringEndsWith(value_lower_case, "mb")) {
+    numerical_value *= 1024 * 1024;  // convert mb -> bytes.
+  } else if (StringEndsWith(value_lower_case, "gb")) {
+    numerical_value *= 1024 * 1024 * 1024;  // convert gb -> bytes.
+  }
+  return static_cast<int64_t>(numerical_value);
+}
 }  // namespace
 
+void MemorySetting::set_memory_scaling_function(ScalingFunction function) {
+  memory_scaling_function_ = function;
+}
+
+double MemorySetting::ComputeAbsoluteMemoryScale(
+    double requested_memory_scale) const {
+  if (memory_scaling_function_.is_null()) {
+    return 1.0;
+  } else {
+    return memory_scaling_function_.Run(requested_memory_scale);
+  }
+}
+
 MemorySetting::MemorySetting(ClassType type, const std::string& name)
     : class_type_(type),
       name_(name),
@@ -77,10 +132,18 @@
 
 int64_t IntSetting::MemoryConsumption() const { return value(); }
 
+void IntSetting::ScaleMemory(double memory_scale) {
+  DCHECK_LE(0.0, memory_scale);
+  DCHECK_LE(memory_scale, 1.0);
+
+  const int64_t new_value = static_cast<int64_t>(value() * memory_scale);
+  set_value(MemorySetting::kAutosetConstrained, new_value);
+}
+
 bool IntSetting::TryParseValue(SourceType source_type,
                                const std::string& string_value) {
   bool parse_ok = false;
-  int64_t int_value = nb::lexical_cast<int64_t>(string_value, &parse_ok);
+  int64_t int_value = ParseMemoryValue(string_value, &parse_ok);
 
   if (parse_ok) {
     set_value(source_type, int_value);
@@ -133,6 +196,87 @@
   return true;
 }
 
+SkiaGlyphAtlasTextureSetting::SkiaGlyphAtlasTextureSetting()
+    : DimensionSetting(switches::kSkiaTextureAtlasDimensions) {
+  set_memory_scaling_function(MakeSkiaGlyphAtlasMemoryScaler());
+}
+
+void SkiaGlyphAtlasTextureSetting::ScaleMemory(double memory_scale) {
+  DCHECK_LE(0.0, memory_scale);
+  DCHECK_LE(memory_scale, 1.0);
+
+  if (!valid()) {
+    return;
+  }
+  const size_t number_of_reductions = NumberOfReductions(memory_scale);
+  if (number_of_reductions == 0) {
+    return;
+  }
+
+  TextureDimensions texture_dims = value();
+  DCHECK_LT(0, texture_dims.width());
+  DCHECK_LT(0, texture_dims.height());
+
+  for (size_t i = 0; i < number_of_reductions; ++i) {
+    if (texture_dims.width() <= 1 && texture_dims.height() <=1) {
+      break;
+    }
+    if (texture_dims.width() > texture_dims.height()) {
+      texture_dims.set_width(texture_dims.width() / 2);
+    } else {
+      texture_dims.set_height(texture_dims.height() / 2);
+    }
+  }
+
+  set_value(MemorySetting::kAutosetConstrained, texture_dims);
+}
+
+size_t SkiaGlyphAtlasTextureSetting::NumberOfReductions(
+    double reduction_factor) {
+  size_t num_of_reductions = 0;
+  while (reduction_factor <= 0.5f) {
+    ++num_of_reductions;
+    reduction_factor *= 2.0;
+  }
+  return num_of_reductions;
+}
+
+JavaScriptGcThresholdSetting::JavaScriptGcThresholdSetting()
+    : IntSetting(switches::kJavaScriptGcThresholdInBytes) {
+}
+
+void JavaScriptGcThresholdSetting::PostInit() {
+  const int64_t normal_memory_consumption = MemoryConsumption();
+  const int64_t min_memory_consumption =
+      std::min<int64_t>(normal_memory_consumption, 1 * 1024 * 1024);
+
+  ScalingFunction function =
+      MakeJavaScriptGCScaler(min_memory_consumption,
+                             normal_memory_consumption);
+  set_memory_scaling_function(function);
+}
+
+int64_t SumMemoryConsumption(
+    base::optional<MemorySetting::MemoryType> memory_type_filter,
+    const std::vector<const MemorySetting*>& memory_settings) {
+  int64_t sum = 0;
+  for (size_t i = 0; i < memory_settings.size(); ++i) {
+    const MemorySetting* setting = memory_settings[i];
+    if (!memory_type_filter || memory_type_filter == setting->memory_type()) {
+      sum += setting->MemoryConsumption();
+    }
+  }
+  return sum;
+}
+
+int64_t SumMemoryConsumption(
+    base::optional<MemorySetting::MemoryType> memory_type_filter,
+    const std::vector<MemorySetting*>& memory_settings) {
+  const std::vector<const MemorySetting*> const_vector(
+      memory_settings.begin(), memory_settings.end());
+  return SumMemoryConsumption(memory_type_filter, const_vector);
+}
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/memory_settings.h b/src/cobalt/browser/memory_settings/memory_settings.h
index 6d27358..2635c99 100644
--- a/src/cobalt/browser/memory_settings/memory_settings.h
+++ b/src/cobalt/browser/memory_settings/memory_settings.h
@@ -19,9 +19,13 @@
 
 #include <map>
 #include <string>
+#include <vector>
 
+#include "base/callback.h"
 #include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
 #include "base/optional.h"
+#include "cobalt/browser/memory_settings/scaling_function.h"
 #include "cobalt/browser/memory_settings/texture_dimensions.h"
 #include "cobalt/math/size.h"
 #include "starboard/configuration.h"
@@ -39,28 +43,54 @@
   // SourceType defines the location where the setting was set from.
   // kNotApplicable means the setting is not supported on the current system
   // configuration.
-  enum SourceType { kUnset, kStarboardAPI, kBuildSetting, kCmdLine, kAutoSet };
+  enum SourceType { kUnset, kStarboardAPI, kBuildSetting, kCmdLine, kAutoSet,
+                    kAutosetConstrained };
   enum ClassType { kInt, kDimensions };
   enum MemoryType { kCPU, kGPU, kNotApplicable };
 
+  // Stringify's the value of this memory setting.
   virtual std::string ValueToString() const = 0;
   // Returns true if the TryParseValue() succeeded when converting the string
   // into the internal value. If false, then the object should not be changed.
   virtual bool TryParseValue(SourceType source_type,
                              const std::string& string_value) = 0;
 
+  // Returns the memory consumption (in bytes) that the memory setting will
+  // be allocated.
   virtual int64_t MemoryConsumption() const = 0;
 
+  // Sets the memory scaling function. This will control whether this
+  // MemorySetting will allow it's memory to be adjusted. If this is not
+  // set then ComputeAbsoluteMemoryScale(...) will return 1.0 for all inputs
+  // values, indicating that it can't be adjusted.
+  void set_memory_scaling_function(ScalingFunction function);
+
+  // Computes the absolute memory scale value from the requested_memory_scale.
+  // The absolute memory scale can be multiplied against MemoryConsumption()
+  // to predict the new memory consumption. This prediction should match the
+  // actual memory consumption after ScaleMemory(memory_scale) is called.
+  double ComputeAbsoluteMemoryScale(double requested_memory_scale) const;
+
+  // Adjusts the memory by the percentage passed in. Note that the base value
+  // is adjusted and repeatedly calling this function will repeatedly adjust
+  // this value. For example, calling AdjustMemory(.5) twice will reduce the
+  // memory by 25%.
+  //
+  // Calling this function will automatically set the source_type to
+  // kAutosetConstrained.
+  //
+  // Note that the expectation here is that the memory scale passed in was
+  // generated from ComputeAbsoluteMemoryScale().
+  virtual void ScaleMemory(double memory_scale) = 0;
+
   // Setting kNotApplicable will invalidate the MemorySetting.
   void set_memory_type(MemoryType memory_type) { memory_type_ = memory_type; }
-
   const std::string& name() const { return name_; }
   SourceType source_type() const { return source_type_; }
   ClassType class_type() const { return class_type_; }
   MemoryType memory_type() const { return memory_type_; }
 
   bool valid() const { return kNotApplicable != memory_type_; }
-
  protected:
   MemorySetting(ClassType type, const std::string& name);
 
@@ -68,6 +98,7 @@
   const std::string name_;
   SourceType source_type_;
   MemoryType memory_type_;  // Defaults to kCPU.
+  ScalingFunction memory_scaling_function_;
 
  private:
   // Default constructor for MemorySetting is forbidden. Do not use it.
@@ -82,6 +113,7 @@
 
   std::string ValueToString() const OVERRIDE;
   virtual int64_t MemoryConsumption() const OVERRIDE;
+  virtual void ScaleMemory(double absolute_constraining_value) OVERRIDE;
 
   int64_t value() const { return valid() ? value_ : 0; }
   base::optional<int64_t> optional_value() const {
@@ -95,7 +127,6 @@
   }
   bool TryParseValue(SourceType source_type,
                      const std::string& string_value) OVERRIDE;
-
  private:
   int64_t value_;
 
@@ -133,6 +164,29 @@
   SB_DISALLOW_COPY_AND_ASSIGN(DimensionSetting);
 };
 
+class SkiaGlyphAtlasTextureSetting : public DimensionSetting {
+ public:
+  SkiaGlyphAtlasTextureSetting();
+  virtual void ScaleMemory(double absolute_constraining_value) OVERRIDE;
+
+ private:
+  static size_t NumberOfReductions(double reduction_factor);
+};
+
+class JavaScriptGcThresholdSetting : public IntSetting {
+ public:
+  JavaScriptGcThresholdSetting();
+  void PostInit();
+};
+
+int64_t SumMemoryConsumption(
+    base::optional<MemorySetting::MemoryType> memory_type_filter,
+    const std::vector<const MemorySetting*>& memory_settings);
+
+int64_t SumMemoryConsumption(
+    base::optional<MemorySetting::MemoryType> memory_type_filter,
+    const std::vector<MemorySetting*>& memory_settings);
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/memory_settings_test.cc b/src/cobalt/browser/memory_settings/memory_settings_test.cc
index 956965f..2ca54ea 100644
--- a/src/cobalt/browser/memory_settings/memory_settings_test.cc
+++ b/src/cobalt/browser/memory_settings/memory_settings_test.cc
@@ -28,6 +28,13 @@
 namespace cobalt {
 namespace browser {
 namespace memory_settings {
+namespace {
+int64_t TestIntSettingParse(const std::string& value) {
+  IntSetting int_setting("dummy");
+  EXPECT_TRUE(int_setting.TryParseValue(MemorySetting::kCmdLine, value));
+  return int_setting.value();
+}
+}  // namespace
 
 TEST(IntSetting, ParseFromString) {
   scoped_ptr<IntSetting> int_setting(new IntSetting("dummy"));
@@ -38,8 +45,50 @@
   EXPECT_EQ(std::string("123"), int_setting->ValueToString());
 }
 
+// Tests the expectation that numerous string variations (whole numbers vs
+// fractions vs units) parse correctly.
+TEST(IntSetting, ParseFromStrings) {
+  // Bytes.
+  EXPECT_EQ(1, TestIntSettingParse("1"));
+  EXPECT_EQ(1, TestIntSettingParse("1B"));
+  EXPECT_EQ(1, TestIntSettingParse("1b"));
+  EXPECT_EQ(1, TestIntSettingParse("1B"));
+  EXPECT_EQ(1, TestIntSettingParse("1b"));
+
+  // Kilobytes and fractional amounts.
+  EXPECT_EQ(1024, TestIntSettingParse("1KB"));
+  EXPECT_EQ(1024, TestIntSettingParse("1Kb"));
+  EXPECT_EQ(1024, TestIntSettingParse("1kB"));
+  EXPECT_EQ(1024, TestIntSettingParse("1kb"));
+
+  EXPECT_EQ(512, TestIntSettingParse(".5kb"));
+  EXPECT_EQ(512, TestIntSettingParse("0.5kb"));
+  EXPECT_EQ(1536, TestIntSettingParse("1.5kb"));
+  EXPECT_EQ(1536, TestIntSettingParse("1.50kb"));
+
+  // Megabytes and fractional amounts.
+  EXPECT_EQ(1024*1024, TestIntSettingParse("1MB"));
+  EXPECT_EQ(1024*1024, TestIntSettingParse("1Mb"));
+  EXPECT_EQ(1024*1024, TestIntSettingParse("1mB"));
+  EXPECT_EQ(1024*1024, TestIntSettingParse("1mb"));
+
+  EXPECT_EQ(512*1024, TestIntSettingParse(".5mb"));
+  EXPECT_EQ(512*1024, TestIntSettingParse("0.5mb"));
+  EXPECT_EQ(1536*1024, TestIntSettingParse("1.5mb"));
+  EXPECT_EQ(1536*1024, TestIntSettingParse("1.50mb"));
+
+  // Gigabytes and fractional amounts.
+  EXPECT_EQ(1024*1024*1024, TestIntSettingParse("1GB"));
+  EXPECT_EQ(1024*1024*1024, TestIntSettingParse("1Gb"));
+  EXPECT_EQ(1024*1024*1024, TestIntSettingParse("1gB"));
+  EXPECT_EQ(1024*1024*1024, TestIntSettingParse("1gb"));
+
+  EXPECT_EQ(512*1024*1024, TestIntSettingParse(".5gb"));
+  EXPECT_EQ(1536*1024*1024, TestIntSettingParse("1.50gb"));
+}
+
 TEST(DimensionSetting, ParseFromString) {
-  scoped_ptr<DimensionSetting> rect_setting(new DimensionSetting("dummy"));
+  scoped_ptr<DimensionSetting> rect_setting(new TestDimensionSetting("dummy"));
   ASSERT_TRUE(
       rect_setting->TryParseValue(MemorySetting::kCmdLine, "1234x5678"));
   EXPECT_EQ(TextureDimensions(1234, 5678, 2), rect_setting->value());
@@ -47,8 +96,17 @@
   EXPECT_EQ(std::string("1234x5678x2"), rect_setting->ValueToString());
 }
 
+TEST(DimensionSetting, ParseFromStringCaseInsensitive) {
+  scoped_ptr<DimensionSetting> rect_setting(new TestDimensionSetting("dummy"));
+  ASSERT_TRUE(
+      rect_setting->TryParseValue(MemorySetting::kCmdLine, "1234X5678"));
+  EXPECT_EQ(TextureDimensions(1234, 5678, 2), rect_setting->value());
+  EXPECT_EQ(MemorySetting::kCmdLine, rect_setting->source_type());
+  EXPECT_EQ(std::string("1234x5678x2"), rect_setting->ValueToString());
+}
+
 TEST(DimensionSetting, ParseFromStringWithBytesPerPixel) {
-  scoped_ptr<DimensionSetting> rect_setting(new DimensionSetting("dummy"));
+  scoped_ptr<DimensionSetting> rect_setting(new TestDimensionSetting("dummy"));
   ASSERT_TRUE(
       rect_setting->TryParseValue(MemorySetting::kCmdLine, "1234x5678x12"));
   EXPECT_EQ(TextureDimensions(1234, 5678, 12), rect_setting->value());
diff --git a/src/cobalt/browser/memory_settings/pretty_print.cc b/src/cobalt/browser/memory_settings/pretty_print.cc
index c8fef61..41c278c 100644
--- a/src/cobalt/browser/memory_settings/pretty_print.cc
+++ b/src/cobalt/browser/memory_settings/pretty_print.cc
@@ -20,6 +20,7 @@
 #include <string>
 #include <vector>
 
+#include "base/string_split.h"
 #include "cobalt/browser/memory_settings/memory_settings.h"
 #include "cobalt/browser/memory_settings/table_printer.h"
 #include "starboard/log.h"
@@ -30,36 +31,8 @@
 namespace memory_settings {
 namespace {
 
-std::string StringifySourceType(const MemorySetting* setting) {
-  if (!setting->valid()) {
-    return "N/A";
-  }
-
-  switch (setting->source_type()) {
-    case MemorySetting::kUnset: {
-      return "Unset";
-    }
-    case MemorySetting::kStarboardAPI: {
-      return "Starboard API";
-    }
-    case MemorySetting::kBuildSetting: {
-      return "Build";
-    }
-    case MemorySetting::kCmdLine: {
-      return "CmdLine";
-    }
-    case MemorySetting::kAutoSet: {
-      return "AutoSet";
-    }
-  }
-
-  SB_NOTIMPLEMENTED() << "Unimplemented string for type: "
-                      << setting->source_type();
-  return "UNKNOWN";
-}
-
-std::string StringifyMemoryType(const MemorySetting* setting) {
-  switch (setting->memory_type()) {
+std::string StringifyMemoryType(const MemorySetting& setting) {
+  switch (setting.memory_type()) {
     case MemorySetting::kCPU: {
       return "CPU";
     }
@@ -72,7 +45,7 @@
   }
 
   SB_NOTIMPLEMENTED() << "Unimplemented string for memory type: "
-                      << setting->memory_type();
+                      << setting.memory_type();
   return "UNKNOWN";
 }
 
@@ -83,21 +56,21 @@
   return setting->ValueToString();
 }
 
-std::string ToMegabyteString(int64_t bytes) {
-  float megabytes = bytes / (1024.0f * 1024.0f);
-
-  char buff[128];
-  SbStringFormatF(buff, sizeof(buff), "%.1f MB", megabytes);
-  // Use 16
-  return std::string(buff);
+void FillStream(size_t count, const char fill_ch, std::stringstream* ss) {
+  for (size_t i = 0; i < count; ++i) {
+    (*ss) << fill_ch;
+  }
 }
 
 }  // namespace
 
 std::string GeneratePrettyPrintTable(
+    bool use_color_ascii,
     const std::vector<const MemorySetting*>& settings) {
   TablePrinter printer;
-
+  if (use_color_ascii) {
+    printer.set_text_color(TablePrinter::kGreen);
+  }
   std::vector<std::string> header;
   header.push_back("SETTING NAME");
   header.push_back("VALUE");
@@ -113,12 +86,12 @@
     row.push_back(setting->name());
     row.push_back(StringifyValue(setting));
     if (setting->valid()) {
-      row.push_back(ToMegabyteString(setting->MemoryConsumption()));
+      row.push_back(ToMegabyteString(setting->MemoryConsumption(), 1));
     } else {
       row.push_back("N/A");
     }
-    row.push_back(StringifyMemoryType(setting));
-    row.push_back(StringifySourceType(setting));
+    row.push_back(StringifyMemoryType(*setting));
+    row.push_back(StringifySourceType(*setting));
     printer.AddRow(row);
   }
 
@@ -126,11 +99,15 @@
   return table_string;
 }
 
-std::string GenerateMemoryTable(const IntSetting& total_cpu_memory,
+std::string GenerateMemoryTable(bool use_color_ascii,
+                                const IntSetting& total_cpu_memory,
                                 const IntSetting& total_gpu_memory,
                                 int64_t settings_cpu_consumption,
                                 int64_t settings_gpu_consumption) {
   TablePrinter printer;
+  if (use_color_ascii) {
+    printer.set_text_color(TablePrinter::kGreen);
+  }
   std::vector<std::string> header;
   header.push_back("MEMORY");
   header.push_back("SOURCE");
@@ -140,29 +117,102 @@
 
   std::vector<std::string> data_row;
   data_row.push_back(total_cpu_memory.name());
-  data_row.push_back(StringifySourceType(&total_cpu_memory));
-  data_row.push_back(ToMegabyteString(total_cpu_memory.value()));
-  data_row.push_back(ToMegabyteString(settings_cpu_consumption));
+  data_row.push_back(StringifySourceType(total_cpu_memory));
+  data_row.push_back(ToMegabyteString(total_cpu_memory.value(), 1));
+  data_row.push_back(ToMegabyteString(settings_cpu_consumption, 1));
   printer.AddRow(data_row);
   data_row.clear();
 
   data_row.push_back(total_gpu_memory.name());
-  data_row.push_back(StringifySourceType(&total_gpu_memory));
+  data_row.push_back(StringifySourceType(total_gpu_memory));
   std::string total_gpu_consumption_str;
-  if (total_gpu_memory.value() <= 0) {
+
+  const bool available_gpu_settings_invalid = (total_gpu_memory.value() <= 0);
+
+  if (available_gpu_settings_invalid) {
     total_gpu_consumption_str = "<UNKNOWN>";
   } else {
-    total_gpu_consumption_str = ToMegabyteString(total_gpu_memory.value());
+    total_gpu_consumption_str = ToMegabyteString(total_gpu_memory.value(), 1);
   }
 
   data_row.push_back(total_gpu_consumption_str);
-  data_row.push_back(ToMegabyteString(settings_gpu_consumption));
+  data_row.push_back(ToMegabyteString(settings_gpu_consumption, 1));
   printer.AddRow(data_row);
   data_row.clear();
-
   return printer.ToString();
 }
 
+std::string ToMegabyteString(int64_t bytes, int decimal_places) {
+  float megabytes = bytes / (1024.0f * 1024.0f);
+
+  std::stringstream ss_fmt;
+  // e.g. "%.1f MB"
+  ss_fmt << "%." << decimal_places << "f MB";
+
+  char buff[128];
+  SbStringFormatF(buff, sizeof(buff), ss_fmt.str().c_str(), megabytes);
+  // Use 16
+  return std::string(buff);
+}
+
+std::string MakeBorder(const std::string& body, const char border_ch) {
+  std::vector<std::string> lines;
+  base::SplitStringDontTrim(body, '\n', &lines);
+
+  size_t max_span = 0;
+  for (size_t i = 0; i < lines.size(); ++i) {
+    max_span = std::max(max_span, lines[i].size());
+  }
+
+  std::stringstream ss;
+  ss << "\n\n";
+
+  FillStream(max_span + 4, border_ch, &ss);
+  ss << "\n";
+  for (size_t i = 0; i < lines.size(); ++i) {
+    const std::string& line = lines[i];
+
+    ss << border_ch << ' ' << line;
+    FillStream(max_span - line.size() + 1, ' ', &ss);
+    ss << border_ch;
+    ss << "\n";
+  }
+  FillStream(max_span + 4, border_ch, &ss);
+  ss << "\n\n";
+  return ss.str();
+}
+
+std::string StringifySourceType(const MemorySetting& setting) {
+  if (!setting.valid()) {
+    return "N/A";
+  }
+
+  switch (setting.source_type()) {
+    case MemorySetting::kUnset: {
+      return "Unset";
+    }
+    case MemorySetting::kStarboardAPI: {
+      return "Starboard API";
+    }
+    case MemorySetting::kBuildSetting: {
+      return "Build";
+    }
+    case MemorySetting::kCmdLine: {
+      return "CmdLine";
+    }
+    case MemorySetting::kAutoSet: {
+      return "AutoSet";
+    }
+    case MemorySetting::kAutosetConstrained: {
+      return "AutoSet (Constrained)";
+    }
+  }
+
+  SB_NOTIMPLEMENTED() << "Unimplemented string for type: "
+                      << setting.source_type();
+  return "UNKNOWN";
+}
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/pretty_print.h b/src/cobalt/browser/memory_settings/pretty_print.h
index 1960e75..de355c2 100644
--- a/src/cobalt/browser/memory_settings/pretty_print.h
+++ b/src/cobalt/browser/memory_settings/pretty_print.h
@@ -50,6 +50,7 @@
 //  | software_surface_cache_size_in_bytes |         N/A |     N/A |  N/A |     N/A |
 //  |______________________________________|_____________|_________|______|_________|
 std::string GeneratePrettyPrintTable(
+    bool use_color_ascii,
     const std::vector<const MemorySetting*>& memory_settings);
 
 // Generates a table, ie:
@@ -64,11 +65,29 @@
 //  |______|__________|__________|
 // When optional total_gpu_memory is null then the the value in the output
 // table will be <UNKNOWN>.
-std::string GenerateMemoryTable(const IntSetting& total_cpu_memory,
+std::string GenerateMemoryTable(bool use_color_ascii,
+                                const IntSetting& total_cpu_memory,
                                 const IntSetting& total_gpu_memory,
                                 int64_t settings_cpu_consumption,
                                 int64_t settings_gpu_consumption);
 
+// Example:
+//   ToMegabyteString(1 * 1024 * 1024, 1)
+// Returns: "1.0MB".
+std::string ToMegabyteString(int64_t bytes, int decimal_places);
+
+// Takes in a body such as "aaaabbbb" and generates a border around it:
+// MakeBoarder("aaaabbbb", '*')
+// Returns:
+//   ************
+//   * aaaabbbb *
+//   ************
+// Works with multiple lines.
+std::string MakeBorder(const std::string& body, const char border_ch);
+
+// Stringify's the MemorySetting::source_type() to a readable string value.
+std::string StringifySourceType(const MemorySetting& setting);
+
 }  // namespace memory_settings
 }  // namespace browser
 }  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/pretty_print_test.cc b/src/cobalt/browser/memory_settings/pretty_print_test.cc
index f0bffb5..7f3db73 100644
--- a/src/cobalt/browser/memory_settings/pretty_print_test.cc
+++ b/src/cobalt/browser/memory_settings/pretty_print_test.cc
@@ -26,6 +26,7 @@
 #include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "cobalt/browser/memory_settings/memory_settings.h"
+#include "cobalt/browser/memory_settings/test_common.h"
 #include "cobalt/browser/switches.h"
 #include "starboard/log.h"
 #include "starboard/memory.h"
@@ -37,93 +38,11 @@
 namespace browser {
 namespace memory_settings {
 
-class TestSettingGroup {
- public:
-  TestSettingGroup() {}
-
-  void LoadDefault() {
-    MakeSetting(MemorySetting::kInt, MemorySetting::kCmdLine,
-                MemorySetting::kGPU, switches::kImageCacheSizeInBytes, "1234");
-
-    MakeSetting(MemorySetting::kInt, MemorySetting::kAutoSet,
-                MemorySetting::kCPU, switches::kJavaScriptGcThresholdInBytes,
-                "1112");
-
-    MakeSetting(MemorySetting::kDimensions, MemorySetting::kCmdLine,
-                MemorySetting::kGPU, switches::kSkiaTextureAtlasDimensions,
-                "1234x4567");
-
-    MakeSetting(MemorySetting::kInt, MemorySetting::kCmdLine,
-                MemorySetting::kGPU, switches::kSkiaCacheSizeInBytes,
-                "12345678");
-
-    MakeSetting(MemorySetting::kInt, MemorySetting::kBuildSetting,
-                MemorySetting::kNotApplicable,
-                switches::kSoftwareSurfaceCacheSizeInBytes, "8910");
-  }
-
-  ~TestSettingGroup() {
-    for (ConstIter it = map_.begin(); it != map_.end(); ++it) {
-      delete it->second;
-    }
-  }
-
-  // The memory setting is owned internally.
-  void MakeSetting(MemorySetting::ClassType class_type,
-                   MemorySetting::SourceType source_type,
-                   MemorySetting::MemoryType memory_type,
-                   const std::string& name, const std::string& value) {
-   const bool found = (map_.find(name) !=  map_.end());
-
-    ASSERT_FALSE(found);
-    map_[name] =
-        CreateMemorySetting(class_type, source_type, memory_type, name, value);
-  }
-
-  std::vector<const MemorySetting*> AsConstVector() const {
-    std::vector<const MemorySetting*> output;
-    for (ConstIter it = map_.begin(); it != map_.end(); ++it) {
-      output.push_back(it->second);
-    }
-    return output;
-  }
-
- private:
-  static MemorySetting* CreateMemorySetting(
-      MemorySetting::ClassType class_type,
-      MemorySetting::SourceType source_type,
-      MemorySetting::MemoryType memory_type, const std::string& name,
-      const std::string& value) {
-    MemorySetting* memory_setting = NULL;
-    switch (class_type) {
-      case MemorySetting::kInt: {
-        memory_setting = new IntSetting(name);
-        break;
-      }
-      case MemorySetting::kDimensions: {
-        memory_setting = new DimensionSetting(name);
-        break;
-      }
-      default: {
-        EXPECT_TRUE(false) << "Unexpected type " << class_type;
-        memory_setting = new IntSetting(name);
-        break;
-      }
-    }
-    EXPECT_TRUE(memory_setting->TryParseValue(source_type, value));
-    memory_setting->set_memory_type(memory_type);
-    return memory_setting;
-  }
-
-  typedef std::map<std::string, MemorySetting*>::const_iterator ConstIter;
-  std::map<std::string, MemorySetting*> map_;
-};
-
 TEST(MemorySettingsPrettyPrint, GeneratePrettyPrintTable) {
   TestSettingGroup setting_group;
   setting_group.LoadDefault();
   std::string actual_string =
-      GeneratePrettyPrintTable(setting_group.AsConstVector());
+      GeneratePrettyPrintTable(false, setting_group.AsConstVector());
 
   const char* expected_string =
       " SETTING NAME                           VALUE                   TYPE   SOURCE    \n"
@@ -154,7 +73,8 @@
   IntSetting gpu_memory_setting("max_gpu_memory");
 
   std::string actual_output =
-      GenerateMemoryTable(cpu_memory_setting,  // 256 MB CPU available
+      GenerateMemoryTable(false,               // No color.
+                          cpu_memory_setting,  // 256 MB CPU available
                           gpu_memory_setting,
                           128 * 1024 * 1024,  // 128 MB CPU consumption
                           0);                 // 0 MB GPU consumption.
@@ -181,7 +101,8 @@
       MemorySetting::kBuildSetting, 64 * 1024 * 1024);
 
   std::string actual_output =
-      GenerateMemoryTable(cpu_memory_setting,  // 256 MB CPU available.
+      GenerateMemoryTable(false,               // No color.
+                          cpu_memory_setting,  // 256 MB CPU available.
                           gpu_memory_setting,   // 64 MB GPU available.
                           128 * 1024 * 1024,  // 128 MB CPU consumption.
                           23592960);          // 22.5 MB GPU consumption.
@@ -204,6 +125,7 @@
   test_setting_group.LoadDefault();
 
   std::string actual_string = GeneratePrettyPrintTable(
+      false,  // No color.
       test_setting_group.AsConstVector());
 
   const char* expected_string =
@@ -237,6 +159,7 @@
 
   const base::optional<int64_t> no_gpu_memory;
   std::string actual_output = GenerateMemoryTable(
+      false,               // No color.
       cpu_memory_setting,  // 256 MB CPU available.
       gpu_memory_setting,  // Signals that no gpu memory is available
                            //   on this system.
diff --git a/src/cobalt/browser/memory_settings/scaling_function.cc b/src/cobalt/browser/memory_settings/scaling_function.cc
new file mode 100644
index 0000000..81cbb87
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/scaling_function.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017 Google Inc. 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.
+ */
+
+#include "cobalt/browser/memory_settings/scaling_function.h"
+
+#include <algorithm>
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/logging.h"
+#include "cobalt/math/clamp.h"
+#include "cobalt/math/linear_interpolator.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+namespace {
+
+class JavaScriptGCMemoryScaler {
+ public:
+  JavaScriptGCMemoryScaler(int64_t min_memory, int64_t max_memory) {
+    DCHECK_LE(min_memory, max_memory);
+    min_memory = std::min(min_memory, max_memory);
+    const double min_factor = static_cast<double>(min_memory) /
+                              static_cast<double>(max_memory);
+    // From 95% -> 0%, the memory will stay the same. This effectivly
+    // clamps the minimum value.
+    interp_table_.Add(0.0, min_factor);
+
+    // At 95% memory, the memory falls to the min_factor. The rationale here
+    // is that most of the memory for JavaScript can be eliminated without
+    // a large performance penalty, so it's quickly reduced.
+    interp_table_.Add(.95, min_factor);
+
+    // At 100% we have 100% of memory.
+    interp_table_.Add(1.0, 1.0);
+  }
+  double Factor(double requested_memory_scale) const {
+    return interp_table_.Map(requested_memory_scale);
+  }
+
+ private:
+  math::LinearInterpolator<double, double> interp_table_;
+};
+
+double LinearFunctionWithClampValue(double min_clamp_value,
+                                    double max_clamp_value,
+                                    double requested_memory_scale) {
+  return math::Clamp(requested_memory_scale,
+                     min_clamp_value, max_clamp_value);
+}
+
+double SkiaAtlasGlyphTextureConstrainer(double requested_memory_scale) {
+  if (requested_memory_scale > 0.5f) {
+    return 1.0f;
+  } else {
+    return 0.5f;
+  }
+}
+
+}  // namespace.
+
+ScalingFunction MakeLinearMemoryScaler(double min_clamp_value,
+                                       double max_clamp_value) {
+  ScalingFunction function =
+      base::Bind(&LinearFunctionWithClampValue,
+                  min_clamp_value, max_clamp_value);
+  return function;
+}
+
+ScalingFunction MakeJavaScriptGCScaler(
+    int64_t min_consumption, int64_t max_consumption) {
+  JavaScriptGCMemoryScaler* constrainer =
+      new JavaScriptGCMemoryScaler(min_consumption, max_consumption);
+  // Note that Bind() will implicitly ref-count the constrainer pointer.
+  return base::Bind(&JavaScriptGCMemoryScaler::Factor,
+                    base::Owned(constrainer));
+}
+
+ScalingFunction MakeSkiaGlyphAtlasMemoryScaler() {
+  ScalingFunction function = base::Bind(&SkiaAtlasGlyphTextureConstrainer);
+  return function;
+}
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/scaling_function.h b/src/cobalt/browser/memory_settings/scaling_function.h
new file mode 100644
index 0000000..86191e7
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/scaling_function.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright 2017 Google Inc. 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_BROWSER_MEMORY_SETTINGS_SCALING_FUNCTION_H_
+#define COBALT_BROWSER_MEMORY_SETTINGS_SCALING_FUNCTION_H_
+
+#include <algorithm>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/logging.h"
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+typedef base::Callback<double(double)> ScalingFunction;
+
+// The ConstrainerFunction generates constraining values which are used to
+// to adjust the memory settings from an input "requested_memory_scale".
+//
+// "requested_memory_scale" requests memory be scaled by a certain amount
+// percentage where 0.0 means "eliminate all memory please" and 1.0 is
+// "don't change" and 2.0 means "expand your memory consumption by 2x".
+//
+// A ScalingFunction works by remapping the input
+// "requested_memory_scale" value to an output "memory scaling factor" which
+// indicates how much memory will actually be reduced at the current scale.
+// This output ranges from ranges from 1.0 (no scaling - 100% of memory is
+// retained) to 0.0 (all memory is eliminated from this setting).
+//
+// Another way to understand the memory_scale value is by the
+// following analogy:
+//  when (1.0 > input => .9) => "Please reduce memory a little"
+//  when (.9 > input >= .5)  => "Please reduce memory - serious!"
+//  when (.5 > input >= .25) => "Please reduce memory - super serious!!"
+//  when (.25 > input >= .0) => "Please reduce memory - last chances!!!"
+//
+// Similarly:
+//  when (2.0 > input >= 1) => "Please expand memory by a lot.".
+//
+// Output "memory scaling factor" value represents the amount of memory that
+// will be scaled at the current requested_memory_scale value. This
+// "memory scaling factor" is an absolute value, such that 0.5 means that
+// the memory consumption will be reduced by 50%.
+//
+// EXAMPLE:
+//   Function(.9) => Returns => 0.1
+//   Means: "You asked me to reduce memory a little, but I can go ahead and
+//          free up 90% of my memory."
+//
+//   Function(.5) => Returns => 1.0
+//   Means: "You asked me to reduce memory and were serious, but I am refusing
+//          to reduce memory consumption."
+//
+//   Function(.25) => Returns => .9
+//   Means: "You are at the final stages of asking me to reduce memory and
+//          I can go ahead and reduce my memory foot print by 10%."
+//
+// More information:
+//
+// Low Priority Memory Settings should respond quickly to constraining
+// situations by quickly shedding memory:
+//
+//    1 *+--------+---------+---------+---------+--------++
+//      +*        +         +         +         +         +
+//      | *                                               |
+//      |  *                                              |
+//  0.8 ++  *                                            ++
+//      |    *                                            |
+//      |     *                                           |
+//      |      **                                         |
+//  0.6 ++      **     y=x*x*x                           ++
+//      |        **                                       |
+//      |          **                                     |
+//  0.4 ++          **                                   ++
+//      |             **                                  |
+//      |              ***                                |
+//      |                ***                              |
+//  0.2 ++                 ***                           ++
+//      |                     ***                         |
+//      |                        ****                     |
+//      +         +         +        *******    +         +
+//    0 ++--------+---------+---------+----****************
+//      1        0.8       0.6       0.4       0.2        0
+//
+//
+// This is a curve of a high priority setting: one which is resistant to giving
+// up memory.
+//    1 ******----+---------+---------+---------+--------++
+//      +     *********     +         +         +         +
+//      |             ********                            |
+//      |                     *******                     |
+//  0.8 ++                          ******               ++
+//      |               y=sqrt(sqrt(x))  *****            |
+//      |                                    ****         |
+//      |                                        ***      |
+//  0.6 ++                                         ***   ++
+//      |                                            **   |
+//      |                                              ** |
+//  0.4 ++                                              *++
+//      |                                                *|
+//      |                                                *|
+//      |                                                 *
+//  0.2 ++                                               +*
+//      |                                                 *
+//      |                                                 *
+//      +         +         +         +         +         *
+//    0 ++--------+---------+---------+---------+--------+*
+//      1        0.8       0.6       0.4       0.2        0
+//
+// While the following graph will refuse to give up any memory whatsoever.
+// For example.
+//                                 y=1
+//    1.0 *************************************************
+//        +         +        +         +        +       * +
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//    0.5 |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        |                                               |
+//        +         +        +         +        +         +
+//   0.0  ++--------+--------+---------+--------+--------++
+//        1        0.8      0.6       0.4      0.2        0
+//
+
+// Generates a functor that will lower the memory consumption linearly with
+// the progress of the input, but will clamp at the input level.
+// Example:
+//   ConstrainerFunction fun = MakeLinearConstrainerFunction(.75);
+//   EXPECT_EQ(.9, fun(.9));
+//   EXPECT_EQ(.75, fun(.75));
+//   EXPECT_EQ(.75, fun(.5));
+//   EXPECT_EQ(.75, fun(0));
+ScalingFunction MakeLinearMemoryScaler(
+    double min_clamp_value,
+    double max_clamp_value);
+
+// Generates a functor that will shed most of the memory of the JavaScriptGC
+// very quickly.
+ScalingFunction MakeJavaScriptGCScaler(
+    int64_t min_consumption, int64_t max_consumption);
+
+// Generates a functor that will shed 50% of memory when the requested
+// memory scale is .5 or less, otherwise no memory is reduced.
+ScalingFunction MakeSkiaGlyphAtlasMemoryScaler();
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
+
+#endif  // COBALT_BROWSER_MEMORY_SETTINGS_SCALING_FUNCTION_H_
diff --git a/src/cobalt/browser/memory_settings/table_printer.cc b/src/cobalt/browser/memory_settings/table_printer.cc
index ee85579..69b9612 100644
--- a/src/cobalt/browser/memory_settings/table_printer.cc
+++ b/src/cobalt/browser/memory_settings/table_printer.cc
@@ -22,6 +22,7 @@
 #include <string>
 
 #include "base/logging.h"
+#include "starboard/log.h"
 
 namespace cobalt {
 namespace browser {
@@ -58,6 +59,14 @@
   return ss.str();
 }
 
+std::string MakeFill(const char* str, size_t n) {
+  std::stringstream ss;
+  for (size_t i = 0; i < n; ++i) {
+    ss << str;
+  }
+  return ss.str();
+}
+
 class TablePrinterImpl {
  public:
   // First row is the header.
@@ -200,35 +209,41 @@
     }
   }
   ss << " ";
-  std::string output = AddColor(text_color_, ss.str());
-  return output;
+  return ss.str();
 }
 
 std::string TablePrinterImpl::MakeDataRow(const Row& row) const {
-  std::stringstream output_ss;
+  // Safe integer math for creating a fill size. Because this size is based on
+  // subtraction of size_t values, it's possible that an empty string could
+  // cause a rollover of size_t as an input to string creation, causing
+  // a crash.
+  // This math is made safe by doing the integer calculations in int64_t and
+  // then clamping to positive values.
+  struct F {
+    static size_t CreateFillSize(size_t col_size, size_t element_size) {
+      int64_t value = static_cast<int64_t>(col_size) -
+                      static_cast<int64_t>(element_size) - 1;
+      value = std::max<int64_t>(0, value);
+      return static_cast<size_t>(value);
+    }
+  };
 
+  std::stringstream output_ss;
   const std::string vertical_bar = AddColor(table_color_, "|");
 
   for (size_t i = 0; i < row.size(); ++i) {
-    std::stringstream token_ss;
-    token_ss << " ";  // Padding
-    token_ss << row[i];
-    token_ss << " ";
-
-    std::string token = token_ss.str();
+    std::string token = AddColor(text_color_, row[i]);
 
     std::stringstream row_ss;
     const int col_size = static_cast<int>(column_sizes_[i]);
     row_ss << vertical_bar;
-    row_ss << std::setfill(' ');
-    row_ss << std::setw(col_size);
+    const size_t fill_size = F::CreateFillSize(col_size, row[i].size());
     if (i == 0) {
-      row_ss << std::left;  // Left justification for first column.
+      row_ss << " " << token << MakeFill(" ", fill_size);
     } else {
-      row_ss << std::right;  // Right justification for all other columns.
+      row_ss << MakeFill(" ", fill_size) << token << " ";
     }
 
-    row_ss << AddColor(text_color_, token);
     output_ss << row_ss.str();
   }
   output_ss << vertical_bar;
@@ -284,6 +299,10 @@
 
 }  // namespace.
 
+bool TablePrinter::SystemSupportsColor() {
+  return SbLogIsTty();
+}
+
 TablePrinter::TablePrinter() : text_color_(kDefault), table_color_(kDefault) {
 }
 
diff --git a/src/cobalt/browser/memory_settings/table_printer.h b/src/cobalt/browser/memory_settings/table_printer.h
index 29d1d0f..8795f51 100644
--- a/src/cobalt/browser/memory_settings/table_printer.h
+++ b/src/cobalt/browser/memory_settings/table_printer.h
@@ -39,6 +39,8 @@
 //      "+--------+--------+\n";
 class TablePrinter {
  public:
+  static bool SystemSupportsColor();
+
   enum Color {
     kDefault,
     kRed,
diff --git a/src/cobalt/browser/memory_settings/table_printer_test.cc b/src/cobalt/browser/memory_settings/table_printer_test.cc
index f03250f..a6de9ad 100644
--- a/src/cobalt/browser/memory_settings/table_printer_test.cc
+++ b/src/cobalt/browser/memory_settings/table_printer_test.cc
@@ -69,10 +69,10 @@
 
   std::string table_str = table.ToString();
   std::string expected_table_str =
-      R(" col1     col2     ") "\n"
+      " col1     col2     \n"
       G(" _________________ ") "\n"
       G("|        |        |") "\n"
-      G("|") R(" value1 ") G("|") R(" value2 ") G("|") "\n"
+      G("|") " " R("value1") " " G("|") " " R("value2") " " G("|") "\n"
       G("|________|________|") "\n";
 
 #undef R
diff --git a/src/cobalt/browser/memory_settings/test_common.h b/src/cobalt/browser/memory_settings/test_common.h
index 7e489ff..9078573 100644
--- a/src/cobalt/browser/memory_settings/test_common.h
+++ b/src/cobalt/browser/memory_settings/test_common.h
@@ -17,15 +17,21 @@
 #ifndef COBALT_BROWSER_MEMORY_SETTINGS_TEST_COMMON_H_
 #define COBALT_BROWSER_MEMORY_SETTINGS_TEST_COMMON_H_
 
+#include <map>
 #include <sstream>
 #include <string>
+#include <vector>
 
+#include "base/compiler_specific.h"
+#include "cobalt/browser/memory_settings/memory_settings.h"
 #include "cobalt/browser/memory_settings/texture_dimensions.h"
+#include "cobalt/browser/switches.h"
 #include "cobalt/math/size.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 // PrintToString() provides the proper functionality to pretty print custom
 // types.
+
 namespace testing {
 
 template <>
@@ -46,4 +52,114 @@
 
 }  // namespace testing
 
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+class TestDimensionSetting : public DimensionSetting {
+ public:
+  explicit TestDimensionSetting(const std::string& name)
+      : DimensionSetting(name) {}
+  virtual void ScaleMemory(double absolute_constraining_value) {
+    UNREFERENCED_PARAMETER(absolute_constraining_value);
+  }
+};
+
+class TestSettingGroup {
+ public:
+  TestSettingGroup() {}
+
+  void LoadDefault() {
+    MakeSetting(MemorySetting::kInt, MemorySetting::kCmdLine,
+                MemorySetting::kGPU, switches::kImageCacheSizeInBytes,
+                "1234");
+
+    MakeSetting(MemorySetting::kInt, MemorySetting::kAutoSet,
+                MemorySetting::kCPU, switches::kJavaScriptGcThresholdInBytes,
+                "1112");
+
+    MakeSetting(MemorySetting::kDimensions, MemorySetting::kCmdLine,
+                MemorySetting::kGPU, switches::kSkiaTextureAtlasDimensions,
+                "1234x4567");
+
+    MakeSetting(MemorySetting::kInt, MemorySetting::kCmdLine,
+                MemorySetting::kGPU, switches::kSkiaCacheSizeInBytes,
+                "12345678");
+
+    MakeSetting(MemorySetting::kInt, MemorySetting::kBuildSetting,
+                MemorySetting::kNotApplicable,
+                switches::kSoftwareSurfaceCacheSizeInBytes,
+                "8910");
+  }
+
+  ~TestSettingGroup() {
+    for (MemoryMap::const_iterator it = map_.begin(); it != map_.end(); ++it) {
+      delete it->second;
+    }
+  }
+
+  // The memory setting is owned internally.
+  void MakeSetting(
+      MemorySetting::ClassType class_type,
+      MemorySetting::SourceType source_type,
+      MemorySetting::MemoryType memory_type,
+      const std::string& name, const std::string& value) {
+    const bool found = (map_.find(name) !=  map_.end());
+
+    ASSERT_FALSE(found);
+    map_[name] =
+        CreateMemorySetting(class_type, source_type, memory_type, name, value);
+  }
+
+  std::vector<const MemorySetting*> AsConstVector() const {
+    std::vector<const MemorySetting*> output;
+    for (MemoryMap::const_iterator it = map_.begin(); it != map_.end(); ++it) {
+      output.push_back(it->second);
+    }
+    return output;
+  }
+
+  std::vector<MemorySetting*> AsMutableVector() {
+    std::vector<MemorySetting*> output;
+    for (MemoryMap::iterator it = map_.begin(); it != map_.end(); ++it) {
+      output.push_back(it->second);
+    }
+    return output;
+  }
+
+ private:
+  static MemorySetting* CreateMemorySetting(
+      MemorySetting::ClassType class_type,
+      MemorySetting::SourceType source_type,
+      MemorySetting::MemoryType memory_type, const std::string& name,
+      const std::string& value) {
+    MemorySetting* memory_setting = NULL;
+    switch (class_type) {
+      case MemorySetting::kInt: {
+        memory_setting = new IntSetting(name);
+        break;
+      }
+      case MemorySetting::kDimensions: {
+        memory_setting = new TestDimensionSetting(name);
+        break;
+      }
+      default: {
+        EXPECT_TRUE(false) << "Unexpected type " << class_type;
+        memory_setting = new IntSetting(name);
+        break;
+      }
+    }
+    EXPECT_TRUE(memory_setting->TryParseValue(source_type, value));
+    memory_setting->set_memory_type(memory_type);
+    return memory_setting;
+  }
+
+  typedef std::map<std::string, MemorySetting*> MemoryMap;
+  MemoryMap map_;
+};
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
+
 #endif  // COBALT_BROWSER_MEMORY_SETTINGS_TEST_COMMON_H_
diff --git a/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.cc b/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.cc
index 5c77791..c06d98a 100644
--- a/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.cc
+++ b/src/cobalt/browser/memory_tracker/tool/malloc_stats_tool.cc
@@ -55,8 +55,7 @@
 }
 
 void MallocStatsTool::Run(Params* params) {
-  // Run function does almost nothing.
-  params->logger()->Output("MallocStatsTool running...");
+  params->logger()->Output("MallocStatsTool running...\n");
 
   Timer output_timer(base::TimeDelta::FromSeconds(30));
   Timer sample_timer(base::TimeDelta::FromMilliseconds(50));
@@ -102,7 +101,8 @@
       // By double the sampling time this keeps the table linear with
       // respect to time. If sampling time was not doubled then there
       // would be time distortion in the graph.
-      sample_timer.ScaleTimerAndReset(2.0);
+      sample_timer.ScaleTriggerTime(2.0);
+      sample_timer.Restart();
     }
   }
 }
diff --git a/src/cobalt/browser/memory_tracker/tool/util.cc b/src/cobalt/browser/memory_tracker/tool/util.cc
index b25c481..5e83b22 100644
--- a/src/cobalt/browser/memory_tracker/tool/util.cc
+++ b/src/cobalt/browser/memory_tracker/tool/util.cc
@@ -125,12 +125,11 @@
   }
 }
 
-void Timer::ScaleTimerAndReset(double scale) {
+void Timer::ScaleTriggerTime(double scale) {
   int64_t old_dt = time_before_expiration_.InMicroseconds();
   int64_t new_dt =
       static_cast<int64_t>(static_cast<double>(old_dt) * scale);
   time_before_expiration_ = base::TimeDelta::FromMicroseconds(new_dt);
-  Restart();
 }
 
 const char* BaseNameFast(const char* file_name) {
diff --git a/src/cobalt/browser/memory_tracker/tool/util.h b/src/cobalt/browser/memory_tracker/tool/util.h
index 02f2ca8..00cb0ff 100644
--- a/src/cobalt/browser/memory_tracker/tool/util.h
+++ b/src/cobalt/browser/memory_tracker/tool/util.h
@@ -72,7 +72,7 @@
   v->erase(write_it, v->end());
 }
 
-// Simple timer class that fires periodically after dt time has elapsed.
+// Simple timer class that fires periodically after time has elapsed.
 class Timer {
  public:
   typedef base::Callback<base::TimeTicks(void)> TimeFunctor;
@@ -82,7 +82,7 @@
 
   void Restart();
   bool UpdateAndIsExpired();  // Returns true if the expiration was triggered.
-  void ScaleTimerAndReset(double scale);
+  void ScaleTriggerTime(double scale);
 
  private:
   base::TimeTicks Now();
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index fcddd62..e4dae06 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-56829
\ No newline at end of file
+58719
\ No newline at end of file
diff --git a/src/cobalt/build/gyp_utils.py b/src/cobalt/build/gyp_utils.py
index 3f1ac0b..4931087 100644
--- a/src/cobalt/build/gyp_utils.py
+++ b/src/cobalt/build/gyp_utils.py
@@ -38,8 +38,9 @@
 
 # The list of directories, relative to "src/", to search through for ports.
 _PORT_SEARCH_PATH = [
-    'third_party/starboard',
     'starboard',
+    os.path.join('starboard', 'port'),
+    os.path.join('third_party', 'starboard'),
 ]
 
 # The path to the build.id file that preserves a build ID.
@@ -279,22 +280,28 @@
 def _FindThirdPartyPlatforms():
   """Workhorse for GetThirdPartyPlatforms().
 
-  Search through directories listed in _PORT_SEARCH_PATH to find valid ports, so
-  that they can be added to the VALID_PLATFORMS list. This allows gyp_cobalt to
-  register new ports without needing to modify code in src/cobalt/.
+  Search through directories listed in _PORT_SEARCH_PATH to find valid
+  ports, so that they can be added to the VALID_PLATFORMS list. This
+  allows gyp_cobalt to register new ports without needing to modify
+  code in src/cobalt/.
 
   Returns:
     A dictionary of name->absolute paths to the port directory.
+
   """
 
   result = {}
-  for path_element in _PORT_SEARCH_PATH:
-    root = os.path.join(paths.REPOSITORY_ROOT, path_element)
-    if not os.path.isdir(root):
-      logging.warning('Port search path directory not found: %s', path_element)
+  search_path = [os.path.realpath(os.path.join(paths.REPOSITORY_ROOT, x))
+                 for x in _PORT_SEARCH_PATH]
+
+  # Ignore search path directories inside other search path directories.
+  exclusion_set = set(search_path)
+
+  for entry in search_path:
+    if not os.path.isdir(entry):
       continue
-    root = os.path.realpath(root)
-    for platform_info in platform.PlatformInfo.EnumeratePorts(root):
+    for platform_info in platform.PlatformInfo.EnumeratePorts(entry,
+                                                              exclusion_set):
       if platform_info.port_name in result:
         logging.error('Found duplicate port name "%s" at "%s" and "%s"',
                       platform_info.port_name, result[platform_info.port_name],
diff --git a/src/cobalt/doc/spherical_video.md b/src/cobalt/doc/spherical_video.md
index f117617..c38da9f 100644
--- a/src/cobalt/doc/spherical_video.md
+++ b/src/cobalt/doc/spherical_video.md
@@ -36,5 +36,42 @@
 }
 ```
 
-Finally, it is required that your platform provides
+It is required that your platform provides
 [decode-to-texture support](../../starboard/doc/howto_decode_to_texture.md).
+
+## Input
+
+Cobalt currently supports input mappings from the following keys (defined in [starboard/key.h](../../starboard/key.h)):
+
+ - `kSbKeyLeft`
+ - `kSbKeyUp`
+ - `kSbKeyRight`
+ - `kSbKeyDown`
+ - `kSbKeyGamepadDPadUp`
+ - `kSbKeyGamepadDPadDown`
+ - `kSbKeyGamepadDPadLeft`
+ - `kSbKeyGamepadDPadRight`
+ - `kSbKeyGamepadLeftStickUp`
+ - `kSbKeyGamepadLeftStickDown`
+ - `kSbKeyGamepadLeftStickLeft`
+ - `kSbKeyGamepadLeftStickRight`
+ - `kSbKeyGamepadRightStickUp`
+ - `kSbKeyGamepadRightStickDown`
+ - `kSbKeyGamepadRightStickLeft`
+ - `kSbKeyGamepadRightStickRight`
+
+Additionally, if your platform generates `kSbInputEventTypeMove` (from
+[starboard/input.h](../../starboard/input.h)) events with
+`SbInputData::position` set to values in the range `[-1, 1]`, for the following
+keys,
+
+ - `kSbKeyGamepadLeftStickUp`
+ - `kSbKeyGamepadLeftStickDown`
+ - `kSbKeyGamepadLeftStickLeft`
+ - `kSbKeyGamepadLeftStickRight`
+ - `kSbKeyGamepadRightStickUp`
+ - `kSbKeyGamepadRightStickDown`
+ - `kSbKeyGamepadRightStickLeft`
+ - `kSbKeyGamepadRightStickRight`
+
+then they will be treated as analog inputs when controlling the camera.
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 32d5f9e..f42ff0b 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -590,10 +590,15 @@
   }
 }
 
-void Document::UpdateComputedStyleOnElementAndAncestor(HTMLElement* element) {
-  if (!element || element->node_document() != this ||
-      !is_computed_style_dirty_) {
-    return;
+bool Document::UpdateComputedStyleOnElementAndAncestor(HTMLElement* element) {
+  TRACE_EVENT0(
+      "cobalt::dom", "Document::UpdateComputedStyleOnElementAndAncestor");
+  if (!element || element->node_document() != this) {
+    return false;
+  }
+
+  if (!is_computed_style_dirty_) {
+    return true;
   }
 
   UpdateSelectorTree();
@@ -607,16 +612,16 @@
   std::vector<HTMLElement*> ancestors;
   while (true) {
     ancestors.push_back(element);
-    if (element->parent_node() == dynamic_cast<Node*>(this)) {
+    if (element->parent_node() == static_cast<Node*>(this)) {
       break;
     }
     Element* parent_element = element->parent_element();
     if (!parent_element) {
-      return;
+      return false;
     }
     element = parent_element->AsHTMLElement();
     if (!element) {
-      return;
+      return false;
     }
   }
 
@@ -640,6 +645,8 @@
     previous_element = current_element;
     ancestors_were_valid = is_valid;
   }
+
+  return true;
 }
 
 void Document::SampleTimelineTime() { default_timeline_->Sample(); }
diff --git a/src/cobalt/dom/document.h b/src/cobalt/dom/document.h
index fd9602c..5c049cf 100644
--- a/src/cobalt/dom/document.h
+++ b/src/cobalt/dom/document.h
@@ -294,7 +294,8 @@
 
   // Updates the computed styles of the element and all its ancestors.
   // Matching rules, media rules, font faces and key frames are also updated.
-  void UpdateComputedStyleOnElementAndAncestor(HTMLElement* element);
+  // Returns whether the computed style is valid after the call.
+  bool UpdateComputedStyleOnElementAndAncestor(HTMLElement* element);
 
   // Manages the clock used by Web Animations.
   //     https://www.w3.org/TR/web-animations
diff --git a/src/cobalt/dom/dom.gyp b/src/cobalt/dom/dom.gyp
index 9e4437d..a1d6fbb 100644
--- a/src/cobalt/dom/dom.gyp
+++ b/src/cobalt/dom/dom.gyp
@@ -321,6 +321,9 @@
             '<(DEPTH)/cobalt/media/media.gyp:media',
           ],
         }],
+        ['enable_map_to_mesh == 1', {
+          'defines' : ['ENABLE_MAP_TO_MESH'],
+        }],
       ],
       # This target doesn't generate any headers, but it exposes generated
       # header files (for idl dictionaries) through this module's public header
diff --git a/src/cobalt/dom/event.cc b/src/cobalt/dom/event.cc
index 2484c59..a3623e9 100644
--- a/src/cobalt/dom/event.cc
+++ b/src/cobalt/dom/event.cc
@@ -76,11 +76,6 @@
 }
 
 void Event::InitEvent(const std::string& type, bool bubbles, bool cancelable) {
-  // Our event is for single use only.
-  DCHECK(!IsBeingDispatched());
-  DCHECK(!target());
-  DCHECK(!current_target());
-
   if (IsBeingDispatched() || target() || current_target()) {
     return;
   }
diff --git a/src/cobalt/dom/html_element.cc b/src/cobalt/dom/html_element.cc
index af05c42..93a6f9f 100644
--- a/src/cobalt/dom/html_element.cc
+++ b/src/cobalt/dom/html_element.cc
@@ -818,7 +818,10 @@
     return false;
   }
 
-  document->UpdateComputedStyleOnElementAndAncestor(this);
+  if (!document->UpdateComputedStyleOnElementAndAncestor(this)) {
+    return false;
+  }
+  DCHECK(computed_style());
 
   return computed_style()->display() != cssom::KeywordValue::GetNone() &&
          computed_style()->visibility() == cssom::KeywordValue::GetVisible();
diff --git a/src/cobalt/dom/html_media_element.cc b/src/cobalt/dom/html_media_element.cc
index 51edf3e..954999f 100644
--- a/src/cobalt/dom/html_media_element.cc
+++ b/src/cobalt/dom/html_media_element.cc
@@ -1614,8 +1614,22 @@
   return media_source_url_.spec();
 }
 
-bool HTMLMediaElement::PreferDecodeToTexture() const {
+bool HTMLMediaElement::PreferDecodeToTexture() {
+  TRACE_EVENT0("cobalt::dom", "HTMLMediaElement::PreferDecodeToTexture");
+
+#if defined(ENABLE_MAP_TO_MESH)
+  if (!node_document()->UpdateComputedStyleOnElementAndAncestor(this)) {
+    LOG(WARNING) << "Could not update computed style.";
+    NOTREACHED();
+    return false;
+  }
+
   if (!computed_style()) {
+    // This has been found to occur when HTMLMediaElement::OnLoadTimer() is on
+    // the callstack, though the visual inspection of the display shows that
+    // we are in the settings menu.
+    LOG(WARNING) << "PreferDecodeToTexture() could not get the computed style.";
+    NOTREACHED();
     return false;
   }
 
@@ -1624,6 +1638,10 @@
           computed_style()->filter());
 
   return map_to_mesh_filter;
+#else  // defined(ENABLE_MAP_TO_MESH)
+  // If map-to-mesh is disabled, we never prefer decode-to-texture.
+  return false;
+#endif  // defined(ENABLE_MAP_TO_MESH)
 }
 
 #if defined(COBALT_MEDIA_SOURCE_2016)
diff --git a/src/cobalt/dom/html_media_element.h b/src/cobalt/dom/html_media_element.h
index 154d73c..9001872 100644
--- a/src/cobalt/dom/html_media_element.h
+++ b/src/cobalt/dom/html_media_element.h
@@ -242,7 +242,7 @@
   void SourceOpened() OVERRIDE;
 #endif  // defined(COBALT_MEDIA_SOURCE_2016)
   std::string SourceURL() const OVERRIDE;
-  bool PreferDecodeToTexture() const OVERRIDE;
+  bool PreferDecodeToTexture() OVERRIDE;
 #if defined(COBALT_MEDIA_SOURCE_2016)
   void EncryptedMediaInitDataEncountered(
       media::EmeInitDataType init_data_type, const unsigned char* init_data,
diff --git a/src/cobalt/fetch/embedded_scripts/fetch.js b/src/cobalt/fetch/embedded_scripts/fetch.js
new file mode 100644
index 0000000..884fabb
--- /dev/null
+++ b/src/cobalt/fetch/embedded_scripts/fetch.js
@@ -0,0 +1,16 @@
+'use strict';(function(g){function p(a){"string"!==typeof a&&(a=String(a));if(/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(a))throw new h("Invalid character in header field name");return a.toLowerCase()}function v(a){"string"!==typeof a&&(a=String(a));var b,d;for(b=0;b<a.length;b++){var c=a.charCodeAt(b);if(9!==c&&10!==c&&13!==c&&32!==c)break}for(d=a.length-1;d>b&&(c=a.charCodeAt(d),9===c||10===c||13===c||32===c);d--);a=a.substring(b,d+1);for(b=0;b<a.length;b++)if(c=a.charCodeAt(b),256<=c||0===c||10===c||13===
+c)throw new h("Invalid character in header field value");return a}function e(a){this.map=new q;if(void 0!==a){if(null===a||"object"!==typeof a)throw new h("Constructing Headers with invalid parameters");a instanceof e?a.forEach(function(a,d){this.append(d,a)},this):m.isArray(a)?a.forEach(function(a){if(2!==a.length)throw new h("Constructing Headers with invalid parameters");this.append(a[0],a[1])},this):Object.getOwnPropertyNames(a).forEach(function(b){this.append(b,a[b])},this)}}function t(a){if(a.bodyUsed)return Promise.reject(new h("Already read"));
+a.bodyUsed=!0}function w(a){return new Promise(function(b,d){a.onload=function(){b(a.result)};a.onerror=function(){d(a.error)}})}function z(a){var b=new FileReader,d=w(b);b.readAsArrayBuffer(a);return d}function A(a){a=new Uint8Array(a);for(var b=new m(a.length),d=0;d<a.length;d++)b[d]=String.fromCharCode(a[d]);return b.join("")}function x(a){if(a.slice)return a.slice(0);var b=new Uint8Array(a.byteLength);b.set(new Uint8Array(a));return b.buffer}function y(){this.bodyUsed=!1;this._initBody=function(a){if(this._bodyInit=
+a)if("string"===typeof a)this._bodyText=a;else if(k.blob&&Blob.prototype.isPrototypeOf(a))this._bodyBlob=a;else if(k.formData&&FormData.prototype.isPrototypeOf(a))this._bodyFormData=a;else if(k.searchParams&&URLSearchParams.prototype.isPrototypeOf(a))this._bodyText=a.toString();else if(k.arrayBuffer&&k.blob&&B(a))this._bodyArrayBuffer=x(a.buffer),this._bodyInit=new Blob([this._bodyArrayBuffer]);else if(k.arrayBuffer&&(ArrayBuffer.prototype.isPrototypeOf(a)||C(a)))this._bodyArrayBuffer=x(a);else throw new u("unsupported BodyInit type");
+else this._bodyText="";this.headers.get("content-type")||("string"===typeof a?this.headers.set("content-type","text/plain;charset=UTF-8"):this._bodyBlob&&this._bodyBlob.type?this.headers.set("content-type",this._bodyBlob.type):k.searchParams&&URLSearchParams.prototype.isPrototypeOf(a)&&this.headers.set("content-type","application/x-www-form-urlencoded;charset=UTF-8"))};k.blob&&(this.blob=function(){var a=t(this);if(a)return a;if(this._bodyBlob)return Promise.resolve(this._bodyBlob);if(this._bodyArrayBuffer)return Promise.resolve(new Blob([this._bodyArrayBuffer]));
+if(this._bodyFormData)throw new u("could not read FormData body as blob");return Promise.resolve(new Blob([this._bodyText]))},this.arrayBuffer=function(){return this._bodyArrayBuffer?t(this)||Promise.resolve(this._bodyArrayBuffer):this.blob().then(z)});this.text=function(){var a=t(this);if(a)return a;if(this._bodyBlob){var a=this._bodyBlob,b=new FileReader,d=w(b);b.readAsText(a);return d}if(this._bodyArrayBuffer)return Promise.resolve(A(this._bodyArrayBuffer));if(this._bodyFormData)throw new u("could not read FormData body as text");
+return Promise.resolve(this._bodyText)};k.formData&&(this.formData=function(){return this.text().then(D)});this.json=function(){return this.text().then(JSON.parse)};return this}function n(a,b){b=b||{};var d=b.body;if(a instanceof n){if(a.bodyUsed)throw new h("Already read");this.url=a.url;this.credentials=a.credentials;b.headers||(this.headers=new e(a.headers));this.method=a.method;this.mode=a.mode;d||null==a._bodyInit||(d=a._bodyInit,a.bodyUsed=!0)}else this.url=String(a);this.credentials=b.credentials||
+this.credentials||"omit";if(b.headers||!this.headers)this.headers=new e(b.headers);a=b.method||this.method||"GET";var c=a.toUpperCase();this.method=-1<E.indexOf(c)?c:a;this.mode=b.mode||this.mode||null;this.referrer=null;if(("GET"===this.method||"HEAD"===this.method)&&d)throw new h("Body not allowed for GET or HEAD requests");this._initBody(d)}function D(a){var b=new FormData;a.trim().split("&").forEach(function(a){if(a){var c=a.split("=");a=c.shift().replace(/\+/g," ");c=c.join("=").replace(/\+/g,
+" ");b.append(decodeURIComponent(a),decodeURIComponent(c))}});return b}function F(a){var b=new e;a.replace(/\r?\n[\t ]+/g," ").split(/\r?\n/).forEach(function(a){var c=a.split(":");if(a=c.shift().trim())c=c.join(":").trim(),b.append(a,c)});return b}function l(a,b){b||(b={});this.type="default";this.status="status"in b?b.status:200;this.ok=200<=this.status&&300>this.status;this.statusText="statusText"in b?b.statusText:"OK";this.headers=new e(b.headers);this.url=b.url||"";this._initBody(a)}if(!g.fetch){var m=
+g.Array,u=g.Error,q=g.Map,G=g.RangeError,h=g.TypeError,r;if(r="FileReader"in g&&"Blob"in g)try{new Blob,r=!0}catch(a){r=!1}var k={searchParams:"URLSearchParams"in g,blob:r,formData:"FormData"in g,arrayBuffer:"ArrayBuffer"in g};if(k.arrayBuffer){var H="[object Int8Array];[object Uint8Array];[object Uint8ClampedArray];[object Int16Array];[object Uint16Array];[object Int32Array];[object Uint32Array];[object Float32Array];[object Float64Array]".split(";");var B=function(a){return a&&DataView.prototype.isPrototypeOf(a)};
+var C=ArrayBuffer.isView||function(a){return a&&-1<H.indexOf(Object.prototype.toString.call(a))}}e.prototype.append=function(a,b){if(2!==arguments.length)throw h("Invalid parameters to append");a=p(a);b=v(b);this.map.has(a)?this.map.set(a,this.map.get(a)+", "+b):this.map.set(a,b)};e.prototype["delete"]=function(a){if(1!==arguments.length)throw h("Invalid parameters to delete");this.map.delete(p(a))};e.prototype.get=function(a){if(1!==arguments.length)throw h("Invalid parameters to get");a=p(a);var b=
+this.map.get(a);return void 0!==b?b:null};e.prototype.has=function(a){if(1!==arguments.length)throw h("Invalid parameters to has");return this.map.has(p(a))};e.prototype.set=function(a,b){if(2!==arguments.length)throw h("Invalid parameters to set");this.map.set(p(a),v(b))};e.prototype.forEach=function(a,b){var d=this;m.from(this.map.entries()).sort().forEach(function(c){a.call(b,c[1],c[0],d)})};e.prototype.keys=function(){return(new q(m.from(this.map.entries()).sort())).keys()};e.prototype.values=
+function(){return(new q(m.from(this.map.entries()).sort())).values()};e.prototype.entries=function(){return(new q(m.from(this.map.entries()).sort())).entries()};e.prototype[Symbol.iterator]=e.prototype.entries;var E="DELETE GET HEAD OPTIONS POST PUT".split(" ");n.prototype.clone=function(){return new n(this,{body:this._bodyInit})};y.call(n.prototype);y.call(l.prototype);l.prototype.clone=function(){return new l(this._bodyInit,{status:this.status,statusText:this.statusText,headers:new e(this.headers),
+url:this.url})};l.error=function(){var a=new l(null,{status:0,statusText:""});a.type="error";return a};var I=[301,302,303,307,308];l.redirect=function(a,b){if(-1===I.indexOf(b))throw new G("Invalid status code");return new l(null,{status:b,headers:{location:a}})};g.Headers=e;g.Request=n;g.Response=l;g.fetch=function(a,b){return new Promise(function(d,c){var e=new n(a,b),f=new XMLHttpRequest;f.onload=function(){var a={status:f.status,statusText:f.statusText,headers:F(f.getAllResponseHeaders()||"")};
+a.url="responseURL"in f?f.responseURL:a.headers.get("X-Request-URL");d(new l("response"in f?f.response:f.responseText,a))};f.onerror=function(){c(new h("Network request failed"))};f.ontimeout=function(){c(new h("Network request failed"))};f.open(e.method,e.url,!0);"include"===e.credentials&&(f.withCredentials=!0);"responseType"in f&&k.blob&&(f.responseType="blob");e.headers.forEach(function(a,b){f.setRequestHeader(b,a)});f.send("undefined"===typeof e._bodyInit?null:e._bodyInit)})};g.fetch.polyfill=
+!0}})(this);
\ No newline at end of file
diff --git a/src/cobalt/fetch/fetch.js b/src/cobalt/fetch/fetch.js
new file mode 100644
index 0000000..b01d35f
--- /dev/null
+++ b/src/cobalt/fetch/fetch.js
@@ -0,0 +1,537 @@
+// ==ClosureCompiler==
+// @output_file_name fetch.js
+// @compilation_level SIMPLE_OPTIMIZATIONS
+// @language_out ES5_STRICT
+// ==/ClosureCompiler==
+
+// Copyright (c) 2014-2016 GitHub, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+// Contact GitHub API Training Shop Blog About
+
+// Fetch API: https://fetch.spec.whatwg.org/
+
+(function(self) {
+  'use strict';
+
+  if (self.fetch) {
+    return
+  }
+
+  var Array = self.Array;
+  var Error = self.Error;
+  var Map = self.Map;
+  var RangeError = self.RangeError;
+  var TypeError = self.TypeError;
+
+  var err_InvalidHeadersInit = 'Constructing Headers with invalid parameters'
+
+  var support = {
+    searchParams: 'URLSearchParams' in self,
+    blob: 'FileReader' in self && 'Blob' in self && (function() {
+      try {
+        new Blob()
+        return true
+      } catch(e) {
+        return false
+      }
+    })(),
+    formData: 'FormData' in self,
+    arrayBuffer: 'ArrayBuffer' in self
+  }
+
+  if (support.arrayBuffer) {
+    var viewClasses = [
+      '[object Int8Array]',
+      '[object Uint8Array]',
+      '[object Uint8ClampedArray]',
+      '[object Int16Array]',
+      '[object Uint16Array]',
+      '[object Int32Array]',
+      '[object Uint32Array]',
+      '[object Float32Array]',
+      '[object Float64Array]'
+    ]
+
+    var isDataView = function(obj) {
+      return obj && DataView.prototype.isPrototypeOf(obj)
+    }
+
+    var isArrayBufferView = ArrayBuffer.isView || function(obj) {
+      return obj && viewClasses.indexOf(Object.prototype.toString.call(obj)) > -1
+    }
+  }
+
+  function normalizeName(name) {
+    if (typeof name !== 'string') {
+      name = String(name)
+    }
+    if (/[^a-z0-9\-#$%&'*+.\^_`|~]/i.test(name)) {
+      throw new TypeError('Invalid character in header field name')
+    }
+    return name.toLowerCase()
+  }
+
+  function normalizeValue(value) {
+    if (typeof value !== 'string') {
+      value = String(value)
+    }
+
+    // https://fetch.spec.whatwg.org/#concept-header-value
+    // The web platform tests don't quite abide by the current spec. Use a
+    // permissive approach that passes the tests while following the spirit
+    // of the spec. Essentially, leading & trailing HTTP whitespace bytes
+    // are trimmed first before checking validity.
+    var c, first, last, i
+
+    //value = value.replace(/^[ \t\n\r]+|[ \t\n\r]+$/g, '')
+    for (first = 0; first < value.length; first++) {
+      c = value.charCodeAt(first)
+      if (c !== 9 && c !== 10 && c !== 13 && c !== 32) {
+        break
+      }
+    }
+    for (last = value.length - 1; last > first; last--) {
+      c = value.charCodeAt(last)
+      if (c !== 9 && c !== 10 && c !== 13 && c !== 32) {
+        break
+      }
+    }
+    value = value.substring(first, last + 1)
+
+    // Follow the chromium implementation of IsValidHTTPHeaderValue(). This
+    // should be updated once the web platform test abides by the fetch spec.
+    for (i = 0; i < value.length; i++) {
+      c = value.charCodeAt(i)
+      if (c >= 256 || c === 0 || c === 10 || c === 13) {
+        throw new TypeError('Invalid character in header field value')
+      }
+    }
+    return value
+  }
+
+  function Headers(headers) {
+    this.map = new Map();
+
+    if (headers === undefined) {
+      return
+    } else if (headers === null || typeof headers !== 'object') {
+      throw new TypeError(err_InvalidHeadersInit)
+    } else if (headers instanceof Headers) {
+      // Should use for..of in case |headers| has a custom Symbol.iterator.
+      // However, this results in the ClosureCompiler polyfilling Symbol.
+      headers.forEach(function(value, name) {
+        this.append(name, value)
+      }, this)
+    } else if (Array.isArray(headers)) {
+      headers.forEach(function(header) {
+        if (header.length !== 2) {
+          throw new TypeError(err_InvalidHeadersInit)
+        }
+        this.append(header[0], header[1])
+      }, this)
+    } else {
+      Object.getOwnPropertyNames(headers).forEach(function(name) {
+        this.append(name, headers[name])
+      }, this)
+    }
+  }
+
+  Headers.prototype.append = function(name, value) {
+    if (arguments.length !== 2) {
+      throw TypeError('Invalid parameters to append')
+    }
+    name = normalizeName(name)
+    value = normalizeValue(value)
+    if (this.map.has(name)) {
+      this.map.set(name, this.map.get(name) + ', ' + value)
+    } else {
+      this.map.set(name, value)
+    }
+  }
+
+  Headers.prototype['delete'] = function(name) {
+    if (arguments.length !== 1) {
+      throw TypeError('Invalid parameters to delete')
+    }
+    this.map.delete(normalizeName(name))
+  }
+
+  Headers.prototype.get = function(name) {
+    if (arguments.length !== 1) {
+      throw TypeError('Invalid parameters to get')
+    }
+    name = normalizeName(name)
+    var value = this.map.get(name)
+    return value !== undefined ? value : null
+  }
+
+  Headers.prototype.has = function(name) {
+    if (arguments.length !== 1) {
+      throw TypeError('Invalid parameters to has')
+    }
+    return this.map.has(normalizeName(name))
+  }
+
+  Headers.prototype.set = function(name, value) {
+    if (arguments.length !== 2) {
+      throw TypeError('Invalid parameters to set')
+    }
+    this.map.set(normalizeName(name), normalizeValue(value))
+  }
+
+  Headers.prototype.forEach = function(callback, thisArg) {
+    var sorted_array = Array.from(this.map.entries()).sort()
+    var that = this
+    sorted_array.forEach(function(value) {
+      callback.call(thisArg, value[1], value[0], that)
+    })
+  }
+
+  Headers.prototype.keys = function() {
+    var sorted_map = new Map(Array.from(this.map.entries()).sort())
+    return sorted_map.keys()
+  }
+
+  Headers.prototype.values = function() {
+    var sorted_map = new Map(Array.from(this.map.entries()).sort())
+    return sorted_map.values()
+  }
+
+  Headers.prototype.entries = function() {
+    var sorted_map = new Map(Array.from(this.map.entries()).sort())
+    return sorted_map.entries()
+  }
+
+  Headers.prototype[Symbol.iterator] = Headers.prototype.entries
+
+  function consumed(body) {
+    if (body.bodyUsed) {
+      return Promise.reject(new TypeError('Already read'))
+    }
+    body.bodyUsed = true
+  }
+
+  function fileReaderReady(reader) {
+    return new Promise(function(resolve, reject) {
+      reader.onload = function() {
+        resolve(reader.result)
+      }
+      reader.onerror = function() {
+        reject(reader.error)
+      }
+    })
+  }
+
+  function readBlobAsArrayBuffer(blob) {
+    var reader = new FileReader()
+    var promise = fileReaderReady(reader)
+    reader.readAsArrayBuffer(blob)
+    return promise
+  }
+
+  function readBlobAsText(blob) {
+    var reader = new FileReader()
+    var promise = fileReaderReady(reader)
+    reader.readAsText(blob)
+    return promise
+  }
+
+  function readArrayBufferAsText(buf) {
+    var view = new Uint8Array(buf)
+    var chars = new Array(view.length)
+
+    for (var i = 0; i < view.length; i++) {
+      chars[i] = String.fromCharCode(view[i])
+    }
+    return chars.join('')
+  }
+
+  function bufferClone(buf) {
+    if (buf.slice) {
+      return buf.slice(0)
+    } else {
+      var view = new Uint8Array(buf.byteLength)
+      view.set(new Uint8Array(buf))
+      return view.buffer
+    }
+  }
+
+  function Body() {
+    this.bodyUsed = false
+
+    this._initBody = function(body) {
+      this._bodyInit = body
+      if (!body) {
+        this._bodyText = ''
+      } else if (typeof body === 'string') {
+        this._bodyText = body
+      } else if (support.blob && Blob.prototype.isPrototypeOf(body)) {
+        this._bodyBlob = body
+      } else if (support.formData && FormData.prototype.isPrototypeOf(body)) {
+        this._bodyFormData = body
+      } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
+        this._bodyText = body.toString()
+      } else if (support.arrayBuffer && support.blob && isDataView(body)) {
+        this._bodyArrayBuffer = bufferClone(body.buffer)
+        // IE 10-11 can't handle a DataView body.
+        this._bodyInit = new Blob([this._bodyArrayBuffer])
+      } else if (support.arrayBuffer && (ArrayBuffer.prototype.isPrototypeOf(body) || isArrayBufferView(body))) {
+        this._bodyArrayBuffer = bufferClone(body)
+      } else {
+        throw new Error('unsupported BodyInit type')
+      }
+
+      if (!this.headers.get('content-type')) {
+        if (typeof body === 'string') {
+          this.headers.set('content-type', 'text/plain;charset=UTF-8')
+        } else if (this._bodyBlob && this._bodyBlob.type) {
+          this.headers.set('content-type', this._bodyBlob.type)
+        } else if (support.searchParams && URLSearchParams.prototype.isPrototypeOf(body)) {
+          this.headers.set('content-type', 'application/x-www-form-urlencoded;charset=UTF-8')
+        }
+      }
+    }
+
+    if (support.blob) {
+      this.blob = function() {
+        var rejected = consumed(this)
+        if (rejected) {
+          return rejected
+        }
+
+        if (this._bodyBlob) {
+          return Promise.resolve(this._bodyBlob)
+        } else if (this._bodyArrayBuffer) {
+          return Promise.resolve(new Blob([this._bodyArrayBuffer]))
+        } else if (this._bodyFormData) {
+          throw new Error('could not read FormData body as blob')
+        } else {
+          return Promise.resolve(new Blob([this._bodyText]))
+        }
+      }
+
+      this.arrayBuffer = function() {
+        if (this._bodyArrayBuffer) {
+          return consumed(this) || Promise.resolve(this._bodyArrayBuffer)
+        } else {
+          return this.blob().then(readBlobAsArrayBuffer)
+        }
+      }
+    }
+
+    this.text = function() {
+      var rejected = consumed(this)
+      if (rejected) {
+        return rejected
+      }
+
+      if (this._bodyBlob) {
+        return readBlobAsText(this._bodyBlob)
+      } else if (this._bodyArrayBuffer) {
+        return Promise.resolve(readArrayBufferAsText(this._bodyArrayBuffer))
+      } else if (this._bodyFormData) {
+        throw new Error('could not read FormData body as text')
+      } else {
+        return Promise.resolve(this._bodyText)
+      }
+    }
+
+    if (support.formData) {
+      this.formData = function() {
+        return this.text().then(decode)
+      }
+    }
+
+    this.json = function() {
+      return this.text().then(JSON.parse)
+    }
+
+    return this
+  }
+
+  // HTTP methods whose capitalization should be normalized
+  var methods = ['DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT']
+
+  function normalizeMethod(method) {
+    var upcased = method.toUpperCase()
+    return (methods.indexOf(upcased) > -1) ? upcased : method
+  }
+
+  function Request(input, options) {
+    options = options || {}
+    var body = options.body
+
+    if (input instanceof Request) {
+      if (input.bodyUsed) {
+        throw new TypeError('Already read')
+      }
+      this.url = input.url
+      this.credentials = input.credentials
+      if (!options.headers) {
+        this.headers = new Headers(input.headers)
+      }
+      this.method = input.method
+      this.mode = input.mode
+      if (!body && input._bodyInit != null) {
+        body = input._bodyInit
+        input.bodyUsed = true
+      }
+    } else {
+      this.url = String(input)
+    }
+
+    this.credentials = options.credentials || this.credentials || 'omit'
+    if (options.headers || !this.headers) {
+      this.headers = new Headers(options.headers)
+    }
+    this.method = normalizeMethod(options.method || this.method || 'GET')
+    this.mode = options.mode || this.mode || null
+    this.referrer = null
+
+    if ((this.method === 'GET' || this.method === 'HEAD') && body) {
+      throw new TypeError('Body not allowed for GET or HEAD requests')
+    }
+    this._initBody(body)
+  }
+
+  Request.prototype.clone = function() {
+    return new Request(this, { body: this._bodyInit })
+  }
+
+  function decode(body) {
+    var form = new FormData()
+    body.trim().split('&').forEach(function(bytes) {
+      if (bytes) {
+        var split = bytes.split('=')
+        var name = split.shift().replace(/\+/g, ' ')
+        var value = split.join('=').replace(/\+/g, ' ')
+        form.append(decodeURIComponent(name), decodeURIComponent(value))
+      }
+    })
+    return form
+  }
+
+  function parseHeaders(rawHeaders) {
+    var headers = new Headers()
+    // Replace instances of \r\n and \n followed by at least one space or horizontal tab with a space
+    // https://tools.ietf.org/html/rfc7230#section-3.2
+    var preProcessedHeaders = rawHeaders.replace(/\r?\n[\t ]+/g, ' ')
+    preProcessedHeaders.split(/\r?\n/).forEach(function(line) {
+      var parts = line.split(':')
+      var key = parts.shift().trim()
+      if (key) {
+        var value = parts.join(':').trim()
+        headers.append(key, value)
+      }
+    })
+    return headers
+  }
+
+  Body.call(Request.prototype)
+
+  function Response(bodyInit, options) {
+    if (!options) {
+      options = {}
+    }
+
+    this.type = 'default'
+    this.status = 'status' in options ? options.status : 200
+    this.ok = this.status >= 200 && this.status < 300
+    this.statusText = 'statusText' in options ? options.statusText : 'OK'
+    this.headers = new Headers(options.headers)
+    this.url = options.url || ''
+    this._initBody(bodyInit)
+  }
+
+  Body.call(Response.prototype)
+
+  Response.prototype.clone = function() {
+    return new Response(this._bodyInit, {
+      status: this.status,
+      statusText: this.statusText,
+      headers: new Headers(this.headers),
+      url: this.url
+    })
+  }
+
+  Response.error = function() {
+    var response = new Response(null, {status: 0, statusText: ''})
+    response.type = 'error'
+    return response
+  }
+
+  var redirectStatuses = [301, 302, 303, 307, 308]
+
+  Response.redirect = function(url, status) {
+    if (redirectStatuses.indexOf(status) === -1) {
+      throw new RangeError('Invalid status code')
+    }
+
+    return new Response(null, {status: status, headers: {location: url}})
+  }
+
+  self.Headers = Headers
+  self.Request = Request
+  self.Response = Response
+
+  self.fetch = function(input, init) {
+    return new Promise(function(resolve, reject) {
+      var request = new Request(input, init)
+      var xhr = new XMLHttpRequest()
+
+      xhr.onload = function() {
+        var options = {
+          status: xhr.status,
+          statusText: xhr.statusText,
+          headers: parseHeaders(xhr.getAllResponseHeaders() || '')
+        }
+        options.url = 'responseURL' in xhr ? xhr.responseURL : options.headers.get('X-Request-URL')
+        var body = 'response' in xhr ? xhr.response : xhr.responseText
+        resolve(new Response(body, options))
+      }
+
+      xhr.onerror = function() {
+        reject(new TypeError('Network request failed'))
+      }
+
+      xhr.ontimeout = function() {
+        reject(new TypeError('Network request failed'))
+      }
+
+      xhr.open(request.method, request.url, true)
+
+      if (request.credentials === 'include') {
+        xhr.withCredentials = true
+      }
+
+      if ('responseType' in xhr && support.blob) {
+        xhr.responseType = 'blob'
+      }
+
+      request.headers.forEach(function(value, name) {
+        xhr.setRequestHeader(name, value)
+      })
+
+      xhr.send(typeof request._bodyInit === 'undefined' ? null : request._bodyInit)
+    })
+  }
+  self.fetch.polyfill = true
+})(this);
diff --git a/src/cobalt/math/clamp.h b/src/cobalt/math/clamp.h
new file mode 100644
index 0000000..94d706e
--- /dev/null
+++ b/src/cobalt/math/clamp.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2017 Google Inc. 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_MATH_CLAMP_H_
+#define COBALT_MATH_CLAMP_H_
+
+#include <algorithm>
+
+namespace cobalt {
+namespace math {
+
+template <typename T>
+T Clamp(const T& input, const T& minimum, const T& maximum) {
+  return std::max<T>(minimum, std::min<T>(maximum, input));
+}
+
+}  // namespace math.
+}  // namespace cobalt.
+
+#endif  // COBALT_MATH_CLAMP_H_
diff --git a/src/cobalt/math/linear_interpolator.h b/src/cobalt/math/linear_interpolator.h
index 728f70f..a1de492 100644
--- a/src/cobalt/math/linear_interpolator.h
+++ b/src/cobalt/math/linear_interpolator.h
@@ -17,6 +17,7 @@
 #ifndef COBALT_MATH_LINEAR_INTERPOLATOR_H_
 #define COBALT_MATH_LINEAR_INTERPOLATOR_H_
 
+#include <iterator>
 #include <utility>
 #include <vector>
 
@@ -41,7 +42,7 @@
 //
 // Discontinuous values:
 //  This table supports discontinuous values. To enable this feature, insert a
-//  pair of duplicate keys, each with a different value. See example below. 
+//  pair of duplicate keys, each with a different value. See example below.
 //
 // Example (continuous):
 //  LinearInterpolator<float, float> interp;
diff --git a/src/cobalt/math/math.gyp b/src/cobalt/math/math.gyp
index f457fdd..a281754 100644
--- a/src/cobalt/math/math.gyp
+++ b/src/cobalt/math/math.gyp
@@ -11,6 +11,7 @@
       'sources': [
         'box_f.cc',
         'box_f.h',
+        'clamp.h',
         'cubic_bezier.cc',
         'cubic_bezier.h',
         'insets.cc',
diff --git a/src/cobalt/media/base/starboard_player.cc b/src/cobalt/media/base/starboard_player.cc
index e4ce5be..4723e68 100644
--- a/src/cobalt/media/base/starboard_player.cc
+++ b/src/cobalt/media/base/starboard_player.cc
@@ -292,6 +292,10 @@
     return;
   }
 
+  if (seek_pending_) {
+    return;
+  }
+
 #if SB_API_VERSION < 4
   SbPlayerSetPause(player_, playback_rate == 0.0);
 #else   // SB_API_VERSION < 4
diff --git a/src/cobalt/media/base/video_codecs.cc b/src/cobalt/media/base/video_codecs.cc
index 89a9264..a82e041 100644
--- a/src/cobalt/media/base/video_codecs.cc
+++ b/src/cobalt/media/base/video_codecs.cc
@@ -290,7 +290,10 @@
   uint8_t level = 0;
   if (ParseAVCCodecId(codec_id, &profile, &level)) return kCodecH264;
   if (codec_id == "vp8" || codec_id == "vp8.0") return kCodecVP8;
-  if (codec_id == "vp9" || codec_id == "vp9.0") return kCodecVP9;
+  if (codec_id == "vp9" || codec_id == "vp9.0" || codec_id == "vp9.1" ||
+      codec_id == "vp9.2") {
+    return kCodecVP9;
+  }
   if (codec_id == "theora") return kCodecTheora;
   if (ParseHEVCCodecId(codec_id, &profile, &level)) return kCodecHEVC;
 
diff --git a/src/cobalt/media/decoder_buffer_allocator.cc b/src/cobalt/media/decoder_buffer_allocator.cc
index 70858e5..bd53da4 100644
--- a/src/cobalt/media/decoder_buffer_allocator.cc
+++ b/src/cobalt/media/decoder_buffer_allocator.cc
@@ -14,6 +14,7 @@
 
 #include "cobalt/media/decoder_buffer_allocator.h"
 
+#include "nb/memory_scope.h"
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/configuration.h"
 #include "starboard/memory.h"
@@ -26,6 +27,7 @@
 }  // namespace
 
 DecoderBufferAllocator::DecoderBufferAllocator() : memory_block_(NULL) {
+  TRACK_MEMORY_SCOPE("Media");
   if (COBALT_MEDIA_BUFFER_INITIAL_CAPACITY > 0) {
     memory_block_ = SbMemoryAllocateAligned(
         DecoderBuffer::kAlignmentSize, COBALT_MEDIA_BUFFER_INITIAL_CAPACITY);
@@ -52,6 +54,7 @@
 
 void* DecoderBufferAllocator::Allocate(Type type, size_t size,
                                        size_t alignment) {
+  TRACK_MEMORY_SCOPE("Media");
   UNREFERENCED_PARAMETER(type);
   if (memory_pool_.is_valid()) {
     return memory_pool_->Allocate(size, alignment);
diff --git a/src/cobalt/media/filters/shell_demuxer.cc b/src/cobalt/media/filters/shell_demuxer.cc
index 5f9e0b8..9909244 100644
--- a/src/cobalt/media/filters/shell_demuxer.cc
+++ b/src/cobalt/media/filters/shell_demuxer.cc
@@ -517,14 +517,15 @@
     return;
   }
   // if both streams had finished downloading, we need to restart the request
-  if (audio_reached_eos_ && video_reached_eos_) {
-    DLOG(INFO) << "restarting stopped request loop";
-    Request(DemuxerStream::AUDIO);
-  }
+  bool issue_new_request = audio_reached_eos_ && video_reached_eos_;
   audio_reached_eos_ = false;
   video_reached_eos_ = false;
   flushing_ = true;
   cb.Run(PIPELINE_OK);
+  if (issue_new_request) {
+    DLOG(INFO) << "restarting stopped request loop";
+    Request(DemuxerStream::AUDIO);
+  }
 }
 
 DemuxerStream* ShellDemuxer::GetStream(media::DemuxerStream::Type type) {
diff --git a/src/cobalt/media/player/web_media_player.h b/src/cobalt/media/player/web_media_player.h
index f81d2ad..94e372d 100644
--- a/src/cobalt/media/player/web_media_player.h
+++ b/src/cobalt/media/player/web_media_player.h
@@ -208,7 +208,7 @@
   // the preferred output mode is not supported, the player will fallback to
   // one that is.  This can be used to indicate that, say, for spherical video
   // playback, we would like a decode-to-texture output mode.
-  virtual bool PreferDecodeToTexture() const { return false; }
+  virtual bool PreferDecodeToTexture() { return false; }
   // Notifies the client that a video is encrypted. Client is supposed to call
   // |WebMediaPlayer::SetDrmSystem| as soon as possible to avoid stalling
   // playback.
diff --git a/src/cobalt/media/player/web_media_player_impl.cc b/src/cobalt/media/player/web_media_player_impl.cc
index 9741314..d145b6a 100644
--- a/src/cobalt/media/player/web_media_player_impl.cc
+++ b/src/cobalt/media/player/web_media_player_impl.cc
@@ -127,7 +127,8 @@
       drm_system_(NULL) {
   TRACE_EVENT0("cobalt::media", "WebMediaPlayerImpl::WebMediaPlayerImpl");
 
-  DCHECK(!s_instance);
+  DLOG_IF(ERROR, s_instance)
+      << "More than one WebMediaPlayerImpl has been created.";
   s_instance = this;
 
   DCHECK(buffer_allocator_);
@@ -151,7 +152,8 @@
 
   DCHECK(!main_loop_ || main_loop_ == MessageLoop::current());
 
-  DCHECK_EQ(s_instance, this);
+  DLOG_IF(ERROR, s_instance != this)
+      << "More than one WebMediaPlayerImpl has been created.";
   s_instance = NULL;
 
   if (delegate_) {
diff --git a/src/cobalt/renderer/backend/egl/graphics_context.cc b/src/cobalt/renderer/backend/egl/graphics_context.cc
index 1211584..c7708af 100644
--- a/src/cobalt/renderer/backend/egl/graphics_context.cc
+++ b/src/cobalt/renderer/backend/egl/graphics_context.cc
@@ -501,16 +501,9 @@
 }
 
 void GraphicsContextEGL::SecurityClear() {
-#if defined(COBALT_SECURITY_SCREEN_CLEAR_TO_UGLY_COLOR)
-  // Clear the screen to a color that is bright and gross to exaggerate that
-  // this is a problem if it is witnessed.
-  GL_CALL(glClearColor(1.0f, 0.4f, 1.0f, 1.0f));
-#else
-  // In release builds we certainly still want to perform this security
-  // clear, but should a poor user actually encounter it, we don't need
-  // to shock them with an ugly pink color.
-  GL_CALL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
-#endif  // defined(COBALT_SECURITY_SCREEN_CLEAR_TO_UGLY_COLOR)
+  // Explicitly clear the screen to transparent to ensure that data from a
+  // previous use of the surface is not visible.
+  GL_CALL(glClearColor(0.0f, 0.0f, 0.0f, 0.0f));
   GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
 }
 
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_rrect.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_rrect.glsl
index 411e72a..7fc1677 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_rrect.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_rrect.glsl
@@ -2,6 +2,7 @@
 precision mediump float;

 uniform vec4 uinnerRect_Stage1;

 uniform float uRTHeight;

+uniform vec2 uscale_Stage1;

 uniform vec2 uinvRadiiXY_Stage1;

 varying vec4 vColor;

 varying vec2 vEllipseOffsets_Stage0;

@@ -27,11 +28,13 @@
 		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

 		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

 		vec2 dxy = max(max(dxy0, dxy1), 0.0);

+		dxy *= uscale_Stage1.y;

 		vec2 Z = dxy * uinvRadiiXY_Stage1;

 		float implicit = dot(Z, dxy) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage1.x;

 		float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);

 		output_Stage1 = (output_Stage0 * alpha);

 	}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture.glsl
index b35a8f4..2f78d28 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture.glsl
@@ -1,6 +1,7 @@
 #version 100

 precision mediump float;

 uniform sampler2D uSampler0_Stage0;

+uniform vec2 uscale_Stage1;

 uniform vec4 uellipse_Stage1;

 uniform float uRTHeight;

 varying vec4 vColor;

@@ -20,11 +21,13 @@
   {

     // Stage 1: Ellipse

     vec2 d = fragCoordYDown.xy - uellipse_Stage1.xy;

+    d *= uscale_Stage1.y;

     vec2 Z = d * uellipse_Stage1.zw;

     float implicit = dot(Z, d) - 1.0;

     float grad_dot = 4.0 * dot(Z, Z);

     grad_dot = max(grad_dot, 1.0e-4);

     float approx_dist = implicit * inversesqrt(grad_dot);

+    approx_dist *= uscale_Stage1.x;

     float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);

     output_Stage1 = (output_Stage0 * alpha);

   }

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_domain.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_domain.glsl
index d8be84d..6279c47 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_domain.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_domain.glsl
@@ -2,6 +2,7 @@
 precision mediump float;

 uniform sampler2D uSampler0_Stage0;

 uniform vec4 uTexDom_Stage0;

+uniform vec2 uscale_Stage1;

 uniform vec4 uellipse_Stage1;

 uniform float uRTHeight;

 varying vec4 vColor;

@@ -22,11 +23,13 @@
   {

     // Stage 1: Ellipse

     vec2 d = fragCoordYDown.xy - uellipse_Stage1.xy;

+    d *= uscale_Stage1.y;

     vec2 Z = d * uellipse_Stage1.zw;

     float implicit = dot(Z, d) - 1.0;

     float grad_dot = 4.0 * dot(Z, Z);

     grad_dot = max(grad_dot, 1.0e-4);

     float approx_dist = implicit * inversesqrt(grad_dot);

+    approx_dist *= uscale_Stage1.x;

     float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);

     output_Stage1 = (output_Stage0 * alpha);

   }

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_negative.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_negative.glsl
index 0c57707..d65609f 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_negative.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_negative.glsl
@@ -1,6 +1,7 @@
 #version 100

 precision mediump float;

 uniform sampler2D uSampler0_Stage0;

+uniform vec2 uscale_Stage1;

 uniform vec4 uellipse_Stage1;

 uniform float uRTHeight;

 varying vec4 vColor;

@@ -20,11 +21,13 @@
   {

     // Stage 1: Ellipse

     vec2 d = fragCoordYDown.xy - uellipse_Stage1.xy;

+    d *= uscale_Stage1.y;

     vec2 Z = d * uellipse_Stage1.zw;

     float implicit = dot(Z, d) - 1.0;

     float grad_dot = 4.0 * dot(Z, Z);

     grad_dot = max(grad_dot, 1.0e-4);

     float approx_dist = implicit * inversesqrt(grad_dot);

+    approx_dist *= uscale_Stage1.x;

     float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);

     output_Stage1 = (output_Stage0 * alpha);

   }

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_outside_masked_ellipse.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_outside_masked_ellipse.glsl
index 3b86ee8..034729d 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_outside_masked_ellipse.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_outside_masked_ellipse.glsl
@@ -1,6 +1,7 @@
 #version 100

 #extension GL_OES_standard_derivatives: require

 precision mediump float;

+uniform vec2 uscale_Stage1;

 uniform vec4 uellipse_Stage1;

 uniform float uRTHeight;

 varying vec4 vColor;

@@ -34,11 +35,13 @@
 	{

 		// Stage 1: Ellipse

 		vec2 d = fragCoordYDown.xy - uellipse_Stage1.xy;

+		d *= uscale_Stage1.y;

 		vec2 Z = d * uellipse_Stage1.zw;

 		float implicit = dot(Z, d) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage1.x;

 		float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);

 		output_Stage1 = (output_Stage0 * alpha);

 	}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_ring_masked_color.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_ring_masked_color.glsl
index 6616121..740a6ee 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_ring_masked_color.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_ring_masked_color.glsl
@@ -1,7 +1,9 @@
 #version 100

 precision mediump float;

+uniform vec2 uscale_Stage1;

 uniform vec4 uellipse_Stage1;

 uniform float uRTHeight;

+uniform vec2 uscale_Stage2;

 uniform vec4 uellipse_Stage2;

 varying vec4 vColor;

 varying vec2 vEllipseOffsets_Stage0;

@@ -25,11 +27,13 @@
 	{

 		// Stage 1: Ellipse

 		vec2 d = fragCoordYDown.xy - uellipse_Stage1.xy;

+		d *= uscale_Stage1.y;

 		vec2 Z = d * uellipse_Stage1.zw;

 		float implicit = dot(Z, d) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage1.x;

 		float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);

 		output_Stage1 = (output_Stage0 * alpha);

 	}

@@ -37,11 +41,13 @@
 	{

 		// Stage 2: Ellipse

 		vec2 d = fragCoordYDown.xy - uellipse_Stage2.xy;

+		d *= uscale_Stage2.y;

 		vec2 Z = d * uellipse_Stage2.zw;

 		float implicit = dot(Z, d) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage2.x;

 		float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);

 		output_Stage2 = (output_Stage1 * alpha);

 	}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rect_edge_masked_ellipse.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rect_edge_masked_ellipse.glsl
index 054570a..0b82ab9 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rect_edge_masked_ellipse.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rect_edge_masked_ellipse.glsl
@@ -4,6 +4,7 @@
 uniform float uRTHeight;

 uniform vec4 urect_Stage1;

 uniform vec4 uinnerRect_Stage2;

+uniform vec2 uscale_Stage2;

 uniform vec2 uinvRadiiXY_Stage2;

 varying vec4 vColor;

 void main() 

@@ -38,11 +39,13 @@
 		vec2 dxy0 = uinnerRect_Stage2.xy - fragCoordYDown.xy;

 		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage2.zw;

 		vec2 dxy = max(max(dxy0, dxy1), 0.0);

+		dxy *= uscale_Stage2.y;

 		vec2 Z = dxy * uinvRadiiXY_Stage2;

 		float implicit = dot(Z, dxy) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage2.x;

 		float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);

 		output_Stage2 = (output_Stage1 * alpha);

 	}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture.glsl
index 2a2574d..13b93f2 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture.glsl
@@ -3,6 +3,7 @@
 uniform sampler2D uSampler0_Stage0;

 uniform vec4 uinnerRect_Stage1;

 uniform float uRTHeight;

+uniform vec2 uscale_Stage1;

 uniform vec2 uinvRadiiXY_Stage1;

 varying vec4 vColor;

 varying vec2 vMatrixCoord_Stage0;

@@ -20,11 +21,13 @@
 		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

 		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

 		vec2 dxy = max(max(dxy0, dxy1), 0.0);

+		dxy *= uscale_Stage1.y;

 		vec2 Z = dxy * uinvRadiiXY_Stage1;

 		float implicit = dot(Z, dxy) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage1.x;

 		float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);

 		output_Stage1 = (output_Stage0 * alpha);

 	}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture_negative.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture_negative.glsl
index b2f1111..90d5a4d 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture_negative.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture_negative.glsl
@@ -3,6 +3,7 @@
 uniform sampler2D uSampler0_Stage0;

 uniform vec4 uinnerRect_Stage1;

 uniform float uRTHeight;

+uniform vec2 uscale_Stage1;

 uniform vec2 uinvRadiiXY_Stage1;

 varying vec4 vColor;

 varying vec2 vMatrixCoord_Stage0;

@@ -20,11 +21,13 @@
 		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

 		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

 		vec2 dxy = max(max(dxy0, dxy1), 0.0);

+		dxy *= uscale_Stage1.y;

 		vec2 Z = dxy * uinvRadiiXY_Stage1;

 		float implicit = dot(Z, dxy) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage1.x;

 		float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);

 		output_Stage1 = (output_Stage0 * alpha);

 	}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_ring_masked_ellipse_edge.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_ring_masked_ellipse_edge.glsl
index 97428cf..cd21c5e 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_ring_masked_ellipse_edge.glsl
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_ring_masked_ellipse_edge.glsl
@@ -2,8 +2,10 @@
 precision mediump float;

 uniform vec4 uinnerRect_Stage1;

 uniform float uRTHeight;

+uniform vec2 uscale_Stage1;

 uniform vec2 uinvRadiiXY_Stage1;

 uniform vec4 uinnerRect_Stage2;

+uniform vec2 uscale_Stage2;

 uniform vec2 uinvRadiiXY_Stage2;

 varying vec4 vColor;

 varying vec2 vEllipseOffsets_Stage0;

@@ -29,11 +31,13 @@
 		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

 		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

 		vec2 dxy = max(max(dxy0, dxy1), 0.0);

+		dxy *= uscale_Stage1.y;

 		vec2 Z = dxy * uinvRadiiXY_Stage1;

 		float implicit = dot(Z, dxy) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage1.x;

 		float alpha = clamp(0.5 + approx_dist, 0.0, 1.0);

 		output_Stage1 = (output_Stage0 * alpha);

 	}

@@ -43,11 +47,13 @@
 		vec2 dxy0 = uinnerRect_Stage2.xy - fragCoordYDown.xy;

 		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage2.zw;

 		vec2 dxy = max(max(dxy0, dxy1), 0.0);

+		dxy *= uscale_Stage2.y;

 		vec2 Z = dxy * uinvRadiiXY_Stage2;

 		float implicit = dot(Z, dxy) - 1.0;

 		float grad_dot = 4.0 * dot(Z, Z);

 		grad_dot = max(grad_dot, 1.0e-4);

 		float approx_dist = implicit * inversesqrt(grad_dot);

+		approx_dist *= uscale_Stage2.x;

 		float alpha = clamp(0.5 - approx_dist, 0.0, 1.0);

 		output_Stage2 = (output_Stage1 * alpha);

 	}

diff --git a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
index 2ed5599..cdd0f00 100644
--- a/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/blitter/hardware_rasterizer.cc
@@ -270,14 +270,19 @@
       render_target_blitter->GetSbRenderTarget();
   CHECK(SbBlitterSetRenderTarget(context, visitor_render_target));
 
-  BoundsStack start_bounds(context_->GetSbBlitterContext(),
-                           math::Rect(render_target_blitter->GetSize()));
+  math::Size size(render_target_blitter->GetSize());
+  BoundsStack start_bounds(context, math::Rect(size));
 
   RenderState initial_render_state(visitor_render_target, Transform(),
                                    start_bounds);
 
+  CHECK(SbBlitterSetBlending(context, false));
+  CHECK(SbBlitterSetColor(context, SbBlitterColorFromRGBA(0, 0, 0, 0)));
+  CHECK(SbBlitterFillRect(
+      context, SbBlitterMakeRect(0, 0, size.width(), size.height())));
+
   RenderTreeNodeVisitor visitor(
-      context_->GetSbBlitterDevice(), context_->GetSbBlitterContext(),
+      context_->GetSbBlitterDevice(), context,
       initial_render_state, NULL, NULL, NULL, NULL, NULL);
   render_tree->Accept(&visitor);
 
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 16b0c2a..cc16d83 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -1740,6 +1740,18 @@
       new ImageNode(image)));
 }
 
+TEST_F(PixelTest, LargeEllipticalViewportOverImage) {
+  // This image has rounded corners that are just large enough to result in
+  // older skia implementations using uniform values that overflow 16-bit float
+  // exponents.
+  scoped_refptr<Image> image =
+      CreateColoredCheckersImage(GetResourceProvider(), math::Size(300, 100));
+
+  TestTree(new FilterNode(
+      ViewportFilter(RectF(0, 0, 300, 100), RoundedCorners(150, 50)),
+      new ImageNode(image)));
+}
+
 TEST_F(PixelTest, EllipticalViewportOverWrappingImage) {
   scoped_refptr<Image> image =
       CreateColoredCheckersImage(GetResourceProvider(), output_surface_size());
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
index b90a09a..1fe1492 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_rasterizer.cc
@@ -520,6 +520,8 @@
       CreateSkiaRenderTargetSurface(skia_render_target);
   SkCanvas* canvas = sk_output_surface->getCanvas();
 
+  canvas->clear(SkColorSetARGB(0, 0, 0, 0));
+
   // Render to the canvas and clean up.
   RasterizeRenderTreeToCanvas(render_tree, canvas);
   canvas->flush();
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkAtomics_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkAtomics_cobalt.h
index 9464ed3..de8c187 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkAtomics_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkAtomics_cobalt.h
@@ -18,7 +18,9 @@
 #include "base/atomicops.h"
 #include "cobalt/renderer/rasterizer/skia/skia/src/ports/atomic_type_conversions.h"
 
-#if defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__)
+#if defined(STARBOARD)
+/* Don't undefine MemoryBarrier */
+#elif defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__)
 // windows.h #defines this (only on x64). This causes problems because the
 // public API also uses MemoryBarrier at the public name for this fence.
 #undef MemoryBarrier
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkBarriers_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkBarriers_cobalt.h
index acdd630..00b666f 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkBarriers_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkBarriers_cobalt.h
@@ -18,7 +18,9 @@
 #include "base/atomicops.h"
 #include "cobalt/renderer/rasterizer/skia/skia/src/ports/atomic_type_conversions.h"
 
-#if defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__) || defined(__LB_XB1__)
+#if defined(STARBOARD)
+/* Don't undefine MemoryBarrier */
+#elif defined(ARCH_CPU_64_BITS) || defined(__LB_XB360__) || defined(__LB_XB1__)
 // windows.h #defines this (only on x64). This causes problems because the
 // public API also uses MemoryBarrier at the public name for this fence.
 #undef MemoryBarrier
diff --git a/src/cobalt/renderer/rasterizer/testdata/LargeEllipticalViewportOverImage-expected.png b/src/cobalt/renderer/rasterizer/testdata/LargeEllipticalViewportOverImage-expected.png
new file mode 100644
index 0000000..f15606a
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/LargeEllipticalViewportOverImage-expected.png
Binary files differ
diff --git a/src/cobalt/script/mozjs-45/mozjs-45.gyp b/src/cobalt/script/mozjs-45/mozjs-45.gyp
index 2a38204..c26b64e 100644
--- a/src/cobalt/script/mozjs-45/mozjs-45.gyp
+++ b/src/cobalt/script/mozjs-45/mozjs-45.gyp
@@ -89,10 +89,11 @@
         'output_path': '<(SHARED_INTERMEDIATE_DIR)/cobalt/script/mozjs-45/embedded_resources.h',
       },
       'sources': [
-        '<(DEPTH)/third_party/promise-polyfill/promise.min.js',
+        '<(DEPTH)/cobalt/fetch/embedded_scripts/fetch.js',
         '<(DEPTH)/cobalt/streams/embedded_scripts/byte_length_queuing_strategy.js',
         '<(DEPTH)/cobalt/streams/embedded_scripts/count_queuing_strategy.js',
         '<(DEPTH)/cobalt/streams/embedded_scripts/readable_stream.js',
+        '<(DEPTH)/third_party/promise-polyfill/promise.min.js',
       ],
       'actions': [
         {
diff --git a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
index 32cf999..ba7b7eb 100644
--- a/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
+++ b/src/cobalt/script/mozjs-45/mozjs_global_environment.cc
@@ -378,6 +378,10 @@
       MozjsEmbeddedResources::readable_stream_js,
       sizeof(MozjsEmbeddedResources::readable_stream_js),
       "readable_stream.js");
+  EvaluateEmbeddedScript(
+      MozjsEmbeddedResources::fetch_js,
+      sizeof(MozjsEmbeddedResources::fetch_js),
+      "fetch.js");
 }
 
 InterfaceData* MozjsGlobalEnvironment::GetInterfaceData(intptr_t key) {
diff --git a/src/cobalt/script/mozjs-45/proxy_handler.cc b/src/cobalt/script/mozjs-45/proxy_handler.cc
index 6e0cbb2..5794038 100644
--- a/src/cobalt/script/mozjs-45/proxy_handler.cc
+++ b/src/cobalt/script/mozjs-45/proxy_handler.cc
@@ -92,7 +92,8 @@
 bool ProxyHandler::delete_(JSContext* context, JS::HandleObject proxy,
                            JS::HandleId id, JS::ObjectOpResult& result) const {
   // https://www.w3.org/TR/WebIDL/#delete
-  if (supports_named_properties() || supports_indexed_properties()) {
+  if (!JSID_IS_SYMBOL(id) &&
+      (supports_named_properties() || supports_indexed_properties())) {
     // Convert the id to a JSValue, so we can easily convert it to Uint32 and
     // JSString.
     JS::RootedValue id_value(context);
@@ -163,7 +164,8 @@
 bool ProxyHandler::LegacyPlatformObjectGetOwnPropertyDescriptor(
     JSContext* context, JS::HandleObject proxy, JS::HandleId id,
     JS::MutableHandle<JSPropertyDescriptor> descriptor) const {
-  if (supports_named_properties() || supports_indexed_properties()) {
+  if (!JSID_IS_SYMBOL(id) &&
+      (supports_named_properties() || supports_indexed_properties())) {
     // Convert the id to a JSValue, so we can easily convert it to Uint32 and
     // JSString.
     JS::RootedValue id_value(context);
@@ -221,6 +223,9 @@
                                             uint32_t* out_index) const {
   // https://www.w3.org/TR/WebIDL/#dfn-array-index-property-name
   // 1. Let i be ToUint32(P).
+  if (property_value.isSymbol()) {
+    return false;
+  }
   uint32_t index;
   if (!JS::ToUint32(context, property_value, &index)) {
     return false;
diff --git a/src/cobalt/websocket/buffered_amount_tracker.cc b/src/cobalt/websocket/buffered_amount_tracker.cc
index 708efc0..b02cab2 100644
--- a/src/cobalt/websocket/buffered_amount_tracker.cc
+++ b/src/cobalt/websocket/buffered_amount_tracker.cc
@@ -28,6 +28,10 @@
     Entry& entry(entries_[0]);
 
     std::size_t potential_payload_delta = 0;
+
+    // Cache this variable in case we do a |pop_front|.
+    const bool is_user_payload = entry.is_user_payload_;
+
     if (entry.message_size_ > size_left_pop) {
       potential_payload_delta = size_left_pop;
       entry.message_size_ -= size_left_pop;
@@ -36,7 +40,7 @@
       entries_.pop_front();
     }
 
-    if (entry.is_user_payload_) {
+    if (is_user_payload) {
       payload_amount += potential_payload_delta;
     }
 
diff --git a/src/media/base/starboard_player.cc b/src/media/base/starboard_player.cc
index f8a838e..07799db 100644
--- a/src/media/base/starboard_player.cc
+++ b/src/media/base/starboard_player.cc
@@ -14,6 +14,12 @@
 
 #include "media/base/starboard_player.h"
 
+#error This implementation of StarboardPlayer is deprecated and will be removed
+#error in the next release.  You should upgrade to Starboard version 4 and
+#error Cobalt 9 to use the StarboardPlayer implementation in cobalt/media.
+#error Please contact us *immediately* if the upcoming removal of this file
+#error will break your port.
+
 #include <algorithm>
 
 #include "base/bind.h"
@@ -229,6 +235,11 @@
   DCHECK(SbPlayerIsValid(player_));
 
   playback_rate_ = playback_rate;
+
+  if (seek_pending_) {
+    return;
+  }
+
 #if SB_API_VERSION < 4
   SbPlayerSetPause(player_, playback_rate == 0.0);
 #else   // SB_API_VERSION < 4
diff --git a/src/media/player/web_media_player.h b/src/media/player/web_media_player.h
index 26a2742..6ab6c02 100644
--- a/src/media/player/web_media_player.h
+++ b/src/media/player/web_media_player.h
@@ -244,7 +244,7 @@
   // the preferred output mode is not supported, the player will fallback to
   // one that is.  This can be used to indicate that, say, for spherical video
   // playback, we would like a decode-to-texture output mode.
-  virtual bool PreferDecodeToTexture() const { return false; }
+  virtual bool PreferDecodeToTexture() { return false; }
   // TODO: Make the EME related functions pure virtual again once
   // we have proper EME implementation. Currently empty implementation are
   // provided to make media temporarily work.
diff --git a/src/media/player/web_media_player_impl.cc b/src/media/player/web_media_player_impl.cc
index d6d920d..f22efba 100644
--- a/src/media/player/web_media_player_impl.cc
+++ b/src/media/player/web_media_player_impl.cc
@@ -139,7 +139,8 @@
       is_local_source_(false),
       supports_save_(true),
       suppress_destruction_errors_(false) {
-  DCHECK(!s_instance);
+  DLOG_IF(ERROR, s_instance)
+      << "More than one WebMediaPlayerImpl has been created.";
   s_instance = this;
 
   media_log_->AddEvent(
@@ -186,7 +187,8 @@
 WebMediaPlayerImpl::~WebMediaPlayerImpl() {
   DCHECK(!main_loop_ || main_loop_ == MessageLoop::current());
 
-  DCHECK_EQ(s_instance, this);
+  DLOG_IF(ERROR, s_instance != this)
+      << "More than one WebMediaPlayerImpl has been created.";
   s_instance = NULL;
 
   if (delegate_) {
diff --git a/src/starboard/client_porting/walk_dir.py b/src/starboard/client_porting/walk_dir.py
new file mode 100644
index 0000000..1ebc6f3
--- /dev/null
+++ b/src/starboard/client_porting/walk_dir.py
@@ -0,0 +1,310 @@
+#
+# Copyright 2017 Google Inc. 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.
+#
+"""A directory walker framework that filter and process files.
+
+It filters file name against filter functions and process filtered files using
+processor function.
+"""
+
+import os
+
+# All filter functions
+
+
+def CppSourceCodeFilter(filename):
+  """Filter function returns true for C++ source code files."""
+  return (filename[-3:] == '.cc' or filename[-4:] == '.cpp' or
+          filename[-2:] == '.h' or filename[-4:] == '.hpp')
+
+
+def SourceCodeFilter(filename):
+  """Filter function returns true for general source code files."""
+  return (filename[-3:] == '.cc' or filename[-4:] == '.cpp' or
+          filename[-2:] == '.h' or filename[-4:] == '.hpp' or
+          filename[-4:] == '.idl' or filename[-11:] == '.h.template' or
+          filename[-12:] == '.cc.template' or filename[-2:] == '.y' or
+          filename[-7:] == '.h.pump' or filename[-3:] == '.js')
+
+
+# All processor functions
+
+
+def AddInvalidSpace(pathname):
+  """Add a space in the very beginning of the file."""
+  with open(pathname, 'r') as f:
+    content = f.read()
+  content = ' ' + content
+  with open(pathname, 'w') as f:
+    f.write(content)
+
+
+def ReplaceLicenseHeader(pathname):
+  """Replace license headers in /* ... */ to // ...."""
+  with open(pathname, 'r') as f:
+    lines = f.readlines()
+  # Guestimate the copyright header
+  for i in range(0, len(lines)):
+    if (len(lines[i]) == 3 and lines[i][:2] == '/*' and
+        lines[i + 1].find('opyright') != -1 and
+        lines[i + 1].find('Google') != -1):
+      del lines[i]
+      for j in range(i, len(lines)):
+        if lines[j].find('*/') != -1:
+          del lines[j]
+          break
+
+        if lines[j][0] == ' ':
+          line_without_star = lines[j][2:]
+        else:
+          line_without_star = lines[j][1:]
+        lines[j] = '//' + line_without_star
+    if i >= len(lines) - 1:
+      break
+  with open(pathname, 'w') as f:
+    f.writelines(lines)
+
+
+def ReplaceMediaNamespace(pathname):
+  """Move namespace media into namespace cobalt."""
+  with open(pathname, 'r') as f:
+    source_lines = f.readlines()
+  target_lines = []
+  for i in range(0, len(source_lines)):
+    if source_lines[i].find('namespace media {') != -1:
+      if i == 0 or source_lines[i - 1].find('namespace cobalt {') == -1:
+        target_lines.append('namespace cobalt {\n')
+    target_lines.append(source_lines[i])
+    if source_lines[i].find('}  // namespace media') != -1:
+      if i == len(source_lines) - 1 or source_lines[i + 1].find(
+          '}  // namespace cobalt') == -1:
+        target_lines.append('}  // namespace cobalt\n')
+
+  with open(pathname, 'w') as f:
+    f.writelines(target_lines)
+
+
+C_FUNCTION_LIST = """
+assert,isalnum,isalpha,iscntrl,isdigit,isgraph,islower,isprint,ispunct,isspace,
+isupper,isxdigit,toupper,tolower,errno,setlocale,acos,asin,atan,atan2,ceil,cos,
+cosh,exp,fabs,floor,fmod,frexp,ldexp,log,log10,modf,pow,sin,sinh,sqrt,tan,tanh,
+setjmp,longjmp,signal,raise,va_start,va_arg,va_end,clearerr,fclose,feof,fflush,
+fgetc,fgetpos,fgets,fopen,fprintf,fputc,fputs,fread,freopen,fscanf,fseek,
+fsetpos,ftell,fwrite,getc,getchar,gets,perror,printf,putchar,puts,remove,rewind,
+scanf,setbuf,setvbuf,sprintf,sscanf,tmpfile,tmpnam,ungetc,vfprintf,vprintf,
+vsprintf,abort,abs,atexit,atof,atoi,atol,bsearch,calloc,div,exit,getenv,free,
+labs,ldiv,malloc,mblen,mbstowcs,mbtowc,qsort,rand,realloc,strtod,strtol,strtoul,
+srand,system,wctomb,wcstombs,memchr,memcmp,memcpy,memmove,memset,strcat,strchr,
+strcmp,strcoll,strcpy,strcspn,strerror,strlen,strncat,strncmp,strncpy,strpbrk,
+strrchr,strspn,strstr,strtok,strxfrm,asctime,clock,ctime,difftime,gmtime,
+localtime,mktime,strftime,time,opendir,closedir,readdir,rewinddir,scandir,
+seekdir,telldir,access,alarm,chdir,chown,close,chroot,ctermid,cuserid,dup,dup2,
+execl,execle,execlp,execv,execve,execvp,fchdir,fork,fpathconf,getegid,geteuid,
+gethostname,getopt,getgid,getgroups,getlogin,getpgrp,getpid,getppid,getuid,
+isatty,link,lseek,mkdir,open,pathconf,pause,pipe,read,rename,rmdir,setgid,
+setpgid,setsid,setuid,sleep,sysconf,tcgetpgrp,tcsetpgrp,ttyname,unlink,write,
+clrscr,getch,getche,statfs,endpwent,fgetpwent,getpw,getpwent,getpwnam,getpwuid,
+getuidx,putpwent,pclose,popen,putenv,setenv,setpwent,setreuid,stat,uname,
+unsetenv,setuidx,setegid,setrgid,seteuid,setruid,getruid
+"""
+
+SB_CHARACTER_REPLACEMENT_DICT = {
+    'isdigit': 'SbCharacterIsDigit',
+    'isspace': 'SbCharacterIsSpace',
+}
+
+SB_MEMORY_REPLACEMENT_DICT = {
+    'free': 'SbMemoryFree',
+    'malloc': 'SbMemoryAllocate',
+    'memchr': 'SbMemoryFindByte',
+    'memcmp': 'SbMemoryCompare',
+    'memcpy': 'SbMemoryCopy',
+    'memmove': 'SbMemoryMove',
+    'memset': 'SbMemorySet',
+    'realloc': 'SbMemoryReallocate'
+}
+
+SB_STRING_REPLACEMENT_DICT = {
+    'atoi': 'SbStringAToI',
+    'strcpy': 'SbStringCopyUnsafe',
+    'strlen': 'SbStringGetLength',
+    'strncpy': 'SbStringCopy',
+}
+
+c_function_list = []
+
+
+def AddProjectHeader(lines, header):
+  """Add a new project header into lines which takes order into account."""
+  assert header.find('.h') != -1 and header.find('/') != -1
+
+  include_statement = '#include "' + header + '"\n'
+
+  last_c_header = -1
+  last_cpp_header = -1
+  last_project_header = -1
+
+  for i in range(0, len(lines)):
+    line = lines[i]
+    if line.find('#include <') != -1:
+      if line.find('.h') != -1:
+        last_c_header = i
+      else:
+        last_cpp_header = i
+    elif line.find('#include "') != -1:
+      if line.find(header) != -1:
+        return
+      last_project_header = i
+
+  if (last_project_header < last_cpp_header or
+      last_project_header < last_c_header):
+    # There is no project header at all, add after last cpp or c header
+    if last_cpp_header != -1:
+      lines.insert(last_cpp_header + 1, include_statement)
+      lines.insert(last_cpp_header + 1, '\n')
+    else:
+      # In the case that there is no C header as well, this will be added to the
+      # first line, maybe before the copyrights, and hopefully will be caught
+      # during code review.
+      lines.insert(last_c_header + 1, include_statement)
+      lines.insert(last_c_header + 1, '\n')
+    return
+
+  # Now we have to add into the project include section with proper ordering
+  while last_project_header > 0:
+    if include_statement > lines[last_project_header]:
+      lines.insert(last_project_header + 1, include_statement)
+      return
+    last_project_header -= 1
+
+  lines.insert(0, include_statement)
+
+
+def RemoveHeader(lines, header):
+  for i in range(0, len(lines)):
+    if lines[i].find('#include') != -1 and lines[i].find(header) != -1:
+      del lines[i]
+      if (lines[i] == '\n' and lines[i + 1] == '\n' or
+          lines[i - 1] == '\n' and lines[i] == '\n'):
+        del lines[i]
+      return
+
+
+def DumpCHeadersAndFunctions(pathname):
+  """Print out C headers included and C functions used."""
+  global c_function_list
+  if not c_function_list:
+    c_function_list = [
+        x for x in C_FUNCTION_LIST.replace('\n', '').split(',') if x
+    ]
+  with open(pathname, 'r') as f:
+    source_lines = f.readlines()
+  first = True
+
+  add_starboard_character_h = False
+  add_starboard_memory_h = False
+  add_starboard_string_h = False
+  add_starboard_types_h = False
+
+  for i in range(0, len(source_lines)):
+    if source_lines[i].find('#include <') != -1 and source_lines[i].find(
+        '.h>') != -1:
+      if source_lines[i].find('stddef.h') or source_lines[i].find('stdint.h'):
+        add_starboard_types_h = True
+        continue  # We can fix this, no need to dump
+
+      if first:
+        print pathname
+        first = False
+      print '    => line ', i + 1, '\t', source_lines[i][:-1]
+    for j in range(0, len(c_function_list)):
+      index = source_lines[i].find(c_function_list[j] + '(')
+      if index == -1:
+        continue
+      if (source_lines[i].find('//') != -1 and
+          source_lines[i].find('//') < index):
+        continue
+      if index == 0 or (not source_lines[i][index - 1].isalpha() and
+                        source_lines[i][index - 1] != '_' and
+                        source_lines[i][index - 1] != ':' and
+                        source_lines[i][index - 1] != '>' and
+                        source_lines[i][index - 1] != '.'):
+        if c_function_list[j] in SB_CHARACTER_REPLACEMENT_DICT:
+          source_lines[i] = source_lines[i].replace(
+              c_function_list[j],
+              SB_CHARACTER_REPLACEMENT_DICT[c_function_list[j]])
+          add_starboard_character_h = True
+          continue  # We fixed this, no need to dump
+        if c_function_list[j] in SB_MEMORY_REPLACEMENT_DICT:
+          source_lines[i] = source_lines[i].replace(
+              c_function_list[j],
+              SB_MEMORY_REPLACEMENT_DICT[c_function_list[j]])
+          add_starboard_memory_h = True
+          continue  # We fixed this, no need to dump
+        if c_function_list[j] in SB_STRING_REPLACEMENT_DICT:
+          source_lines[i] = source_lines[i].replace(
+              c_function_list[j],
+              SB_STRING_REPLACEMENT_DICT[c_function_list[j]])
+          add_starboard_string_h = True
+          continue  # We fixed this, no need to dump
+        if first:
+          print pathname
+          first = False
+        print '    => line ', i + 1, '\t', source_lines[
+            i][:-1], 'contains', c_function_list[j]
+
+  if add_starboard_character_h:
+    AddProjectHeader(source_lines, 'starboard/character.h')
+
+  if add_starboard_memory_h:
+    AddProjectHeader(source_lines, 'starboard/memory.h')
+
+  if add_starboard_string_h:
+    AddProjectHeader(source_lines, 'starboard/string.h')
+
+  if add_starboard_types_h:
+    RemoveHeader(source_lines, 'stddef.h')
+    RemoveHeader(source_lines, 'stdint.h')
+    AddProjectHeader(source_lines, 'starboard/types.h')
+
+  with open(pathname, 'w') as f:
+    f.writelines(source_lines)
+
+
+def CollectFilesInDirectory(root, file_filter=None):
+  """Traverse the folder and call filters."""
+  result = []
+  for current_dir, _, files in os.walk(root):
+    for f in files:
+      pathname = current_dir + '/' + f
+      if file_filter and not file_filter(pathname):
+        continue
+      result.append(pathname)
+  return result
+
+
+def ProcessFiles(pathnames, processor):
+  for pathname in pathnames:
+    processor(pathname)
+
+
+# ProcessFiles(CollectFilesInDirectory('.', CppSourceCodeFilter),
+#                                      AddInvalidSpace)
+# ProcessFiles(CollectFilesInDirectory('.', SourceCodeFilter),
+#                                      ReplaceLicenseHeader)
+# ProcessFiles(CollectFilesInDirectory('.', SourceCodeFilter),
+#                                      ReplaceMediaNamespace)
+ProcessFiles(
+    CollectFilesInDirectory('.', CppSourceCodeFilter), DumpCHeadersAndFunctions)
diff --git a/src/starboard/common/flat_map.h b/src/starboard/common/flat_map.h
index 2e04d60..a232b24 100644
--- a/src/starboard/common/flat_map.h
+++ b/src/starboard/common/flat_map.h
@@ -154,7 +154,9 @@
 
     vector_.erase(new_end, vector_.end());
 
-    return std::distance(vector_.begin() + partition_idx, new_end);
+    // partition_idx was the previous size of the vector_.
+    const size_t num_elements_added = vector_.size() - partition_idx;
+    return num_elements_added;
   }
 
   std::pair<iterator, bool> insert(const value_type& entry) {
diff --git a/src/starboard/egl_and_gles/egl_and_gles_angle.gyp b/src/starboard/egl_and_gles/egl_and_gles_angle.gyp
index 2bcc9b2..8812c25 100644
--- a/src/starboard/egl_and_gles/egl_and_gles_angle.gyp
+++ b/src/starboard/egl_and_gles/egl_and_gles_angle.gyp
@@ -19,8 +19,8 @@
       'type': 'none',
 
       'dependencies': [
-        '<(DEPTH)/third_party/angle/src/build_angle.gyp:libEGL',
-        '<(DEPTH)/third_party/angle/src/build_angle.gyp:libGLESv2',
+        '<(DEPTH)/third_party/angle/angle.gyp:libEGL',
+        '<(DEPTH)/third_party/angle/angle.gyp:libGLESv2',
       ],
       'direct_dependent_settings': {
         'include_dirs': [
diff --git a/src/starboard/linux/shared/compiler_flags.gypi b/src/starboard/linux/shared/compiler_flags.gypi
index 931779b..762dfa7 100644
--- a/src/starboard/linux/shared/compiler_flags.gypi
+++ b/src/starboard/linux/shared/compiler_flags.gypi
@@ -69,6 +69,11 @@
           '-Wno-unnamed-type-template-args',
           # Triggered by the COMPILE_ASSERT macro.
           '-Wno-unused-local-typedef',
+          # Do not warn if a function or variable cannot be implicitly
+          # instantiated.
+          '-Wno-undefined-var-template',
+          # Do not warn about an implicit exception spec mismatch.
+          '-Wno-implicit-exception-spec-mismatch',
         ],
       }],
       ['cobalt_fastbuild==0', {
@@ -126,6 +131,7 @@
           '-Wno-shift-negative-value',
           # Width of bit-field exceeds width of its type- value will be truncated
           '-Wno-bitfield-width',
+          '-Wno-undefined-var-template',
         ],
       }],
       ['use_asan==1', {
diff --git a/src/starboard/linux/x64directfb/gyp_configuration.gypi b/src/starboard/linux/x64directfb/gyp_configuration.gypi
index 1fbc03e..98b7048 100644
--- a/src/starboard/linux/x64directfb/gyp_configuration.gypi
+++ b/src/starboard/linux/x64directfb/gyp_configuration.gypi
@@ -27,8 +27,8 @@
 
     # This should have a default value in cobalt/base.gypi. See the comment
     # there for acceptable values for this variable.
-    'javascript_engine': 'mozjs',
-    'cobalt_enable_jit': 1,
+    'javascript_engine': 'mozjs-45',
+    'cobalt_enable_jit': 0,
   },
 
   'target_defaults': {
diff --git a/src/starboard/linux/x64x11/clang/3.3/compiler_flags.gypi b/src/starboard/linux/x64x11/clang/3.3/compiler_flags.gypi
index b11221f..a6629b0 100644
--- a/src/starboard/linux/x64x11/clang/3.3/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/clang/3.3/compiler_flags.gypi
@@ -106,10 +106,6 @@
       '-std=c99',
     ],
     'cflags_cc': [
-      # Limit to gnu++98. This allows Linux to be a canary build for any
-      # C++11 features that are not supported on some platforms' compilers.
-      # We do allow ourselves GNU extensions, which are assumed to exist
-      # by Chromium code.
       '-std=gnu++98',
     ],
     'target_conditions': [
diff --git a/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.gypi b/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.gypi
index df35330..05d38d0 100644
--- a/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/clang/3.3/gyp_configuration.gypi
@@ -13,6 +13,12 @@
 # limitations under the License.
 
 {
+  'variables': {
+    # This should have a default value in cobalt/base.gypi. See the comment
+    # there for acceptable values for this variable.
+    'javascript_engine': 'mozjs',
+    'cobalt_enable_jit': 1,
+  },
   'target_defaults': {
     'default_configuration': 'linux-x64x11-clang-3-3_debug',
     'configurations': {
diff --git a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.gypi b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.gypi
index 4b85d62..f1961e0 100644
--- a/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/clang/3.6/gyp_configuration.gypi
@@ -14,6 +14,10 @@
 
 {
   'variables': {
+    # This should have a default value in cobalt/base.gypi. See the comment
+    # there for acceptable values for this variable.
+    'javascript_engine': 'mozjs-45',
+    'cobalt_enable_jit': 0,
     'linker_flags!': [
             '-Wl,--wrap=malloc',
             '-Wl,--wrap=free',
diff --git a/src/starboard/linux/x64x11/clang/gyp_configuration.gypi b/src/starboard/linux/x64x11/clang/gyp_configuration.gypi
index 0df5d5f..2ede477 100644
--- a/src/starboard/linux/x64x11/clang/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/clang/gyp_configuration.gypi
@@ -13,12 +13,6 @@
 # limitations under the License.
 
 {
-  'variables': {
-    # This should have a default value in cobalt/base.gypi. See the comment
-    # there for acceptable values for this variable.
-    'javascript_engine': 'mozjs',
-    'cobalt_enable_jit': 1,
-  },
   'includes': [
     '../libraries.gypi',
     '../../shared/gyp_configuration.gypi',
diff --git a/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi b/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi
index 3bd32d7..a59e9c6 100644
--- a/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi
@@ -128,6 +128,8 @@
           '-Wno-shift-negative-value',
           # Width of bit-field exceeds width of its type- value will be truncated
           '-Wno-bitfield-width',
+          # Do not warn if a function or variable cannot be implicitly
+          # instantiated.
           '-Wno-undefined-var-template',
         ],
       }],
diff --git a/src/starboard/linux/x64x11/gcc/4.2/compiler_flags.gypi b/src/starboard/linux/x64x11/gcc/4.2/compiler_flags.gypi
index 7870304..cbc3aeb 100644
--- a/src/starboard/linux/x64x11/gcc/4.2/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/gcc/4.2/compiler_flags.gypi
@@ -93,10 +93,6 @@
       '-std=c99',
     ],
     'cflags_cc': [
-      # Limit to gnu++98. This allows Linux to be a canary build for any
-      # C++11 features that are not supported on some platforms' compilers.
-      # We do allow ourselves GNU extensions, which are assumed to exist
-      # by Chromium code.
       '-std=gnu++98',
       # Don't warn for invalid access to non-static data member of NULL object.
       '-Wno-invalid-offsetof',
diff --git a/src/starboard/linux/x64x11/gcc/4.2/gyp_configuration.gypi b/src/starboard/linux/x64x11/gcc/4.2/gyp_configuration.gypi
index f5c5ee5..b8a22da 100644
--- a/src/starboard/linux/x64x11/gcc/4.2/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/gcc/4.2/gyp_configuration.gypi
@@ -13,6 +13,12 @@
 # limitations under the License.
 
 {
+  'variables': {
+    # This should have a default value in cobalt/base.gypi. See the comment
+    # there for acceptable values for this variable.
+    'javascript_engine': 'mozjs',
+    'cobalt_enable_jit': 1,
+  },
   'target_defaults': {
     'default_configuration': 'linux-x64x11-gcc-4-2_debug',
     'configurations': {
diff --git a/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi b/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi
index 9fc908e..7af753c 100644
--- a/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/gcc/4.4/compiler_flags.gypi
@@ -89,10 +89,6 @@
       '-std=c99',
     ],
     'cflags_cc': [
-      # Limit to gnu++98. This allows Linux to be a canary build for any
-      # C++11 features that are not supported on some platforms' compilers.
-      # We do allow ourselves GNU extensions, which are assumed to exist
-      # by Chromium code.
       '-std=gnu++98',
       # Don't warn for invalid access to non-static data member of NULL object.
       '-Wno-invalid-offsetof',
diff --git a/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.gypi b/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.gypi
index 5749404..322ade0 100644
--- a/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/gcc/4.4/gyp_configuration.gypi
@@ -13,6 +13,12 @@
 # limitations under the License.
 
 {
+  'variables': {
+    # This should have a default value in cobalt/base.gypi. See the comment
+    # there for acceptable values for this variable.
+    'javascript_engine': 'mozjs',
+    'cobalt_enable_jit': 1,
+  },
   'target_defaults': {
     'default_configuration': 'linux-x64x11-gcc-4-4_debug',
     'configurations': {
diff --git a/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.gypi b/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.gypi
index dc9ec62..e781887 100644
--- a/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/gcc/6.3/gyp_configuration.gypi
@@ -13,6 +13,12 @@
 # limitations under the License.
 
 {
+  'variables': {
+    # This should have a default value in cobalt/base.gypi. See the comment
+    # there for acceptable values for this variable.
+    'javascript_engine': 'mozjs-45',
+    'cobalt_enable_jit': 0,
+  },
   'target_defaults': {
     'default_configuration': 'linux-x64x11-gcc-6-3_debug',
     'configurations': {
diff --git a/src/starboard/linux/x64x11/gcc/gyp_configuration.gypi b/src/starboard/linux/x64x11/gcc/gyp_configuration.gypi
index 0df5d5f..6fe92c5 100644
--- a/src/starboard/linux/x64x11/gcc/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/gcc/gyp_configuration.gypi
@@ -14,10 +14,7 @@
 
 {
   'variables': {
-    # This should have a default value in cobalt/base.gypi. See the comment
-    # there for acceptable values for this variable.
-    'javascript_engine': 'mozjs',
-    'cobalt_enable_jit': 1,
+
   },
   'includes': [
     '../libraries.gypi',
diff --git a/src/starboard/linux/x64x11/gyp_configuration.gypi b/src/starboard/linux/x64x11/gyp_configuration.gypi
index 1203c9d..948e2b7 100644
--- a/src/starboard/linux/x64x11/gyp_configuration.gypi
+++ b/src/starboard/linux/x64x11/gyp_configuration.gypi
@@ -16,8 +16,8 @@
   'variables': {
     # This should have a default value in cobalt/base.gypi. See the comment
     # there for acceptable values for this variable.
-    'javascript_engine': 'mozjs',
-    'cobalt_enable_jit': 1,
+    'javascript_engine': 'mozjs-45',
+    'cobalt_enable_jit': 0,
   },
   'target_defaults': {
     'default_configuration': 'linux-x64x11_debug',
diff --git a/src/starboard/nplb/cryptography_helpers.cc b/src/starboard/nplb/cryptography_helpers.cc
new file mode 100644
index 0000000..ccdba66
--- /dev/null
+++ b/src/starboard/nplb/cryptography_helpers.cc
@@ -0,0 +1,145 @@
+/* ====================================================================
+ * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ==================================================================== */
+
+// Modifications Copyright 2017 Google Inc. 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.
+
+#include "starboard/nplb/cryptography_helpers.h"
+
+#include <string>
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/log.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+
+namespace {
+int FromHex(uint8_t* out, char in) {
+  if (in >= '0' && in <= '9') {
+    *out = in - '0';
+    return 1;
+  }
+  if (in >= 'a' && in <= 'f') {
+    *out = in - 'a' + 10;
+    return 1;
+  }
+  if (in >= 'A' && in <= 'F') {
+    *out = in - 'A' + 10;
+    return 1;
+  }
+
+  return 0;
+}
+}  // namespace
+
+void DecodeHex(scoped_array<uint8_t>* out,
+               int* out_len,
+               const char* in,
+               int test_num,
+               const char* description) {
+  if (in == NULL) {
+    out->reset();
+    *out_len = 0;
+    return;
+  }
+
+  size_t len = SbStringGetLength(in);
+  if (len & 1) {
+    ADD_FAILURE() << description << ": Odd length.";
+    return;
+  }
+
+  scoped_array<uint8_t> buf(new uint8_t[len / 2]);
+  if (!buf) {
+    ADD_FAILURE() << description << ": Memory fail.";
+    return;
+  }
+
+  for (size_t i = 0; i < len; i += 2) {
+    uint8_t v, v2;
+    bool result = FromHex(&v, in[i]) && FromHex(&v2, in[i + 1]);
+    if (!result) {
+      ADD_FAILURE() << description << ": Invalid character at " << i << ".";
+      continue;
+    }
+
+    buf[i / 2] = (v << 4) | v2;
+  }
+
+  *out = buf.Pass();
+  *out_len = static_cast<int>(len / 2);
+}
+
+std::string HexDump(const void* in, int len) {
+  const uint8_t* data = reinterpret_cast<const uint8_t*>(in);
+
+  std::string result;
+  for (size_t i = 0; i < len; i++) {
+    char hex[3] = {0};
+    SbStringFormatF(hex, 3, "%02x", data[i]);
+    result += hex;
+  }
+
+  return result;
+}
+
+}  // namespace nplb
+}  // namespace starboard
diff --git a/src/starboard/nplb/cryptography_helpers.h b/src/starboard/nplb/cryptography_helpers.h
new file mode 100644
index 0000000..fdadcd5
--- /dev/null
+++ b/src/starboard/nplb/cryptography_helpers.h
@@ -0,0 +1,85 @@
+/* ====================================================================
+ * Copyright (c) 2008 The OpenSSL Project.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ *    software must display the following acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ *    endorse or promote products derived from this software without
+ *    prior written permission. For written permission, please contact
+ *    openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ *    nor may "OpenSSL" appear in their names without prior written
+ *    permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ *    acknowledgment:
+ *    "This product includes software developed by the OpenSSL Project
+ *    for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ==================================================================== */
+
+// Modifications Copyright 2017 Google Inc. 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 STARBOARD_NPLB_CRYPTOGRAPHY_HELPERS_H_
+#define STARBOARD_NPLB_CRYPTOGRAPHY_HELPERS_H_
+
+#include <string>
+
+#include "starboard/common/scoped_ptr.h"
+#include "starboard/log.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace starboard {
+namespace nplb {
+
+void DecodeHex(scoped_array<uint8_t>* out,
+               int* out_len,
+               const char* in,
+               int test_num,
+               const char* description);
+std::string HexDump(const void* in, int len);
+
+}  // namespace nplb
+}  // namespace starboard
+
+#endif  // STARBOARD_NPLB_CRYPTOGRAPHY_HELPERS_H_
diff --git a/src/starboard/nplb/cryptography_transform_gcm_test.cc b/src/starboard/nplb/cryptography_transform_gcm_test.cc
index d2674a4..6f42daa 100644
--- a/src/starboard/nplb/cryptography_transform_gcm_test.cc
+++ b/src/starboard/nplb/cryptography_transform_gcm_test.cc
@@ -66,6 +66,7 @@
 
 #include "starboard/common/scoped_ptr.h"
 #include "starboard/log.h"
+#include "starboard/nplb/cryptography_helpers.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -108,34 +109,43 @@
   },
   {
     "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
     NULL,
     "cafebabefacedbaddecaf888",
-    "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
+    "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b254"
+    "66931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
     "4d5c2af327cd64a62cf35abd2ba6fab4",
   },
   {
     "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
     "cafebabefacedbaddecaf888",
-    "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
+    "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b254"
+    "66931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
     "5bc94fbc3221a5db94fae95ae7121a47",
   },
   {
     "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
     "cafebabefacedbad",
-    "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
+    "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e4"
+    "9f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
     "3612d2e79e3b0785561be14aaca2fccb",
   },
   {
     "feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
-    "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
+    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156"
+    "809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+    "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fb"
+    "a43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
     "619cc5aefffe0bfa462af43c1699d050",
   },
   {
@@ -156,42 +166,53 @@
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
     NULL,
     "cafebabefacedbaddecaf888",
-    "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
+    "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c1"
+    "44c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
     "9924a7c8587336bfb118024db8674a14",
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
     "cafebabefacedbaddecaf888",
-    "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
+    "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c1"
+    "44c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
     "2519498e80f1478f37ba55bd6d27618c",
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
     "cafebabefacedbad",
-    "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+    "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a"
+    "471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
     "65dcc57fcf623a24094fcca40d3533f8",
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
     "cafebabefacedbad",
-    "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+    "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a"
+    "471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
     "65dcc57fcf623a24094fcca40d3533f8",
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
-    "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
+    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156"
+    "809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+    "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af"
+    "34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
     "dcf566ff291c25bbb8568fc3d376a6d9",
   },
   {
@@ -212,120 +233,82 @@
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
     NULL,
     "cafebabefacedbaddecaf888",
-    "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+    "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e4859"
+    "0dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
     "b094dac5d93471bdec1a502270e3cc6c",
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
     "cafebabefacedbaddecaf888",
-    "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
+    "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e4859"
+    "0dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
     "76fc6ece0f4e1768cddf8853bb2d551b",
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
     "cafebabefacedbad",
-    "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
+    "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d339"
+    "34a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
     "3a337dbf46a792c45e454913fe2ea8f2",
   },
   {
     "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
     "feedfacedeadbeeffeedfacedeadbeefabaddad2",
-    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
-    "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
+    "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156"
+    "809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+    "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780"
+    "f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
     "a44a8266ee1c8eb0c8b5d4cf5ae9f19a",
   },
   {
     "00000000000000000000000000000000",
     NULL,
-    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+    "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c9595"
+    "6809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255522dc1f099567d07f47f"
+    "37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b10568288"
+    "38c5f61e6393ba7a0abcc9f662898015ad",
     "000000000000000000000000",
     NULL,
     "5fea793a2d6f974d37e68e0cb8ff9492",
   },
   {
     "00000000000000000000000000000000",
-    "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+    "00000000000000000000000000000000000000000000000000000000000000000000000000"
+    "00000000000000000000000000000000000000000000000000000000000000000000000000"
+    "00000000000000000000000000000000000000000000000000000000000000000000000000"
+    "00000000000000000000000000000000000000000000000000000000000000000000000000"
+    "00000000000000000000000000000000000000000000000000000000000000000000000000"
+    "00000000000000000000000000000000000000000000000000000000000000000000000000"
+    "00000000000000000000000000000000000000000000000000000000000000000000000000"
+    "0000000000000000000000000000000000000000000000000000000000",
     NULL,
     /* This nonce results in 0xfff in counter LSB. */
-    "ffffffff000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
-    "56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48cf7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e501511221376a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b1070bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dcf3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a439c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c",
+    "ffffffff000000000000000000000000000000000000000000000000000000000000000000"
+    "000000000000000000000000000000000000000000000000000000",
+    "56b3373ca9ef6e4a2b64fe1e9a17b61425f10d47a75a5fce13efc6bc784af24f4141bdd48c"
+    "f7c770887afd573cca5418a9aeffcd7c5ceddfc6a78397b9a85b499da558257267caab2ad0"
+    "b23ca476a53cb17fb41c4b8b475cb4f3f7165094c229c9e8c4dc0a2a5ff1903e5015112213"
+    "76a1cdb8364c5061a20cae74bc4acd76ceb0abc9fd3217ef9f8c90be402ddf6d8697f4f880"
+    "dff15bfb7a6b28241ec8fe183c2d59e3f9dfff653c7126f0acb9e64211f42bae12af462b10"
+    "70bef1ab5e3606872ca10dee15b3249b1a1b958f23134c4bccb7d03200bce420a2f8eb66dc"
+    "f3644d1423c1b5699003c13ecef4bf38a3b60eedc34033bac1902783dc6d89e2e774188a43"
+    "9c7ebcc0672dbda4ddcfb2794613b0be41315ef778708a70ee7d75165c",
     "8b307f6b33286d0ab026a9ed3fe1e85f",
   },
 };
 
-int from_hex(uint8_t *out, char in) {
-  if (in >= '0' && in <= '9') {
-    *out = in - '0';
-    return 1;
-  }
-  if (in >= 'a' && in <= 'f') {
-    *out = in - 'a' + 10;
-    return 1;
-  }
-  if (in >= 'A' && in <= 'F') {
-    *out = in - 'A' + 10;
-    return 1;
-  }
-
-  return 0;
-}
-
-void decode_hex(scoped_array<uint8_t> *out, int *out_len, const char *in,
-                int test_num, const char *description) {
-  if (in == NULL) {
-    out->reset();
-    *out_len = 0;
-    return;
-  }
-
-  size_t len = SbStringGetLength(in);
-  if (len & 1) {
-    ADD_FAILURE() << description << ": Odd length.";
-    return;
-  }
-
-  scoped_array<uint8_t> buf(new uint8_t[len / 2]);
-  if (!buf) {
-    ADD_FAILURE() << description << ": Memory fail.";
-    return;
-  }
-
-  for (size_t i = 0; i < len; i += 2) {
-    uint8_t v, v2;
-    bool result = from_hex(&v, in[i]) && from_hex(&v2, in[i + 1]);
-    if (!result) {
-      ADD_FAILURE() << description << ": Invalid character at " << i << ".";
-      continue;
-    }
-
-    buf[i / 2] = (v << 4) | v2;
-  }
-
-  *out = buf.Pass();
-  *out_len = static_cast<int>(len / 2);
-}
-
-std::string hexdump(const void *in, int len) {
-  const uint8_t* data = reinterpret_cast<const uint8_t*>(in);
-
-  std::string result;
-  for (size_t i = 0; i < len; i++) {
-    char hex[3] = {0};
-    SbStringFormatF(hex, 3, "%02x", data[i]);
-    result += hex;
-  }
-
-  return result;
-}
-
 class Gcm
     : public ::testing::TestWithParam<int> {
  public:
@@ -350,15 +333,15 @@
   scoped_array<uint8_t> tag;
   scoped_array<uint8_t> out;
 
-  decode_hex(&key, &key_len, test->key, test_num, "key");
-  decode_hex(&plaintext, &plaintext_len, test->plaintext, test_num,
+  DecodeHex(&key, &key_len, test->key, test_num, "key");
+  DecodeHex(&plaintext, &plaintext_len, test->plaintext, test_num,
              "plaintext");
-  decode_hex(&additional_data, &additional_data_len,
+  DecodeHex(&additional_data, &additional_data_len,
              test->additional_data, test_num, "additional_data");
-  decode_hex(&nonce, &nonce_len, test->nonce, test_num, "nonce");
-  decode_hex(&ciphertext, &ciphertext_len, test->ciphertext, test_num,
+  DecodeHex(&nonce, &nonce_len, test->nonce, test_num, "nonce");
+  DecodeHex(&ciphertext, &ciphertext_len, test->ciphertext, test_num,
              "ciphertext");
-  decode_hex(&tag, &tag_len, test->tag, test_num, "tag");
+  DecodeHex(&tag, &tag_len, test->tag, test_num, "tag");
 
   if (plaintext_len != ciphertext_len) {
     FAIL() << "Plaintext and ciphertext have differing lengths.";
@@ -407,13 +390,13 @@
   SbMemorySet(actual_tag.get(), 0, tag_len);
   SbCryptographyGetTag(encrypter, actual_tag.get(), tag_len);
   if (tag) {
-    EXPECT_STREQ(hexdump(tag.get(), tag_len).c_str(),
-                 hexdump(actual_tag.get(), tag_len).c_str());
+    EXPECT_STREQ(HexDump(tag.get(), tag_len).c_str(),
+                 HexDump(actual_tag.get(), tag_len).c_str());
   }
 
   if (ciphertext) {
-    EXPECT_STREQ(hexdump(ciphertext.get(), plaintext_len).c_str(),
-                 hexdump(out.get(), plaintext_len).c_str());
+    EXPECT_STREQ(HexDump(ciphertext.get(), plaintext_len).c_str(),
+                 HexDump(out.get(), plaintext_len).c_str());
   }
 
   SbCryptographyDestroyTransformer(encrypter);
@@ -443,13 +426,13 @@
   SbMemorySet(actual_tag.get(), 0, tag_len);
   SbCryptographyGetTag(decrypter, actual_tag.get(), tag_len);
   if (tag) {
-    EXPECT_STREQ(hexdump(tag.get(), tag_len).c_str(),
-                 hexdump(actual_tag.get(), tag_len).c_str());
+    EXPECT_STREQ(HexDump(tag.get(), tag_len).c_str(),
+                 HexDump(actual_tag.get(), tag_len).c_str());
   }
 
   if (plaintext) {
-    EXPECT_STREQ(hexdump(plaintext.get(), plaintext_len).c_str(),
-                 hexdump(out.get(), plaintext_len).c_str());
+    EXPECT_STREQ(HexDump(plaintext.get(), plaintext_len).c_str(),
+                 HexDump(out.get(), plaintext_len).c_str());
   }
   SbCryptographyDestroyTransformer(decrypter);
 }
diff --git a/src/starboard/nplb/cryptography_transform_test.cc b/src/starboard/nplb/cryptography_transform_test.cc
index fc44126..1b5770f 100644
--- a/src/starboard/nplb/cryptography_transform_test.cc
+++ b/src/starboard/nplb/cryptography_transform_test.cc
@@ -14,7 +14,9 @@
 
 #include "starboard/cryptography.h"
 
+#include "starboard/common/scoped_ptr.h"
 #include "starboard/log.h"
+#include "starboard/nplb/cryptography_helpers.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if SB_API_VERSION >= 4
@@ -23,50 +25,183 @@
 namespace nplb {
 namespace {
 
+class Aes : public ::testing::TestWithParam<SbCryptographyBlockCipherMode> {
+ protected:
+  SbCryptographyBlockCipherMode GetMode() { return GetParam(); }
+
+  bool ShouldSetIvAtInitialization() {
+    return GetIvMode() == kIvModeSetAtInitialization ||
+           GetIvMode() == kIvModeSetAnyTime;
+  }
+
+  bool ShouldSetIvAfterInitialization() {
+    return GetIvMode() == kIvModeSetAfterInitialization ||
+           GetIvMode() == kIvModeSetAnyTime;
+  }
+
+  bool ShouldSetAuthenticatedData() {
+    switch (GetMode()) {
+      case kSbCryptographyBlockCipherModeGcm:
+        return true;
+      case kSbCryptographyBlockCipherModeEcb:
+      case kSbCryptographyBlockCipherModeCtr:
+      case kSbCryptographyBlockCipherModeCbc:
+      case kSbCryptographyBlockCipherModeCfb:
+      case kSbCryptographyBlockCipherModeOfb:
+        return false;
+      default:
+        ADD_FAILURE() << "Unrecognized SbCryptographyBlockCipherMode "
+                      << GetMode();
+        return false;
+    }
+  }
+
+  const char* GetExpectedEncryptedValueHex() {
+    switch (GetMode()) {
+      case kSbCryptographyBlockCipherModeGcm:
+        return "6a7b6e871f851db21a29f6aef579cfb77238d34b2f099404f20bb44c6b2d4d2"
+               "0a2788f8ffc0a36eba4cd8e69ee95e973b5eb52d1e218ee991ccc0ee1ba2fa7"
+               "d1dc83a5d2e3c317e5637b67c2524bd073ec6fe547edf6044111e2e16c239ed"
+               "e845d4b7b235f24fbdb2673dbdd1c5d5c46d7b69059ff4b1566b01bec4f4ca6"
+               "a4c500";
+
+      case kSbCryptographyBlockCipherModeEcb:
+        return "36aa40499dccc9f25bb3c1abcf4b73cf5993dc6127c534e7491a31a54f09bc4"
+               "8e9fc157e380ca1457dedac9147e158be1c8eba2ec679d6bdc54cb2878cd2ab"
+               "6736aa40499dccc9f25bb3c1abcf4b73cf5993dc6127c534e7491a31a54f09b"
+               "c48e9fc157e380ca1457dedac9147e158beae602e043e0572ed2f71acf5438c"
+               "e78200";
+
+      case kSbCryptographyBlockCipherModeCtr:
+        return "f32f8a813cea30e0f4c6e2efeab52ab92976cc06fa5f69409c3358ef2f3782d"
+               "daff201f56acd9b61fea4c3e4739deab176ad764da16d1248d59337962c7ab0"
+               "f2cd4c292ed34ae4125d8fb142344b2d2fc4ff533b80f5e8e311cde700ceaed"
+               "a613c6f27f72a0602e6e4891e6b4f5a0a64e795998a40544d88363d124d5294"
+               "c91700";
+
+      case kSbCryptographyBlockCipherModeCbc:
+        return "eaa929d637cde55115d43257e920ff8d39d1dec8240255a5db79a0cf79501a1"
+               "4bc62c4d16fc45dd7fa9d15b3346a74301260dfeb96e22259787344d7e47047"
+               "3eb4187eeac16a74afd1c5fdc67fb145cc494667ea4b16dccc83cc1cc1b2c36"
+               "2f2a03e90d6c3a9adbf53c4cb8e4987719928ef7c47c4403f0cfe5a0ff77325"
+               "6eaa00";
+
+      case kSbCryptographyBlockCipherModeCfb:
+      case kSbCryptographyBlockCipherModeOfb:
+        ADD_FAILURE() << "Unsupported SbCryptographyBlockCipherMode "
+                      << GetMode();
+        return "";
+      default:
+        ADD_FAILURE() << "Unrecognized SbCryptographyBlockCipherMode "
+                      << GetMode();
+        return "";
+    }
+  }
+
+ private:
+  enum IvMode {
+    kIvModeNotUsed,
+    kIvModeSetAtInitialization,
+    kIvModeSetAfterInitialization,
+    kIvModeSetAnyTime,
+  };
+
+  IvMode GetIvMode() {
+    switch (GetMode()) {
+      case kSbCryptographyBlockCipherModeEcb:
+        return kIvModeNotUsed;
+      case kSbCryptographyBlockCipherModeGcm:
+        return kIvModeSetAfterInitialization;
+      case kSbCryptographyBlockCipherModeCtr:
+        return kIvModeSetAnyTime;
+      case kSbCryptographyBlockCipherModeCbc:
+      case kSbCryptographyBlockCipherModeCfb:
+      case kSbCryptographyBlockCipherModeOfb:
+        return kIvModeSetAtInitialization;
+      default:
+        ADD_FAILURE() << "Unrecognized SbCryptographyBlockCipherMode "
+                      << GetMode();
+        return kIvModeNotUsed;
+    }
+  }
+};
+
 const int kBlockSizeBits = 128;
 const int kBlockSizeBytes = kBlockSizeBits / 8;
 
-TEST(SbCryptographyTransform, SunnyDay) {
-  char initialization_vector[kBlockSizeBytes + 1] = "0123456789ABCDEF";
-  char key[kBlockSizeBytes + 1] = "RijndaelRijndael";
-  const char kClearText[] =
-      "This test text is designed to be a multiple of "
-      "128 bits, huzzah.";
+const char kClearText[] =
+    "This test text is designed to be a multiple of 128 bits, huzzah-"
+    "This test text is designed to be a multiple of 128 bits, huzzah!";
+const char kAdditionalDataString[] = "000000000000000000000000";
+const char kInitializationVector[kBlockSizeBytes + 1] = "0123456789ABCDEF";
+const char kKey[kBlockSizeBytes + 1] = "Rijndael";
 
-  // Try to create a transformer for the most likely algorithm to be supported:
-  // AES-128-CBC
-  SbCryptographyTransformer transformer = SbCryptographyCreateTransformer(
+TEST_P(Aes, SunnyDayIdentity) {
+  SbCryptographyBlockCipherMode mode = GetMode();
+
+  SbCryptographyTransformer encrypter = SbCryptographyCreateTransformer(
       kSbCryptographyAlgorithmAes, kBlockSizeBits,
-      kSbCryptographyDirectionEncode, kSbCryptographyBlockCipherModeCbc,
-      initialization_vector, kBlockSizeBytes, key, kBlockSizeBytes);
+      kSbCryptographyDirectionEncode, mode,
+      ShouldSetIvAtInitialization() ? kInitializationVector : NULL,
+      ShouldSetIvAtInitialization() ? kBlockSizeBytes : 0, kKey,
+      kBlockSizeBytes);
 
-  if (!SbCryptographyIsTransformerValid(transformer)) {
+  if (!SbCryptographyIsTransformerValid(encrypter)) {
+    SB_LOG(WARNING) << "Skipping test, as there is no implementation.";
     // Test over if there's no implementation.
     return;
   }
 
+  if (ShouldSetIvAfterInitialization()) {
+    SbCryptographySetInitializationVector(encrypter, kInitializationVector,
+                                          kBlockSizeBytes);
+  }
+
+  if (ShouldSetAuthenticatedData()) {
+    scoped_array<uint8_t> aad;
+    int aad_len = 0;
+    DecodeHex(&aad, &aad_len, kAdditionalDataString, GetMode(), "aad");
+    SbCryptographySetAuthenticatedData(encrypter, aad.get(), aad_len);
+  }
+
   const int kInputSize = static_cast<int>(SbStringGetLength(kClearText));
   const int kBufferSize = static_cast<int>(sizeof(kClearText));
   char* cipher_text = new char[kBufferSize];
   SbMemorySet(cipher_text, 0, kBufferSize);
-  int count = SbCryptographyTransform(transformer, kClearText, kInputSize,
-                                      cipher_text);
+  int count =
+      SbCryptographyTransform(encrypter, kClearText, kInputSize, cipher_text);
   EXPECT_EQ(kInputSize, count);
   EXPECT_NE(0, SbStringCompare(kClearText, cipher_text, kBufferSize));
 
-  SbCryptographyTransformer decode_transformer =
-      SbCryptographyCreateTransformer(
-          kSbCryptographyAlgorithmAes, kBlockSizeBits,
-          kSbCryptographyDirectionDecode, kSbCryptographyBlockCipherModeCbc,
-          initialization_vector, kBlockSizeBytes, key, kBlockSizeBytes);
+  EXPECT_STREQ(GetExpectedEncryptedValueHex(),
+               HexDump(cipher_text, kBufferSize).c_str());
 
-  ASSERT_TRUE(SbCryptographyIsTransformerValid(decode_transformer));
+  SbCryptographyTransformer decrypter = SbCryptographyCreateTransformer(
+      kSbCryptographyAlgorithmAes, kBlockSizeBits,
+      kSbCryptographyDirectionDecode, mode,
+      ShouldSetIvAtInitialization() ? kInitializationVector : NULL,
+      ShouldSetIvAtInitialization() ? kBlockSizeBytes : 0, kKey,
+      kBlockSizeBytes);
+
+  ASSERT_TRUE(SbCryptographyIsTransformerValid(decrypter))
+      << "Cryptographic support for a set of parameters must be symmetrical.";
+
+  if (ShouldSetIvAfterInitialization()) {
+    SbCryptographySetInitializationVector(decrypter, kInitializationVector,
+                                          kBlockSizeBytes);
+  }
+
+  if (ShouldSetAuthenticatedData()) {
+    scoped_array<uint8_t> aad;
+    int aad_len = 0;
+    DecodeHex(&aad, &aad_len, kAdditionalDataString, GetMode(), "aad");
+    SbCryptographySetAuthenticatedData(decrypter, aad.get(), aad_len);
+  }
 
   char* decrypted_text = new char[kBufferSize];
   SbMemorySet(decrypted_text, 0, kBufferSize);
-  count =
-      SbCryptographyTransform(decode_transformer, cipher_text, kInputSize,
-                              decrypted_text);
+  count = SbCryptographyTransform(decrypter, cipher_text, kInputSize,
+                                  decrypted_text);
 
   EXPECT_EQ(kInputSize, count);
   EXPECT_EQ(kInputSize, SbStringGetLength(decrypted_text));
@@ -74,10 +209,19 @@
 
   delete[] decrypted_text;
   delete[] cipher_text;
-  SbCryptographyDestroyTransformer(decode_transformer);
-  SbCryptographyDestroyTransformer(transformer);
+  SbCryptographyDestroyTransformer(decrypter);
+  SbCryptographyDestroyTransformer(encrypter);
 }
 
+INSTANTIATE_TEST_CASE_P(SbCryptographyTransform,
+                        Aes,
+                        ::testing::Values(kSbCryptographyBlockCipherModeCbc,
+                                          kSbCryptographyBlockCipherModeCfb,
+                                          kSbCryptographyBlockCipherModeCtr,
+                                          kSbCryptographyBlockCipherModeEcb,
+                                          kSbCryptographyBlockCipherModeOfb,
+                                          kSbCryptographyBlockCipherModeGcm));
+
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/src/starboard/nplb/memory_reporter_test.cc b/src/starboard/nplb/memory_reporter_test.cc
index e225324..d60e010 100644
--- a/src/starboard/nplb/memory_reporter_test.cc
+++ b/src/starboard/nplb/memory_reporter_test.cc
@@ -328,7 +328,7 @@
     return;
   }
   const int64_t kMemSize = 4096;
-  const int kFlags = 0;
+  const int kFlags = kSbMemoryMapProtectReadWrite;
   EXPECT_EQ_NO_TRACKING(0, mem_reporter()->number_allocs());
   void* mem_chunk = SbMemoryMap(kMemSize, kFlags, "TestMemMap");
   EXPECT_EQ_NO_TRACKING(1, mem_reporter()->number_allocs());
diff --git a/src/starboard/nplb/nplb.gyp b/src/starboard/nplb/nplb.gyp
index 782c729..174b062 100644
--- a/src/starboard/nplb/nplb.gyp
+++ b/src/starboard/nplb/nplb.gyp
@@ -82,6 +82,8 @@
         'condition_variable_wait_timed_test.cc',
         'configuration_test.cc',
         'cryptography_create_transformer_test.cc',
+        'cryptography_helpers.cc',
+        'cryptography_helpers.h',
         'cryptography_transform_test.cc',
         'cryptography_transform_gcm_test.cc',
         'decode_target_create_test.cc',
@@ -153,6 +155,7 @@
         'socket_connect_test.cc',
         'socket_create_test.cc',
         'socket_destroy_test.cc',
+        'socket_get_interface_address_test.cc',
         'socket_get_last_error_test.cc',
         'socket_get_local_address_test.cc',
         'socket_get_local_interface_address_test.cc',
diff --git a/src/starboard/nplb/socket_get_interface_address_test.cc b/src/starboard/nplb/socket_get_interface_address_test.cc
new file mode 100644
index 0000000..a9d3f5a
--- /dev/null
+++ b/src/starboard/nplb/socket_get_interface_address_test.cc
@@ -0,0 +1,197 @@
+// Copyright 2017 Google Inc. 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.
+
+#include "starboard/nplb/socket_helpers.h"
+#include "starboard/socket.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+const unsigned char kInvalidByte = 0xFE;
+
+}  // namespace
+
+namespace starboard {
+namespace nplb {
+namespace {
+
+#if SB_API_VERSION >= 4
+class SbSocketGetInterfaceAddressTest
+    : public ::testing::TestWithParam<SbSocketAddressType> {
+ public:
+  SbSocketAddressType GetAddressType() { return GetParam(); }
+};
+
+TEST(SbSocketGetInterfaceAddressTest, SunnyDay) {
+  SbSocketAddress invalid_address;
+  SbSocketAddress address;
+
+  // Initialize to something invalid.
+  SbMemorySet(&address, kInvalidByte, sizeof(address));
+  SbMemorySet(&invalid_address, kInvalidByte, sizeof(invalid_address));
+
+  EXPECT_TRUE(SbSocketGetInterfaceAddress(NULL, &address, NULL));
+  EXPECT_EQ(0, address.port);
+  EXPECT_FALSE(IsUnspecified(&address));
+  EXPECT_FALSE(IsLocalhost(&address));
+  EXPECT_NE(0, SbMemoryCompare(address.address, invalid_address.address,
+                               SB_ARRAY_SIZE(address.address)));
+}
+
+TEST(SbSocketGetInterfaceAddressTest, RainyDayNull) {
+  EXPECT_FALSE(SbSocketGetInterfaceAddress(NULL, NULL, NULL));
+}
+
+TEST(SbSocketGetInterfaceAddressTest, SunnyDayNullDestination) {
+  SbSocketAddress netmask;
+  SbSocketAddress source;
+
+  SbMemorySet(&netmask, kInvalidByte, sizeof(netmask));
+  SbMemorySet(&source, kInvalidByte, sizeof(source));
+
+  // If destination address is NULL, then any IP address that is valid for
+  // |destination| set to 0.0.0.0 (IPv4) or :: (IPv6) can be returned.
+
+  EXPECT_TRUE(SbSocketGetInterfaceAddress(NULL, &source, NULL));
+  EXPECT_TRUE(source.type == kSbSocketAddressTypeIpv4 ||
+              source.type == kSbSocketAddressTypeIpv6);
+
+  EXPECT_TRUE(SbSocketGetInterfaceAddress(NULL, &source, &netmask));
+  // A netmask that starts with 0 is likely incorrect.
+  EXPECT_TRUE(netmask.address[0] & 0x8);
+  EXPECT_TRUE(source.type == kSbSocketAddressTypeIpv4 ||
+              source.type == kSbSocketAddressTypeIpv6);
+  EXPECT_TRUE(netmask.type == kSbSocketAddressTypeIpv4 ||
+              netmask.type == kSbSocketAddressTypeIpv6);
+}
+
+TEST_P(SbSocketGetInterfaceAddressTest, SunnyDayDestination) {
+  SbSocketAddress destination = {0};
+  destination.type = GetAddressType();
+
+  SbSocketAddress netmask;
+  SbSocketAddress source;
+
+  // Initialize to something invalid.
+  SbMemorySet(&netmask, kInvalidByte, sizeof(netmask));
+  SbMemorySet(&source, kInvalidByte, sizeof(source));
+
+  EXPECT_TRUE(SbSocketGetInterfaceAddress(&destination, &source, NULL));
+  EXPECT_TRUE(source.type == GetAddressType());
+  EXPECT_TRUE(SbSocketGetInterfaceAddress(&destination, &source, &netmask));
+
+  EXPECT_FALSE(IsLocalhost(&source));
+
+  // A netmask that starts with 0 is likely incorrect.
+  EXPECT_TRUE(netmask.address[0] & 0x8);
+  EXPECT_EQ(source.type, GetAddressType());
+  EXPECT_EQ(netmask.type, GetAddressType());
+  EXPECT_EQ(source.port, 0);
+}
+
+TEST_P(SbSocketGetInterfaceAddressTest, SunnyDaySourceForDestination) {
+  const char kTestHostName[] = "www.example.com";
+
+  SbSocketResolveFilter resolve_filter = kSbSocketResolveFilterNone;
+  switch (GetAddressType()) {
+    case kSbSocketAddressTypeIpv4:
+      resolve_filter = kSbSocketResolveFilterIpv4;
+      break;
+    case kSbSocketAddressTypeIpv6:
+      resolve_filter = kSbSocketResolveFilterIpv6;
+      break;
+    default:
+      FAIL() << "Invalid address type " << GetAddressType();
+  }
+  SbSocketResolution* resolution =
+      SbSocketResolve(kTestHostName, resolve_filter);
+
+  // TODO: Switch to nullptr, when C++11 is available.
+  ASSERT_NE(resolution, reinterpret_cast<SbSocketResolution*>(NULL));
+  ASSERT_NE(resolution->address_count, 0);
+  SbSocketAddress& destination_address = resolution->addresses[0];
+
+  SbSocketAddress source;
+  SbSocketAddress netmask;
+  SbSocketAddress invalid_address;
+  SbMemorySet(&netmask, kInvalidByte, sizeof(netmask));
+  SbMemorySet(&source, kInvalidByte, sizeof(source));
+  SbMemorySet(&invalid_address, kInvalidByte, sizeof(source));
+  SbSocketGetInterfaceAddress(&destination_address, &source, &netmask);
+
+  EXPECT_TRUE(source.type == GetAddressType());
+  EXPECT_NE(source.port, 0);
+  // A netmask that starts with 0 is likely incorrect.
+  EXPECT_TRUE(netmask.address[0] & 0x8);
+  EXPECT_EQ(netmask.type, GetAddressType());
+  EXPECT_NE(0, SbMemoryCompare(source.address, invalid_address.address,
+                               SB_ARRAY_SIZE(source.address)));
+  EXPECT_NE(0, SbMemoryCompare(netmask.address, invalid_address.address,
+                               SB_ARRAY_SIZE(netmask.address)));
+
+  SbSocketFreeResolution(resolution);
+}
+
+TEST_P(SbSocketGetInterfaceAddressTest, SunnyDaySourceNotLoopback) {
+  SbSocketAddress destination = {0};
+  destination.type = GetAddressType();
+
+  // If the destination address is 0.0.0.0, and its |type| is
+  // |kSbSocketAddressTypeIpv4|, then any IPv4 local interface that is up and
+  // not a loopback interface is a valid return value.
+  //
+  // If the destination address is ::, and its |type| is
+  // |kSbSocketAddressTypeIpv6| then any IPv6 local interface that is up and
+  // not loopback or a link-local IP is a valid return value.  However, in the
+  // case of IPv6, the address with the biggest scope must be returned.  E.g., a
+  // globally scoped and routable IP is prefered over a unique local address
+  // (ULA). Also, the IP address that is returned must be permanent.
+
+  SbSocketAddress netmask;
+  SbSocketAddress source;
+  SbSocketAddress invalid_address;
+
+  // Initialize to something invalid.
+  SbMemorySet(&netmask, kInvalidByte, sizeof(netmask));
+  SbMemorySet(&source, kInvalidByte, sizeof(source));
+  SbMemorySet(&invalid_address, kInvalidByte, sizeof(invalid_address));
+
+  EXPECT_TRUE(SbSocketGetInterfaceAddress(&destination, &source, NULL));
+  EXPECT_EQ(source.type, GetAddressType());
+  EXPECT_TRUE(SbSocketGetInterfaceAddress(&destination, &source, &netmask));
+  EXPECT_FALSE(IsLocalhost(&source));
+  EXPECT_FALSE(IsUnspecified(&source));
+
+  EXPECT_NE(0, SbMemoryCompare(netmask.address, invalid_address.address,
+                               SB_ARRAY_SIZE(netmask.address)));
+  EXPECT_NE(0, SbMemoryCompare(source.address, invalid_address.address,
+                               SB_ARRAY_SIZE(source.address)));
+}
+
+#if SB_HAS(IPV6)
+INSTANTIATE_TEST_CASE_P(SbSocketAddressTypes,
+                        SbSocketGetInterfaceAddressTest,
+                        ::testing::Values(kSbSocketAddressTypeIpv4,
+                                          kSbSocketAddressTypeIpv6));
+#else
+INSTANTIATE_TEST_CASE_P(SbSocketAddressTypes,
+                        SbSocketGetInterfaceAddressTest,
+                        ::testing::Values(kSbSocketAddressTypeIpv4));
+#endif  // SB_HAS(IPV6)
+
+#endif  // SB_API_VERSION >= 4
+
+}  // namespace
+}  // namespace nplb
+}  // namespace starboard
diff --git a/src/starboard/nplb/socket_get_local_interface_address_test.cc b/src/starboard/nplb/socket_get_local_interface_address_test.cc
index a282f61..db8e0eb 100644
--- a/src/starboard/nplb/socket_get_local_interface_address_test.cc
+++ b/src/starboard/nplb/socket_get_local_interface_address_test.cc
@@ -20,28 +20,24 @@
 namespace nplb {
 namespace {
 
+#if SB_API_VERSION < 4
+
 TEST(SbSocketGetLocalInterfaceAddressTest, SunnyDay) {
   SbSocketAddress address;
   // Initialize to something invalid.
   SbMemorySet(&address, 0xFE, sizeof(address));
-#if SB_API_VERSION < 4
   EXPECT_TRUE(SbSocketGetLocalInterfaceAddress(&address));
-#else
-  EXPECT_TRUE(SbSocketGetInterfaceAddress(NULL, &address, NULL));
-#endif  // SB_API_VERSION < 4
   EXPECT_EQ(0, address.port);
   EXPECT_FALSE(IsUnspecified(&address));
   EXPECT_FALSE(IsLocalhost(&address));
 }
 
 TEST(SbSocketGetLocalInterfaceAddressTest, RainyDayNull) {
-#if SB_API_VERSION < 4
   EXPECT_FALSE(SbSocketGetLocalInterfaceAddress(NULL));
-#else
-  EXPECT_FALSE(SbSocketGetInterfaceAddress(NULL, NULL, NULL));
-#endif  // SB_API_VERSION < 4
 }
 
+#endif  // SB_API_VERSION < 4
+
 }  // namespace
 }  // namespace nplb
 }  // namespace starboard
diff --git a/src/starboard/nplb/socket_set_options_test.cc b/src/starboard/nplb/socket_set_options_test.cc
index a6557a8..b7825df 100644
--- a/src/starboard/nplb/socket_set_options_test.cc
+++ b/src/starboard/nplb/socket_set_options_test.cc
@@ -27,10 +27,9 @@
   SbSocketAddressType GetAddressType() { return GetParam(); }
 };
 
-TEST_P(SbSocketSetOptionsTest, TryThemAll) {
+TEST_P(SbSocketSetOptionsTest, TryThemAllTCP) {
   SbSocket socket = SbSocketCreate(GetAddressType(), kSbSocketProtocolTcp);
 
-  EXPECT_TRUE(SbSocketSetBroadcast(socket, true));
   EXPECT_TRUE(SbSocketSetReuseAddress(socket, true));
   EXPECT_TRUE(SbSocketSetReceiveBufferSize(socket, 16 * 1024));
   EXPECT_TRUE(SbSocketSetSendBufferSize(socket, 16 * 1024));
@@ -44,6 +43,17 @@
   EXPECT_TRUE(SbSocketDestroy(socket));
 }
 
+TEST_P(SbSocketSetOptionsTest, TryThemAllUDP) {
+  SbSocket socket = SbSocketCreate(GetAddressType(), kSbSocketProtocolUdp);
+
+  EXPECT_TRUE(SbSocketSetBroadcast(socket, true));
+  EXPECT_TRUE(SbSocketSetReuseAddress(socket, true));
+  EXPECT_TRUE(SbSocketSetReceiveBufferSize(socket, 16 * 1024));
+  EXPECT_TRUE(SbSocketSetSendBufferSize(socket, 16 * 1024));
+
+  EXPECT_TRUE(SbSocketDestroy(socket));
+}
+
 // TODO: Come up with some way to test the effects of these options.
 
 #if SB_HAS(IPV6)
diff --git a/src/starboard/shared/linux/socket_get_interface_address.cc b/src/starboard/shared/linux/socket_get_interface_address.cc
index 923e4c0..b9bd9c4 100644
--- a/src/starboard/shared/linux/socket_get_interface_address.cc
+++ b/src/starboard/shared/linux/socket_get_interface_address.cc
@@ -96,7 +96,8 @@
 template <typename in_addr_type>
 bool GetNetmaskForInterfaceAddress(const SbSocketAddress& interface_address,
                                    SbSocketAddress* out_netmask) {
-  SB_DCHECK(interface_address.type == kSbSocketAddressTypeIpv4);
+  SB_DCHECK((interface_address.type == kSbSocketAddressTypeIpv4) ||
+            (interface_address.type == kSbSocketAddressTypeIpv6));
   struct ifaddrs* interface_addrs = NULL;
 
   int retval = getifaddrs(&interface_addrs);
@@ -125,7 +126,7 @@
     }
 
     sbposix::SockAddr sock_addr;
-    sock_addr.FromSockaddr(interface->ifa_addr);
+    sock_addr.FromSockaddr(interface->ifa_netmask);
     if (sock_addr.ToSbSocketAddress(out_netmask)) {
       found_netmask = true;
       break;
@@ -137,29 +138,18 @@
   return found_netmask;
 }
 
-bool GetNetMaskForIPv4InterfaceAddress(const SbSocketAddress& interface_address,
-                                       SbSocketAddress* out_netmask) {
-  return GetNetmaskForInterfaceAddress<in_addr>(interface_address, out_netmask);
-}
-
-#if SB_HAS(IPV6)
-bool GetNetMaskForIPv6InterfaceAddress(const SbSocketAddress& interface_address,
-                                       SbSocketAddress* out_netmask) {
-  return GetNetmaskForInterfaceAddress<in6_addr>(interface_address,
-                                                 out_netmask);
-}
-#endif
-
 bool GetNetMaskForInterfaceAddress(const SbSocketAddress& interface_address,
                                    SbSocketAddress* out_netmask) {
   SB_DCHECK(out_netmask);
 
   switch (interface_address.type) {
     case kSbSocketAddressTypeIpv4:
-      return GetNetMaskForIPv4InterfaceAddress(interface_address, out_netmask);
+      return GetNetmaskForInterfaceAddress<in_addr>(interface_address,
+                                                    out_netmask);
 #if SB_HAS(IPV6)
     case kSbSocketAddressTypeIpv6:
-      return GetNetMaskForIPv6InterfaceAddress(interface_address, out_netmask);
+      return GetNetmaskForInterfaceAddress<in6_addr>(interface_address,
+                                                     out_netmask);
 #endif
     default:
       SB_NOTREACHED() << "Invalid address type " << interface_address.type;
diff --git a/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc b/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc
index f38eea8..19c286d 100644
--- a/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc
+++ b/src/starboard/shared/starboard/cryptography/cryptography_create_transformer.cc
@@ -94,7 +94,6 @@
   int result = -1;
   if (direction == kSbCryptographyDirectionDecode &&
       mode != kSbCryptographyBlockCipherModeCtr &&
-      mode != kSbCryptographyBlockCipherModeEcb &&
       mode != kSbCryptographyBlockCipherModeGcm) {
     result = AES_set_decrypt_key(key, key_size * 8, &aeskey);
   } else {
diff --git a/src/starboard/shared/starboard/cryptography/cryptography_transform.cc b/src/starboard/shared/starboard/cryptography/cryptography_transform.cc
index bc78761..fc297c4 100644
--- a/src/starboard/shared/starboard/cryptography/cryptography_transform.cc
+++ b/src/starboard/shared/starboard/cryptography/cryptography_transform.cc
@@ -32,6 +32,16 @@
 using starboard::shared::starboard::cryptography::kAlgorithmAes128Ecb;
 using starboard::shared::starboard::cryptography::kAlgorithmAes128Gcm;
 
+namespace {
+inline void* AddPtr(void* pointer, int value) {
+  return reinterpret_cast<char*>(pointer) + value;
+}
+
+inline const void* AddPtr(const void* pointer, int value) {
+  return reinterpret_cast<const char*>(pointer) + value;
+}
+}  // namespace
+
 int SbCryptographyTransform(SbCryptographyTransformer transformer,
                             const void* in_data,
                             int in_data_size,
@@ -65,9 +75,21 @@
       }
 
       if (transformer->direction == kSbCryptographyDirectionEncode) {
-        AES_encrypt(in_data, out_data, &transformer->key);
+        const void* in = in_data;
+        void* out = out_data;
+        for (int i = 0, blocks = in_data_size / 16; i < blocks; ++i) {
+          AES_encrypt(in, out, &transformer->key);
+          in = AddPtr(in, 16);
+          out = AddPtr(out, 16);
+        }
       } else if (transformer->direction == kSbCryptographyDirectionDecode) {
-        AES_decrypt(in_data, out_data, &transformer->key);
+        const void* in = in_data;
+        void* out = out_data;
+        for (int i = 0, blocks = in_data_size / 16; i < blocks; ++i) {
+          AES_decrypt(in, out, &transformer->key);
+          in = AddPtr(in, 16);
+          out = AddPtr(out, 16);
+        }
       } else {
         SB_NOTREACHED();
       }
diff --git a/src/starboard/shared/starboard/log_message.cc b/src/starboard/shared/starboard/log_message.cc
index 444bcd6..5e267b2 100644
--- a/src/starboard/shared/starboard/log_message.cc
+++ b/src/starboard/shared/starboard/log_message.cc
@@ -14,10 +14,12 @@
 
 #include "starboard/log.h"
 
+#include <algorithm>
 #include <iomanip>
 #include <sstream>
 #include <string>
 
+#include "starboard/client_porting/poem/string_poem.h"
 #include "starboard/mutex.h"
 #include "starboard/system.h"
 #include "starboard/thread.h"
@@ -124,7 +126,11 @@
     // Ensure the first characters of the string are on the stack so they
     // are contained in minidumps for diagnostic purposes.
     char str_stack[1024];
-    str_newline.copy(str_stack, SB_ARRAY_SIZE(str_stack));
+    const size_t copy_bytes =
+        std::min(SB_ARRAY_SIZE(str_stack), str_newline.length() + 1);
+    PoemStringCopyN(str_stack, str_newline.c_str(),
+                    static_cast<int>(copy_bytes));
+
     Alias(str_stack);
     Break();
   }
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
index 96e38a7..7041009 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.cc
@@ -26,6 +26,12 @@
 namespace player {
 namespace filter {
 
+namespace {
+
+const SbTime kEndOfStreamWrittenUpdateInterval = 5 * kSbTimeMillisecond;
+
+}  // namespace
+
 AudioRendererImpl::AudioRendererImpl(JobQueue* job_queue,
                                      scoped_ptr<AudioDecoder> decoder,
                                      const SbMediaAudioHeader& audio_header)
@@ -46,7 +52,9 @@
       end_of_stream_written_(false),
       end_of_stream_decoded_(false),
       decoder_(decoder.Pass()),
-      audio_sink_(kSbAudioSinkInvalid) {
+      audio_sink_(kSbAudioSinkInvalid),
+      decoder_needs_full_reset_(false),
+      buffers_in_decoder_(0) {
   SB_DCHECK(job_queue != NULL);
   SB_DCHECK(decoder_ != NULL);
   SB_DCHECK(job_queue_->BelongsToCurrentThread());
@@ -96,6 +104,8 @@
   decoder_->Decode(input_buffer);
 
   ScopedLock lock(mutex_);
+  buffers_in_decoder_++;
+  decoder_needs_full_reset_ = true;
   if (!read_from_decoder_closure_.is_valid()) {
     read_from_decoder_closure_ =
         Bind(&AudioRendererImpl::ReadFromDecoder, this);
@@ -111,10 +121,13 @@
   if (end_of_stream_written_) {
     return;
   }
+
   decoder_->WriteEndOfStream();
 
   ScopedLock lock(mutex_);
+  buffers_in_decoder_++;
   end_of_stream_written_ = true;
+  decoder_needs_full_reset_ = true;
   // If we are seeking, we consider the seek is finished if end of stream is
   // reached as there won't be any audio data in future.
   if (seeking_) {
@@ -166,8 +179,12 @@
   end_of_stream_written_ = false;
   end_of_stream_decoded_ = false;
   pending_decoded_audio_ = NULL;
+  buffers_in_decoder_ = 0;
 
-  decoder_->Reset();
+  if (decoder_needs_full_reset_) {
+    decoder_->Reset();
+    decoder_needs_full_reset_ = false;
+  }
 }
 
 bool AudioRendererImpl::IsEndOfStreamPlayed() const {
@@ -184,7 +201,7 @@
   if (end_of_stream_written_) {
     return false;
   }
-  return pending_decoded_audio_ == NULL;
+  return buffers_in_decoder_ < kMaxbuffersInDecoder;
 }
 
 bool AudioRendererImpl::IsSeekingInProgress() const {
@@ -211,6 +228,16 @@
 
   *is_eos_reached = end_of_stream_decoded_;
 
+  if (!end_of_stream_decoded_ && !read_from_decoder_closure_.is_valid()) {
+    read_from_decoder_closure_ =
+        Bind(&AudioRendererImpl::ReadFromDecoder, this);
+    if (paused_ || seeking_) {
+      job_queue_->Schedule(read_from_decoder_closure_, 10 * kSbTimeMillisecond);
+    } else {
+      job_queue_->Schedule(read_from_decoder_closure_);
+    }
+  }
+
   if (paused_ || seeking_) {
     *is_playing = false;
     *frames_in_buffer = *offset_in_frames = 0;
@@ -220,12 +247,6 @@
   *is_playing = true;
   *frames_in_buffer = frames_in_buffer_;
   *offset_in_frames = offset_in_frames_;
-
-  if (!end_of_stream_decoded_ && !read_from_decoder_closure_.is_valid()) {
-    read_from_decoder_closure_ =
-        Bind(&AudioRendererImpl::ReadFromDecoder, this);
-    job_queue_->Schedule(read_from_decoder_closure_);
-  }
 }
 
 void AudioRendererImpl::ConsumeFrames(int frames_consumed) {
@@ -263,8 +284,34 @@
   SB_DCHECK(read_from_decoder_closure_.is_valid());
   read_from_decoder_closure_.reset();
 
-  scoped_refptr<DecodedAudio> decoded_audio =
-      pending_decoded_audio_ ? pending_decoded_audio_ : decoder_->Read();
+  // Create the audio sink if it is the first incoming AU after seeking.
+  if (audio_sink_ == kSbAudioSinkInvalid) {
+    int sample_rate = decoder_->GetSamplesPerSecond();
+    // TODO: Implement resampler.
+    SB_DCHECK(sample_rate ==
+              SbAudioSinkGetNearestSupportedSampleFrequency(sample_rate));
+    // TODO: Handle sink creation failure.
+    audio_sink_ = SbAudioSinkCreate(
+        channels_, sample_rate, decoder_->GetSampleType(),
+        kSbMediaAudioFrameStorageTypeInterleaved,
+        reinterpret_cast<SbAudioSinkFrameBuffers>(frame_buffers_),
+        kMaxCachedFrames, &AudioRendererImpl::UpdateSourceStatusFunc,
+        &AudioRendererImpl::ConsumeFramesFunc, this);
+#if SB_API_VERSION >= 4
+    audio_sink_->SetPlaybackRate(playback_rate_);
+#endif  // SB_API_VERSION >= 4
+  }
+
+  scoped_refptr<DecodedAudio> decoded_audio;
+  if (pending_decoded_audio_) {
+    decoded_audio = pending_decoded_audio_;
+  } else {
+    decoded_audio = decoder_->Read();
+    if (decoded_audio) {
+      SB_DCHECK(buffers_in_decoder_ > 0);
+      buffers_in_decoder_--;
+    }
+  }
   pending_decoded_audio_ = NULL;
   if (!decoded_audio) {
     return;
@@ -291,24 +338,6 @@
   if (seeking_ && frame_buffer_.size() > kPrerollFrames * bytes_per_frame_) {
     seeking_ = false;
   }
-
-  // Create the audio sink if it is the first incoming AU after seeking.
-  if (audio_sink_ == kSbAudioSinkInvalid) {
-    int sample_rate = decoder_->GetSamplesPerSecond();
-    // TODO: Implement resampler.
-    SB_DCHECK(sample_rate ==
-              SbAudioSinkGetNearestSupportedSampleFrequency(sample_rate));
-    // TODO: Handle sink creation failure.
-    audio_sink_ = SbAudioSinkCreate(
-        channels_, sample_rate, decoder_->GetSampleType(),
-        kSbMediaAudioFrameStorageTypeInterleaved,
-        reinterpret_cast<SbAudioSinkFrameBuffers>(frame_buffers_),
-        kMaxCachedFrames, &AudioRendererImpl::UpdateSourceStatusFunc,
-        &AudioRendererImpl::ConsumeFramesFunc, this);
-#if SB_API_VERSION >= 4
-    audio_sink_->SetPlaybackRate(playback_rate_);
-#endif  // SB_API_VERSION >= 4
-  }
 }
 
 // TODO: This function should be executed when lock is not acquired as it copies
diff --git a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
index 70915f6..3e50194 100644
--- a/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/audio_renderer_impl_internal.h
@@ -73,6 +73,9 @@
   // 2. Have the audio cache full to simulate the state that the renderer can
   //    no longer accept more data.
   static const size_t kMaxCachedFrames = 256 * 1024;
+  // When there are more than |kMaxBuffersInDecoder| buffers inside the audio
+  // decoder, the renderer won't accept more data.
+  static const int kMaxbuffersInDecoder = 32;
 
   void UpdateSourceStatus(int* frames_in_buffer,
                           int* offset_in_frames,
@@ -119,6 +122,15 @@
   SbAudioSink audio_sink_;
   scoped_refptr<DecodedAudio> pending_decoded_audio_;
   Closure read_from_decoder_closure_;
+
+  // Our owner will attempt to seek to pts 0 when playback begins.  In
+  // general, seeking could require a full reset of the underlying decoder on
+  // some platforms, so we make an effort to improve playback startup
+  // performance by keeping track of whether we already have a fresh decoder,
+  // and can thus avoid doing a full reset.
+  bool decoder_needs_full_reset_;
+
+  int buffers_in_decoder_;
 };
 
 }  // namespace filter
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
index 810f5d2..78ab565 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.cc
@@ -28,7 +28,8 @@
       end_of_stream_written_(false),
       need_more_input_(true),
       dropped_frames_(0),
-      decoder_(decoder.Pass()) {
+      decoder_(decoder.Pass()),
+      decoder_needs_full_reset_(false) {
   SB_DCHECK(decoder_ != NULL);
   decoder_->SetHost(this);
 }
@@ -48,6 +49,7 @@
   }
 
   decoder_->WriteInputBuffer(input_buffer);
+  decoder_needs_full_reset_ = true;
 }
 
 void VideoRendererImpl::WriteEndOfStream() {
@@ -60,13 +62,17 @@
   }
   end_of_stream_written_ = true;
   decoder_->WriteEndOfStream();
+  decoder_needs_full_reset_ = true;
 }
 
 void VideoRendererImpl::Seek(SbMediaTime seek_to_pts) {
   SB_DCHECK(thread_checker_.CalledOnValidThread());
   SB_DCHECK(seek_to_pts >= 0);
 
-  decoder_->Reset();
+  if (decoder_needs_full_reset_) {
+    decoder_->Reset();
+    decoder_needs_full_reset_ = false;
+  }
 
   ScopedLock lock(mutex_);
 
diff --git a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
index e56051d..2a35283 100644
--- a/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
+++ b/src/starboard/shared/starboard/player/filter/video_renderer_impl_internal.h
@@ -97,6 +97,13 @@
   int dropped_frames_;
 
   scoped_ptr<HostedVideoDecoder> decoder_;
+
+  // Our owner will attempt to seek to pts 0 when playback begins.  In
+  // general, seeking could require a full reset of the underlying decoder on
+  // some platforms, so we make an effort to improve playback startup
+  // performance by keeping track of whether we already have a fresh decoder,
+  // and can thus avoid doing a full reset.
+  bool decoder_needs_full_reset_;
 };
 
 }  // namespace filter
diff --git a/src/starboard/shared/win32/gyp_configuration.py b/src/starboard/shared/win32/gyp_configuration.py
new file mode 100644
index 0000000..46fa1a7
--- /dev/null
+++ b/src/starboard/shared/win32/gyp_configuration.py
@@ -0,0 +1,141 @@
+# Copyright 2016 Google Inc. 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.
+import logging
+import os
+
+import config.starboard
+import gyp_utils
+
+required_sdk_version = '10.0.15063.0'
+
+# Default Windows SDK bin directory.
+windows_sdk_bin_dir = 'C:\\Program Files (x86)\\Windows Kits\\10\\bin'
+
+# Maybe override Windows SDK bin directory with environment variable.
+windows_sdk_bin_var = 'WindowsSdkBinPath'
+if windows_sdk_bin_var in os.environ:
+  windows_sdk_bin_dir = os.environ[windows_sdk_bin_var]
+elif not os.path.exists(windows_sdk_bin_dir):
+  # If the above fails, this is our last guess.
+  windows_sdk_bin_dir = windows_sdk_bin_dir.replace('Program Files (x86)',
+                                                    'mappedProgramFiles')
+
+# Default Visual Studio Install directory.
+vs_install_dir = ('C:\\Program Files (x86)\\Microsoft Visual Studio'
+                  + '\\2017\\Professional')
+# Maybe override Visual Studio install directory with environment variable.
+vs_install_dir_var = 'VSINSTALLDIR'
+if vs_install_dir_var in os.environ:
+  vs_install_dir = os.environ[vs_install_dir_var]
+elif not os.path.exists(vs_install_dir):
+  # If the above fails, this is our last guess.
+  vs_install_dir = vs_install_dir.replace('Program Files (x86)',
+                                          'mappedProgramFiles')
+
+
+vs_install_dir_with_version = (vs_install_dir + '\\VC\\Tools\\MSVC'
+                               + '\\14.10.25017')
+vs_cl_path = vs_install_dir_with_version + '\\bin\\HostX64\\x64'
+
+
+
+def _CheckVisualStudioVersion():
+  if os.path.exists(vs_cl_path):
+    return True
+  logging.critical('Expected Visual Studio path \"%s\" not found.',
+                   vs_cl_path)
+
+def _QuotePath(path):
+  return '"' + path + '"'
+
+def _CheckWindowsSdkVersion():
+  required_sdk_bin_dir = os.path.join(windows_sdk_bin_dir,
+                                      required_sdk_version)
+  if os.path.exists(required_sdk_bin_dir):
+    return True
+
+  if os.path.exists(windows_sdk_bin_dir):
+    contents = os.listdir(windows_sdk_bin_dir)
+    contents = [content for content in contents
+                if os.path.isdir(os.path.join(windows_sdk_bin_dir, content))]
+    non_sdk_dirs = ['arm', 'arm64', 'x64', 'x86']
+    installed_sdks = [content for content in contents
+                      if content not in non_sdk_dirs]
+    logging.critical('Windows SDK versions \"%s\" found." \"%s\" required.',
+                     installed_sdks, required_sdk_version)
+  else:
+    logging.critical('Windows SDK versions \"%s\" required.',
+                     required_sdk_version)
+  return False
+
+
+class PlatformConfig(config.starboard.PlatformConfigStarboard):
+  """Starboard Microsoft Windows platform configuration."""
+
+  def __init__(self, platform):
+    super(PlatformConfig, self).__init__(platform)
+    _CheckWindowsSdkVersion()
+    _CheckVisualStudioVersion()
+
+  def GetVariables(self, configuration):
+    variables = super(PlatformConfig, self).GetVariables(configuration)
+    windows_sdk_path = os.path.abspath(os.path.join(windows_sdk_bin_dir,
+                                                    os.pardir))
+    variables.update({
+      'visual_studio_install_path': vs_install_dir_with_version,
+      'windows_sdk_path': windows_sdk_path,
+      'windows_sdk_version': required_sdk_version,
+      })
+    return variables
+
+  def GetEnvironmentVariables(self):
+    cl = _QuotePath(os.path.join(vs_cl_path, 'cl.exe'))
+    lib = _QuotePath(os.path.join(vs_cl_path, 'lib.exe'))
+    link = _QuotePath(os.path.join(vs_cl_path, 'link.exe'))
+    rc = _QuotePath(os.path.join(windows_sdk_bin_dir, required_sdk_version,
+                                 'x64', 'rc.exe'))
+    env_variables = {
+        'AR' : lib,
+        'AR_HOST' : lib,
+        'CC': cl,
+        'CXX': cl,
+        'LD': link,
+        'RC': rc,
+        'VS_INSTALL_DIR': vs_install_dir,
+        'CC_HOST': cl,
+        'CXX_HOST': cl,
+        'LD_HOST': link,
+        'ARFLAGS_HOST': 'rcs',
+        'ARTHINFLAGS_HOST': 'rcsT',
+    }
+    return env_variables
+
+  def GetBuildFormat(self):
+    """Returns the desired build format."""
+    # The comma means that ninja, msvs_makefile, will be chained and use the
+    # same input information so that .gyp files will only have to be parsed
+    # once.
+    return 'ninja,msvs_makefile'
+
+  def GetGeneratorVariables(self, configuration):
+    """Returns a dict of generator variables for the given configuration."""
+    _ = configuration
+    generator_variables = {
+        'msvs_version': 2017,
+        'msvs_platform': 'x64',
+        'msvs_template_prefix': 'win/',
+        'msvs_deploy_dir': '',
+        'qtcreator_session_name_prefix': 'cobalt',
+    }
+    return generator_variables
diff --git a/src/starboard/shared/win32/socket_accept.cc b/src/starboard/shared/win32/socket_accept.cc
index 08be946..dfc68db 100644
--- a/src/starboard/shared/win32/socket_accept.cc
+++ b/src/starboard/shared/win32/socket_accept.cc
@@ -47,5 +47,6 @@
 
   // Adopt the newly accepted socket.
   return new SbSocketPrivate(socket->address_type, socket->protocol,
-                             socket_handle);
+                             socket_handle,
+                             SbSocketPrivate::BindTarget::kAccepted);
 }
diff --git a/src/starboard/shared/win32/socket_bind.cc b/src/starboard/shared/win32/socket_bind.cc
index 9bc2afe..100c8e1 100644
--- a/src/starboard/shared/win32/socket_bind.cc
+++ b/src/starboard/shared/win32/socket_bind.cc
@@ -27,6 +27,9 @@
 bool IsIpv6InaddrAny(const SbSocketAddress* local_address) {
   return SbMemoryIsZero(local_address->address, sbwin32::kAddressLengthIpv6);
 }
+bool IsIpv4InaddrAny(const SbSocketAddress* local_address) {
+  return SbMemoryIsZero(local_address->address, sbwin32::kAddressLengthIpv4);
+}
 
 }  // namespace
 
@@ -51,16 +54,30 @@
     return (socket->error = sbwin32::TranslateSocketErrorStatus(EAFNOSUPPORT));
   }
 
-  // When binding to the IPV6 any address, ensure that the IPV6_V6ONLY flag is
-  // off to allow incoming IPV4 connections on the same socket.
-  // See https://www.ietf.org/rfc/rfc3493.txt for details.
-  if (local_address && (local_address->type == kSbSocketAddressTypeIpv6) &&
-      IsIpv6InaddrAny(local_address)) {
-    if (!sbwin32::SetBooleanSocketOption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
-                                         "IPV6_V6ONLY", false)) {
-      // Silently ignore errors, assume the default behavior is as expected.
-      socket->error = kSbSocketOk;
+  switch (local_address->type) {
+    case kSbSocketAddressTypeIpv6:
+      if (!IsIpv6InaddrAny(local_address)) {
+        socket->bound_to = SbSocketPrivate::BindTarget::kOther;
+        break;
+      }
+
+      socket->bound_to = SbSocketPrivate::BindTarget::kAny;
+
+      // When binding to the IPV6 any address, ensure that the IPV6_V6ONLY flag
+      // is off to allow incoming IPV4 connections on the same socket.
+      // See https://www.ietf.org/rfc/rfc3493.txt for details.
+      if (!sbwin32::SetBooleanSocketOption(socket, IPPROTO_IPV6, IPV6_V6ONLY,
+                                           "IPV6_V6ONLY", false)) {
+        // Silently ignore errors, assume the default behavior is as expected.
+        socket->error = kSbSocketOk;
     }
+
+    break;
+    case kSbSocketAddressTypeIpv4:
+      socket->bound_to = IsIpv4InaddrAny(local_address)
+                             ? SbSocketPrivate::BindTarget::kAny
+                             : SbSocketPrivate::BindTarget::kOther;
+      break;
   }
 
   int result =
diff --git a/src/starboard/shared/win32/socket_connect.cc b/src/starboard/shared/win32/socket_connect.cc
index 4287d48..4c33768 100644
--- a/src/starboard/shared/win32/socket_connect.cc
+++ b/src/starboard/shared/win32/socket_connect.cc
@@ -44,11 +44,13 @@
       connect(socket->socket_handle, sock_addr.sockaddr(), sock_addr.length);
 
   if (result != SOCKET_ERROR) {
+    socket->bound_to = SbSocketPrivate::BindTarget::kAny;
     return (socket->error = kSbSocketOk);
   }
 
   const int last_error = WSAGetLastError();
   if (last_error == WSAEWOULDBLOCK) {
+    socket->bound_to = SbSocketPrivate::BindTarget::kAny;
     return (socket->error = kSbSocketPending);
   }
 
diff --git a/src/starboard/shared/win32/socket_create.cc b/src/starboard/shared/win32/socket_create.cc
index bc3a89c..561967f 100644
--- a/src/starboard/shared/win32/socket_create.cc
+++ b/src/starboard/shared/win32/socket_create.cc
@@ -114,5 +114,6 @@
     return kSbSocketInvalid;
   }
 
-  return new SbSocketPrivate(address_type, protocol, socket_handle);
+  return new SbSocketPrivate(address_type, protocol, socket_handle,
+                             SbSocketPrivate::BindTarget::kUnbound);
 }
diff --git a/src/starboard/shared/win32/socket_get_interface_address.cc b/src/starboard/shared/win32/socket_get_interface_address.cc
index a8f8b04..7b4118a 100644
--- a/src/starboard/shared/win32/socket_get_interface_address.cc
+++ b/src/starboard/shared/win32/socket_get_interface_address.cc
@@ -135,7 +135,7 @@
       address_length_bytes = sbwin32::kAddressLengthIpv6;
       break;
     default:
-      SB_NOTREACHED() << "Invalid address type.";
+      SB_NOTREACHED() << "Invalid address type: " << address_type;
       return false;
   }
 
diff --git a/src/starboard/shared/win32/socket_get_local_address.cc b/src/starboard/shared/win32/socket_get_local_address.cc
index d49d5b0..e4a1bf9 100644
--- a/src/starboard/shared/win32/socket_get_local_address.cc
+++ b/src/starboard/shared/win32/socket_get_local_address.cc
@@ -17,6 +17,7 @@
 #include <winsock2.h>
 
 #include "starboard/log.h"
+#include "starboard/memory.h"
 #include "starboard/shared/win32/socket_internal.h"
 
 namespace sbwin32 = starboard::shared::win32;
@@ -26,6 +27,25 @@
     return false;
   }
 
+  // winsock2 considers calling getsockname() on unbound sockets to be an error.
+  // Therefore, SbSocketListen() will call SbSocketBind().
+  if (socket->bound_to == SbSocketPrivate::BindTarget::kUnbound) {
+    out_address->type = socket->address_type;
+    switch (socket->address_type) {
+      case kSbSocketAddressTypeIpv4:
+        SbMemorySet(out_address->address, 0, sbwin32::kAddressLengthIpv4);
+        out_address->port = 0;
+        return true;
+      case kSbSocketAddressTypeIpv6:
+        SbMemorySet(out_address->address, 0, sbwin32::kAddressLengthIpv6);
+        out_address->port = 0;
+        return true;
+      default:
+        SB_NOTREACHED() << "Invalid address type: " << socket->address_type;
+        return false;
+    }
+  }
+
   SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
   sbwin32::SockAddr sock_addr;
   int result = getsockname(socket->socket_handle, sock_addr.sockaddr(),
diff --git a/src/starboard/shared/win32/socket_internal.h b/src/starboard/shared/win32/socket_internal.h
index 3a92e18..ce32fcf 100644
--- a/src/starboard/shared/win32/socket_internal.h
+++ b/src/starboard/shared/win32/socket_internal.h
@@ -24,14 +24,23 @@
 #include "starboard/types.h"
 
 struct SbSocketPrivate {
+  enum struct BindTarget {
+    kUnbound = 0,
+    kAny = 1,
+    kOther = 2,
+    kAccepted = 3,
+  };
+
   SbSocketPrivate(SbSocketAddressType address_type,
                   SbSocketProtocol protocol,
-                  SOCKET fd)
+                  SOCKET handle,
+                  BindTarget bound_to)
       : address_type(address_type),
         protocol(protocol),
-        socket_handle(fd),
+        socket_handle(handle),
         error(kSbSocketOk),
-        waiter(kSbSocketWaiterInvalid) {}
+        waiter(kSbSocketWaiterInvalid),
+        bound_to(bound_to) {}
   ~SbSocketPrivate() {}
 
   // The address domain of this socket, IPv4 or IPv6.
@@ -48,6 +57,8 @@
 
   // The waiter this socket is registered with, or kSbSocketWaiterInvalid.
   SbSocketWaiter waiter;
+
+  BindTarget bound_to;
 };
 
 namespace starboard {
diff --git a/src/starboard/shared/win32/socket_listen.cc b/src/starboard/shared/win32/socket_listen.cc
index fb8de43..96f28fb 100644
--- a/src/starboard/shared/win32/socket_listen.cc
+++ b/src/starboard/shared/win32/socket_listen.cc
@@ -27,12 +27,28 @@
   }
 
   SB_DCHECK(socket->socket_handle != INVALID_SOCKET);
+
+  // Under winsock, a socket must be bound before we can listen on it.
+  if (socket->bound_to == SbSocketPrivate::BindTarget::kUnbound) {
+    // By listening on ::, we can accept both IPv4 and IPv6 connections.
+    SbSocketAddress any_address = {0};
+    any_address.type = socket->address_type;
+    if (SbSocketBind(socket, &any_address) != kSbSocketOk) {
+      SB_DLOG(ERROR) << "Unable to bind a socket during SbListen.";
+      return (socket->error = kSbSocketErrorFailed);
+    }
+
+    socket->bound_to = SbSocketPrivate::BindTarget::kAny;
+  }
+
   // TODO: Determine if we need to specify a > 0 backlog. It can go up to
   // SOMAXCONN according to the documentation. Several places in chromium
   // specify the literal "10" with the comment "maybe dont allow any backlog?"
   int result = listen(socket->socket_handle, 0);
   if (result == SOCKET_ERROR) {
-    return (socket->error = sbwin32::TranslateSocketErrorStatus(result));
+    int last_error = WSAGetLastError();
+    SB_LOG(ERROR) << "listen() failed with last_error = " << last_error;
+    return (socket->error = sbwin32::TranslateSocketErrorStatus(last_error));
   }
 
   return (socket->error = kSbSocketOk);
diff --git a/src/starboard/shared/win32/thread_create.cc b/src/starboard/shared/win32/thread_create.cc
index 5220aad..a579c0b 100644
--- a/src/starboard/shared/win32/thread_create.cc
+++ b/src/starboard/shared/win32/thread_create.cc
@@ -20,13 +20,43 @@
 #include "starboard/log.h"
 #include "starboard/once.h"
 #include "starboard/shared/win32/thread_private.h"
+#include "starboard/shared/win32/wchar_utils.h"
 
 using starboard::shared::win32::GetThreadSubsystemSingleton;
 using starboard::shared::win32::SbThreadPrivate;
 using starboard::shared::win32::ThreadSubsystemSingleton;
+using starboard::shared::win32::wchar_tToUTF8;
 
 namespace {
 
+void ResetWinError() {
+  SetLastError(0);
+}
+
+// Checks for system errors and logs a human-readable error if GetLastError()
+// returns an error code. Noops on non-debug builds.
+void DebugLogWinError() {
+#if defined(_DEBUG)
+  DWORD error_code = GetLastError();
+  if (!error_code)
+    return;
+
+  LPWSTR error_message;
+  HRESULT hresult = HRESULT_FROM_WIN32(error_code);
+  int message_size = FormatMessage(
+      FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER |
+          FORMAT_MESSAGE_IGNORE_INSERTS,
+      nullptr,  // Unused with FORMAT_MESSAGE_FROM_SYSTEM.
+      hresult, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+      (LPTSTR)&error_message,
+      0,  // Minimum size for output buffer.
+      nullptr);
+  SB_DCHECK(message_size);
+  SB_LOG(ERROR) << wchar_tToUTF8(error_message);
+  LocalFree(error_message);
+#endif  // defined(_DEBUG)
+}
+
 class ThreadCreateInfo {
  public:
   SbThreadPrivate thread_private_;
@@ -83,11 +113,29 @@
   return 0;
 }
 
+int SbThreadPriorityToWin32Priority(SbThreadPriority priority) {
+  switch (priority) {
+    case kSbThreadPriorityLowest:
+      return THREAD_PRIORITY_LOWEST;
+    case kSbThreadPriorityLow:
+      return THREAD_PRIORITY_BELOW_NORMAL;
+    case kSbThreadPriorityNormal:
+    case kSbThreadNoPriority:
+      return THREAD_PRIORITY_NORMAL;
+    case kSbThreadPriorityHigh:
+      return THREAD_PRIORITY_ABOVE_NORMAL;
+    case kSbThreadPriorityHighest:
+    case kSbThreadPriorityRealTime:
+      return THREAD_PRIORITY_HIGHEST;
+  }
+  SB_NOTREACHED() << "Invalid priority " << priority;
+  return 0;
+}
 }  // namespace
 
 SbThread SbThreadCreate(int64_t stack_size,
-                        SbThreadPriority /*priority*/,
-                        SbThreadAffinity /*affinity*/,
+                        SbThreadPriority priority,
+                        SbThreadAffinity affinity,
                         bool joinable,
                         const char* name,
                         SbThreadEntryPoint entry_point,
@@ -110,8 +158,26 @@
   uintptr_t handle =
       _beginthreadex(NULL, static_cast<unsigned int>(stack_size),
                      ThreadTrampoline, info, CREATE_SUSPENDED, NULL);
-
+  SB_DCHECK(handle);
   info->thread_private_.handle_ = reinterpret_cast<HANDLE>(handle);
+  ResetWinError();
+  if (affinity != kSbThreadNoAffinity &&
+      !SetThreadAffinityMask(info->thread_private_.handle_,
+                             static_cast<DWORD_PTR>(affinity)) &&
+      !GetLastError()) {
+    SB_LOG(ERROR) << "Failed to set affinity for thread " << (name ? name : "")
+                  << ". Attempted to set affinity to: " << affinity;
+    DebugLogWinError();
+  }
+  ResetWinError();
+  if (priority != kSbThreadNoPriority &&
+      !SetThreadPriority(info->thread_private_.handle_,
+                         SbThreadPriorityToWin32Priority(priority)) &&
+      !GetLastError()) {
+    SB_LOG(ERROR) << "Failed to set priority for thread " << (name ? name : "")
+                  << " to " << priority;
+    DebugLogWinError();
+  }
 
   ResumeThread(info->thread_private_.handle_);
 
diff --git a/src/starboard/shared/win32/thread_private.h b/src/starboard/shared/win32/thread_private.h
index 4bacbd8..9bdf0d6 100644
--- a/src/starboard/shared/win32/thread_private.h
+++ b/src/starboard/shared/win32/thread_private.h
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#ifndef STARBOARD_WIN32_THREAD_PRIVATE_H_
-#define STARBOARD_WIN32_THREAD_PRIVATE_H_
+#ifndef STARBOARD_SHARED_WIN32_THREAD_PRIVATE_H_
+#define STARBOARD_SHARED_WIN32_THREAD_PRIVATE_H_
 
 #include <windows.h>
 #include <string>
@@ -106,4 +106,4 @@
 }  // namespace shared
 }  // namespace starboard
 
-#endif  // STARBOARD_WIN32_THREAD_PRIVATE_H_
+#endif  // STARBOARD_SHARED_WIN32_THREAD_PRIVATE_H_
diff --git a/src/starboard/thread.h b/src/starboard/thread.h
index f642f28..c6d17ab 100644
--- a/src/starboard/thread.h
+++ b/src/starboard/thread.h
@@ -65,7 +65,7 @@
   //
   // For platforms where that is not offered, or otherwise not meaningful, this
   // will just be the highest priority available in the platform's scheme, which
-  // may be the same as kThreadPriority_Highest.
+  // may be the same as kSbThreadPriorityHighest.
   kSbThreadPriorityRealTime,
 
   // Well-defined constant value to mean "no priority."  This means to use the
diff --git a/src/starboard/tools/platform.py b/src/starboard/tools/platform.py
index e763abe..7c760f8 100644
--- a/src/starboard/tools/platform.py
+++ b/src/starboard/tools/platform.py
@@ -65,9 +65,15 @@
   """Information about a specific starboard port."""
 
   @classmethod
-  def EnumeratePorts(cls, root_path):
+  def EnumeratePorts(cls, root_path, exclusion_set = None):
     """Generator that iterates over starboard ports found under |path|."""
-    for current_path, _, filenames in os.walk(root_path):
+    if not exclusion_set:
+      exclusion_set = set()
+    for current_path, directories, filenames in os.walk(root_path):
+      # Don't walk into any directories in the exclusion set.
+      directories[:] = (x for x in directories
+                        if os.path.join(current_path, x) not in exclusion_set)
+      # Determine if the current directory is a valid port directory.
       if _IsValidPortFilenameList(current_path, filenames):
         if current_path == root_path:
           logging.warning('Found port at search path root: %s', current_path)
diff --git a/src/starboard/win/console/atomic_public.h b/src/starboard/win/console/atomic_public.h
new file mode 100644
index 0000000..51f81a1
--- /dev/null
+++ b/src/starboard/win/console/atomic_public.h
@@ -0,0 +1,20 @@
+// Copyright 2017 Google Inc. 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 STARBOARD_WIN_CONSOLE_ATOMIC_PUBLIC_H_
+#define STARBOARD_WIN_CONSOLE_ATOMIC_PUBLIC_H_
+
+#include "starboard/shared/win32/atomic_public.h"
+
+#endif  // STARBOARD_WIN_CONSOLE_ATOMIC_PUBLIC_H_
diff --git a/src/starboard/win/console/configuration_public.h b/src/starboard/win/console/configuration_public.h
new file mode 100644
index 0000000..324627f
--- /dev/null
+++ b/src/starboard/win/console/configuration_public.h
@@ -0,0 +1,23 @@
+// Copyright 2017 Google Inc. 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.
+
+// Other source files should never include this header directly, but should
+// include the generic "starboard/configuration.h" instead.
+
+#ifndef STARBOARD_WIN_CONSOLE_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_WIN_CONSOLE_CONFIGURATION_PUBLIC_H_
+
+#include "starboard/win/shared/configuration_public.h"
+
+#endif  // STARBOARD_WIN_CONSOLE_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/win/console/gyp_configuration.gypi b/src/starboard/win/console/gyp_configuration.gypi
new file mode 100644
index 0000000..ef90ebd
--- /dev/null
+++ b/src/starboard/win/console/gyp_configuration.gypi
@@ -0,0 +1,94 @@
+# Copyright 2017 Google Inc. 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.
+
+{
+  'variables': {
+    'javascript_engine': 'mozjs',
+    'cobalt_enable_jit': 0,
+  },
+  'includes': [
+    '../shared/gyp_configuration.gypi',
+  ],
+  'target_defaults': {
+    'default_configuration': 'win-console_debug',
+    'configurations': {
+      'win-console_debug': {
+        'inherit_from': ['debug_base', 'msvs_base'],
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'Optimization': '0',
+            'BasicRuntimeChecks': '3', # Check stack frame validity and check for uninitialized variables at run time.
+            'AdditionalOptions': [
+              '/MDd', # Use debug multithreaded library.
+              '/GS',
+            ],
+          },
+          'VCLinkerTool': {
+            'AdditionalDependencies': ['dbghelp.lib'],
+            'LinkIncremental': '2',  # INCREMENTAL:YES
+          },
+        },
+      },
+      'win-console_devel': {
+        'inherit_from': ['devel_base', 'msvs_base'],
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'Optimization': '2',
+            'AdditionalOptions': [
+              '/MDd', # Use debug multithreaded library.
+              '/GS',
+            ],
+          },
+          'VCLinkerTool': {
+            'AdditionalDependencies': ['dbghelp.lib'],
+            'LinkIncremental': '2',  # INCREMENTAL:YES
+          },
+        },
+      },
+      'win-console_qa': {
+        'inherit_from': ['qa_base', 'msvs_base'],
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'Optimization': '2',
+            'AdditionalOptions': [
+              '/MD', # Use release multithreaded library.
+            ],
+          },
+          'VCLinkerTool': {
+            'AdditionalDependencies': ['dbghelp.lib'],
+            'LinkIncremental': '1',  # INCREMENTAL:NO
+            'OptimizeReferences' : '2',  # OPT:REF
+            'EnableCOMDATFolding' : '2',  # OPT:ICF
+          },
+        },
+      },
+      'win-console_gold': {
+        'inherit_from': ['gold_base', 'msvs_base'],
+         'msvs_settings': {
+          'VCCLCompilerTool': {
+            'Optimization': '2',
+            'AdditionalOptions': [
+              '/MD', # Use release multithreaded library.
+            ],
+          },
+          'VCLinkerTool': {
+            'LinkIncremental': '1',  # INCREMENTAL:NO
+            'OptimizeReferences' : '2',  # OPT:REF
+            'EnableCOMDATFolding' : '2',  # OPT:ICF
+          },
+        },
+      },
+    },  # end of configurations
+  },
+}
diff --git a/src/starboard/win/console/gyp_configuration.py b/src/starboard/win/console/gyp_configuration.py
new file mode 100644
index 0000000..68f835a
--- /dev/null
+++ b/src/starboard/win/console/gyp_configuration.py
@@ -0,0 +1,33 @@
+# Copyright 2016 Google Inc. 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.
+
+import logging
+import os
+import sys
+
+# Import the shared win platform configuration.
+sys.path.append(
+    os.path.realpath(
+        os.path.join(
+            os.path.dirname(__file__), os.pardir,
+            os.pardir, 'shared', 'win32')))
+import gyp_configuration
+
+
+def CreatePlatformConfig():
+  try:
+    return gyp_configuration.PlatformConfig('win-console')
+  except RuntimeError as e:
+    logging.critical(e)
+    return None
diff --git a/src/starboard/win/console/starboard_platform.gyp b/src/starboard/win/console/starboard_platform.gyp
new file mode 100644
index 0000000..bcfd1cb
--- /dev/null
+++ b/src/starboard/win/console/starboard_platform.gyp
@@ -0,0 +1,26 @@
+# Copyright 2017 Google Inc. 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.
+{
+  'includes': [ '../shared/starboard_platform.gypi' ],
+  'sources': [
+    'atomic_public.h',
+    'configuration_public.h',
+    'thread_types_public.h',
+  ],
+  'variables': {
+    'starboard_platform_dependent_sources': [
+      '../shared/system_get_path.cc',
+    ],
+  },
+}
diff --git a/src/starboard/win/console/starboard_platform_tests.gyp b/src/starboard/win/console/starboard_platform_tests.gyp
new file mode 100644
index 0000000..93f812b
--- /dev/null
+++ b/src/starboard/win/console/starboard_platform_tests.gyp
@@ -0,0 +1,41 @@
+# Copyright 2017 Google Inc. 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.
+{
+  'targets': [
+    {
+      'target_name': 'starboard_platform_tests',
+      'type': '<(gtest_target_type)',
+      'sources': [
+        '<(DEPTH)/starboard/common/test_main.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_type_test.cc',
+      ],
+      'dependencies': [
+        '<(DEPTH)/starboard/starboard.gyp:starboard',
+        '<(DEPTH)/testing/gmock.gyp:gmock',
+        '<(DEPTH)/testing/gtest.gyp:gtest',
+      ],
+    },
+    {
+      'target_name': 'starboard_platform_tests_deploy',
+      'type': 'none',
+      'dependencies': [
+        '<(DEPTH)/<(starboard_path)/starboard_platform_tests.gyp:starboard_platform_tests',
+      ],
+      'variables': {
+        'executable_name': 'starboard_platform_tests',
+      },
+      'includes': [ '../../build/deploy.gypi' ],
+    },
+  ],
+}
diff --git a/src/starboard/win/console/thread_types_public.h b/src/starboard/win/console/thread_types_public.h
new file mode 100644
index 0000000..b8cc69e
--- /dev/null
+++ b/src/starboard/win/console/thread_types_public.h
@@ -0,0 +1,22 @@
+// Copyright 2017 Google Inc. 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.
+
+// Includes threading primitive types and initializers.
+
+#ifndef STARBOARD_WIN_CONSOLE_THREAD_TYPES_PUBLIC_H_
+#define STARBOARD_WIN_CONSOLE_THREAD_TYPES_PUBLIC_H_
+
+#include "starboard/shared/win32/thread_types_public.h"
+
+#endif  // STARBOARD_WIN_CONSOLE_THREAD_TYPES_PUBLIC_H_
diff --git a/src/starboard/win/shared/configuration_public.h b/src/starboard/win/shared/configuration_public.h
new file mode 100644
index 0000000..94eb71c
--- /dev/null
+++ b/src/starboard/win/shared/configuration_public.h
@@ -0,0 +1,466 @@
+// Copyright 2017 Google Inc. 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.
+
+// Other source files should never include this header directly, but should
+// include the generic "starboard/configuration.h" instead.
+
+#ifndef STARBOARD_WIN_SHARED_CONFIGURATION_PUBLIC_H_
+#define STARBOARD_WIN_SHARED_CONFIGURATION_PUBLIC_H_
+
+// The API version implemented by this platform. This will generally be set to
+// the current value of SB_MAXIMUM_API_VERSION at the time of implementation.
+#define SB_API_VERSION SB_EXPERIMENTAL_API_VERSION
+
+// --- Architecture Configuration --------------------------------------------
+
+// Whether the current platform is big endian. SB_IS_LITTLE_ENDIAN will be
+// automatically set based on this.
+#define SB_IS_BIG_ENDIAN 0
+
+// Whether the current platform is an ARM architecture.
+#define SB_IS_ARCH_ARM 0
+
+// Whether the current platform is a MIPS architecture.
+#define SB_IS_ARCH_MIPS 0
+
+// Whether the current platform is a PPC architecture.
+#define SB_IS_ARCH_PPC 0
+
+// Whether the current platform is an x86 architecture.
+#define SB_IS_ARCH_X86 1
+
+#define SB_IS_32_BIT 0
+#define SB_IS_64_BIT 1
+
+#define SB_HAS_32_BIT_LONG 1
+#define SB_HAS_32_BIT_POINTERS 0
+
+#define SB_HAS_64_BIT_LONG 0
+#define SB_HAS_64_BIT_POINTERS 1
+
+// Configuration parameters that allow the application to make some general
+// compile-time decisions with respect to the the number of cores likely to be
+// available on this platform. For a definitive measure, the application should
+// still call SbSystemGetNumberOfProcessors at runtime.
+
+// Whether the current platform is expected to have many cores (> 6), or a
+// wildly varying number of cores.
+#define SB_HAS_MANY_CORES 0
+
+// Whether the current platform is expected to have exactly 1 core.
+#define SB_HAS_1_CORE 0
+
+// Whether the current platform is expected to have exactly 2 cores.
+#define SB_HAS_2_CORES 0
+
+// Whether the current platform is expected to have exactly 4 cores.
+#define SB_HAS_4_CORES 1
+
+// Whether the current platform is expected to have exactly 6 cores.
+#define SB_HAS_6_CORES 0
+
+// Whether the current platform supports thread priorities.
+#define SB_HAS_THREAD_PRIORITY_SUPPORT 1
+
+// Whether the current platform's thread scheduler will automatically balance
+// threads between cores, as opposed to systems where threads will only ever run
+// on the specifically pinned core.
+#define SB_HAS_CROSS_CORE_SCHEDULER 1
+
+// Some platforms will not align variables on the stack with an alignment
+// greater than 16 bytes. Platforms where this is the case should define the
+// following quirk.
+#undef SB_HAS_QUIRK_DOES_NOT_STACK_ALIGN_OVER_16_BYTES
+
+// --- System Header Configuration -------------------------------------------
+
+// Any system headers listed here that are not provided by the platform will be
+// emulated in starboard/types.h.
+
+// Whether the current platform provides the standard header stdarg.h.
+#define SB_HAS_STDARG_H 0
+
+// Whether the current platform provides the standard header stdbool.h.
+#define SB_HAS_STDBOOL_H 0
+
+// Whether the current platform provides the standard header stddef.h.
+#define SB_HAS_STDDEF_H 1
+
+// Whether the current platform provides the standard header stdint.h.
+#define SB_HAS_STDINT_H 1
+
+// Whether the current platform provides the standard header inttypes.h.
+#define SB_HAS_INTTYPES_H 1
+
+// Whether the current platform provides the standard header wchar.h.
+#define SB_HAS_WCHAR_H 1
+
+// Whether the current platform provides the standard header limits.h.
+#define SB_HAS_LIMITS_H 1
+
+// Whether the current platform provides the standard header float.h.
+#define SB_HAS_FLOAT_H 1
+
+// Whether the current platform provides ssize_t.
+#define SB_HAS_SSIZE_T 0
+
+// Whether the current platform has microphone supported.
+#define SB_HAS_MICROPHONE 0
+
+// Whether the current platform has speech synthesis.
+#define SB_HAS_SPEECH_SYNTHESIS 0
+
+// Whether the current platform has speech recognizer.
+#define SB_HAS_SPEECH_RECOGNIZER 0
+
+#if !defined(__WCHAR_MAX__)
+#include <wchar.h>
+#define __WCHAR_MAX__ WCHAR_MAX
+#endif
+
+// Type detection for wchar_t.
+#if defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
+#define SB_IS_WCHAR_T_UTF32 1
+#elif defined(__WCHAR_MAX__) && \
+    (__WCHAR_MAX__ == 0x7fff || __WCHAR_MAX__ == 0xffff)
+#define SB_IS_WCHAR_T_UTF16 1
+#endif
+
+// Chrome only defines these two if ARMEL or MIPSEL are defined.
+#if defined(__ARMEL__)
+// Chrome has an exclusion for iOS here, we should too when we support iOS.
+#define SB_IS_WCHAR_T_UNSIGNED 1
+#elif defined(__MIPSEL__)
+#define SB_IS_WCHAR_T_SIGNED 1
+#endif
+
+// --- Compiler Configuration ------------------------------------------------
+
+// The platform's annotation for forcing a C function to be inlined.
+//   https://msdn.microsoft.com/en-us/library/bw1hbe6y.aspx#Anchor_1
+#define SB_C_FORCE_INLINE __forceinline
+
+// The platform's annotation for marking a C function as suggested to be
+// inlined.
+#define SB_C_INLINE inline
+
+// The platform's annotation for marking a C function as forcibly not
+// inlined.
+#define SB_C_NOINLINE __declspec(noinline)
+
+// The platform's annotation for marking a symbol as exported outside of the
+// current shared library.
+#define SB_EXPORT_PLATFORM __attribute__((visibility("default")))
+
+// The platform's annotation for marking a symbol as imported from outside of
+// the current linking unit.
+#define SB_IMPORT_PLATFORM
+
+// On some platforms the __GNUC__ is defined even though parts of the
+// functionality are missing. Setting this to non-zero allows disabling missing
+// functionality encountered.
+#undef SB_HAS_QUIRK_COMPILER_SAYS_GNUC_BUT_ISNT
+
+// On some compilers, the frontend has a quirk such that #ifdef cannot
+// correctly detect __has_feature is defined, and an example error you get is:
+#undef SB_HAS_QUIRK_HASFEATURE_NOT_DEFINED_BUT_IT_IS
+
+// --- Extensions Configuration ----------------------------------------------
+
+// GCC/Clang doesn't define a long long hash function, except for Android and
+// Game consoles.
+#define SB_HAS_LONG_LONG_HASH 1
+
+// GCC/Clang doesn't define a string hash function, except for Game Consoles.
+#define SB_HAS_STRING_HASH 1
+
+// Desktop Linux needs a using statement for the hash functions.
+#define SB_HAS_HASH_USING 1
+
+// Set this to 1 if hash functions for custom types can be defined as a
+// hash_value() function. Otherwise, they need to be placed inside a
+// partially-specified hash struct template with an operator().
+#define SB_HAS_HASH_VALUE 1
+
+// Set this to 1 if use of hash_map or hash_set causes a deprecation warning
+// (which then breaks the build).
+#define SB_HAS_HASH_WARNING 1
+#define _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS
+
+// The location to include hash_map on this platform.
+#define SB_HASH_MAP_INCLUDE <hash_map>
+
+// C++'s hash_map and hash_set are often found in different namespaces depending
+// on the compiler.
+#define SB_HASH_NAMESPACE stdext
+
+// The location to include hash_set on this platform.
+#define SB_HASH_SET_INCLUDE <hash_set>
+
+// Define this to how this platform copies varargs blocks.
+#define SB_VA_COPY(dest, source) va_copy(dest, source)
+
+// --- Filesystem Configuration ----------------------------------------------
+
+// The current platform's maximum length of the name of a single directory
+// entry, not including the absolute path.
+#define SB_FILE_MAX_NAME 260
+
+// The current platform's maximum length of an absolute path.
+#define SB_FILE_MAX_PATH 4096
+
+// The current platform's maximum number of files that can be opened at the
+// same time by one process.
+#define SB_FILE_MAX_OPEN 64
+
+// The current platform's file path component separator character. This is the
+// character that appears after a directory in a file path. For example, the
+// absolute canonical path of the file "/path/to/a/file.txt" uses '/' as a path
+// component separator character.
+#define SB_FILE_SEP_CHAR '\\'
+
+// The current platform's alternate file path component separator character.
+// This is like SB_FILE_SEP_CHAR, except if your platform supports an alternate
+// character, then you can place that here. For example, on windows machines,
+// the primary separator character is probably '\', but the alternate is '/'.
+#define SB_FILE_ALT_SEP_CHAR '/'
+
+// The current platform's search path component separator character. When
+// specifying an ordered list of absolute paths of directories to search for a
+// given reason, this is the character that appears between entries. For
+// example, the search path of "/etc/search/first:/etc/search/second" uses ':'
+// as a search path component separator character.
+#define SB_PATH_SEP_CHAR ':'
+
+// The string form of SB_FILE_SEP_CHAR.
+#define SB_FILE_SEP_STRING "\\"
+
+// The string form of SB_FILE_ALT_SEP_CHAR.
+#define SB_FILE_ALT_SEP_STRING "/"
+
+// The string form of SB_PATH_SEP_CHAR.
+#define SB_PATH_SEP_STRING ":"
+
+// On some platforms the file system stores access times at a coarser
+// granularity than other times. When this quirk is defined, we assume the
+// access time is of 1 day precision.
+#undef SB_HAS_QUIRK_FILESYSTEM_COARSE_ACCESS_TIME
+
+// --- Memory Configuration --------------------------------------------------
+
+// The memory page size, which controls the size of chunks on memory that
+// allocators deal with, and the alignment of those chunks. This doesn't have to
+// be the hardware-defined physical page size, but it should be a multiple of
+// it.
+#define SB_MEMORY_PAGE_SIZE 4096
+
+// Whether this platform has and should use an MMAP function to map physical
+// memory to the virtual address space.
+#define SB_HAS_MMAP 1
+
+// Whether this platform can map executable memory. Implies SB_HAS_MMAP. This is
+// required for platforms that want to JIT.
+#define SB_CAN_MAP_EXECUTABLE_MEMORY 0
+
+// Whether this platform has and should use an growable heap (e.g. with sbrk())
+// to map physical memory to the virtual address space.
+#define SB_HAS_VIRTUAL_REGIONS 0
+
+// Specifies the alignment for IO Buffers, in bytes. Some low-level network APIs
+// may require buffers to have a specific alignment, and this is the place to
+// specify that.
+#define SB_NETWORK_IO_BUFFER_ALIGNMENT 16
+
+// Determines the alignment that allocations should have on this platform.
+#define SB_MALLOC_ALIGNMENT ((size_t)16U)
+
+// Determines the threshhold of allocation size that should be done with mmap
+// (if available), rather than allocated within the core heap.
+#define SB_DEFAULT_MMAP_THRESHOLD ((size_t)(256 * 1024U))
+
+// Defines the path where memory debugging logs should be written to.
+#define SB_MEMORY_LOG_PATH "/tmp/starboard"
+
+// --- Thread Configuration --------------------------------------------------
+
+// Defines the maximum number of simultaneous threads for this platform. Some
+// platforms require sharing thread handles with other kinds of system handles,
+// like mutexes, so we want to keep this managable.
+#define SB_MAX_THREADS 90
+
+// The maximum number of thread local storage keys supported by this platform.
+#define SB_MAX_THREAD_LOCAL_KEYS 512
+
+// The maximum length of the name for a thread, including the NULL-terminator.
+#define SB_MAX_THREAD_NAME_LENGTH 16;
+
+// --- Graphics Configuration ------------------------------------------------
+
+// Specifies whether this platform supports a performant accelerated blitter
+// API. The basic requirement is a scaled, clipped, alpha-blended blit.
+#define SB_HAS_BLITTER 0
+
+// Specifies the preferred byte order of color channels in a pixel. Refer to
+// starboard/configuration.h for the possible values. EGL/GLES platforms should
+// generally prefer a byte order of RGBA, regardless of endianness.
+#define SB_PREFERRED_RGBA_BYTE_ORDER SB_PREFERRED_RGBA_BYTE_ORDER_RGBA
+
+// Indicates whether or not the given platform supports bilinear filtering.
+// This can be checked to enable/disable renderer tests that verify that this is
+// working properly.
+#define SB_HAS_BILINEAR_FILTERING_SUPPORT 1
+
+// Indicates whether or not the given platform supports rendering of NV12
+// textures. These textures typically originate from video decoders.
+#define SB_HAS_NV12_TEXTURE_SUPPORT 0
+
+// Whether the current platform should frequently flip its display buffer.  If
+// this is not required (i.e. SB_MUST_FREQUENTLY_FLIP_DISPLAY_BUFFER is set to
+// 0), then optimizations are enabled so the display buffer is not flipped if
+// the scene hasn't changed.
+#define SB_MUST_FREQUENTLY_FLIP_DISPLAY_BUFFER 0
+
+#define SB_HAS_VIRTUAL_REALITY 0
+
+// --- Media Configuration ---------------------------------------------------
+
+// Specifies whether this platform has support for a possibly-decrypting
+// elementary stream player for at least H.264/AAC (and AES-128-CTR, if
+// decrypting). A player is responsible for ingesting an audio and video
+// elementary stream, optionally-encrypted, and ultimately producing
+// synchronized audio/video. If a player is defined, it must choose one of the
+// supported composition methods below.
+#define SB_HAS_PLAYER 1
+
+#if SB_API_VERSION < 4
+// Specifies whether this platform's player will produce an OpenGL texture that
+// the client must draw every frame with its graphics rendering. It may be that
+// we get a texture handle, but cannot perform operations like GlReadPixels on
+// it if it is DRM-protected.
+#define SB_IS_PLAYER_PRODUCING_TEXTURE 0
+
+// Specifies whether this platform's player is composited with a formal
+// compositor, where the client must specify how video is to be composited into
+// the graphicals scene.
+#define SB_IS_PLAYER_COMPOSITED 0
+
+// Specifies whether this platform's player uses a "punch-out" model, where
+// video is rendered to the far background, and the graphics plane is
+// automatically composited on top of the video by the platform. The client must
+// punch an alpha hole out of the graphics plane for video to show through.  In
+// this case, changing the video bounds must be tightly synchronized between the
+// player and the graphics plane.
+#define SB_IS_PLAYER_PUNCHED_OUT 1
+#endif  // SB_API_VERSION < 4
+
+// After a seek is triggerred, the default behavior is to append video frames
+// from the last key frame before the seek time and append audio frames from the
+// seek time because usually all audio frames are key frames.  On platforms that
+// cannot decode video frames without displaying them, this will cause the video
+// being played without audio for several seconds after seeking.  When the
+// following macro is defined, the app will append audio frames start from the
+// timestamp that is before the timestamp of the video key frame being appended.
+#undef SB_HAS_QUIRK_SEEK_TO_KEYFRAME
+
+// dlmalloc will use the ffs intrinsic if available.  Platforms on which this is
+// not available should define the following quirk.
+#undef SB_HAS_QUIRK_NO_FFS
+
+#if SB_API_VERSION >= 4
+
+// The maximum audio bitrate the platform can decode.  The following value
+// equals to 5M bytes per seconds which is more than enough for compressed
+// audio.
+#define SB_MEDIA_MAX_AUDIO_BITRATE_IN_BITS_PER_SECOND (40 * 1024 * 1024)
+
+// The maximum video bitrate the platform can decode.  The following value
+// equals to 25M bytes per seconds which is more than enough for compressed
+// video.
+#define SB_MEDIA_MAX_VIDEO_BITRATE_IN_BITS_PER_SECOND (200 * 1024 * 1024)
+
+#endif  // SB_API_VERSION >= 4
+
+// Specifies whether this platform has webm/vp9 support.  This should be set to
+// non-zero on platforms with webm/vp9 support.
+#define SB_HAS_MEDIA_WEBM_VP9_SUPPORT 0
+
+// Specifies the stack size for threads created inside media stack.  Set to 0 to
+// use the default thread stack size.  Set to non-zero to explicitly set the
+// stack size for media stack threads.
+#define SB_MEDIA_THREAD_STACK_SIZE 0U
+
+// --- Decoder-only Params ---
+
+// Specifies how media buffers must be aligned on this platform as some
+// decoders may have special requirement on the alignment of buffers being
+// decoded.
+#define SB_MEDIA_BUFFER_ALIGNMENT 128U
+
+// Specifies how video frame buffers must be aligned on this platform.
+#define SB_MEDIA_VIDEO_FRAME_ALIGNMENT 256U
+
+// The encoded video frames are compressed in different ways, so their decoding
+// time can vary a lot.  Occasionally a single frame can take longer time to
+// decode than the average time per frame.  The player has to cache some frames
+// to account for such inconsistency.  The number of frames being cached are
+// controlled by SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES and
+// SB_MEDIA_MAXIMUM_VIDEO_FRAMES.
+//
+// Specify the number of video frames to be cached before the playback starts.
+// Note that setting this value too large may increase the playback start delay.
+#define SB_MEDIA_MAXIMUM_VIDEO_PREROLL_FRAMES 4
+
+// Specify the number of video frames to be cached during playback.  A large
+// value leads to more stable fps but also causes the app to use more memory.
+#define SB_MEDIA_MAXIMUM_VIDEO_FRAMES 12
+
+// --- Network Configuration -------------------------------------------------
+
+// Specifies whether this platform supports IPV6.
+#define SB_HAS_IPV6 1
+
+// Specifies whether this platform supports pipe.
+#define SB_HAS_PIPE 1
+
+// --- Tuneable Parameters ---------------------------------------------------
+
+// Specifies the network receive buffer size in bytes, set via
+// SbSocketSetReceiveBufferSize().
+//
+// Setting this to 0 indicates that SbSocketSetReceiveBufferSize() should
+// not be called. Use this for OSs (such as Linux) where receive buffer
+// auto-tuning is better.
+//
+// On some platforms, this may affect max TCP window size which may
+// dramatically affect throughput in the presence of latency.
+//
+// If your platform does not have a good TCP auto-tuning mechanism,
+// a setting of (128 * 1024) here is recommended.
+#define SB_NETWORK_RECEIVE_BUFFER_SIZE (0)
+
+// --- User Configuration ----------------------------------------------------
+
+// The maximum number of users that can be signed in at the same time.
+#define SB_USER_MAX_SIGNED_IN 1
+
+// --- Timing API ------------------------------------------------------------
+
+// Whether this platform has an API to retrieve how long the current thread
+// has spent in the executing state.
+#define SB_HAS_TIME_THREAD_NOW 0
+
+// --- Platform Specific Audits ----------------------------------------------
+
+#endif  // STARBOARD_WIN_SHARED_CONFIGURATION_PUBLIC_H_
diff --git a/src/starboard/win/shared/gyp_configuration.gypi b/src/starboard/win/shared/gyp_configuration.gypi
new file mode 100644
index 0000000..b9fa447
--- /dev/null
+++ b/src/starboard/win/shared/gyp_configuration.gypi
@@ -0,0 +1,286 @@
+# Copyright 2017 Google Inc. 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.
+{
+  'variables': {
+    'target_arch': 'x64',
+    'target_os': 'win',
+
+    # Use a stub rasterizer and graphical setup.
+    'rasterizer_type': 'stub',
+
+    # Link with angle
+    'gl_type': 'angle',
+
+    'cobalt_media_source_2016': 1,
+
+    # Define platform specific compiler and linker flags.
+    # Refer to base.gypi for a list of all available variables.
+    'compiler_flags_host': [
+      '-O2',
+    ],
+    'compiler_flags': [
+      # We'll pretend not to be Linux, but Starboard instead.
+      '-U__linux__',
+    ],
+    'linker_flags': [
+    ],
+    'compiler_flags_debug': [
+      '-frtti',
+      '-O0',
+    ],
+    'compiler_flags_devel': [
+      '-frtti',
+      '-O2',
+    ],
+    'compiler_flags_qa': [
+      '-fno-rtti',
+      '-O2',
+      '-gline-tables-only',
+    ],
+    'compiler_flags_gold': [
+      '-fno-rtti',
+      '-O2',
+      '-gline-tables-only',
+    ],
+    'conditions': [
+      ['cobalt_fastbuild==0', {
+        'msvs_settings': {
+          'VCCLCompilerTool': {
+            'DebugInformationFormat': '3',
+          },
+          'VCLinkerTool': {
+            'GenerateDebugInformation': 'true',
+          },
+        }
+        }],
+    ],
+  },
+
+  'target_defaults': {
+    'configurations': {
+      'msvs_base': {
+        'abstract': 1,
+        'msvs_configuration_attributes': {
+          'OutputDirectory': '<(DEPTH)\\build\\<(build_dir_prefix)$(ConfigurationName)',
+          'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
+          'CharacterSet': '1',
+        },
+        'msvs_system_include_dirs': [
+          '<(windows_sdk_path)/include/<(windows_sdk_version)/shared',
+          '<(windows_sdk_path)/include/<(windows_sdk_version)/ucrt',
+          '<(windows_sdk_path)/include/<(windows_sdk_version)/um',
+          '<(windows_sdk_path)/include/<(windows_sdk_version)/winrt',
+          '<(windows_sdk_path)/include/<(windows_sdk_version)',
+          '<(visual_studio_install_path)/include',
+          '<(visual_studio_install_path)/atlmfc/include',
+        ],
+        'msvs_settings': {
+          'VCLinkerTool': {
+            'AdditionalDependencies': [
+              'windowsapp.lib',
+            ],
+            'AdditionalLibraryDirectories!': [
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/ucrt/x86',
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/um/x86',
+              ],
+            'AdditionalLibraryDirectories': [
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/ucrt/x64',
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/um/x64',
+              '<(visual_studio_install_path)/lib/x64',
+              ],
+          },
+          'VCLibrarianTool': {
+            'AdditionalLibraryDirectories!': [
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/ucrt/x86',
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/um/x86',
+              ],
+            'AdditionalLibraryDirectories': [
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/ucrt/x64',
+              '<(windows_sdk_path)/lib/<(windows_sdk_version)/um/x64',
+              '<(visual_studio_install_path)/lib/x64',
+              ],
+          },
+        },
+        'msvs_target_platform': 'x64',
+        # Add the default import libs.
+        'conditions': [
+          ['cobalt_fastbuild==0', {
+            'msvs_settings': {
+              'VCCLCompilerTool': {
+                'DebugInformationFormat': '3',
+                'AdditionalOptions': [
+                '/FS',
+                ],
+              },
+              'VCLinkerTool': {
+                'GenerateDebugInformation': 'true',
+              },
+            },
+          }],
+        ],
+      },
+    },
+    'defines': [
+      # Disable suggestions to switch to Microsoft-specific secure CRT.
+      '_CRT_SECURE_NO_WARNINGS',
+      # Disable support for exceptions in STL in order to detect their use
+      # (the use of exceptions is forbidden by Google C++ style guide).
+      '_HAS_EXCEPTIONS=0',
+      '__STDC_FORMAT_MACROS', # so that we get PRI*
+      # Enable GNU extensions to get prototypes like ffsl.
+      #'_GNU_SOURCE=1',
+      'WIN32_LEAN_AND_MEAN',
+      # By defining this, M_PI will get #defined.
+      '_USE_MATH_DEFINES',
+      # min and max collide with std::min and std::max
+      'NOMINMAX',
+      # Conform with C99 spec.
+      '_CRT_STDIO_ISO_WIDE_SPECIFIERS',
+    ],
+    'msvs_settings': {
+      'VCCLCompilerTool': {
+        'ForcedIncludeFiles': [],
+        # Check for buffer overruns.
+        'BufferSecurityCheck': 'true',
+        'Conformance': [
+          # "for" loop's initializer go out of scope after the for loop.
+          'forScope',
+          # wchar_t is treated as a built-in type.
+          'wchar_t',
+        ],
+        # Check for 64-bit portability issues.
+        'Detect64BitPortabilityProblems': 'true',
+        # Disable Microsoft-specific header dependency tracking.
+        # Incremental linker does not support the Windows metadata included
+        # in .obj files compiled with C++/CX support (/ZW).
+        'MinimalRebuild': 'false',
+        # Treat warnings as errors.
+        'WarnAsError': 'false',
+        # Enable some warnings, even those that are disabled by default.
+        # See https://msdn.microsoft.com/en-us/library/23k5d385.aspx
+        'WarningLevel': '3',
+
+        'AdditionalOptions': [
+          '/errorReport:none', # don't send error reports to MS.
+          '/permissive-', # Visual C++ conformance mode.
+          '/FS', # Force sync PDB updates for parallel compile.
+        ],
+      },
+      'VCLinkerTool': {
+        'RandomizedBaseAddress': '2', # /DYNAMICBASE
+        # TODO: SubSystem is hardcoded in
+        # win\sources_template.vcxproj. This will have the exe behave in the
+        # expected way in MSVS: when it's run without debug (Ctrl+F5), it
+        # will pause after finish; when debugging (F5) it will not pause
+        # before the cmd window disappears.
+        # Currently the value is ignored by msvs_makefile.py which generates
+        # the MSVS project files (it's in "data" in GenerateOutput()). Fix
+        # it if we ever need to change SubSystem.
+        'SubSystem': '1', # CONSOLE
+        'TargetMachine': '17', # x86 - 64
+        'AdditionalOptions': [
+          '/WINMD:NO', # Do not generate a WinMD file.
+          '/errorReport:none', # don't send error reports to MS.
+        ],
+      },
+      'VCLibrarianTool': {
+        'AdditionalOptions': [
+          # Linking statically with C++/CX library is not recommended.
+          # TODO: Remove after removing ComponentExtensions
+          '/ignore:4264',
+        ],
+      },
+    },
+    'msvs_disabled_warnings': [
+      # Conditional expression is constant.
+      # Triggers in many legitimate cases, like branching on a constant declared
+      # in type traits.
+      4127,
+      # Class has virtual functions, but destructor is not virtual.
+      # Far less useful than in GCC because doesn't take into account the fact
+      # that destructor is not public.
+      4265,
+      # no function prototype given: converting '()' to '(void)'.
+      # We do not care.
+      4255,
+      # cast truncates constant value.
+      # We do not care.
+      4310,
+      # An rvalue cannot be bound to a non-const reference.
+      # In previous versions of Visual C++, it was possible to bind an rvalue
+      # to a non-const reference in a direct initialization. This warning
+      # is useless as it simply describes proper C++ behavior.
+      4350,
+      # layout of class may have changed from a previous version of
+      # the compiler due to better packing of member. We don't care about
+      # binary compatibility with other compiler versions.
+      4371,
+      # relative include path contains '..'.
+      # This occurs in a lot third party libraries and we don't care.
+      4464,
+      # decorated name length exceeded, name was truncated.
+      4503,
+      # assignment operator could not be generated.
+      # This is expected for structs with const members.
+      4512,
+      # Unreferenced inline function has been removed.
+      # While detection of dead code is good, this warning triggers in
+      # third-party libraries which renders it useless.
+      4514,
+      # Expression before comma has no effect.
+      # Cannot be used because Microsoft uses _ASSERTE(("message", 0)) trick
+      # in malloc.h which is included pretty much everywhere.
+      4548,
+      # Copy constructor could not be generated because a base class copy
+      # constructor is inaccessible.
+      # This is an expected consequence of using DISALLOW_COPY_AND_ASSIGN().
+      4625,
+      # Assignment operator could not be generated because a base class
+      # assignment operator is inaccessible.
+      # This is an expected consequence of using DISALLOW_COPY_AND_ASSIGN().
+      4626,
+      # Digraphs not supported.
+      # Thanks god!
+      4628,
+      # Symbol is not defined as a preprocessor macro, replacing with '0'.
+      # Seems like common practice, used in Windows SDK and gtest.
+      4668,
+      # Function not inlined.
+      # It's up to the compiler to decide what to inline.
+      4710,
+      # Function selected for inline expansion.
+      # It's up to the compiler to decide what to inline.
+      4711,
+      # The type and order of elements caused the compiler to add padding
+      # to the end of a struct.
+      # Unsurprisingly, most of the structs become larger because of padding
+      # but it's a universally acceptable price for better performance.
+      4820,
+      # Disable static analyzer warning for std::min and std::max with
+      # objects.
+      # https://connect.microsoft.com/VisualStudio/feedback/details/783808/static-analyzer-warning-c28285-for-std-min-and-std-max
+      28285,
+    ],
+    'target_conditions': [
+      ['cobalt_code==1', {
+        'cflags': [
+          '-Wall',
+          '-Wextra',
+          '-Wunreachable-code',
+        ],
+      },
+      ],
+    ],
+  }, # end of target_defaults
+}
diff --git a/src/starboard/win/shared/main.cc b/src/starboard/win/shared/main.cc
new file mode 100644
index 0000000..928cd84
--- /dev/null
+++ b/src/starboard/win/shared/main.cc
@@ -0,0 +1,69 @@
+// Copyright 2017 Google Inc. 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.
+
+#include <windows.h>
+
+#include <WinSock2.h>
+
+#include <string>
+#include <vector>
+
+#include "starboard/configuration.h"
+#include "starboard/shared/uwp/application_uwp.h"
+#include "starboard/shared/win32/thread_private.h"
+#include "starboard/shared/win32/wchar_utils.h"
+
+using starboard::shared::win32::wchar_tToUTF8;
+
+int main(Platform::Array<Platform::String^>^ args) {
+  if (!IsDebuggerPresent()) {
+    _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+    _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG);
+    _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+  }
+
+  const int kWinSockVersionMajor = 2;
+  const int kWinSockVersionMinor = 2;
+  WSAData wsaData;
+  int init_result = WSAStartup(
+      MAKEWORD(kWinSockVersionMajor, kWinSockVersionMajor), &wsaData);
+
+  SB_CHECK(init_result == 0);
+  // WSAStartup returns the highest version that is supported up to the version
+  // we request.
+  SB_CHECK(LOBYTE(wsaData.wVersion) == kWinSockVersionMajor &&
+           HIBYTE(wsaData.wVersion) == kWinSockVersionMinor);
+
+  starboard::shared::win32::RegisterMainThread();
+
+  std::vector<std::string> string_args;
+  for (auto it = args->begin(); it != args->end(); ++it) {
+    Platform::String^ s = *it;
+    string_args.push_back(wchar_tToUTF8(s->Data(), s->Length()));
+  }
+
+  std::vector<const char*> utf8_args;
+  for (auto it = string_args.begin(); it != string_args.end(); ++it) {
+    utf8_args.push_back(it->data());
+  }
+
+  starboard::shared::uwp::ApplicationUwp application;
+  int return_value = application.Run(static_cast<int>(utf8_args.size()),
+                                     const_cast<char**>(utf8_args.data()));
+
+  WSACleanup();
+
+  return return_value;
+}
diff --git a/src/starboard/win/shared/starboard_platform.gypi b/src/starboard/win/shared/starboard_platform.gypi
new file mode 100644
index 0000000..c059193
--- /dev/null
+++ b/src/starboard/win/shared/starboard_platform.gypi
@@ -0,0 +1,299 @@
+# Copyright 2016 Google Inc. 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.
+{
+  'targets': [
+    {
+      'target_name': 'starboard_platform',
+      'type': 'static_library',
+      'msvs_settings': {
+        'VCCLCompilerTool': {
+          'AdditionalOptions': [
+            '/ZW',  # Windows Runtime (Needed for UWP)
+            '/EHsx', # C++ exceptions (required with /ZW)
+            # For 'platform.winmd'. Note that replacing x86 with
+            # x64 here does not work.
+            '/AI"<(visual_studio_install_path)/lib/x86/store/references"',
+            # For 'Windows.winmd'
+            '/AI"<(windows_sdk_path)/UnionMetadata/<(windows_sdk_version)"',
+          ]
+        }
+      },
+      'sources': [
+        '<(DEPTH)/starboard/shared/iso/character_is_alphanumeric.cc',
+        '<(DEPTH)/starboard/shared/iso/character_is_digit.cc',
+        '<(DEPTH)/starboard/shared/iso/character_is_hex_digit.cc',
+        '<(DEPTH)/starboard/shared/iso/character_is_space.cc',
+        '<(DEPTH)/starboard/shared/iso/character_is_upper.cc',
+        '<(DEPTH)/starboard/shared/iso/character_to_lower.cc',
+        '<(DEPTH)/starboard/shared/iso/character_to_upper.cc',
+        '<(DEPTH)/starboard/shared/iso/double_absolute.cc',
+        '<(DEPTH)/starboard/shared/iso/double_exponent.cc',
+        '<(DEPTH)/starboard/shared/iso/double_floor.cc',
+        '<(DEPTH)/starboard/shared/iso/double_is_finite.cc',
+        '<(DEPTH)/starboard/shared/iso/double_is_nan.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_compare.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_copy.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_find_byte.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_move.cc',
+        '<(DEPTH)/starboard/shared/iso/memory_set.cc',
+        '<(DEPTH)/starboard/shared/iso/string_compare.cc',
+        '<(DEPTH)/starboard/shared/iso/string_compare_all.cc',
+        '<(DEPTH)/starboard/shared/iso/string_find_character.cc',
+        '<(DEPTH)/starboard/shared/iso/string_find_last_character.cc',
+        '<(DEPTH)/starboard/shared/iso/string_find_string.cc',
+        '<(DEPTH)/starboard/shared/iso/string_get_length.cc',
+        '<(DEPTH)/starboard/shared/iso/string_get_length_wide.cc',
+        '<(DEPTH)/starboard/shared/iso/string_parse_double.cc',
+        '<(DEPTH)/starboard/shared/iso/string_parse_signed_integer.cc',
+        '<(DEPTH)/starboard/shared/iso/string_parse_uint64.cc',
+        '<(DEPTH)/starboard/shared/iso/string_parse_unsigned_integer.cc',
+        '<(DEPTH)/starboard/shared/iso/string_scan.cc',
+        '<(DEPTH)/starboard/shared/starboard/application.cc',
+        '<(DEPTH)/starboard/shared/starboard/command_line.cc',
+        '<(DEPTH)/starboard/shared/starboard/command_line.h',
+        '<(DEPTH)/starboard/shared/starboard/event_cancel.cc',
+        '<(DEPTH)/starboard/shared/starboard/event_schedule.cc',
+        '<(DEPTH)/starboard/shared/starboard/file_mode_string_to_flags.cc',
+        '<(DEPTH)/starboard/shared/starboard/log_message.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_type.cc',
+        '<(DEPTH)/starboard/shared/starboard/media/mime_type.h',
+        '<(DEPTH)/starboard/shared/starboard/string_concat.cc',
+        '<(DEPTH)/starboard/shared/starboard/string_concat_wide.cc',
+        '<(DEPTH)/starboard/shared/starboard/string_copy.cc',
+        '<(DEPTH)/starboard/shared/starboard/string_copy_wide.cc',
+        '<(DEPTH)/starboard/shared/starboard/string_duplicate.cc',
+        '<(DEPTH)/starboard/shared/starboard/queue_application.cc',
+        '<(DEPTH)/starboard/shared/stub/accessibility_get_display_settings.cc',
+        '<(DEPTH)/starboard/shared/stub/accessibility_get_text_to_speech_settings.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_create.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_get_max_channels.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_get_nearest_supported_sample_frequency.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_is_audio_frame_storage_type_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_is_audio_sample_type_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/audio_sink_is_valid.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_create_transformer.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_destroy_transformer.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_get_tag.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_set_authenticated_data.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_set_initialization_vector.cc',
+        '<(DEPTH)/starboard/shared/stub/cryptography_transform.cc',
+        '<(DEPTH)/starboard/shared/stub/decode_target_release.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_close_session.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_create_system.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_destroy_system.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_generate_session_update_request.cc',
+        '<(DEPTH)/starboard/shared/stub/drm_system_internal.h',
+        '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
+        '<(DEPTH)/starboard/shared/stub/image_decode.cc',
+        '<(DEPTH)/starboard/shared/stub/image_is_decode_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_can_play_mime_and_key_system.cc',
+        '<(DEPTH)/starboard/shared/stub/media_get_audio_configuration.cc',
+        '<(DEPTH)/starboard/shared/stub/media_get_audio_output_count.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_audio_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_output_protected.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_video_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_set_output_protection.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_close.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_create.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_get_available.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_is_sample_rate_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_open.cc',
+        '<(DEPTH)/starboard/shared/stub/microphone_read.cc',
+        '<(DEPTH)/starboard/shared/stub/player_create.cc',
+        '<(DEPTH)/starboard/shared/stub/player_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/player_get_current_frame.cc',
+        '<(DEPTH)/starboard/shared/stub/player_get_info.cc',
+        '<(DEPTH)/starboard/shared/stub/player_output_mode_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/player_seek.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_bounds.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_pause.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_playback_rate.cc',
+        '<(DEPTH)/starboard/shared/stub/player_set_volume.cc',
+        '<(DEPTH)/starboard/shared/stub/player_write_end_of_stream.cc',
+        '<(DEPTH)/starboard/shared/stub/player_write_sample.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_add.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_create.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_remove.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_wait.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_wait_timed.cc',
+        '<(DEPTH)/starboard/shared/stub/socket_waiter_wake_up.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_close_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_delete_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_get_record_size.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_open_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_read_record.cc',
+        '<(DEPTH)/starboard/shared/stub/storage_write_record.cc',
+        '<(DEPTH)/starboard/shared/stub/system_binary_search.cc',
+        '<(DEPTH)/starboard/shared/stub/system_clear_last_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_connection_type.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_device_type.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_error_string.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_last_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_locale_id.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_number_of_processors.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_property.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_random_data.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_stack.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_total_cpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_total_gpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_used_cpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_get_used_gpu_memory.cc',
+        '<(DEPTH)/starboard/shared/stub/system_has_capability.cc',
+        '<(DEPTH)/starboard/shared/stub/system_hide_splash_screen.cc',
+        '<(DEPTH)/starboard/shared/stub/system_is_debugger_attached.cc',
+        '<(DEPTH)/starboard/shared/stub/system_raise_platform_error.cc',
+        '<(DEPTH)/starboard/shared/stub/system_request_pause.cc',
+        '<(DEPTH)/starboard/shared/stub/system_request_stop.cc',
+        '<(DEPTH)/starboard/shared/stub/system_request_suspend.cc',
+        '<(DEPTH)/starboard/shared/stub/system_request_unpause.cc',
+        '<(DEPTH)/starboard/shared/stub/system_sort.cc',
+        '<(DEPTH)/starboard/shared/stub/system_symbolize.cc',
+        '<(DEPTH)/starboard/shared/stub/time_zone_get_dst_name.cc',
+        '<(DEPTH)/starboard/shared/stub/time_zone_get_name.cc',
+        '<(DEPTH)/starboard/shared/stub/user_get_current.cc',
+        '<(DEPTH)/starboard/shared/stub/user_get_property.cc',
+        '<(DEPTH)/starboard/shared/stub/user_get_signed_in.cc',
+        '<(DEPTH)/starboard/shared/stub/window_create.cc',
+        '<(DEPTH)/starboard/shared/stub/window_destroy.cc',
+        '<(DEPTH)/starboard/shared/stub/window_get_platform_handle.cc',
+        '<(DEPTH)/starboard/shared/stub/window_get_size.cc',
+        '<(DEPTH)/starboard/shared/stub/window_set_default_options.cc',
+        '<(DEPTH)/starboard/shared/win32/atomic_public.h',
+        '<(DEPTH)/starboard/shared/win32/byte_swap.cc',
+        '<(DEPTH)/starboard/shared/win32/condition_variable_broadcast.cc',
+        '<(DEPTH)/starboard/shared/win32/condition_variable_create.cc',
+        '<(DEPTH)/starboard/shared/win32/condition_variable_destroy.cc',
+        '<(DEPTH)/starboard/shared/win32/condition_variable_signal.cc',
+        '<(DEPTH)/starboard/shared/win32/condition_variable_wait.cc',
+        '<(DEPTH)/starboard/shared/win32/condition_variable_wait_timed.cc',
+        '<(DEPTH)/starboard/shared/win32/directory_can_open.cc',
+        '<(DEPTH)/starboard/shared/win32/directory_close.cc',
+        '<(DEPTH)/starboard/shared/win32/directory_create.cc',
+        '<(DEPTH)/starboard/shared/win32/directory_get_next.cc',
+        '<(DEPTH)/starboard/shared/win32/directory_internal.h',
+        '<(DEPTH)/starboard/shared/win32/directory_open.cc',
+        '<(DEPTH)/starboard/shared/win32/file_can_open.cc',
+        '<(DEPTH)/starboard/shared/win32/file_close.cc',
+        '<(DEPTH)/starboard/shared/win32/file_delete.cc',
+        '<(DEPTH)/starboard/shared/win32/file_exists.cc',
+        '<(DEPTH)/starboard/shared/win32/file_flush.cc',
+        '<(DEPTH)/starboard/shared/win32/file_get_info.cc',
+        '<(DEPTH)/starboard/shared/win32/file_get_path_info.cc',
+        '<(DEPTH)/starboard/shared/win32/file_internal.cc',
+        '<(DEPTH)/starboard/shared/win32/file_internal.h',
+        '<(DEPTH)/starboard/shared/win32/file_open.cc',
+        '<(DEPTH)/starboard/shared/win32/file_read.cc',
+        '<(DEPTH)/starboard/shared/win32/file_seek.cc',
+        '<(DEPTH)/starboard/shared/win32/file_truncate.cc',
+        '<(DEPTH)/starboard/shared/win32/file_write.cc',
+        '<(DEPTH)/starboard/shared/win32/log.cc',
+        '<(DEPTH)/starboard/shared/win32/log_flush.cc',
+        '<(DEPTH)/starboard/shared/win32/log_format.cc',
+        '<(DEPTH)/starboard/shared/win32/log_is_tty.cc',
+        '<(DEPTH)/starboard/shared/win32/log_raw.cc',
+        '<(DEPTH)/starboard/shared/win32/log_raw_dump_stack.cc',
+        '<(DEPTH)/starboard/shared/win32/log_raw_format.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_allocate_aligned_unchecked.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_allocate_unchecked.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_free.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_free_aligned.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_get_stack_bounds.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_map.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_reallocate_unchecked.cc',
+        '<(DEPTH)/starboard/shared/win32/memory_unmap.cc',
+        '<(DEPTH)/starboard/shared/win32/mutex_acquire.cc',
+        '<(DEPTH)/starboard/shared/win32/mutex_acquire_try.cc',
+        '<(DEPTH)/starboard/shared/win32/mutex_create.cc',
+        '<(DEPTH)/starboard/shared/win32/mutex_destroy.cc',
+        '<(DEPTH)/starboard/shared/win32/mutex_release.cc',
+        '<(DEPTH)/starboard/shared/win32/once.cc',
+        '<(DEPTH)/starboard/shared/win32/set_non_blocking_internal.cc',
+        '<(DEPTH)/starboard/shared/win32/set_non_blocking_internal.h',
+        '<(DEPTH)/starboard/shared/win32/socket_accept.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_bind.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_clear_last_error.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_connect.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_create.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_destroy.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_free_resolution.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_get_last_error.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_get_local_address.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_get_interface_address.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_internal.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_internal.h',
+        '<(DEPTH)/starboard/shared/win32/socket_is_connected.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_is_connected_and_idle.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_join_multicast_group.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_listen.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_receive_from.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_resolve.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_send_to.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_set_broadcast.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_set_receive_buffer_size.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_set_reuse_address.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_set_send_buffer_size.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_set_tcp_keep_alive.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_set_tcp_no_delay.cc',
+        '<(DEPTH)/starboard/shared/win32/socket_set_tcp_window_scaling.cc',
+        '<(DEPTH)/starboard/shared/win32/string_compare_no_case.cc',
+        '<(DEPTH)/starboard/shared/win32/string_compare_no_case_n.cc',
+        '<(DEPTH)/starboard/shared/win32/string_compare_wide.cc',
+        '<(DEPTH)/starboard/shared/win32/string_format.cc',
+        '<(DEPTH)/starboard/shared/win32/string_format_wide.cc',
+        '<(DEPTH)/starboard/shared/win32/system_break_into_debugger.cc',
+        '<(DEPTH)/starboard/shared/win32/system_get_random_uint64.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_create.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_create_local_key.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_detach.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_destroy_local_key.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_get_current.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_get_id.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_get_local_value.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_get_name.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_is_equal.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_join.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_private.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_private.h',
+        '<(DEPTH)/starboard/shared/win32/thread_set_local_value.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_set_name.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_sleep.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_types_public.h',
+        '<(DEPTH)/starboard/shared/win32/thread_yield.cc',
+        '<(DEPTH)/starboard/shared/win32/thread_yield.h',
+        '<(DEPTH)/starboard/shared/win32/time_get_monotonic_now.cc',
+        '<(DEPTH)/starboard/shared/win32/time_get_now.cc',
+        '<(DEPTH)/starboard/shared/win32/time_zone_get_current.cc',
+        '<(DEPTH)/starboard/shared/win32/time_utils.h',
+        '<(DEPTH)/starboard/shared/win32/wchar_utils.h',
+        '<(DEPTH)/starboard/shared/uwp/application_uwp.cc',
+        '<(DEPTH)/starboard/shared/uwp/application_uwp.h',
+        'configuration_public.h',
+        'main.cc',
+        # Include private stubs, if present.
+        '<!@(python "<(DEPTH)/starboard/tools/find_private_files.py" "<(DEPTH)" "shared/stub/*.cc")',
+        '<@(starboard_platform_dependent_sources)',
+      ],
+      'defines': [
+        # This must be defined when building Starboard, and must not when
+        # building Starboard client code.
+        'STARBOARD_IMPLEMENTATION',
+      ],
+    },
+  ],
+}
diff --git a/src/starboard/win/shared/system_get_path.cc b/src/starboard/win/shared/system_get_path.cc
new file mode 100644
index 0000000..fdc35c2
--- /dev/null
+++ b/src/starboard/win/shared/system_get_path.cc
@@ -0,0 +1,112 @@
+// Copyright 2017 Google Inc. 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.
+
+#include "starboard/system.h"
+
+#include <windows.h>
+#include <codecvt>
+#include <cstring>
+#include <locale>
+
+#include "Pathcch.h"
+
+#include "starboard/directory.h"
+#include "starboard/log.h"
+#include "starboard/shared/win32/directory_internal.h"
+#include "starboard/shared/win32/wchar_utils.h"
+#include "starboard/string.h"
+
+bool GetExecutablePath(char* out_path, int path_size) {
+  if (!out_path || !path_size) {
+    return false;
+  }
+
+  static const int kPathSize = SB_FILE_MAX_PATH;
+
+  wchar_t w_file_path[SB_FILE_MAX_PATH];
+  DWORD characters_written =
+      GetModuleFileName(NULL, w_file_path, SB_FILE_MAX_PATH);
+  if (characters_written == 0) {
+    return false;
+  }
+  PathCchRemoveFileSpec(w_file_path, SB_FILE_MAX_PATH);
+  std::string utf8_string =
+      starboard::shared::win32::wchar_tToUTF8(w_file_path, SB_FILE_MAX_PATH);
+  return SbStringCopy(out_path, utf8_string.c_str(), SB_FILE_MAX_PATH);
+}
+
+// Note: This function is only minimally implemented to allow tests to run.
+bool SbSystemGetPath(SbSystemPathId path_id, char* out_path, int path_size) {
+  if (!out_path || !path_size) {
+    return false;
+  }
+
+  static const int kPathSize = SB_FILE_MAX_PATH;
+
+  char file_path[kPathSize];
+  file_path[0] = '\0';
+
+  switch (path_id) {
+    case kSbSystemPathContentDirectory: {
+      if (!GetExecutablePath(file_path, kPathSize)) {
+        return false;
+      }
+      if (SbStringConcat(file_path, "/content/data", kPathSize) >= kPathSize) {
+        return false;
+      }
+      SbStringCopy(out_path, file_path, path_size);
+      break;
+    }
+    case kSbSystemPathTempDirectory: {
+      wchar_t w_file_path[kPathSize];
+      w_file_path[0] = '\0';
+
+      DWORD characters_written = GetTempPathW(kPathSize, w_file_path);
+      if (characters_written >= (kPathSize - 1)) {
+        return false;
+      }
+
+      if (characters_written < 1) {
+        return false;
+      }
+      // Remove the last slash, to match other Starboard implementations.
+      w_file_path[characters_written - 1] = L'\0';
+
+      std::string utf8_string =
+          starboard::shared::win32::wchar_tToUTF8(w_file_path);
+
+      if (SbStringCopy(file_path, utf8_string.c_str(), kPathSize) >=
+          kPathSize) {
+        return false;
+      }
+      SbDirectoryCreate(file_path);
+
+      size_t length = SbStringGetLength(file_path);
+      if (length < 1 || length > path_size) {
+        return false;
+      }
+
+      SbStringCopy(out_path, file_path, path_size);
+      break;
+    }
+    case kSbSystemPathExecutableFile: {
+      return GetExecutablePath(out_path, path_size);
+    }
+    // TODO: implement all the other cases.
+    default:
+      SB_NOTIMPLEMENTED();
+      return false;
+  }
+  return true;
+}
diff --git a/src/third_party/angle/.clang-format b/src/third_party/angle/.clang-format
new file mode 100644
index 0000000..9b4c96a
--- /dev/null
+++ b/src/third_party/angle/.clang-format
@@ -0,0 +1,35 @@
+# Defines the ANGLE style for automatic reformatting.
+# https://code.google.com/p/angleproject/wiki/CodingStandard
+# See Clang docs: http://clang.llvm.org/docs/ClangFormatStyleOptions.html
+BasedOnStyle: Chromium
+
+# Allow double brackets such as std::vector<std::vector<int>>.
+Standard: Cpp11
+
+# Indent 4 spaces at a time.
+IndentWidth: 4
+
+# Keep lines under 100 columns long.
+ColumnLimit: 100
+
+# Always break before braces
+BreakBeforeBraces: Allman
+
+# Indent case labels.
+IndentCaseLabels: true
+
+# Right-align pointers and references
+PointerAlignment: Right
+
+# ANGLE likes to align things as much as possible.
+AlignOperands: true
+AlignConsecutiveAssignments: true
+
+# Use 2 space negative offset for access modifiers
+AccessModifierOffset: -2
+
+# TODO(jmadill): Decide if we want this on. Doesn't have an "all or none" mode.
+AllowShortCaseLabelsOnASingleLine: false
+
+# Useful for spacing out functions in classes
+KeepEmptyLinesAtTheStartOfBlocks: true
diff --git a/src/third_party/angle/AUTHORS b/src/third_party/angle/AUTHORS
index a2ce915..9830cce 100644
--- a/src/third_party/angle/AUTHORS
+++ b/src/third_party/angle/AUTHORS
@@ -1,4 +1,4 @@
-# This is the official list of The ANGLE Project Authors
+# This is the official list of The ANGLE Project Authors
 # for copyright purposes.
 # This file is distinct from the CONTRIBUTORS files.
 # See the latter for an explanation.
@@ -13,15 +13,26 @@
 
 Adobe Systems Inc.
 Autodesk, Inc.
+BlackBerry Limited
+Cable Television Laboratories, Inc.
 Cloud Party, Inc.
+Imagination Technologies Ltd.
 Intel Corporation
 Mozilla Corporation
 Turbulenz
 Klarälvdalens Datakonsult AB
+Microsoft Corporation
+Microsoft Open Technologies, Inc.
+NVIDIA Corporation
+Opera Software ASA
+The Qt Company Ltd.
+Advanced Micro Devices, Inc.
 
 Jacek Caban
 Mark Callow
 Ginn Chen
+Tibor den Ouden
+Régis Fénéon
 James Hauxwell
 Sam Hocevar
 Pierre Leveille
@@ -30,3 +41,10 @@
 Aitor Moreno
 Yuri O'Donnell
 Josh Soref
+Maks Naumov
+Jinyoung Hur
+Sebastian Bergstein
+James Ross-Gowan
+Nickolay Artamonov
+Ihsan Akmal
+Andrei Volykhin
diff --git a/src/third_party/angle/BUILD.gn b/src/third_party/angle/BUILD.gn
new file mode 100644
index 0000000..dca6a20
--- /dev/null
+++ b/src/third_party/angle/BUILD.gn
@@ -0,0 +1,745 @@
+# Copyright 2014-2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+# import the use_x11 variable
+import("//build/config/dcheck_always_on.gni")
+import("//build/config/linux/pkg_config.gni")
+import("//build/config/ui.gni")
+import("//testing/libfuzzer/fuzzer_test.gni")
+import("//third_party/angle/gni/angle.gni")
+import("//ui/ozone/ozone.gni")
+
+declare_args() {
+  # Use the PCI lib to collect GPU information on Linux.
+  use_libpci = is_linux && (!is_chromecast || is_cast_desktop_build) &&
+               (use_x11 || use_ozone)
+}
+
+if (ozone_platform_gbm) {
+  pkg_config("libdrm") {
+    packages = [ "libdrm" ]
+  }
+}
+
+angle_git_is_present = exec_script("src/commit_id.py",
+                                   [
+                                     "check",
+                                     rebase_path(".", root_build_dir),
+                                   ],
+                                   "value")
+
+angle_use_commit_id = angle_git_is_present == 1
+
+gles_gypi = exec_script("//build/gypi_to_gn.py",
+                        [ rebase_path("src/libGLESv2.gypi") ],
+                        "scope",
+                        [ "src/libGLESv2.gypi" ])
+
+compiler_gypi = exec_script("//build/gypi_to_gn.py",
+                            [ rebase_path("src/compiler.gypi") ],
+                            "scope",
+                            [ "src/compiler.gypi" ])
+
+# This config is exported to dependent targets (and also applied to internal
+# ones).
+config("external_config") {
+  include_dirs = [ "include" ]
+}
+
+# This config is applied to internal Angle targets (not pushed to dependents).
+config("internal_config") {
+  include_dirs = [
+    "include",
+    "src",
+  ]
+
+  # Prevent the GL headers from redeclaring ANGLE entry points.
+  defines = [
+    "GL_GLEXT_PROTOTYPES",
+    "EGL_EGLEXT_PROTOTYPES",
+  ]
+
+  if (target_cpu == "x86") {
+    defines += [ "ANGLE_X86_CPU" ]
+  }
+  if (target_cpu == "x64") {
+    defines += [ "ANGLE_X64_CPU" ]
+  }
+}
+
+config("extra_warnings") {
+  # Enable more default warnings on Windows.
+  if (is_win) {
+    cflags = [
+      "/we4244",  # Conversion: possible loss of data.
+      "/we4456",  # Variable shadowing.
+      "/we4458",  # declaration hides class member.
+    ]
+  }
+}
+
+if (is_win) {
+  copy("copy_compiler_dll") {
+    sources = [
+      "$windows_sdk_path/Redist/D3D/$target_cpu/d3dcompiler_47.dll",
+    ]
+    outputs = [
+      "$root_out_dir/d3dcompiler_47.dll",
+    ]
+  }
+}
+
+angle_undefine_configs = [ "//build/config/compiler:default_include_dirs" ]
+
+# Holds the shared includes so we only need to list them once.
+source_set("includes") {
+  sources = [
+    "include/EGL/egl.h",
+    "include/EGL/eglext.h",
+    "include/EGL/eglplatform.h",
+    "include/GLES2/gl2.h",
+    "include/GLES2/gl2ext.h",
+    "include/GLES2/gl2platform.h",
+    "include/GLES3/gl3.h",
+    "include/GLES3/gl31.h",
+    "include/GLES3/gl32.h",
+    "include/GLES3/gl3platform.h",
+    "include/GLSLANG/ShaderLang.h",
+    "include/KHR/khrplatform.h",
+  ]
+}
+
+static_library("preprocessor") {
+  sources = rebase_path(compiler_gypi.angle_preprocessor_sources, ".", "src")
+
+  configs -= angle_undefine_configs
+  configs += [ ":internal_config" ]
+
+  public_deps = [
+    ":angle_common",
+  ]
+}
+
+config("translator_disable_pool_alloc") {
+  defines = [ "ANGLE_TRANSLATOR_DISABLE_POOL_ALLOC" ]
+}
+
+config("debug_annotations_config") {
+  if (is_debug) {
+    defines = [ "ANGLE_ENABLE_DEBUG_ANNOTATIONS" ]
+  }
+}
+
+config("angle_release_asserts_config") {
+  if (dcheck_always_on) {
+    defines = [ "ANGLE_ENABLE_RELEASE_ASSERTS" ]
+  }
+}
+
+config("angle_common_config") {
+  include_dirs = [ "src/common/third_party/numerics" ]
+}
+
+static_library("angle_common") {
+  sources = rebase_path(gles_gypi.libangle_common_sources, ".", "src")
+
+  if (is_linux || is_android) {
+    sources += rebase_path(gles_gypi.libangle_common_linux_sources, ".", "src")
+  }
+
+  if (is_mac) {
+    sources += rebase_path(gles_gypi.libangle_common_mac_sources, ".", "src")
+  }
+
+  if (is_win) {
+    sources += rebase_path(gles_gypi.libangle_common_win_sources, ".", "src")
+  }
+
+  configs -= angle_undefine_configs
+  configs += [
+    ":angle_common_config",
+    ":debug_annotations_config",
+    ":extra_warnings",
+    ":internal_config",
+  ]
+
+  public_deps = [
+    ":commit_id",
+  ]
+  public_configs = [ ":angle_common_config" ]
+  all_dependent_configs = [ ":angle_release_asserts_config" ]
+}
+
+config("angle_image_util_config") {
+  include_dirs = [
+    "include",
+    "src",
+  ]
+}
+
+static_library("angle_image_util") {
+  sources = rebase_path(gles_gypi.libangle_image_util_sources, ".", "src")
+
+  configs -= angle_undefine_configs
+  configs += [
+    ":internal_config",
+    ":extra_warnings",
+  ]
+
+  public_configs = [ ":angle_image_util_config" ]
+
+  public_deps = [
+    ":angle_common",
+  ]
+}
+
+config("angle_gpu_info_util_config") {
+  include_dirs = [
+    "include",
+    "src",
+  ]
+}
+
+static_library("angle_gpu_info_util") {
+  configs -= angle_undefine_configs
+  configs += [
+    ":internal_config",
+    ":extra_warnings",
+  ]
+
+  public_configs = [ ":angle_gpu_info_util_config" ]
+
+  public_deps = [
+    ":angle_common",
+  ]
+
+  sources = rebase_path(gles_gypi.libangle_gpu_info_util_sources, ".", "src")
+  deps = []
+  libs = []
+  defines = []
+
+  if (is_win) {
+    sources +=
+        rebase_path(gles_gypi.libangle_gpu_info_util_win_sources, ".", "src")
+    libs += [ "setupapi.lib" ]
+    defines += [ "GPU_INFO_USE_SETUPAPI" ]
+  }
+
+  if (is_linux) {
+    sources +=
+        rebase_path(gles_gypi.libangle_gpu_info_util_linux_sources, ".", "src")
+
+    if (use_x11) {
+      sources +=
+          rebase_path(gles_gypi.libangle_gpu_info_util_x11_sources, ".", "src")
+      deps += [ "src/third_party/libXNVCtrl:libXNVCtrl" ]
+      defines += [ "GPU_INFO_USE_X11" ]
+      libs += [
+        "X11",
+        "Xi",
+        "Xext",
+      ]
+    }
+  }
+
+  if (use_libpci) {
+    sources +=
+        rebase_path(gles_gypi.libangle_gpu_info_util_libpci_sources, ".", "src")
+    defines += [ "GPU_INFO_USE_LIBPCI" ]
+    libs += [ "pci" ]
+  }
+
+  if (is_mac) {
+    sources +=
+        rebase_path(gles_gypi.libangle_gpu_info_util_mac_sources, ".", "src")
+    libs += [
+      "IOKit.framework",
+      "CoreFoundation.framework",
+    ]
+  }
+}
+
+static_library("translator") {
+  sources = rebase_path(compiler_gypi.angle_translator_sources, ".", "src")
+  defines = []
+
+  if (angle_enable_essl || use_libfuzzer) {
+    sources +=
+        rebase_path(compiler_gypi.angle_translator_essl_sources, ".", "src")
+    defines += [ "ANGLE_ENABLE_ESSL" ]
+  }
+
+  if (angle_enable_glsl || use_libfuzzer) {
+    sources +=
+        rebase_path(compiler_gypi.angle_translator_glsl_sources, ".", "src")
+    defines += [ "ANGLE_ENABLE_GLSL" ]
+  }
+
+  if (angle_enable_hlsl || use_libfuzzer) {
+    sources +=
+        rebase_path(compiler_gypi.angle_translator_hlsl_sources, ".", "src")
+    defines += [ "ANGLE_ENABLE_HLSL" ]
+  }
+
+  if (angle_enable_vulkan || use_libfuzzer) {
+    sources += rebase_path(compiler_gypi.angle_translator_lib_vulkan_sources,
+                           ".",
+                           "src")
+    defines += [ "ANGLE_ENABLE_VULKAN" ]
+  }
+
+  configs -= angle_undefine_configs
+  configs += [ ":internal_config" ]
+  public_configs = [ ":external_config" ]
+  if (use_libfuzzer) {
+    all_dependent_configs = [ ":translator_disable_pool_alloc" ]
+  }
+
+  deps = [
+    ":includes",
+    ":preprocessor",
+  ]
+
+  public_deps = [
+    ":angle_common",
+  ]
+
+  if (is_win) {
+    # Necessary to suppress some system header xtree warnigns in Release.
+    # For some reason this warning doesn't get triggered in Chromium
+    cflags = [ "/wd4718" ]
+  }
+}
+
+source_set("translator_fuzzer") {
+  sources = [
+    "src/compiler/fuzz/translator_fuzzer.cpp",
+  ]
+
+  include_dirs = [
+    "include",
+    "src",
+  ]
+
+  deps = [
+    ":translator",
+  ]
+}
+
+config("commit_id_config") {
+  include_dirs = [ "$root_gen_dir/angle" ]
+}
+
+commit_id_output_file = "$root_gen_dir/angle/id/commit.h"
+if (angle_use_commit_id) {
+  action("commit_id") {
+    script = "src/commit_id.py"
+    outputs = [
+      commit_id_output_file,
+    ]
+
+    args = [
+      "gen",
+      rebase_path(".", root_build_dir),
+      rebase_path(commit_id_output_file, root_build_dir),
+    ]
+
+    public_configs = [ ":commit_id_config" ]
+  }
+} else {
+  copy("commit_id") {
+    sources = [
+      "src/commit.h",
+    ]
+    outputs = [
+      commit_id_output_file,
+    ]
+    public_configs = [ ":commit_id_config" ]
+  }
+}
+
+config("libANGLE_config") {
+  cflags = []
+  defines = []
+  if (angle_enable_d3d9) {
+    defines += [ "ANGLE_ENABLE_D3D9" ]
+  }
+  if (angle_enable_d3d11) {
+    defines += [ "ANGLE_ENABLE_D3D11" ]
+  }
+  if (angle_enable_gl) {
+    defines += [ "ANGLE_ENABLE_OPENGL" ]
+    if (use_x11) {
+      defines += [ "ANGLE_USE_X11" ]
+    }
+  }
+  if (angle_enable_vulkan) {
+    defines += [ "ANGLE_ENABLE_VULKAN" ]
+  }
+  if (angle_enable_null) {
+    defines += [ "ANGLE_ENABLE_NULL" ]
+  }
+  defines += [ "LIBANGLE_IMPLEMENTATION" ]
+
+  if (is_win) {
+    cflags += [ "/wd4530" ]  # C++ exception handler used, but unwind semantics are not enabled.
+  }
+}
+
+static_library("libANGLE") {
+  sources = rebase_path(gles_gypi.libangle_sources, ".", "src")
+
+  include_dirs = []
+  libs = []
+  defines = []
+  public_deps = [
+    ":angle_common",
+  ]
+  deps = [
+    ":angle_gpu_info_util",
+    ":angle_image_util",
+    ":commit_id",
+    ":includes",
+    ":translator",
+  ]
+
+  # Shared D3D sources.
+  if (angle_enable_d3d9 || angle_enable_d3d11) {
+    sources += rebase_path(gles_gypi.libangle_d3d_shared_sources, ".", "src")
+
+    defines += [ "ANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES={ " + "\"d3dcompiler_47.dll\", \"d3dcompiler_46.dll\", \"d3dcompiler_43.dll\" }" ]
+  }
+
+  if (angle_enable_d3d9) {
+    sources += rebase_path(gles_gypi.libangle_d3d9_sources, ".", "src")
+    libs += [ "d3d9.lib" ]
+  }
+
+  if (angle_enable_d3d11) {
+    sources += rebase_path(gles_gypi.libangle_d3d11_sources, ".", "src")
+    sources += rebase_path(gles_gypi.libangle_d3d11_win32_sources, ".", "src")
+    libs += [ "dxguid.lib" ]
+  }
+
+  if (angle_enable_gl) {
+    sources += rebase_path(gles_gypi.libangle_gl_sources, ".", "src")
+    include_dirs += [ "src/third_party/khronos" ]
+
+    if (is_win) {
+      sources += rebase_path(gles_gypi.libangle_gl_wgl_sources, ".", "src")
+    }
+    if (use_x11) {
+      sources += rebase_path(gles_gypi.libangle_gl_glx_sources, ".", "src")
+      deps += [ "src/third_party/libXNVCtrl:libXNVCtrl" ]
+      libs += [
+        "X11",
+        "Xi",
+        "Xext",
+      ]
+    }
+    if (is_mac) {
+      sources += rebase_path(gles_gypi.libangle_gl_cgl_sources, ".", "src")
+      libs += [
+        "Cocoa.framework",
+        "IOSurface.framework",
+        "OpenGL.framework",
+        "QuartzCore.framework",
+      ]
+    }
+    if (is_android) {
+      sources += rebase_path(gles_gypi.libangle_gl_egl_sources, ".", "src")
+      sources += rebase_path(gles_gypi.libangle_gl_egl_dl_sources, ".", "src")
+      sources +=
+          rebase_path(gles_gypi.libangle_gl_egl_android_sources, ".", "src")
+      libs += [
+        "android",
+        "log",
+      ]
+    }
+    if (ozone_platform_gbm) {
+      configs += [ ":libdrm" ]
+      defines += [ "ANGLE_USE_OZONE" ]
+      deps += [ "//third_party/minigbm" ]
+      sources += rebase_path(gles_gypi.libangle_gl_egl_sources, ".", "src")
+      sources += rebase_path(gles_gypi.libangle_gl_egl_dl_sources, ".", "src")
+      sources += rebase_path(gles_gypi.libangle_gl_ozone_sources, ".", "src")
+    }
+  }
+
+  if (angle_enable_vulkan) {
+    sources += rebase_path(gles_gypi.libangle_vulkan_sources, ".", "src")
+    if (is_win) {
+      sources +=
+          rebase_path(gles_gypi.libangle_vulkan_win32_sources, ".", "src")
+    }
+    if (is_linux) {
+      sources += rebase_path(gles_gypi.libangle_vulkan_xcb_sources, ".", "src")
+    }
+    deps += [ "//third_party/angle/src/vulkan_support:angle_vulkan" ]
+  }
+
+  if (angle_enable_null) {
+    sources += rebase_path(gles_gypi.libangle_null_sources, ".", "src")
+  }
+
+  if (is_debug) {
+    defines += [ "ANGLE_GENERATE_SHADER_DEBUG_INFO" ]
+  }
+
+  configs -= angle_undefine_configs
+
+  configs += [
+    ":commit_id_config",
+    ":debug_annotations_config",
+    ":extra_warnings",
+    ":internal_config",
+  ]
+
+  public_configs = [ ":libANGLE_config" ]
+
+  if (is_win) {
+    data_deps = [
+      ":copy_compiler_dll",
+    ]
+  }
+}
+
+config("shared_library_public_config") {
+  if (is_mac && !is_component_build) {
+    # Executable targets that depend on the shared libraries below need to have
+    # the rpath setup in non-component build configurations.
+    ldflags = [
+      "-rpath",
+      "@executable_path/",
+    ]
+  }
+}
+
+# This config controls export definitions on ANGLE API calls.
+config("angle_static") {
+  defines = [
+    "ANGLE_EXPORT=",
+    "EGLAPI=",
+    "GL_APICALL=",
+  ]
+}
+
+shared_library("libGLESv2") {
+  sources = rebase_path(gles_gypi.libglesv2_sources, ".", "src")
+
+  if (is_android) {
+    configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
+  }
+
+  if (is_win) {
+    ldflags =
+        [ "/DEF:" + rebase_path("src/libGLESv2/libGLESv2.def", root_build_dir) ]
+  }
+
+  if (is_mac && !is_component_build) {
+    ldflags = [
+      "-install_name",
+      "@rpath/${target_name}.dylib",
+    ]
+    public_configs = [ ":shared_library_public_config" ]
+  }
+
+  configs -= angle_undefine_configs
+  configs += [
+    ":commit_id_config",
+    ":debug_annotations_config",
+    ":internal_config",
+  ]
+
+  defines = [ "LIBGLESV2_IMPLEMENTATION" ]
+  if (is_win) {
+    defines += [ "GL_APICALL=" ]
+  } else {
+    defines += [ "GL_APICALL=__attribute__((visibility(\"default\")))" ]
+  }
+
+  deps = [
+    ":includes",
+    ":libANGLE",
+  ]
+}
+
+static_library("libGLESv2_static") {
+  sources = rebase_path(gles_gypi.libglesv2_sources, ".", "src")
+
+  configs -= angle_undefine_configs
+  configs += [
+    ":commit_id_config",
+    ":debug_annotations_config",
+    ":internal_config",
+  ]
+
+  public_configs = [ ":angle_static" ]
+
+  deps = [
+    ":includes",
+    ":libANGLE",
+  ]
+}
+
+shared_library("libEGL") {
+  sources = rebase_path(gles_gypi.libegl_sources, ".", "src")
+
+  if (is_android) {
+    configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
+  }
+  configs -= angle_undefine_configs
+  configs += [
+    ":commit_id_config",
+    ":debug_annotations_config",
+    ":extra_warnings",
+    ":internal_config",
+  ]
+
+  defines = [ "LIBEGL_IMPLEMENTATION" ]
+  if (is_win) {
+    defines += [ "EGLAPI=" ]
+  } else {
+    defines += [ "EGLAPI=__attribute__((visibility(\"default\")))" ]
+  }
+
+  if (is_win) {
+    ldflags = [ "/DEF:" + rebase_path("src/libEGL/libEGL.def", root_build_dir) ]
+  }
+
+  if (is_mac && !is_component_build) {
+    ldflags = [
+      "-install_name",
+      "@rpath/${target_name}.dylib",
+    ]
+    public_configs = [ ":shared_library_public_config" ]
+  }
+
+  deps = [
+    ":includes",
+    ":libGLESv2",
+  ]
+}
+
+static_library("libEGL_static") {
+  sources = rebase_path(gles_gypi.libegl_sources, ".", "src")
+
+  configs -= angle_undefine_configs
+  configs += [
+    ":commit_id_config",
+    ":debug_annotations_config",
+    ":extra_warnings",
+    ":internal_config",
+  ]
+
+  public_configs = [ ":angle_static" ]
+
+  deps = [
+    ":includes",
+    ":libGLESv2_static",
+  ]
+}
+
+util_gypi = exec_script("//build/gypi_to_gn.py",
+                        [ rebase_path("util/util.gyp") ],
+                        "scope",
+                        [ "util/util.gyp" ])
+
+config("angle_util_config") {
+  include_dirs = [ "util" ]
+  if (is_linux && use_x11) {
+    libs = [ "X11" ]
+  }
+}
+
+foreach(is_shared_library,
+        [
+          true,
+          false,
+        ]) {
+  if (is_shared_library) {
+    library_type = "shared_library"
+    library_name = "angle_util"
+    dep_suffix = ""
+  } else {
+    library_type = "static_library"
+    library_name = "angle_util_static"
+    dep_suffix = "_static"
+  }
+
+  target(library_type, library_name) {
+    sources = rebase_path(util_gypi.util_sources, ".", "util")
+
+    if (is_win) {
+      sources += rebase_path(util_gypi.util_win32_sources, ".", "util")
+    }
+
+    if (is_linux) {
+      sources += rebase_path(util_gypi.util_linux_sources, ".", "util")
+      libs = [
+        "rt",
+        "dl",
+      ]
+    }
+
+    if (is_mac) {
+      sources += rebase_path(util_gypi.util_osx_sources, ".", "util")
+      libs = [
+        "AppKit.framework",
+        "QuartzCore.framework",
+      ]
+    }
+
+    if (use_x11) {
+      sources += rebase_path(util_gypi.util_x11_sources, ".", "util")
+    }
+
+    if (is_android) {
+      if (is_shared_library) {
+        configs -= [ "//build/config/android:hide_all_but_jni_onload" ]
+      }
+
+      # To prevent linux sources filtering on android
+      set_sources_assignment_filter([])
+      sources += rebase_path(util_gypi.util_linux_sources, ".", "util")
+      sources += rebase_path(util_gypi.util_android_sources, ".", "util")
+      libs = [
+        "android",
+        "log",
+      ]
+    }
+
+    if (use_ozone) {
+      sources += rebase_path(util_gypi.util_ozone_sources, ".", "util")
+    }
+
+    configs += [
+      ":debug_annotations_config",
+      ":extra_warnings",
+    ]
+
+    public_configs = [
+      ":angle_util_config",
+      ":internal_config",
+    ]
+
+    deps = [
+      ":angle_common",
+      ":libEGL${dep_suffix}",
+      ":libGLESv2${dep_suffix}",
+    ]
+
+    if (is_shared_library) {
+      defines = [ "LIBANGLE_UTIL_IMPLEMENTATION" ]
+
+      if (is_mac && !is_component_build) {
+        ldflags = [
+          "-install_name",
+          "@rpath/lib${target_name}.dylib",
+        ]
+        public_configs += [ ":shared_library_public_config" ]
+      }
+    }
+  }
+}
diff --git a/src/third_party/angle/CONTRIBUTORS b/src/third_party/angle/CONTRIBUTORS
index 00ebe7c..3692682 100644
--- a/src/third_party/angle/CONTRIBUTORS
+++ b/src/third_party/angle/CONTRIBUTORS
@@ -1,76 +1,124 @@
-# This is the official list of people who can contribute

-# (and who have contributed) code to the ANGLE project

-# repository.

-# The AUTHORS file lists the copyright holders; this file

-# lists people.  For example, Google employees are listed here

-# but not in AUTHORS, because Google holds the copyright.

-#

-

-TransGaming Inc.

- Nicolas Capens

- Daniel Koch

- Geoff Lang

- Andrew Lewycky

- Jamie Madill

- Gavriel State

- Shannon Woods

-

-Google Inc.

- Brent Austin

- Michael Bai

- John Bauman

- Peter Beverloo

- Steve Block

- Rachel Blum

- Eric Boren

- Henry Bridge

- Nat Duca

- Peter Kasting

- Vangelis Kokkevis

- Zhenyao Mo

- Daniel Nicoara

- Alastair Patrick

- Alok Priyadarshi

- Kenneth Russell

- Brian Salomon

- Gregg Tavares

- Jeff Timanus

- Ben Vanik

- Adrienne Walker

- thestig@chromium.org

- Justin Schuh

-

-Adobe Systems Inc.

- Alexandru Chiculita

- Steve Minns

- Max Vujovic

-

-Autodesk, Inc.

- Ranger Harke

-

-Cloud Party, Inc.

- Conor Dickinson

-

-Intel Corporation

- Jin Yang

- Andy Chen

- Josh Triplett

-

-Klarälvdalens Datakonsult AB

- Milian Wolff

-

-Mozilla Corp.

- Ehsan Akhgari

- Jeff Gilbert

- Mike Hommey

- Benoit Jacob

- Makoto Kato

- Vladimir Vukicevic

-

-Turbulenz

- Michael Braithwaite

-

-Ulrik Persson (ddefrostt)

-Mark Banner (standard8mbp)

-David Kilzer

-

+# This is the official list of people who can contribute
+# (and who have contributed) code to the ANGLE project
+# repository.
+# The AUTHORS file lists the copyright holders; this file
+# lists people.  For example, Google employees are listed here
+# but not in AUTHORS, because Google holds the copyright.
+#
+
+TransGaming Inc.
+ Nicolas Capens
+ Daniel Koch
+ Geoff Lang
+ Andrew Lewycky
+ Jamie Madill
+ Gavriel State
+ Shannon Woods
+
+Google Inc.
+ Brent Austin
+ Michael Bai
+ John Bauman
+ Peter Beverloo
+ Steve Block
+ Rachel Blum
+ Eric Boren
+ Henry Bridge
+ Nat Duca
+ Peter Kasting
+ Vangelis Kokkevis
+ Zhenyao Mo
+ Daniel Nicoara
+ Alastair Patrick
+ Alok Priyadarshi
+ Kenneth Russell
+ Brian Salomon
+ Gregg Tavares
+ Jeff Timanus
+ Ben Vanik
+ Adrienne Walker
+ thestig@chromium.org
+ Justin Schuh
+ Scott Graham
+ Corentin Wallez
+
+Adobe Systems Inc.
+ Alexandru Chiculita
+ Steve Minns
+ Max Vujovic
+
+Autodesk, Inc.
+ Ranger Harke
+
+Cloud Party, Inc.
+ Conor Dickinson
+
+The Qt Company Ltd.
+ Andrew Knight
+
+Imagination Technologies Ltd.
+ Gregoire Payen de La Garanderie
+
+Intel Corporation
+ Jin Yang
+ Andy Chen
+ Josh Triplett
+ Sudarsana Nagineni
+ Jiajia Qin
+ Jiawei Shao
+ Jie Chen
+ Qiankun Miao
+ Bryan Bernhart
+ Yunchao He
+ Xinghua Cao
+
+Klarälvdalens Datakonsult AB
+ Milian Wolff
+
+Mozilla Corp.
+ Ehsan Akhgari
+ Edwin Flores
+ Jeff Gilbert
+ Mike Hommey
+ Benoit Jacob
+ Makoto Kato
+ Vladimir Vukicevic
+
+Turbulenz
+ Michael Braithwaite
+
+Ulrik Persson (ddefrostt)
+Mark Banner (standard8mbp)
+David Kilzer
+Jacek Caban
+Tibor den Ouden
+Régis Fénéon
+Sebastian Bergstein
+James Ross-Gowan
+Andrei Volykhin
+
+Microsoft Corporation
+ Cooper Partin
+ Austin Kinross
+ Minmin Gong
+ Shawn Hargreaves
+
+Microsoft Open Technologies, Inc.
+ Cooper Partin
+ Austin Kinross
+
+NVIDIA Corporation
+ Olli Etuaho
+ Arun Patole
+ Qingqing Deng
+ Kimmo Kinnunen
+ Sami Väisänen
+ Martin Radev
+
+Opera Software ASA
+ Daniel Bratell
+ Tomasz Moniuszko
+ David Landell
+
+Advanced Micro Devices, Inc.
+ Russ Lind
diff --git a/src/third_party/angle/DEPS.chromium b/src/third_party/angle/DEPS.chromium
new file mode 100644
index 0000000..5678485
--- /dev/null
+++ b/src/third_party/angle/DEPS.chromium
@@ -0,0 +1,64 @@
+# This file is used to manage the ANGLE's dependencies in the Chromium src repo. It is
+# used by gclient to determine what version of each dependency to check out, and
+# where.
+#
+# These deps are duplicated in ANGLE's DEPS file which we use for the standalone
+# build. The dual file setup is necessary because Chromium can only recurse into
+# a single file and we do not want to import all of ANGLE's standalone DEPS.
+#
+# If you make a change to one of these dependencies please also update the
+# standalone DEPS file.
+
+vars = {
+  'android_git': 'https://android.googlesource.com',
+
+  # Current revision of dEQP.
+  'deqp_revision': '455d82c60b096e7bd83b6a2f5ed70c61e4bfa759',
+
+  # Current revision of glslang, the Khronos SPIRV compiler.
+  'glslang_revision': '1e275c8486325aaab34734ad9a650c0121c5efdb',
+
+  # Current revision fo the SPIRV-Headers Vulkan support library.
+  'spirv_headers_revision': 'c470b68225a04965bf87d35e143ae92f831e8110',
+
+  # Current revision of SPIRV-Tools for Vulkan.
+  'spirv_tools_revision': '68c5f0436f1d4f1f137e608780190865d0b193ca',
+
+  # Current revision of the Vulkan Validation Layers SDK.
+  'vulkan_revision': 'f47c534fee2f26f6b783209d56e0ade48e30eb8d',
+}
+
+deps_os = {
+  'win': {
+    'src/third_party/deqp/src':
+      Var('android_git') + '/platform/external/deqp@' + Var('deqp_revision'),
+
+    'src/third_party/glslang-angle/src':
+      Var('android_git') + '/platform/external/shaderc/glslang@' + Var('glslang_revision'),
+
+    'src/third_party/spirv-headers/src':
+      Var('android_git') + '/platform/external/shaderc/spirv-headers@' + Var('spirv_headers_revision'),
+
+    'src/third_party/spirv-tools-angle/src':
+      Var('android_git') + '/platform/external/shaderc/spirv-tools@' + Var('spirv_tools_revision'),
+
+    'src/third_party/vulkan-validation-layers/src':
+      Var('android_git') + '/platform/external/vulkan-validation-layers@' + Var('vulkan_revision'),
+  },
+  'unix': {
+    'src/third_party/deqp/src':
+      Var('android_git') + '/platform/external/deqp@' + Var('deqp_revision'),
+
+    'src/third_party/glslang-angle/src':
+      Var('android_git') + '/platform/external/shaderc/glslang@' + Var('glslang_revision'),
+
+    'src/third_party/spirv-headers/src':
+      Var('android_git') + '/platform/external/shaderc/spirv-headers@' + Var('spirv_headers_revision'),
+
+    'src/third_party/spirv-tools-angle/src':
+      Var('android_git') + '/platform/external/shaderc/spirv-tools@' + Var('spirv_tools_revision'),
+
+    'src/third_party/vulkan-validation-layers/src':
+      Var('android_git') + '/platform/external/vulkan-validation-layers@' + Var('vulkan_revision'),
+  },
+}
diff --git a/src/third_party/angle/README.md b/src/third_party/angle/README.md
new file mode 100644
index 0000000..91a4744
--- /dev/null
+++ b/src/third_party/angle/README.md
@@ -0,0 +1,75 @@
+# ANGLE - Almost Native Graphics Layer Engine
+
+The goal of ANGLE is to allow users of multiple operating systems to seamlessly run WebGL and other
+OpenGL ES content by translating OpenGL ES API calls to one of the hardware-supported APIs available
+for that platform. ANGLE currently provides translation from OpenGL ES 2.0 and 3.0 to desktop
+OpenGL, OpenGL ES, Direct3D 9, and Direct3D 11. Support for translation from OpenGL ES to Vulkan is
+underway, and future plans include compute shader support (ES 3.1) and MacOS support.
+
+### Level of OpenGL ES support via backing renderers
+
+|                |  Direct3D 9   |  Direct3D 11     |   Desktop GL   |    GL ES      |    Vulkan     |
+|----------------|:-------------:|:----------------:|:--------------:|:-------------:|:-------------:|
+| OpenGL ES 2.0  |    complete   |    complete      |    complete    |   complete    |  in progress  |
+| OpenGL ES 3.0  |               |    complete      |    complete    |  in progress  |  not started  |
+| OpenGL ES 3.1  |               |   not started    |   in progress  |  in progress  |  not started  |
+
+### Platform support via backing renderers
+
+|             |    Direct3D 9  |   Direct3D 11  |   Desktop GL  |    GL ES    |   Vulkan    |
+|------------:|:--------------:|:--------------:|:-------------:|:-----------:|:-----------:|
+| Windows     |    complete    |    complete    |   complete    |   complete  | in progress |
+| Linux       |                |                |   complete    |             |   planned   |
+| Mac OS X    |                |                |   in progress |             |             |
+| Chrome OS   |                |                |               |   complete  |   planned   |
+| Android     |                |                |               |   complete  |   planned   |
+
+ANGLE v1.0.772 was certified compliant by passing the ES 2.0.3 conformance tests in October 2011.
+ANGLE also provides an implementation of the EGL 1.4 specification.
+
+ANGLE is used as the default WebGL backend for both Google Chrome and Mozilla Firefox on Windows
+platforms. Chrome uses ANGLE for all graphics rendering on Windows, including the accelerated
+Canvas2D implementation and the Native Client sandbox environment.
+
+Portions of the ANGLE shader compiler are used as a shader validator and translator by WebGL
+implementations across multiple platforms. It is used on Mac OS X, Linux, and in mobile variants of
+the browsers. Having one shader validator helps to ensure that a consistent set of GLSL ES shaders
+are accepted across browsers and platforms. The shader translator can be used to translate shaders
+to other shading languages, and to optionally apply shader modifications to work around bugs or
+quirks in the native graphics drivers. The translator targets Desktop GLSL, Direct3D HLSL, and even
+ESSL for native GLES2 platforms.
+
+## Sources
+
+ANGLE repository is hosted by Chromium project and can be
+[browsed online](https://chromium.googlesource.com/angle/angle) or cloned with
+
+    git clone https://chromium.googlesource.com/angle/angle
+
+
+## Building
+
+View the [Dev setup instructions](doc/DevSetup.md). For generating a Windows Store version of ANGLE view the [Windows Store instructions](doc/BuildingAngleForWindowsStore.md)
+
+## Contributing
+
+* Join our [Google group](https://groups.google.com/group/angleproject) to keep up to date.
+* Join us on IRC in the #ANGLEproject channel on FreeNode.
+* File bugs in the [issue tracker](http://code.google.com/p/angleproject/issues/list) (preferably with an isolated test-case).
+* [Choose an ANGLE branch](doc/ChoosingANGLEBranch.md) to track in your own project.
+
+
+* Read ANGLE development [documentation](doc).
+* Look at [pending](https://chromium-review.googlesource.com/#/q/project:angle/angle+status:open)
+  and [merged](https://chromium-review.googlesource.com/#/q/project:angle/angle+status:merged) changes.
+* Become a [code contributor](doc/ContributingCode.md).
+* Use ANGLE's [coding standard](doc/CodingStandard.md).
+* Learn how to [build ANGLE for Chromium development](doc/BuildingAngleForChromiumDevelopment.md).
+* Get help on [debugging ANGLE](doc/DebuggingTips.md).
+
+
+* Read about WebGL on the [Khronos WebGL Wiki](http://khronos.org/webgl/wiki/Main_Page).
+* Learn about implementation details in the [OpenGL Insights chapter on ANGLE](http://www.seas.upenn.edu/~pcozzi/OpenGLInsights/OpenGLInsights-ANGLE.pdf) and this [ANGLE presentation](https://drive.google.com/file/d/0Bw29oYeC09QbbHoxNE5EUFh0RGs/view?usp=sharing).
+* Learn about the past, present, and future of the ANGLE implementation in [this recent presentation](https://docs.google.com/presentation/d/1CucIsdGVDmdTWRUbg68IxLE5jXwCb2y1E9YVhQo0thg/pub?start=false&loop=false).
+* If you use ANGLE in your own project, we'd love to hear about it!
+
diff --git a/src/third_party/angle/angle.gyp b/src/third_party/angle/angle.gyp
new file mode 100644
index 0000000..3aea864
--- /dev/null
+++ b/src/third_party/angle/angle.gyp
@@ -0,0 +1,390 @@
+# Copyright (c) 2012 The ANGLE Project Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+    'variables':
+    {
+        'angle_code': 1,
+        'angle_gen_path': '<(SHARED_INTERMEDIATE_DIR)/angle',
+        'angle_use_commit_id%': 0,
+        'angle_enable_d3d9%': 0,
+        'angle_enable_d3d11%': 0,
+        'angle_enable_gl%': 0,
+        'angle_enable_vulkan%': 0,
+        'angle_enable_essl%': 1, # Enable this for all configs by default
+        'angle_enable_glsl%': 1, # Enable this for all configs by default
+        'angle_enable_hlsl%': 0,
+        'angle_link_glx%': 0,
+        'angle_gl_library_type%': 'static_library',
+        'dcheck_always_on%': 0,
+        'conditions':
+        [
+            ['OS=="win"',
+            {
+                'angle_enable_gl%': 1,
+                'angle_enable_d3d9%': 1,
+                'angle_enable_d3d11%': 1,
+                'angle_enable_hlsl%': 1,
+                'angle_enable_vulkan%': 1,
+            }],
+            ['OS=="linux" and use_x11==1 and chromeos==0',
+            {
+                'angle_enable_gl%': 1,
+                'angle_enable_vulkan%': 1,
+            }],
+            ['OS=="mac"',
+            {
+                'angle_enable_gl%': 1,
+            }],
+        ],
+        'angle_enable_null%': 1, # Available on all platforms
+    },
+    'includes':
+    [
+        './src/compiler.gypi',
+        './src/libGLESv2.gypi',
+        './src/libEGL.gypi',
+        './src/vulkan_support/vulkan.gypi',
+    ],
+
+    'targets':
+    [
+        {
+            'target_name': 'angle_common',
+            'type': 'static_library',
+            'includes': [ './gyp/common_defines.gypi', ],
+            'sources':
+            [
+                '<@(libangle_common_sources)',
+            ],
+            'include_dirs':
+            [
+                './include',
+                './src',
+                './src/common/third_party/numerics',
+            ],
+            'direct_dependent_settings':
+            {
+                'include_dirs':
+                [
+                    '<(DEPTH)/third_party/angle/include',
+                    '<(DEPTH)/third_party/angle/src',
+                    '<(DEPTH)/third_party/angle/src/common/third_party/numerics',
+                ],
+                'conditions':
+                [
+                    ['dcheck_always_on==1',
+                    {
+                        'configurations':
+                        {
+                            'Release_Base':
+                            {
+                                'defines':
+                                [
+                                    'ANGLE_ENABLE_RELEASE_ASSERTS',
+                                ],
+                            },
+                        },
+                    }],
+                    ['OS=="win"',
+                    {
+                        'configurations':
+                        {
+                            'Debug_Base':
+                            {
+                                'defines':
+                                [
+                                    'ANGLE_ENABLE_DEBUG_ANNOTATIONS'
+                                ],
+                            },
+                        },
+                    }],
+                ],
+            },
+            'conditions':
+            [
+                ['dcheck_always_on==1',
+                {
+                    'configurations':
+                    {
+                        'Release_Base':
+                        {
+                            'defines':
+                            [
+                                'ANGLE_ENABLE_RELEASE_ASSERTS',
+                            ],
+                        },
+                    },
+                }],
+                ['OS=="win"',
+                {
+                    'configurations':
+                    {
+                        'Debug_Base':
+                        {
+                            'defines':
+                            [
+                                'ANGLE_ENABLE_DEBUG_ANNOTATIONS'
+                            ],
+                        },
+                    },
+                    'sources':
+                    [
+                        '<@(libangle_common_win_sources)',
+                    ],
+                }],
+                ['OS=="mac"',
+                {
+                    'sources':
+                    [
+                        '<@(libangle_common_mac_sources)',
+                    ],
+                    'link_settings':
+                    {
+                        'libraries':
+                        [
+                            '$(SDKROOT)/System/Library/Frameworks/IOKit.framework',
+                            '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+                        ],
+                    },
+                }],
+                ['OS=="linux"',
+                {
+                    'sources':
+                    [
+                        '<@(libangle_common_linux_sources)',
+                    ],
+                }]
+            ],
+        },
+
+        {
+            'target_name': 'angle_image_util',
+            'type': 'static_library',
+            'includes': [ './gyp/common_defines.gypi', ],
+            'sources':
+            [
+                '<@(libangle_image_util_sources)',
+            ],
+            'include_dirs':
+            [
+                './include',
+                './src',
+            ],
+            'dependencies':
+            [
+                'angle_common',
+            ],
+            'direct_dependent_settings':
+            {
+                'include_dirs':
+                [
+                    '<(DEPTH)/third_party/angle/include',
+                    '<(DEPTH)/third_party/angle/src',
+                ],
+            },
+        },
+
+        {
+            'target_name': 'angle_gpu_info_util',
+            'type': 'static_library',
+            'includes': [ './gyp/common_defines.gypi', ],
+            'sources':
+            [
+                '<@(libangle_gpu_info_util_sources)',
+            ],
+            'include_dirs':
+            [
+                './include',
+                './src',
+            ],
+            'dependencies':
+            [
+                'angle_common',
+            ],
+            'direct_dependent_settings':
+            {
+                'include_dirs':
+                [
+                    '<(DEPTH)/third_party/angle/include',
+                    '<(DEPTH)/third_party/angle/src',
+                ],
+            },
+            'conditions':
+            [
+                ['OS=="win"',
+                {
+                    'sources':
+                    [
+                        '<@(libangle_gpu_info_util_win_sources)',
+                    ],
+                }],
+                ['OS=="win" and angle_build_winrt==0',
+                {
+                    'link_settings':
+                    {
+                        'msvs_settings':
+                        {
+                            'VCLinkerTool':
+                            {
+                                'AdditionalDependencies':
+                                [
+                                    'setupapi.lib'
+                                ]
+                            }
+                        }
+                    },
+                    'defines':
+                    [
+                        'GPU_INFO_USE_SETUPAPI',
+                    ],
+                },
+                {
+                    'link_settings':
+                    {
+                        'msvs_settings':
+                        {
+                            'VCLinkerTool':
+                            {
+                                'AdditionalDependencies':
+                                [
+                                    'dxgi.lib'
+                                ]
+                            }
+                        }
+                    },
+                    'defines':
+                    [
+                        'GPU_INFO_USE_DXGI',
+                    ],
+                }],
+                ['OS=="linux"',
+                {
+                    'sources':
+                    [
+                        '<@(libangle_gpu_info_util_linux_sources)',
+                    ],
+                }],
+                ['OS=="linux" and use_x11==1',
+                {
+                    'sources':
+                    [
+                        '<@(libangle_gpu_info_util_x11_sources)',
+                    ],
+                    'defines':
+                    [
+                        'GPU_INFO_USE_X11',
+                    ],
+                    'dependencies':
+                    [
+                        '<(DEPTH)/third_party/angle/src/third_party/libXNVCtrl/libXNVCtrl.gyp:libXNVCtrl',
+                    ],
+                    'link_settings':
+                    {
+                        'ldflags':
+                        [
+                            '<!@(<(pkg-config) --libs-only-L --libs-only-other x11 xi xext)',
+                        ],
+                        'libraries':
+                        [
+                            '<!@(<(pkg-config) --libs-only-l x11 xi xext) -ldl',
+                        ],
+                    },
+                }],
+                ['OS=="linux" and use_libpci==1',
+                {
+                    'sources':
+                    [
+                        '<@(libangle_gpu_info_util_libpci_sources)',
+                    ],
+                    'defines':
+                    [
+                        'GPU_INFO_USE_LIBPCI',
+                    ],
+                    'link_settings':
+                    {
+                        'ldflags':
+                        [
+                            '<!@(<(pkg-config) --libs-only-L --libs-only-other libpci)',
+                        ],
+                        'libraries':
+                        [
+                            '<!@(<(pkg-config) --libs-only-l libpci)',
+                        ],
+                    },
+                }],
+                ['OS=="mac"',
+                {
+                    'sources':
+                    [
+                        '<@(libangle_gpu_info_util_mac_sources)',
+                    ],
+                }],
+            ],
+        },
+
+        {
+            'target_name': 'copy_scripts',
+            'type': 'none',
+            'includes': [ './gyp/common_defines.gypi', ],
+            'hard_dependency': 1,
+            'copies':
+            [
+                {
+                    'destination': '<(angle_gen_path)',
+                    'files': [ 'copy_compiler_dll.bat' ],
+                },
+            ],
+            'conditions':
+            [
+                ['angle_build_winrt==1',
+                {
+                    'type' : 'shared_library',
+                }],
+            ],
+        },
+    ],
+    'conditions':
+    [
+        ['OS=="win"',
+        {
+            'targets':
+            [
+                {
+                    'target_name': 'copy_compiler_dll',
+                    'type': 'none',
+                    'dependencies': [ 'copy_scripts', ],
+                    'includes': [ './gyp/common_defines.gypi', ],
+                    'conditions':
+                    [
+                        ['angle_build_winrt==0',
+                        {
+                            'actions':
+                            [
+                                {
+                                    'action_name': 'copy_dll',
+                                    'message': 'Copying D3D Compiler DLL...',
+                                    'msvs_cygwin_shell': 0,
+                                    'inputs': [ 'copy_compiler_dll.bat' ],
+                                    'outputs': [ '<(PRODUCT_DIR)/d3dcompiler_47.dll' ],
+                                    'action':
+                                    [
+                                        "<(angle_gen_path)/copy_compiler_dll.bat",
+                                        "$(PlatformName)",
+                                        "<(windows_sdk_path)",
+                                        "<(PRODUCT_DIR)"
+                                    ],
+                                },
+                            ], #actions
+                        }],
+                        ['angle_build_winrt==1',
+                        {
+                            'type' : 'shared_library',
+                        }],
+                    ]
+                },
+            ], # targets
+        }],
+    ] # conditions
+}
diff --git a/src/third_party/angle/build/all.gyp b/src/third_party/angle/build/all.gyp
deleted file mode 100644
index fff9998..0000000
--- a/src/third_party/angle/build/all.gyp
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'targets': [
-    {
-      'target_name': 'all',
-      'type': 'none',
-      'dependencies': [
-        # TODO(alokp): build_ prefix should be removed from the gyp files
-        # as soon as we can get rid of manually-maintained sln files.
-        # Otherwise auto-generated sln files will overwrite/conflict the
-        # manually maintained ones.
-        '../samples/build_samples.gyp:*',
-        '../src/build_angle.gyp:*',
-        '../tests/build_tests.gyp:*',
-      ],
-    },
-  ],
-}
-
-# Local Variables:
-# tab-width:2
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/src/third_party/angle/build/common.gypi b/src/third_party/angle/build/common.gypi
deleted file mode 100644
index fc9f295..0000000
--- a/src/third_party/angle/build/common.gypi
+++ /dev/null
@@ -1,190 +0,0 @@
-# Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'variables': {
-    'component%': 'static_library',
-    # angle_code is set to 1 for the core ANGLE targets defined in src/build_angle.gyp.
-    # angle_code is set to 0 for test code, sample code, and third party code.
-    # When angle_code is 1, we build with additional warning flags on Mac and Linux.
-    'angle_code%': 0,
-    'gcc_or_clang_warnings': [
-      '-Wall',
-      '-Wchar-subscripts',
-      '-Werror',
-      '-Wextra',
-      '-Wformat=2',
-      '-Winit-self',
-      '-Wno-sign-compare',
-      '-Wno-unused-function',
-      '-Wno-unused-parameter',
-      '-Wno-unknown-pragmas',
-      '-Wpacked',
-      '-Wpointer-arith',
-      '-Wundef',
-      '-Wwrite-strings',
-    ],
-  },
-  'target_defaults': {
-    'default_configuration': 'Debug',
-    'variables': {
-      'warn_as_error%': 1,
-    },
-    'target_conditions': [
-      ['warn_as_error == 1', {
-        'msvs_settings': {
-          'VCCLCompilerTool': {
-            'WarnAsError': 'true',
-          },
-        },
-      }],
-    ],
-    'configurations': {
-      'Common': {
-        'abstract': 1,
-        'msvs_configuration_attributes': {
-          'OutputDirectory': '$(SolutionDir)$(ConfigurationName)',
-          'IntermediateDirectory': '$(OutDir)\\obj\\$(ProjectName)',
-          'CharacterSet': '1',  # UNICODE
-        },
-        'msvs_configuration_platform': 'Win32',
-        'msvs_settings': {
-          'VCCLCompilerTool': {
-            'BufferSecurityCheck': 'true',
-            'DebugInformationFormat': '3',
-            # TODO(alokp): Disable exceptions before integrating with chromium.
-            #'ExceptionHandling': '0',
-            'EnableFunctionLevelLinking': 'true',
-            'MinimalRebuild': 'false',
-            'PreprocessorDefinitions': [
-              '_CRT_SECURE_NO_DEPRECATE',
-              '_HAS_EXCEPTIONS=0',
-              '_WIN32_WINNT=0x0600',
-              '_WINDOWS',
-              'NOMINMAX',
-              'WIN32',
-              'WIN32_LEAN_AND_MEAN',
-              'WINVER=0x0600',
-            ],
-            'RuntimeTypeInfo': 'false',
-            'WarningLevel': '4',
-            'DisableSpecificWarnings': [4100, 4127, 4189, 4239, 4244, 4245, 4512, 4702],
-          },
-          'VCLinkerTool': {
-            'FixedBaseAddress': '1',
-            'GenerateDebugInformation': 'true',
-            'ImportLibrary': '$(OutDir)\\lib\\$(TargetName).lib',
-            'MapFileName': '$(OutDir)\\$(TargetName).map',
-            # Most of the executables we'll ever create are tests
-            # and utilities with console output.
-            'SubSystem': '1',  # /SUBSYSTEM:CONSOLE
-            'AdditionalLibraryDirectories': [
-              '$(ProgramFiles)/Windows Kits/8.0/Lib/win8/um/x86',
-            ],
-          },
-          'VCLibrarianTool': {
-            'AdditionalLibraryDirectories': [
-              '$(ProgramFiles)/Windows Kits/8.0/Lib/win8/um/x86',
-            ],
-          },
-          'VCResourceCompilerTool': {
-            'Culture': '1033',
-          },
-        },
-        'msvs_system_include_dirs': [
-          '$(ProgramFiles)/Windows Kits/8.0/Include/shared',
-          '$(ProgramFiles)/Windows Kits/8.0/Include/um',
-        ],
-      },  # Common
-      'Debug': {
-        'inherit_from': ['Common'],
-        'msvs_settings': {
-          'VCCLCompilerTool': {
-            'Optimization': '0',  # /Od
-            'PreprocessorDefinitions': ['_DEBUG'],
-            'BasicRuntimeChecks': '3',
-            'RuntimeLibrary': '1',  # /MTd (debug static)
-          },
-          'VCLinkerTool': {
-            'LinkIncremental': '2',
-          },
-        },
-        'xcode_settings': {
-          'COPY_PHASE_STRIP': 'NO',
-          'GCC_OPTIMIZATION_LEVEL': '0',
-        },
-      },  # Debug
-      'Release': {
-        'inherit_from': ['Common'],
-        'msvs_settings': {
-          'VCCLCompilerTool': {
-            'Optimization': '2',  # /Os
-            'PreprocessorDefinitions': ['NDEBUG'],
-            'RuntimeLibrary': '0',  # /MT (static)
-          },
-          'VCLinkerTool': {
-            'LinkIncremental': '1',
-          },
-        },
-      },  # Release
-    },  # configurations
-    'conditions': [
-      ['component=="shared_library"', {
-        'defines': ['COMPONENT_BUILD'],
-      }],
-    ],
-  },  # target_defaults
-  'conditions': [
-    ['OS=="win"', {
-      'target_defaults': {
-        'msvs_cygwin_dirs': ['../third_party/cygwin'],
-      },
-    }],
-    ['OS!="win" and OS!="mac"', {
-      'target_defaults': {
-        'cflags': [
-          '-pthread',
-          '-fno-exceptions',
-        ],
-        'ldflags': [
-          '-pthread',
-        ],
-        'configurations': {
-          'Debug': {
-            'variables': {
-              'debug_optimize%': '0',
-            },
-            'defines': [
-              '_DEBUG',
-            ],
-            'cflags': [
-              '-O>(debug_optimize)',
-              '-g',
-            ],
-          }
-        },
-      },
-    }],
-    ['angle_code==1', {
-      'target_defaults': {
-        'conditions': [
-          ['OS=="mac"', {
-            'xcode_settings': {
-              'WARNING_CFLAGS': ['<@(gcc_or_clang_warnings)']
-            },
-          }],
-          ['OS!="win" and OS!="mac"', {
-            'cflags': ['<@(gcc_or_clang_warnings)']
-          }],
-        ]
-      }
-    }],
-  ],
-}
-
-# Local Variables:
-# tab-width:2
-# indent-tabs-mode:nil
-# End:
-# vim: set expandtab tabstop=2 shiftwidth=2:
diff --git a/src/third_party/angle/build/gyp_angle b/src/third_party/angle/build/gyp_angle
deleted file mode 100644
index 2aa38a5..0000000
--- a/src/third_party/angle/build/gyp_angle
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/python
-
-# Copyright (c) 2010 The ANGLE Project Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This script is wrapper for ANGLE that adds some support for how GYP
-# is invoked by ANGLE beyond what can be done in the gclient hooks.
-
-import os
-import sys
-
-script_dir = os.path.dirname(__file__)
-angle_dir = os.path.normpath(os.path.join(script_dir, os.pardir))
-
-sys.path.append(os.path.join(angle_dir, 'third_party', 'gyp', 'pylib'))
-import gyp
-
-if __name__ == '__main__':
-  args = sys.argv[1:]
-
-  print 'Updating projects from gyp files...'
-  sys.stdout.flush()
-
-  # Set the depth to get the top-level Makefile generated into the
-  # correct directory. This only has an effect on Linux.
-  args.append('--depth');
-  args.append('./trunk');
-  # Add common.gypi to the include path.
-  args.append('-I' + os.path.join(script_dir, 'common.gypi'))
-  # Add all.gyp as the main gyp file to be generated.
-  args.append(os.path.join(script_dir, 'all.gyp'))
-  sys.exit(gyp.main(args))
diff --git a/src/third_party/angle/doc/64BitSafety.md b/src/third_party/angle/doc/64BitSafety.md
new file mode 100644
index 0000000..94ed064
--- /dev/null
+++ b/src/third_party/angle/doc/64BitSafety.md
@@ -0,0 +1,15 @@
+# 64-bit Safety In the Compiler
+
+An issue that has arisen recently for contributors making changes to the GLSL ES
+grammar files has been that certain versions of flex, the lexer on which ANGLE
+relies, produce outputs which are not safe in 64-bit builds.
+
+To address this issue, ANGLE has added a step to its generation scripts to apply
+64-bit safety fixes to newly regenerated outputs. This should be unnoticeable to
+developers invoking flex via the generate\_parser.sh scripts in the relevant
+compiler directories, as the fixes will be applied by the patch utility as part
+of that script.
+
+When making code contributions that affect the grammar files, please ensure that
+you've generated the outputs using the script, to make certain that the 64-bit
+safety fixes are applied.
diff --git a/src/third_party/angle/doc/BranchingAndRolling.md b/src/third_party/angle/doc/BranchingAndRolling.md
new file mode 100644
index 0000000..19e2abc
--- /dev/null
+++ b/src/third_party/angle/doc/BranchingAndRolling.md
@@ -0,0 +1,55 @@
+# How to Branch and Roll Chromium's ANGLE Dependency
+
+ANGLE provides an implementation of OpenGL ES on Windows, which Chromium relies
+upon for hardware accelerated rendering and WebGL support. Chromium specifies
+its dependency on a specific version of ANGLE in the repository; this document
+describes how to update that dependency, and, if necessary, create an ANGLE
+branch to correspond to a branched release of Chrome.
+
+## Rolling DEPS
+
+Chromium's dependency on third-party projects is tracked in [the Chromium
+repository's src/DEPS file]
+(http://src.chromium.org/viewvc/chrome/trunk/src/DEPS). To update the ANGLE
+dependency:
+
+ * Find the line in this file that defines "src/third\_party/angle"
+for deps (**not** deps\_os)
+ * Change the [git SHA-1 revision number]
+(http://git-scm.com/book/ch6-1.html) to be that of the commit on which Chromium
+should depend. Please use the full SHA-1, not a shortened version.
+ * You can
+find the SHA-1 for a particular commit with `git log` on the appropriate branch
+of the repository, or via [the public repository viewer]
+(https://chromium.googlesource.com/angle/angle).
+ * If using the public repository viewer, you will need to select the branch whose log you wish to view
+from the list on the left-hand side, and then click on the "tree" link at the
+top of the resulting page. Alternatively, you can navigate to
+`https://chromium.googlesource.com/angle/angle/+/<branch name>/` -- including
+the terminating forward slash. (e.g.
+`https://chromium.googlesource.com/angle/angle/+/master/`)
+
+## Branching ANGLE
+
+Sometimes, individual changes to ANGLE are needed for a release of Chrome which
+has already been branched. If this is the case, a branch of ANGLE should be
+created to correspond to the Chrome release version, so that Chrome may
+incorporate only these changes, and not everything that has been committed since
+the version on which Chrome depended at branch time. **Please note: Only ANGLE
+admins can create a new branch.** To create a branch of ANGLE for a branched
+Chrome release:
+
+ * Determine what the ANGLE dependency is for the Chrome release
+by checking the DEPS file for that branch.
+ * Check out this commit as a new branch in your local repository.
+    * e.g., for [the Chrome 34 release at chrome/branches/1847]
+(http://src.chromium.org/viewvc/chrome/branches/1847/src/DEPS), the ANGLE
+version is 4df02c1ed5e97dd54576b06964b1da67ea30238e. To check this commit out
+locally and create a new branch named 'mybranch' from this commit, use: ```git
+checkout -b mybranch 4df02c1ed5e97dd54576b06964b1da67ea30238e```
+ * To create this new branch in the public repository, you'll need to push the
+branch to the special Gerrit reference location, 'refs/heads/<branch name>'. You
+must be an ANGLE administrator to be able to push this new branch.
+    * e.g., to use your local 'mybranch' to create a branch in the public repository called
+'chrome\_m34', use: ```git push origin mybranch:refs/heads/chrome_m34```
+    * The naming convention that ANGLE uses for its release-dedicated branches is 'chrome\_m##'.
diff --git a/src/third_party/angle/doc/BufferImplementation.md b/src/third_party/angle/doc/BufferImplementation.md
new file mode 100644
index 0000000..99eaf00
--- /dev/null
+++ b/src/third_party/angle/doc/BufferImplementation.md
@@ -0,0 +1,122 @@
+# Introduction
+
+Since Direct3D 9 only supports buffers that either contain vertex or index data,
+and OpenGL buffers can contain both, ANGLE waits till a draw call is issued to
+determine which resources to create/update. The generic implementation 'streams'
+the data into global vertex and index buffers. This streaming buffer
+implementation works in all circumstances, but does not offer optimal
+performance. When buffer data isn't updated, there's no reason to copy the data
+again. For these cases a 'static' buffer implementation is used.
+
+The OpenGL ES 2.0 glBufferData() function allows to specify a usage hint
+parameter (GL\_STREAM\_DRAW, GL\_DYNAMIC\_DRAW or GL\_STATIC\_DRAW). Both
+GL\_STREAM\_DRAW and GL\_DYNAMIC\_DRAW use the streaming buffer implementation.
+With the GL\_STATIC\_DRAW hint, ANGLE will attempt to use the static buffer
+implementation. If you update the buffer data after it has already been used in
+a draw call, it falls back to the streaming buffer implementation, because
+updating static ones would involve creating new ones, which is slower than
+updating streaming ones (more on this later).
+
+Because some applications use GL\_STREAM\_DRAW or GL\_DYNAMIC\_DRAW even when
+the data is not or very infrequently updated, ANGLE also has a heuristic to
+promote buffers to use the static implementation.
+
+# Streaming buffers
+
+The streaming buffers implementation uses one Context-global vertex buffer
+(VertexDataManager::mStreamingBuffer) and two index buffers
+(IndexDataManager::mStreamingBufferShort and
+IndexDataManager::mStreamingBufferInt). The streaming behavior is achieved by
+writing new data behind previously written data (i.e. without overwriting old
+data). Direct3D 9 allows to efficiently update vertex and index buffers when
+you're not reading or overwriting anything (it won't stall waiting for the GPU
+finish using it).
+
+When the end of these streaming buffers is reached, they are 'recycled' by
+discarding their content. D3D9 will still keep a copy of the data that's in use,
+so this recycling efficiently renames the driver level buffers. ANGLE can then
+write new data to the beginning of the vertex or index buffer.
+
+The ArrayVertexBuffer::mWritePosition variable holds the current end position of
+the last data that was written. StreamingVertexBuffer::reserveRequiredSpace()
+allocates space to write the data, and StreamingVertexBuffer::map() actually
+locks the D3D buffer and updates the write position. Similar for index buffers.
+
+# Static buffers
+
+Each GL buffer object can have a corresponding static vertex or index buffer
+(Buffer::mVertexBuffer and Buffer::mIndexBuffer). When a GL buffer with static
+usage is used in a draw call for the first time, all of its data is converted to
+a D3D vertex or index buffer, based on the attribute or index formats
+respectively. If a subsequent draw call uses different formats, the static
+buffer is invalidated (deleted) and the streaming buffer implementation is used
+for this buffer object instead. So for optimal performance it's important to
+store only a single format of vertices or indices in a buffer. This is highly
+typical, and even when in some cases it falls back to the streaming buffer
+implementation the performance isn't bad at all.
+
+The StreamingVertexBuffer and StaticVertexBuffer classes share a common base
+class, ArrayVertexBuffer. StaticVertexBuffer also has access to the write
+position, but it's used only for the initial conversion of the data. So the
+interfaces of both classes are not that different. Static buffers have an exact
+size though, and can't be changed afterwards (streaming buffers can grow to
+handle draw calls which use more data, and avoid excessive recycling).
+StaticVertexBuffer has a lookupAttribute() method to retrieve the location of a
+certain attribute (this is also used to verify that the formats haven't changed,
+which would result in invalidating the static buffer). The descriptions of all
+the attribute formats a static buffer contains are stored in the
+StaticVertexBuffer::mCache vector.
+
+StaticIndexBuffer also caches information about what's stored in them, namely
+the minimum and maximum value for certain ranges of indices. This information is
+required by the Direct3D 9 draw calls, and is also used to know the range of
+vertices that need to be copied to the streaming vertex buffer in case it needs
+to be used (e.g. it is not uncommon to have a buffer with static vertex position
+data and a buffer with streaming texture coordinate data for skinning).
+
+# Constant attributes
+
+Aside from using array buffers to feed attribute data to the vertex shader,
+OpenGL also supports attributes which remain constant for all vertices used in a
+draw call. Direct3D 9 doesn't have a similar concept, at least not explicitly.
+
+Constant attributes are implemented using separate (static) vertex buffers,
+and uses a stride of 0 to ensure that every vertex retrieves the same data.
+Using a stride of 0 is not possible with streaming buffers because on some
+hardware it is incompatible with the D3DUSAGE\_DYNAMIC flag. We found that with
+static usage, all hardware tested so far can handle stride 0 fine.
+
+This functionality was implemented in a ConstantVertexBuffer class, and it
+integrates nicely with the rest of the static buffer implementation.
+
+# Line loops
+
+Direct3D 9 does not support the 'line loop' primitive type directly. This is
+implemented by drawing the 'closing' line segment separately, constructing a
+tiny temporary index buffer connecting the last and first vertex.
+
+# Putting it all together
+
+glDrawElements() calls IndexDataManager::prepareIndexData() to retrieve a
+Direct3D index buffer containing the necessary data. If an element array is used
+(i.e. a buffer object), it has static usage, and it hasn't been invalidated, the
+GL buffer's static D3D index buffer will be returned. Else the updated streaming
+index buffer is returned, as well as the index offset (write position) where the
+new data is located. When prepareIndexData() does find a static index buffer,
+but it's empty, it means the GL buffer's data hasn't been converted and stored
+in the D3D index buffer yet. So in the convertIndices() call it will convert the
+entire buffer. prepareIndexData() will also look up the min/max value of a range
+of indices, or computes it when not already in the static buffer or when a
+streaming buffer is used.
+
+Similarly, both glDrawElements() and glDrawArrays() both call
+VertexDataManager::prepareVertexData() to retrieve a set of Direct3D vertex
+buffers and their translated format and offset information. It's implementation
+is more complicated than prepareIndexData() because buffer objects can contain
+multiple vertex attributes, and multiple buffers can be used as input to the
+vertex shader. So first it accumulates how much storage space is required for
+each of the buffers in use. For all static non-empty buffers in use, it
+determines whether the stored attributes still match what is required by the
+draw call, and invalidates them if not (at which point more space is allocated
+in the streaming buffer). Converting the GL buffer object's data into D3D
+compatible vertex formats is still done by specialized template functions.
diff --git a/src/third_party/angle/doc/BuildingAngleForChromiumDevelopment.md b/src/third_party/angle/doc/BuildingAngleForChromiumDevelopment.md
new file mode 100644
index 0000000..a3eac3e
--- /dev/null
+++ b/src/third_party/angle/doc/BuildingAngleForChromiumDevelopment.md
@@ -0,0 +1,83 @@
+# How to build ANGLE in Chromium for dev
+
+## Introduction
+
+On Windows, Linux, and Mac ANGLE now builds most core components cross platform, including the shader validator and translator as well as the graphics API translator. These parts can be built and tested inside a Chromium checkout.
+
+Steps:
+
+  * Checkout and build [Chromium](http://dev.chromium.org/Home).
+  * You should now be able to use `ninja -C out/Debug angle_end2end_tests`, for example.
+
+## Building Standalone ANGLE inside Chromium
+
+On Mac, ANGLE doesn't yet include the dEQP tests or the API translation libraries as part of Chromium. ANGLE also includes some sample applications and a few other targets that don't build on Chromium. These steps describe how to build such targets within a Chromium checkout.
+
+Steps:
+
+  * Checkout and build [Chromium](http://dev.chromium.org/Home).
+  * To setup run these commands (note similarity to [DevSetup](DevSetup.md)):
+
+```bash
+cd src/third_party/angle
+gclient config --name . --unmanaged https://chromium.googlesource.com/angle/angle.git
+
+gclient sync
+git checkout master
+```
+
+  * To make the build files run these commands
+
+```bash
+cd src/third_party/angle
+GYP_GENERATORS=ninja gclient runhooks
+```
+
+  * To build
+
+```bash
+cd src/third_party/angle
+ninja -j 10 -k1 -C out/Debug
+```
+
+  * To build a specific target add the target at the end:
+
+```bash
+cd src/third_party/angle
+ninja -j 10 -k1 -C out/Debug angle_gles2_deqp_tests
+```
+
+  * To run
+
+```bash
+cd src/third_party/angle
+./out/Debug/hello_triangle
+```
+
+If you decide to go back to the Chromium-managed version, just remove the `.gclient` file.
+
+## Working with Top of Tree ANGLE in Chromium
+
+If you're actively developing within ANGLE in your Chromium workspace you will want to work with top of tree ANGLE. To do this do the following:
+
+  * Ignore ANGLE in your `.gclient`
+
+```python
+solutions = [
+  {
+    # ...
+    u'custom_deps':
+    {
+      "src/third_party/angle": None,
+    },
+  },
+]
+```
+
+You then have full control over your ANGLE workspace and are responsible for running all git commands (pull, rebase, etc.) for managing your branches.
+
+If you decide you need to go back to the DEPS version of ANGLE:
+
+  * Comment out the `src/third_party/angle` line in your `custom_deps`.
+  * Go into your ANGLE workspace and switch back to the master branch (ensure there are no modified or new files).
+  * `gclient sync` your Chromium workspace.
diff --git a/src/third_party/angle/doc/BuildingAngleForWindowsStore.md b/src/third_party/angle/doc/BuildingAngleForWindowsStore.md
new file mode 100644
index 0000000..35f77c2
--- /dev/null
+++ b/src/third_party/angle/doc/BuildingAngleForWindowsStore.md
@@ -0,0 +1,55 @@
+# How to build ANGLE for Windows Store
+
+ANGLE provides OpenGL ES 2.0 and EGL 1.4 libraries and dlls.  You can use these to build and run OpenGL ES 2.0 applications on Windows.
+
+## Development setup
+
+ANGLE for Windows Store uses most of the same steps found in [ANGLE Development](DevSetup.md) with a few changes.
+
+### Required Tools
+ * [Visual Studio Community 2015](http://www.visualstudio.com/downloads/download-visual-studio-vs)
+   * Required to build ANGLE on Windows and for the packaged Windows 10 SDK.
+
+
+### Getting the source
+Set the following environment variables as needed:
+
+ * `GYP_GENERATORS` to `msvs`
+ * `GYP_MSVS_VERSION` to `2015`
+ * `GYP_GENERATE_WINRT` to `1`
+
+Download the ANGLE source by running the following commands:
+
+```
+git clone https://chromium.googlesource.com/angle/angle
+python angle/scripts/bootstrap.py
+gclient sync
+git checkout master
+```
+
+Gyp will generate multiple VS2015 solution files
+ * `winrt/10/src/angle.sln` for Windows 10
+
+
+### Building ANGLE
+ 1. Open one of the ANGLE Visual Studio solution files (see [Getting the source](BuildingAngleForWindowsStore.md#Development-setup-Getting-the-source)).
+ 2. Select Build -> Configuration Manager
+ 3. In the "Active solution configuration:" drop down, select the desired configuration (eg. Release), and close the Configuration Manager.
+ 4. Select Build -> Build Solution.
+Once the build completes, the output directory for your selected configuration (eg. `Release_Win32`, located next to the solution file) will contain the required libraries and dlls to build and run an OpenGL ES 2.0 application.
+
+### To Use ANGLE in Your Application
+ 1. A template for creating a Windows Store application that uses ANGLE can be found [here](http://blogs.msdn.com/b/vcblog/archive/2015/07/30/cross-platform-code-sharing-with-visual-c.aspx).
+ 2. Configure your build environment to have access to the `include` folder to provide access to the standard Khronos EGL and GLES2 header files.
+  * For Visual C++
+     * Right-click your project in the _Solution Explorer_, and select _Properties_.
+     * Under the _Configuration Properties_ branch, click _C/C++_.
+     * Add the relative path to the Khronos EGL and GLES2 header files to _Additional Include Directories_.
+ 3. Configure your build environment to have access to `libEGL.lib` and `libGLESv2.lib` found in the build output directory (see [Building ANGLE](DevSteup.md#Building-ANGLE)).
+   * For Visual C++
+     * Right-click your project in the _Solution Explorer_, and select _Properties_.
+     * Under the _Configuration Properties_ branch, open the _Linker_ branch and click _Input_.
+     * Add the relative paths to both the `libEGL.lib` file and `libGLESv2.lib` file to _Additional Dependencies_, separated by a semicolon.
+ 4. Copy `libEGL.dll` and `libGLESv2.dll` from the build output directory (see [Building ANGLE](DevSetup.md#Building-ANGLE)) into your application folder or packages location if a ANGLE Windows Store NuGet was used.
+ 5. Code your application to the Khronos [OpenGL ES 2.0](http://www.khronos.org/registry/gles/) and [EGL 1.4](http://www.khronos.org/registry/egl/) APIs.
+
diff --git a/src/third_party/angle/doc/ChoosingANGLEBranch.md b/src/third_party/angle/doc/ChoosingANGLEBranch.md
new file mode 100644
index 0000000..c2ac1ae
--- /dev/null
+++ b/src/third_party/angle/doc/ChoosingANGLEBranch.md
@@ -0,0 +1,68 @@
+# Choosing an ANGLE branch for your project
+
+ANGLE is under continuous development, and does not create release tarballs or
+tag specific revisions as releases, which may make the process of choosing a
+point in ANGLE's history as the dependency for your project less than obvious.
+This document illustrates how to choose a branch of ANGLE which can be expected
+to be updated with critical fixes, should they be needed.
+
+## ANGLE automatic branching
+
+Branches are created automatically in ANGLE to correspond to branches created in
+Chromium. These branches are named `chromium/####`, where the number is the
+matching Chromium branch. These branches will be created from the revision which
+that Chromium branch points to as its dependency. So, for example, the
+`chromium/2013` branch point is at r28bcf4ff, because [Chromium's dependency
+file for the 2013 branch]
+(http://src.chromium.org/viewvc/chrome/branches/2013/src/DEPS?revision=272741)
+uses this ANGLE revision.
+
+It isn't necessary to be familiar with how Chromium's dependency management
+works to choose an appropriate ANGLE branch for your project. You will, however,
+likely want to make sure that you choose a branch that is used for a relatively
+stable Chromium release channel build, as those branches will be deployed with
+Chromium, and receive updates if bugs are found and fixed during release
+lifetime, while the more volatile channels will turn over quickly, and their
+branches will be short-lived.
+
+**We recommend choosing a branch corresponding to a Beta or Stable Chromium
+release** if you are pursuing periodic, not continuous, integration of ANGLE.
+
+## Matching a Chromium release to an ANGLE branch
+
+In order to determine which branches are used by Chromium releases, please use
+[the OmahaProxy tool](http://omahaproxy.appspot.com/), which lists build
+information about current Chromium releases. Find the entry for a suitable
+release channel (for now, we recommend one of the Windows desktop releases), and
+note the branch listed in the `true_branch` column. This identifies the ANGLE
+branch used by that Chromium release.
+
+## Updates to release branches
+
+If bugs (stability, security, performance, or otherwise) are discovered after a
+branch has been created, and that branch is used by a Chromium release, the
+fixes for those bugs will be applied to the ANGLE branches for uptake by
+Chromium and any other projects using that branch. You should need only to
+perform a `git pull` to check for and apply any such changes.
+
+## Cherry-picking a change to a release branch
+
+Occasionally a bug fix must be merged back to an earlier Chromium
+release branch. To do this, first look up the branch number in
+[OmahaProxy](https://omahaproxy.appspot.com/). For example, M55
+corresponds to branch number 2883.
+
+In the simple case where there are no conflicts, the merge can be done
+entirely in the Gerrit UI. Click the "Cherry pick" button and enter
+`chromium/[branch_number]` as the branch to merge to.
+
+If there are conflicts, however, follow these steps:
+
+1. `git checkout chromium/[branch_number]`
+2. `git cherry-pick [commit_hash]`
+3. Fix any merge conflicts.
+4. `git cl upload`
+
+Have the cherry-pick reviewed, and then land it. It's also OK to skip
+the review and land it yourself with TBR= in the issue description, if
+you have that ability.
diff --git a/src/third_party/angle/doc/CodeReviewProcess.md b/src/third_party/angle/doc/CodeReviewProcess.md
new file mode 100644
index 0000000..9a53e2a
--- /dev/null
+++ b/src/third_party/angle/doc/CodeReviewProcess.md
@@ -0,0 +1,57 @@
+# ANGLE's Code Review Process
+
+This page describes the review process for ANGLE reviewers and committers. For
+instructions on submitting your change list for review, please see
+[ContributingCode](ContributingCode.md).
+
+## Reviewing Changes
+
+The author of a CL may designate reviewers. Please feel free to weigh in on
+changes even if you are not a designated reviewer!
+
+1.  To review a change, you can either navigate directly to the URL for the CL,
+    or, if you are one of the designated reviewers, the change will appear in
+    your dashboard at https://chromium-review.googlesource.com/
+2.  Review the change listed by looking over the diffs listed in the most recent
+    patch set.
+    *   You may view the diffs either side-to-side, or in unified diff format.
+    *   You can comment on a specific line of code by double-clicking that line,
+        or on the file as a whole by clicking the "Add file comment" icon, which
+        appears above the diff, in the line number column.
+    *   Note that, for CLs submitted as fixes to standing bugs, style issues
+        that pre-exist the CL are not required to be addressed in the CL. As a
+        reviewer, you can request a follow-up CL to address the style issue if
+        you desire. This exception doesn't apply for CLs which implement new
+        functionality, perform refactoring, or introduce style issues
+        themselves.
+3.  Once your review is complete, click the "Review" button
+    *   If you are satisfied with the change list as it is, give a positive
+        review (Code-Review +1 or +2).
+    *   If you think the change list is a good idea, but needs changes, leave
+        comments and a neutral review. (Code-Review 0)
+    *   If you think the change list should be abandoned, give a negative
+        review. (Code-Review -1 or -2)
+    *   A +2 code review is required before landing. Only ANGLE committers may
+        provide a +2 code review.
+    *   ANGLE has a 2-reviewer policy for CLs. This means all changes should get
+        a positive review from more than one person before they are accepted.
+        This is most usually handled by reserving the +2 review for the second
+        reviewer to clear the CL.
+    *   If you made comments on the files, the draft comments will appear below
+        the cover message. These comments are not published until you click on
+        the "Publish Comments" button.
+4.  Verification and landing:
+    *   If the CL author is not an ANGLE committer, the CL should be verified
+        and landed by a committer. Once verified, the "+1 Verified" status may
+        be added, and the CL may be landed with the "Publish and Submit" button.
+        There should be no need to rebase via the "Rebase Change" button prior
+        to landing.
+    *   If the CL author is an ANGLE committer, they should verify and land the
+        CL themselves.
+    *   Please note: Verification and commit-queue workflow may be subject to
+        change in the near future.
+5.  Cherry-picking to other branches
+    *   If the change is needed on other branches, you may be able to land it
+        using the "Cherry Pick To" button on the CL page.
+    *   If this cherry pick fails, you will need to rebase the patch yourself
+        and submit a new change for review on the branch.
diff --git a/src/third_party/angle/doc/CodingStandard.md b/src/third_party/angle/doc/CodingStandard.md
new file mode 100644
index 0000000..cc43b26
--- /dev/null
+++ b/src/third_party/angle/doc/CodingStandard.md
@@ -0,0 +1,155 @@
+# Coding Standard for the ANGLE Project
+
+## Google Style Guide
+
+We generally use the [Google C++ Style Guide]
+(http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml) as a basis for
+our Coding Standard, however we will deviate from it in a few areas, as noted
+below.
+
+Items marked {DEV} indicate a deviation from the Google guidelines. Items marked
+{DO} are reiterating points from the Google guidelines.
+
+Before you upload code to Gerrit, use `git cl format` to auto-format your code.
+This will catch most of the trivial formatting errors and save you time.
+
+### [Header Files](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Header_Files)
+
+*   We will use **`.h`** for C++ headers.
+*   {DEV} #define guards should be of the form: `<PATH>_<FILE>_H_`. (Compiler
+    codebase is varied, including `<PROJECT>_` makes the names excessively
+    long).
+
+### [Scoping](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Scoping)
+
+*   {DO} avoid globally scoped variables, unless absolutely necessary.
+
+### [Classes](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Classes)
+
+*   {DEV} Inherit (privately) from angle::NonCopyable helper class (defined in
+    common/angleutils.h) to disable default copy and assignment operators.
+
+### [Other C++ Features](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Other_C++_Features)
+
+*   {DEV} all parameters passed by reference, except for STL containers (e.g.
+    std::vector, std::list), must be labeled `const`. For return parameters
+    other than STL containers, use a pointer.
+*   {DO} avoid use of default arguments.
+*   {DONT} use C++ exceptions, they are disabled in the builds and not caught.
+*   {DO} use nullptr (instead of 0 or NULL) for pointers.
+*   {DO} use size\_t for loop iterators and size values.
+*   {DO} use uint8\_t pointers instead of void pointers to denote binary data.
+*   {DO} use C++11 according to the [Chromium guide on C++11]
+    (http://chromium-cpp.appspot.com/).
+
+### [Naming ](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Naming)
+
+#### File Names
+
+*   {DEV} Filenames should be all lowercase and can include underscores (`_`).
+    If the file is an implementation of a class, the filename may be capitalized
+    the same as the major class.
+*   {DEV} We use .cpp (instead of .cc), .h and .inl (inlined files) for C++
+    files and headers.
+
+#### Directory Names
+*   Directory names should be all lowercase, unless following an externally
+    imposed capitalization (eg include/EGL, or src/libGLESv2, etc)
+
+#### Variable Names
+
+Use the following guidelines, they do deviate somewhat from the Google
+guidelines.
+
+* class and type names: start with capital letter and use CamelCase.
+* {DEV} class member variables: use an **`m`** prefix instead of trailing
+underscore and use CamelCase.
+* global variables (if they must be used): use a **`g_`** prefix.
+* {DEV} variable names: start with lower case and use CamelCase (chosen for consistency)
+* {DEV} function names: Member functions start with lower case and use CamelCase. Non-member functions start with capital letter and
+use CamelCase (chosen for consistency)
+* Constants: start with a **`k`** and use CamelCase
+* namespaces: use all lower case
+* Enum Names - use class enums, and the values should be uppercase with underscores.
+* macros: all uppercase with underscores
+* exceptions to naming: use common sense!
+
+### [Comments](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Comments)
+
+*   {DO} read and follow Google's recommendations.
+*   Each file **must** start with the following boilerplate notice:
+
+```
+//
+//  Copyright (c) 2016 The ANGLE Project Authors. All rights reserved.
+//  Use of this source code is governed by a BSD-style license that can be
+//  found in the LICENSE file.
+//
+```
+
+### [Formatting](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Formatting)
+
+*   {DEV} Avoid excessively long lines. Please keep lines under 100 columns
+    long.
+*   Use unix-style newlines.
+*   {DO} use only spaces. No tab characters. Configure your editor to emit
+    spaces when you hit the TAB-key.
+*   {DEV} indent 4 spaces at a time.
+*   conditionals: place space outside the parenthesis. No spaces inside.
+*   switch statements: use the output of `git cl format`.
+*   class format(eg private, public, protected): indent by 2 spaces. Regular
+    4-space indent from the outer scope for declarations/definitions.
+*   pointers and references: **`*`** and **`&`** tight against the variable
+*   namespaces: are not indented.
+*   extern code blocks: are not indented.
+*   {DEV} braces should go on a separate line, except for functions defined in a
+    header file where the whole function declaration and definition fit on one
+    line.
+
+Examples:
+
+```
+if (conditional)
+{
+    stuff();
+}
+else
+{
+    otherstuff()
+}
+```
+
+```
+switch (conditional)
+{
+  case foo:
+    dostuff();
+    break;
+  case bar:
+    otherstuff();
+    break;
+  default:
+    WTFBBQ();
+}
+```
+
+```
+class MyClass : public Foo
+{
+  public:
+    MyClass();
+    ~MyClass() {};
+  private:
+    DISALLOW_COPY_AND_ASSIGN(MyClass);
+};
+```
+
+```
+char *c;
+const string &str;
+```
+
+### [Exceptions to the Rules](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Exceptions_to_the_Rules)
+
+*   If modifying pre-existing code that does not match the standard, the altered
+    portions of the code should be changed to match the standard.
diff --git a/src/third_party/angle/doc/CompilingTranslatorWithEmscripten.md b/src/third_party/angle/doc/CompilingTranslatorWithEmscripten.md
new file mode 100644
index 0000000..fc7b17f
--- /dev/null
+++ b/src/third_party/angle/doc/CompilingTranslatorWithEmscripten.md
@@ -0,0 +1,109 @@
+# Introduction
+
+There are many situations in which it's useful for WebGL applications to
+transform shaders in various ways. ANGLE's shader translator can be used for
+this purpose: compiling it with [Emscripten](http://emscripten.org/) allows it
+to be invoked from a web page. This wiki page provides some preliminary details
+about how to do this.
+
+# Details
+
+Pull top of tree ANGLE.
+
+Install the Emscripten toolchain per the [instructions]
+(http://kripken.github.io/emscripten-site/).
+
+Symlink (preferred) or copy the ANGLE directory into ...emsdk/emscripten/master.
+
+Put a shader to compile into a file (named with .vert or .frag suffix) in the
+same directory. For example, put the following shader from the [WebGL Aquarium]
+(http://webglsamples.org/aquarium/aquarium.html) into `aq-fish-nm.frag`:
+
+```
+precision mediump float;
+uniform vec4 lightColor;
+varying vec4 v_position;
+varying vec2 v_texCoord;
+varying vec3 v_tangent;  // #normalMap
+varying vec3 v_binormal;  // #normalMap
+varying vec3 v_normal;
+varying vec3 v_surfaceToLight;
+varying vec3 v_surfaceToView;
+
+uniform vec4 ambient;
+uniform sampler2D diffuse;
+uniform vec4 specular;
+uniform sampler2D normalMap;  // #normalMap
+uniform float shininess;
+uniform float specularFactor;
+// #fogUniforms
+
+vec4 lit(float l ,float h, float m) {
+  return vec4(1.0,
+              max(l, 0.0),
+              (l > 0.0) ? pow(max(0.0, h), m) : 0.0,
+              1.0);
+}
+void main() {
+  vec4 diffuseColor = texture2D(diffuse, v_texCoord);
+  mat3 tangentToWorld = mat3(v_tangent,  // #normalMap
+                             v_binormal,  // #normalMap
+                             v_normal);  // #normalMap
+  vec4 normalSpec = texture2D(normalMap, v_texCoord.xy);  // #normalMap
+  vec3 tangentNormal = normalSpec.xyz - vec3(0.5, 0.5, 0.5);  // #normalMap
+  tangentNormal = normalize(tangentNormal + vec3(0, 0, 2));  // #normalMap
+  vec3 normal = (tangentToWorld * tangentNormal);  // #normalMap
+  normal = normalize(normal);  // #normalMap
+  vec3 surfaceToLight = normalize(v_surfaceToLight);
+  vec3 surfaceToView = normalize(v_surfaceToView);
+  vec3 halfVector = normalize(surfaceToLight + surfaceToView);
+  vec4 litR = lit(dot(normal, surfaceToLight),
+                    dot(normal, halfVector), shininess);
+  vec4 outColor = vec4(
+    (lightColor * (diffuseColor * litR.y + diffuseColor * ambient +
+                  specular * litR.z * specularFactor * normalSpec.a)).rgb,
+      diffuseColor.a);
+  // #fogCode
+  gl_FragColor = outColor;
+}
+```
+
+Compile the shader translator, the translator sample, and the shader all
+together:
+
+```
+./emcc -Iangle/include -Iangle/src angle/samples/translator/translator.cpp angle/src/compiler/preprocessor/*.cpp angle/src/compiler/translator/*.cpp angle/src/compiler/translator/timing/*.cpp angle/src/compiler/translator/depgraph/*.cpp angle/src/third_party/compiler/*.cpp angle/src/common/*.cpp -o translator.html --preload-file aq-fish-nm.frag -s NO_EXIT_RUNTIME=1
+```
+
+Serve up the resulting translator.html via `python -m SimpleHTTPServer`.
+Navigate the browser to localhost:8000.
+
+The translator sample will run, displaying its output into the text area on the
+page. Since it isn't receiving any input, it simply outputs a help message and
+exits.
+
+To invoke the translator again, processing the shader we included along with the
+source code, open the JavaScript console and type:
+
+```
+Module['callMain'](['-s=w', '-u', 'aq-fish-nm.frag'])
+```
+
+The active uniforms and their types will be printed to the text area after the
+translator sample processes the shader.
+
+# Issues and Next Steps
+
+It's clearly not useful to have to compile the shader in to the
+Emscripten-translated executable. It would be helpful to define a simple wrapper
+function which can easily be called from JavaScript and which defines enough
+parameters to pass in a shader as a string, transform it somehow or compile it
+to another language target, and return the compiled result (or other
+information). A simple JavaScript library that wraps all of the interactions
+with the Emscripten binary would be useful.
+
+It's not feasible to interact with the translator's data structures, nor
+traverse the AST from JavaScript. The code that operates upon the shader must be
+written in C++ and compiled in to the shader translator.
+
+emcc should be integrated better with ANGLE's build system.
diff --git a/src/third_party/angle/doc/ContributingCode.md b/src/third_party/angle/doc/ContributingCode.md
new file mode 100644
index 0000000..ff11143
--- /dev/null
+++ b/src/third_party/angle/doc/ContributingCode.md
@@ -0,0 +1,105 @@
+# Contributing Code
+
+## Communicate
+
+ * Whether you're writing a new feature or fixing an existing bug, it pays to get a second opinion before you get too far. If it's a new feature idea, post to the discussion group ([angleproject](https://groups.google.com/forum/?fromgroups#!forum/angleproject)) and propose it or talk with the ANGLE team on IRC in the #ANGLEproject channel on FreeNode.
+ * Not all bugs in our [bug system](https://code.google.com/p/angleproject/issues/list) are assigned, but if the one you're interested in fixing is, send a note to the person it's assigned to and ask if they would like a patch.
+ * Behavior changes and anything nontrivial (i.e. anything other than simple cleanups and style fixes) should generally be tracked in the bug system. Please [file a bug](http://anglebug.com/new) and describe what you're doing if there isn't one already.
+
+## Get your code ready
+### Code
+ 1. Must conform to the [ANGLE style](CodingStandard.md) guidelines.
+ 2. Must be tested. (see the 'Testing' section below)
+ 3.  Should be a reasonable size to review.  Giant patches are unlikely to get reviewed quickly.
+
+### Build maintenance
+ 1. If you added or removed source files:
+    * You _must_ update the gyp build scripts lists with your changes. See `src/libEGL.gypi`, `src/libGLESv2.gypi`, and `src/compiler.gypi`.
+ 2. ANGLE also now maintains a BUILD.gn script for  [Chromium's gn build](https://code.google.com/p/chromium/wiki/gn).  If you changed the gyp files other than to add or remove new files, you will also need to update BUILD.gn. Ask a project member for help with testing if you don't have a Chromium checkout.
+ 3. If you modified `glslang.y` or `glslang.l`:
+    * You _must_ update the bison-generated compiler sources. Download and install the latest 64-bit Bison and flex from official [Cygwin](https://cygwin.com/install.html) on _Windows_. From the Cygwin shell run `generate_parser.sh` in `src/compiler/translator` and update your CL. Do not edit the generated files by hand.
+    * _NOTE:_ You can ignore failing chunk messages if there are no compile errors.
+    * If you modified `ExpressionParser.y` or `Tokenizer.l`, follow the same process by running `src/compiler/preprocessor/generate_parser.sh`.
+
+### Testing
+ * ANGLE uses trybots to test on a variety of platforms. Please run your changes against our bots and check the results before landing changes or requesting reviews.
+    * Upload your change (see [Making changes](ContributingCode.md#making-changes)).
+    * To kick of a try job, use the 'CQ Dry Run' button, or set the Commit-Queue +1 label to trigger a dry run of the CQ (will not land the change).
+    * If you are not part of the `angle-committers` group, you will need to either ask to be added or ask a member of the group to submit the tryjob for you. Add jmadill or geofflang as a reviewer for assistance.
+    * Wait for the bots to report the result on the code review page. The bot results should be visible in Gerrit as yellow (in-progress), green (passed), or red (failed). This can take up to two hours for some of the debug bots. Click on the colored rectangle to open the bot log to triage failed tests.
+    * If a failure is unexpected, or seems likely unrelated to your change, ask an ANGLE project member for advice.
+    * We do not currently have the capability to run individual bots or tests in a run.
+ * Tests can also be run locally, ANGLE's main testing methods are:
+    * `angle_unittests`, `angle_end2end_tests` and `angle_white_box_tests` targets.
+    * The [Top-of-Tree WebGL Conformance tests](https://www.khronos.org/registry/webgl/sdk/tests/webgl-conformance-tests.html).
+      * If you are a Chromium developer, see [Building ANGLE for Chromium Development](BuildingAngleForChromiumDevelopment.md) for instructions on building ANGLE within Chromium.
+      * If you aren't a browser developer, you should be able to drop your compiled DLLs into a Chrome installation, in place of those distributed with Chrome, to check WebGL conformance. [Chrome Canary](https://www.google.com/chrome/browser/canary.html) is well-suited for this.
+    * If your code isn't covered by an existing test, you are *strongly encouraged* to add new test coverage. This both ensures that your code is correct and that new contributors won't break it in the future.
+    * Add new tests to `angle_end2end_tests` for OpenGL-based API tests, `angle_unittests` for cross-platform internal tests, and `angle_white_box_tests` for rendering tests which also need visibility into internal ANGLE classes.
+   * If you are submitting a performance fix, test your code with `angle_perftests` and add a new performance test if it is not covered by the existing benchmarks.
+   * The [Chromium GPU FYI bot waterfall](http://build.chromium.org/p/chromium.gpu.fyi/console) provides continuous integration for ANGLE patches that have been committed.  There may be hardware configurations that are not tested by the ANGLE trybots, if you notice breakage on this waterfall after landing a patch, please notify a project member.
+   * ANGLE also includes the [drawElements Quality Program (dEQP)](dEQP.md) for additional testing. If you're working on a new feature, there may be some extensive tests for it already written.
+
+### Legal
+ 1. You must complete the [Individual Contributor License Agreement](http://code.google.com/legal/individual-cla-v1.0.html). You can do this online, and it only takes a minute. If you are contributing on behalf of a corporation, you must fill out the [Corporate Contributor License Agreement](http://code.google.com/legal/corporate-cla-v1.0.html) and send it to Google as described on that page.
+ 2. Once you've submitted the CLA, please email the following information (as entered on the CLA) to `shannonwoods at chromium dot org` for record keeping purposes:
+    * Full Name:
+    * Email:
+    * Company (If applicable):
+ 3. If you've never submitted code before, you must add your (or your organization's) name and contact info to the [AUTHORS](../AUTHORS) file.
+ 4. *NOTE TO REVIEWERS*: Follow the [External Contributor Checklist](http://www.chromium.org/developers/contributing-code/external-contributor-checklist).
+
+## Life of a Change List
+
+### Getting started with Gerrit for ANGLE
+  1. Go to [https://chromium-review.googlesource.com/new-password](https://chromium-review.googlesource.com/new-password)
+  2. Log in with the email you use for your git commits.
+  3. Follow the directions on the new-password page to set up authentication with your Google account.
+  4. Make sure to set your real name.
+     * Visit [https://chromium-review.googlesource.com/#/settings](https://chromium-review.googlesource.com/#/settings) and check the "Full Name" field.
+  5. Check out the repository (see [DevSetup](DevSetup.md)).
+  6. Install the Gerrit `commit_msg` hook
+     * Gerrit requires a hook to append a change ID tag to each commit, so that it can associate your CL with a particular review, and track dependencies between commits.
+     * Download the hook from [https://chromium-review.googlesource.com/tools/hooks/commit-msg](https://chromium-review.googlesource.com/tools/hooks/commit-msg) and copy this file to `.git/hooks/commit-msg` within your local repository. On non-Windows, platforms, ensure that permissions are set to allow execution.
+     * *BE AWARE:* Some patch management tools, such as StGit, currently bypass git hooks. They should not currently be used with changes intended for review.
+
+### Making changes {#making-changes}
+ 1. Commit your changes locally:
+    * `git add src/../FileName.cpp`
+    * `git commit`
+    * A text editor will open. Add a description at the top of the file.
+       * If your changes are associated with an issue in the issue tracker (e.g. a fix for a reported bug), please associate the CL with that issue by adding the following line to the commit message: `BUG=angleproject:<issue number>`.
+    * Save.
+    * Close the text editor.
+    * Use `git commit --amend` to update your CL with new changes.
+    * Use `git cl format` to amend the style of your CL. This saves both your time and the reviewers'!
+ 2. Ensure your code is landed on top of latest changes
+    * `git pull --rebase`
+    * Resolve conflicts if necessary
+ 3. Upload the change list
+    * `git cl upload`
+    * The change list and modified files will be uploaded to
+      [ANGLE Gerrit](https://chromium-review.googlesource.com/#/q/project:angle/angle).
+    * Follow the generated URL to the new issue.
+    * Take a moment to perform a self-review of your code. Gerrit's viewer makes it easy to see whitespace errors, erroneous tabs, and other simple style problems.
+    * Designate reviewers-- if you don't do this, reviewers may not realize you're requesting a review!
+      * If you don't know who to use, select either `geofflang at chromium dot org` or `jmadill at chromium dot org`.
+    * Make changes, upload and repeat as necessary.
+    * Project members and others will review your code as described in the [CodeReviewProcess](CodeReviewProcess.md).
+ 5. If your change list needs revision:
+    * If you have correctly installed the commit hook from the section above, Gerrit will be able to track your changes by Change-Id.
+    * You should need only to update your commit with `git commit --amend` and re-upload with `git cl upload`.
+ 6. Landing change after it receives +2 Code Review:
+    * If you are a committer, you may submit the change yourself via the Gerrit web interface.
+    * If you are not a committer, ask your reviewer to submit the change list.
+ 7. Pull and integrate reviewed CL:
+    * `git pull --rebase`
+
+
+See also:
+
+* [ANGLE Gerrit](https://chromium-review.googlesource.com/#/q/project:angle/angle)
+* [Chromium Projects: Contributing Code](http://www.chromium.org/developers/contributing-code/)
+* [depot_tools tutorial](http://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html)
+
+
diff --git a/src/third_party/angle/doc/DebuggingTips.md b/src/third_party/angle/doc/DebuggingTips.md
new file mode 100644
index 0000000..f7bcf24
--- /dev/null
+++ b/src/third_party/angle/doc/DebuggingTips.md
@@ -0,0 +1,25 @@
+# Debugging Tips
+
+There are many ways to debug ANGLE using generic or platform-dependent tools. Here is a list of tips on how to use them.
+
+## Running ANGLE under apitrace on Linux
+
+[Apitrace](http://apitrace.github.io/) that captures traces of OpenGL commands for later analysis, allowing us to see how ANGLE translates OpenGL ES commands. In order to capture the trace, it inserts a driver shim using `LD_PRELOAD` that records the command and then forwards it to the OpenGL driver.
+
+The problem with ANGLE is that it exposes the same symbols as the OpenGL driver so apitrace captures the entry point calls intended for ANGLE and reroutes them to the OpenGL driver. In order to avoid this problem, use the following:
+
+1. Compile ANGLE as a static library so that it doesn't get shadowed by apitrace's shim using the `-D angle_gl_library_type=static_library` gyp flag.
+2. Ask apitrace to explicitly load the driver instead of using a dlsym on the current module. Otherwise apitrace will use ANGLE's symbols as the OpenGL driver entrypoint (causing infinite recursion). To do this you must point an environment variable to your GL driver. For example: `export TRACE_LIBGL=/usr/lib/libGL.so.1`. You can find your libGL with `ldconfig -p | grep libGL`.
+3. Link ANGLE against libGL instead of dlsyming the symbols at runtime; otherwise ANGLE won't use the replaced driver entry points. This can be done by adding `-D angle_link_glx=1`.
+
+If you follow these steps, apitrace will work correctly aside from a few minor bugs like not being able to figure out what the default framebuffer size is if there is no glViewport command.
+
+For example, to trace a run of `hello_triangle`, assuming you are using the ninja gyp generator and the apitrace executables are in `$PATH`:
+
+```
+./gyp/gyp_angle -D angle_link_glx=1 -D angle_gl_library_type=static_library
+ninja -C out/Debug
+export TRACE_LIBGL="/usr/lib/libGL.so.1" # may require a different path
+apitrace trace -o mytrace ./out/Debug/hello_triangle
+qapitrace mytrace
+```
diff --git a/src/third_party/angle/doc/DevSetup.md b/src/third_party/angle/doc/DevSetup.md
new file mode 100644
index 0000000..0553301
--- /dev/null
+++ b/src/third_party/angle/doc/DevSetup.md
@@ -0,0 +1,165 @@
+# ANGLE Development
+
+ANGLE provides OpenGL ES 2.0 and EGL 1.4 libraries and dlls.  You can use these to build and run OpenGL ES 2.0 applications on Windows.
+
+## Development setup
+
+### Version Control
+ANGLE uses git for version control. If you are not familiar with git, helpful documentation can be found at [http://git-scm.com/documentation](http://git-scm.com/documentation).
+
+### Required Tools
+On all platforms:
+
+ * [depot_tools](http://dev.chromium.org/developers/how-tos/install-depot-tools)
+   * Required to generate projects and build files, contribute patches, run the unit tests or build the shader compiler on non-Windows systems.
+
+On Windows:
+
+ * [Visual Studio Community 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs)
+   * Required to build ANGLE on Windows and for the packaged Windows 10 SDK. Note: Chrome is in the process of upgrading to Visual Studio 2017. ANGLE will switch over once Chrome does.
+ * [Windows 10 Standalone SDK](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) (recommended)
+    * Not required to build, but comes with additional features that aid ANGLE development, such as the Debug runtime for D3D11.
+ * [Cygwin's Bison, flex, and patch](https://cygwin.com/setup-x86_64.exe) (optional)
+    * This is only required if you need to modify GLSL ES grammar files (`glslang.l` and `glslang.y` under `src/compiler/translator`, or `ExpressionParser.y` and `Tokenizer.l` in `src/compiler/preprocessor`).
+     Use the latest versions of bison, flex and patch from the 64-bit cygwin distribution.
+
+On Linux:
+
+ * The GCC or Clang compilers
+ * Development packages for OpenGL, X11 and libpci
+ * Bison and flex are not needed as we only support generating the translator grammar on Windows.
+
+On MacOS:
+
+ * [XCode](https://developer.apple.com/xcode/) for Clang and development files.
+ * Bison and flex are not needed as we only support generating the translator grammar on Windows.
+
+### Getting the source
+Set the following environment variables as needed:
+
+On Windows:
+
+ * `GYP_GENERATORS` to `msvs` (other options include `ninja` and `make`)
+ * `GYP_MSVS_VERSION` to `2015`
+
+On Linux and MacOS:
+
+ * `GYP_GENERATORS` to `ninja` (defaults to 'make' that pollutes your source directory)
+
+Download the ANGLE source by running the following commands:
+
+```
+git clone https://chromium.googlesource.com/angle/angle
+cd angle
+python scripts/bootstrap.py
+gclient sync
+git checkout master
+```
+
+GYP will generate the project files, if you update ANGLE or make a change to the projects, they can be regenerated by executing `gclient runhooks`.
+
+On Windows GYP will generate the main VS2015 solution file as gyp/ANGLE.sln. For generating a Windows Store version of ANGLE view the [Windows Store instructions](doc/BuildingAngleForWindowsStore.md).
+
+On Linux and MacOS, GYP will generate the `out/Debug` and `out/Release` directories.
+
+### Building ANGLE on Windows
+ 1. Open one of the ANGLE Visual Studio solution files (see [Getting the source](DevSetup.md#Development-setup-Getting-the-source)).
+ 2. Select Build -> Configuration Manager
+ 3. In the "Active solution configuration:" drop down, select the desired configuration (eg. Release), and close the Configuration Manager.
+ 4. Select Build -> Build Solution.
+Once the build completes, the output directory for your selected configuration (eg. `Release_Win32`, located next to the solution file) will contain the required libraries and dlls to build and run an OpenGL ES 2.0 application.
+
+### Building ANGLE on Linux and MacOS
+Run `ninja -C out/Debug` or `ninja -C out/Release`. Ninja is provided by `depot_tools` so make sure you set up your `PATH` correctly.
+Once the build completes, the `out/Debug` or `out/Release` directories will contain the .so or .dylib libraries and test binaries.
+
+### Building ANGLE for Android
+Presently, it is not possible to build standalone ANGLE for Android.
+But, ANGLE for Android can be built within a Chromium checkout.
+The reason for that is a dependency on Chromium for Android toolchain and that it only supports GN.
+Also, it can only be built on Linux, as this is the only platfrom that Chromium for Android supports.
+In theory, once ANGLE supports standalone GN build, it may be possible to put Chromium for Android toolchain in `third_party` or `buildtools` to build standalone ANGLE for Android.
+
+But, for now, the steps in [Checking out and building Chromium for Android](https://chromium.googlesource.com/chromium/src/+/master/docs/android_build_instructions.md) should be followed to check out Chromium for Android and set up build environment.
+Name your output directories `out/Debug` and `out/Release`, because Chromium GPU tests look for browser binaries in these folders. Replacing `out` with other names seems to be OK when working with multiple build configurations.
+It's best to use a build configuration of some Android bot on [GPU.FYI waterfall](https://build.chromium.org/p/chromium.gpu.fyi/waterfall). Look for `generate_build_files` step output of that bot. Remove `goma_dir` flag.
+For example, these are the build flags from Nexus 5X bot:
+```
+build_angle_deqp_tests = true
+dcheck_always_on = true
+ffmpeg_branding = "Chrome"
+is_component_build = false
+is_debug = false
+proprietary_codecs = true
+symbol_level = 1
+target_cpu = "arm64"          # Nexus 5X is 64 bit, remove this on 32 bit devices
+target_os = "android"
+use_goma = true               # Remove this if you don't have goma
+```
+
+These ANGLE targets are supported:
+`ninja -C out/Release translator libEGL libGLESv2 angle_unittests angle_end2end_tests angle_white_box_tests angle_deqp_gles2_tests angle_deqp_gles3_tests angle_deqp_egl_tests`
+In order to run ANGLE tests, prepend `bin/run_` to the test name, for example: `./out/Release/bin/run_angle_unittests`.
+Additional details are in [Android Test Instructions](https://chromium.googlesource.com/chromium/src/+/master/docs/android_test_instructions.md).
+
+Note: Running the tests not using the test runner is tricky, but is necessary in order to get a complete TestResults.qpa from the dEQP tests (since the runner shards the tests, only the results of the last shard will be available when using the test runner). First, use the runner to install the APK, test data and test expectations on the device. After the tests start running, the test runner can be stopped with Ctrl+C. Then, run
+```
+adb shell am start -a android.intent.action.MAIN -n org.chromium.native_test/.NativeUnitTestNativeActivity -e org.chromium.native_test.NativeTest.StdoutFile /sdcard/chromium_tests_root/out.txt
+```
+After the tests finish, get the results with
+```
+adb pull /sdcard/chromium_tests_root/third_party/deqp/src/data/TestResults.qpa .
+```
+
+In order to run GPU telemetry tests, build `chrome_public_apk` target. Then follow [GPU Testing](http://www.chromium.org/developers/testing/gpu-testing#TOC-Running-the-GPU-Tests-Locally) doc, using `--browser=android-chromium` argument. Make sure to set your `CHROMIUM_OUT_DIR` environment variable, so that your browser is found, otherwise the stock one will run.
+
+Also, follow [How to build ANGLE in Chromium for dev](https://chromium.googlesource.com/angle/angle/+/HEAD/doc/BuildingAngleForChromiumDevelopment.md) to work with Top of Tree ANGLE in Chromium.
+
+## Application Development with ANGLE
+This sections describes how to use ANGLE to build an OpenGL ES application.
+
+### Choosing a D3D Backend
+ANGLE can use either a backing renderer which uses D3D11 on systems where it is available, or a D3D9-only renderer.
+
+ANGLE provides an EGL extension called `EGL_ANGLE_platform_angle` which allows uers to select which renderer to use at EGL initialization time by calling eglGetPlatformDisplayEXT with special enums. Details of the extension can be found in it's specification in `extensions/ANGLE_platform_angle.txt` and `extensions/ANGLE_platform_angle_d3d.txt` and examples of it's use can be seen in the ANGLE samples and tests, particularly `util/EGLWindow.cpp`.
+
+By default, ANGLE will use a D3D11 renderer. To change the default:
+
+ 1. Open `src/libANGLE/renderer/d3d/DisplayD3D.cpp`
+ 2. Locate the definition of `ANGLE_DEFAULT_D3D11` near the head of the file, and set it to your preference.
+
+### To Use ANGLE in Your Application
+On Windows:
+
+ 1. Configure your build environment to have access to the `include` folder to provide access to the standard Khronos EGL and GLES2 header files.
+  * For Visual C++
+     * Right-click your project in the _Solution Explorer_, and select _Properties_.
+     * Under the _Configuration Properties_ branch, click _C/C++_.
+     * Add the relative path to the Khronos EGL and GLES2 header files to _Additional Include Directories_.
+ 2. Configure your build environment to have access to `libEGL.lib` and `libGLESv2.lib` found in the build output directory (see [Building ANGLE](DevSteup.md#Building-ANGLE)).
+   * For Visual C++
+     * Right-click your project in the _Solution Explorer_, and select _Properties_.
+     * Under the _Configuration Properties_ branch, open the _Linker_ branch and click _Input_.
+     * Add the relative paths to both the `libEGL.lib` file and `libGLESv2.lib` file to _Additional Dependencies_, separated by a semicolon.
+ 3. Copy `libEGL.dll` and `libGLESv2.dll` from the build output directory (see [Building ANGLE](DevSetup.md#Building-ANGLE)) into your application folder.
+ 4. Code your application to the Khronos [OpenGL ES 2.0](http://www.khronos.org/registry/gles/) and [EGL 1.4](http://www.khronos.org/registry/egl/) APIs.
+
+On Linux and MacOS, either:
+
+ - Link you application against `libGLESv2` and `libEGL`
+ - Use `dlopen` to load the OpenGL ES and EGL entry points at runtime.
+
+## GLSL ES to GLSL Translator
+In addition to OpenGL ES 2.0 and EGL 1.4 libraries, ANGLE also provides a GLSL ES to GLSL translator. This is useful for implementing OpenGL ES emulators on top of desktop OpenGL.
+
+### Getting the source
+The translator code is fully independent of the rest of ANGLE code and resides in `src/compiler`.  It is cross-platform and build files for operating systems other than Windows can be generated by following the `Generating project files` steps above.
+
+### Usage
+The basic usage is shown in `essl_to_glsl` sample under `samples/translator`. To translate a GLSL ES shader, following functions need to be called in the same order:
+
+ * `ShInitialize()` initializes the translator library and must be called only once from each process using the translator.
+ * `ShContructCompiler()` creates a translator object for vertex or fragment shader.
+ * `ShCompile()` translates the given shader.
+ * `ShDestruct()` destroys the given translator.
+ * `ShFinalize()` shuts down the translator library and must be called only once from each process using the translator.
diff --git a/src/third_party/angle/doc/DynamicShaderCompilation.md b/src/third_party/angle/doc/DynamicShaderCompilation.md
new file mode 100644
index 0000000..894142f
--- /dev/null
+++ b/src/third_party/angle/doc/DynamicShaderCompilation.md
@@ -0,0 +1,24 @@
+# About
+
+Because ANGLE can only generate full HLSL programs after we known the signatures
+between the vertex and pixel stages, we can not immediately call the D3D
+compiler at GL shader compile time. Moreover, we can insert additional
+optimization code right at draw-time.
+
+ESSL 1.00 shaders treat all vertex inputs as floating point. We insert a
+conversion routine to transform un-normalized integer vertex attributes in the
+shader preamble to floating point, saving CPU conversion time.
+
+At draw-time, we also optimize out any unused render target outputs. This
+improved draw call performance significantly on lower spec and integrated
+devices. Changing render target setups may trigger a shader recompile at draw
+time.
+
+# Addendum
+
+ANGLE is not the only program to do this kind of draw-time optimization. A
+common complaint from application developers is that draw calls sometimes
+perform very slowly due to dynamic shader re-compilation. A future design
+direction for ANGLE, when targeting a more modern API, is to perform the vertex
+conversion in a separate shader pass, which would then be linked with another
+compiled shader.
diff --git a/src/third_party/angle/doc/ExtensionSupport.md b/src/third_party/angle/doc/ExtensionSupport.md
new file mode 100644
index 0000000..cda2789
--- /dev/null
+++ b/src/third_party/angle/doc/ExtensionSupport.md
@@ -0,0 +1,66 @@
+# Introduction
+
+This page details the extensions that are supported by ANGLE.
+
+Specifications for GLES extensions can be found in the [Khronos OpenGL ES API
+Registry](http://www.khronos.org/registry/gles/)
+
+Specifications for EGL extensions can be found in the [Khronos EGL API Registry]
+(http://www.khronos.org/registry/egl/)
+
+Specifications for ANGLE-specific extensions can be found in the [ANGLE
+extension registry]
+(https://code.google.com/p/angleproject/source/browse/?name=master#git%2Fextensions)
+
+# Details
+
+## GLES extensions
+
+*   GL\_OES\_element\_index\_uint (fn1)
+*   GL\_OES\_get\_program\_binary
+*   GL\_OES\_packed\_depth\_stencil
+*   GL\_OES\_rgb8\_rgba8
+*   GL\_OES\_standard\_derivatives
+*   GL\_OES\_texture\_half\_float (fn1)
+*   GL\_OES\_texture\_half\_float\_linear (fn1)
+*   GL\_OES\_texture\_float (fn1)
+*   GL\_OES\_texture\_float\_linear (fn1)
+*   GL\_OES\_texture\_npot (fn1)
+*   GL\_EXT\_occlusion\_query\_boolean (fn1)
+*   GL\_EXT\_read\_format\_bgra
+*   GL\_EXT\_robustness
+    *   reset notifications and sized queries only, no robust buffer access
+*   GL\_EXT\_texture\_compression\_dxt1 (fn1)
+*   GL\_EXT\_texture\_filter\_anisotropic (fn1)
+*   GL\_EXT\_texture\_format\_BGRA8888
+*   GL\_EXT\_texture\_storage
+*   GL\_ANGLE\_depth\_texture
+    *   requires support for INTZ and NULL surfaces in D3D9 (see
+        http://aras-p.info/texts/D3D9GPUHacks.html)
+*   GL\_ANGLE\_framebuffer\_blit
+*   GL\_ANGLE\_framebuffer\_multisample (fn1)
+*   GL\_ANGLE\_instanced\_arrays
+    *   requires SM3 support
+*   GL\_ANGLE\_pack\_reverse\_row\_order
+*   GL\_ANGLE\_texture\_compression\_dxt3 (fn1)
+*   GL\_ANGLE\_texture\_compression\_dxt5 (fn1)
+*   GL\_ANGLE\_texture\_usage
+*   GL\_ANGLE\_translated\_shader\_source
+*   GL\_NV\_fence (fn1)
+
+## EGL Extensions
+
+*   EGL\_EXT\_create\_context\_robustness
+    *   only reset notifications supported
+*   EGL\_ANGLE\_d3d\_share\_handle\_client\_buffer (fn2)
+*   EGL\_ANGLE\_query\_surface\_pointer
+*   EGL\_ANGLE\_software\_display (fn3)
+*   EGL\_ANGLE\_surface\_d3d\_texture\_2d\_share\_handle (fn2)
+*   EGL\_NV\_post\_sub\_buffer
+
+### Notes
+
+*   fn1: extensions are only exposed if underlying D3D9 device has support for
+    the required features
+*   fn2: extensions are only exposed when running on D3D9Ex (ie Win Vista/7)
+*   fn3: extension is only exposed when swiftshader is present
diff --git a/src/third_party/angle/doc/MANGLE.md b/src/third_party/angle/doc/MANGLE.md
new file mode 100644
index 0000000..2bca69b
--- /dev/null
+++ b/src/third_party/angle/doc/MANGLE.md
@@ -0,0 +1,9 @@
+# M(ulti-platform)ANGLE effort
+
+Starting in early 2014, the ANGLE team has begun work on refactoring the code
+with the goal of supporting translation to desktop OpenGL. The new purpose of
+ANGLE will be provide a consistent OpenGL ES and EGL context on as many
+platforms as possible.
+
+The design doc is available [here]
+(https://docs.google.com/document/d/17mxRfzXuEWyvGM3t2KqVY4svvfRj_GzysOEpmnDpqeo/edit?usp=sharing).
diff --git a/src/third_party/angle/doc/ResourceLimits.md b/src/third_party/angle/doc/ResourceLimits.md
new file mode 100644
index 0000000..bc44a49
--- /dev/null
+++ b/src/third_party/angle/doc/ResourceLimits.md
@@ -0,0 +1,34 @@
+# Resource Limits
+
+OpenGL ES 2.0 API is quite powerful but there are still some features that are
+optional or allow for wide variability between implementations.
+
+Applications that need more than the minimum values for these limits should
+query the capabilities of the GL device and scale their usage based on the
+device’s feature set. Failing to do so and assuming sufficient limits typically
+results in reduced portability.
+
+The various implementation dependent limits can be found in Tables 6.18 – 6.20
+of the [OpenGL ES 2.0.25 specification]
+(http://www.khronos.org/registry/gles/specs/2.0/es_full_spec_2.0.25.pdf).
+
+# Capabilities
+
+Capability                                 | ES 2.0 Minimum | ANGLE            | SM2   | SM3      | SM4+
+:----------------------------------------- | :------------- | :--------------- | :---- | :------- | :-------
+GL\_MAX\_VERTEX\_ATTRIBS                   | 8              | 16               |       |          |
+GL\_MAX\_VERTEX\_UNIFORM\_VECTORS          | 128            | 254              |       |          |
+GL\_MAX\_VERTEX\_TEXTURE\_IMAGE\_UNITS     | 0              | (fn1)            | 0     | 0        | 4
+GL\_MAX\_VARYING\_VECTORS                  | 8              | (fn1)            | 8     | 10       | 10
+GL\_MAX\_FRAGMENT\_UNIFORM\_VECTORS        | 16             | (fn1)            | 29    | 221      | 221
+GL\_MAX\_TEXTURE\_IMAGE\_UNITS             | 8              | 16               |       |          |
+GL\_MAX\_TEXTURE\_SIZE                     | 64             | 2048-16384 (fn1) |       |          |
+GL\_MAX\_CUBE\_MAP\_SIZE                   | 16             | 2048-16384 (fn1) |       |          |
+GL\_MAX\_RENDERBUFFER\_SIZE                | 1              | 2048-16384 (fn1) |       |          |
+GL\_ALIASED\_POINT\_SIZE\_RANGE (min, max) | (1, 1)         | (fn2)            | (1,1) | (1, fn2) | (1, fn2)
+GL\_ALIASED\_LINE\_WIDTH\_RANGE (min, max) | (1, 1)         | (1, 1)           |       |          |
+
+## Notes
+
+*   fn1: limits vary based on the underlying hardware capabilities
+*   fn2: on SM3 or better hardware the max point size is D3DCAPS9.MaxPointSize
diff --git a/src/third_party/angle/doc/SourceAccess.md b/src/third_party/angle/doc/SourceAccess.md
new file mode 100644
index 0000000..89a5b18
--- /dev/null
+++ b/src/third_party/angle/doc/SourceAccess.md
@@ -0,0 +1,15 @@
+# ANGLE Source Code
+
+# Browsing
+
+ANGLE's source no longer resides at code.google.com! To browse the ANGLE source,
+please visit https://chromium.googlesource.com/angle/angle
+
+# Checkout
+
+You may clone the ANGLE repository with:
+
+> `git clone https://chromium.googlesource.com/angle/angle`
+
+For full instructions on setting up your system with the necessary prerequisites
+for development with ANGLE, please see the DevSetup page.
diff --git a/src/third_party/angle/doc/Update20120704.md b/src/third_party/angle/doc/Update20120704.md
new file mode 100644
index 0000000..c3d8033
--- /dev/null
+++ b/src/third_party/angle/doc/Update20120704.md
@@ -0,0 +1,119 @@
+# ANGLE Development Update - July 4, 2012
+
+We haven't posted an update on the development status of ANGLE in quite some
+time and we'd like to provide an update on some of the new features and
+improvements that we've been working on.
+
+## Conformance
+
+As announced in the [Chromium Blog]
+(http://blog.chromium.org/2011/11/opengl-es-20-certification-for-angle.html),
+ANGLE v1.0 has passed the Khronos OpenGL ES 2.0 certification process and is now
+a [conformant](http://www.khronos.org/conformance/adopters/conformant-products/)
+OpenGL ES 2.0 implementation.
+
+## Extensions
+
+We have recently completed the implementation of depth texture support
+([ANGLE\_depth\_texture]
+(https://code.google.com/p/angleproject/source/browse/extensions/ANGLE_depth_texture.txt?name=master))
+and earlier in the year we added support for instancing via attribute array
+divisors ([ANGLE\_instanced\_arrays]
+(https://code.google.com/p/angleproject/source/browse/extensions/ANGLE_instanced_arrays.txt?name=master)).
+See ExtensionSupport for a complete list of extensions that are supported by
+ANGLE.
+
+## Shader Compiler
+
+We have also made a number of improvements in the shader compiler.
+
+* We addressed a number of defects related to scoping differences between HLSL and
+GLSL and improved the scoping support in ANGLE's compiler front-end. We also
+worked with The Khronos Group to get an ESSL spec bug fixed and several items
+clarified.
+* We addressed a number of correctness issues in the GLSL to HLSL
+translation process. We fixed some bugs related to constant propagation and
+comma conditional assignments. More importantly, we fully implemented support
+for short-circuiting boolean logic operations. In GLSL, Boolean expressions do
+short-circuit evaluation as in C, but HLSL evaluates them entirely. This only
+has an observable effect if a short-circuited operation has side effects, such
+as a function call that modifies global variables.
+* We implemented detection
+for discontinuous gradient or derivative computations inside loops and replace
+them with explicitly defined continuous behaviour. HLSL and GLSL differ in their
+specified behaviour for operations which compute gradients or derivatives.
+Gradients are computed by texture sampling functions which don't specify a
+specific mipmap LOD level, and by the OES\_standard\_derivatives built-in
+functions. To determine the gradient, the corresponding values in neighbouring
+pixels are differentiated. If neighbouring pixels execute different paths
+through the shader this can cause a discontinuity in the gradient. GLSL
+specifies that in these cases the gradient is undefined. HLSL tries to avoid the
+discontinuity in the compiler by unrolling loops so that every pixel executes
+all iterations. This can make the D3D HLSL compiler spend a long time generating
+code permutations, and possibly even fail compilation due to running out of
+instruction slots or registers. Because the GLSL specification allows undefined
+behaviour, we can define such texture sampling functions to use mipmap LOD level
+0, and have the derivatives functions return 0.0. To do this we examine the GLSL
+code's abstract syntax tree and detect whether the shader contains any loops
+with discontinuities and gradient operations. Within such loops, we generate
+HLSL code that uses explicitly defined texture LODs and derivative information.
+One additional consideration is that within these loops there can be calls to
+user-defined functions which may contain gradient operations. In this case, we
+generate variants of user-defined functions where these operations are
+explicitly defined. We use these new functions instead of the original ones in
+loops with discontinuities.
+
+These fixes result in ANGLE being able successfully compile a number of the more
+complex shaders. Unfortunately there are still some complex shaders which we
+have not yet been able to obtain solutions for. Ultimately Direct3D 9 SM3
+shaders are more restricted than what can be expressed in GLSL.  Most of the
+problematic shaders we've encountered will also not compile successfully on
+current ES 2.0 implementations.  We would only be able to achieve parity with
+Desktop GL implementations by using Direct3D 10 or above.
+
+## Texture Origin Changes
+
+We have also made a major change to ANGLE in the way the origin difference
+between D3D and OpenGL is handled. This difference is normally observable when
+using render-to-texture techniques, and if not accounted for, it would appear
+that images rendered to textures are upside down. In recent versions of ANGLE
+(r536 (on Google Code)-r1161 (on Google Code)), we have been storing surfaces
+following the D3D Y convention where (0, 0) is the top-left, rather than GL's
+bottom-left convention. This was done by vertically flipping textures on load
+and then adjusting the texture coordinates in the shaders to compensate. This
+approach worked well, but it did leave the orientation of pbuffers inverted when
+compared to native GL implementations. As of ANGLE r1162 (on Google Code), we
+have changed this back to the original way it was implemented - textures are
+loaded and stored in the GL orientation, and the final rendered scene is flipped
+when it is displayed to a window by eglSwapBuffers. This should be essentially
+transparent to applications except that orientation of pbuffers will change.  In
+addition to fixing the pbuffer orientation, this change:
+
+* eliminates
+dependent-texture look-ups in the shaders, caused by flipping the texture
+y-coordinates
+* rounding of texture coordinates (while previously within spec)
+will be more consistent with other implementations, and
+* allows potential
+faster paths for loading texture data to be implemented. The only potential
+downside to this approach is that window-based rendering may be a bit slower for
+simple scenes. The good news is that this path is not used by browser
+implementations on most versions of Windows.
+
+## Preprocessor
+
+Finally, Alok P. from Google has been working on implementing a new shader
+preprocessor for the last number of months and this effort is nearly complete.
+This new preprocessor should be more robust and much more maintainable. It also
+includes many (~5000) unit tests and passes all WebGL conformance tests. If you
+wish to try this out before it is enabled by default, define
+ANGLE\_USE\_NEW\_PREPROCESSOR=1 in your project settings for the
+translator\_common project.
+
+## Contributions
+
+As always we welcome contributions either in the bug reports (preferably with an
+isolated test-case) or in the form of code contributions. We have added a
+[ContributingCode](ContributingCode.md) wiki page documenting the preferred
+process for contributing code. We do need to ask that you sign a Contributor
+License Agreement before we can integrate your patches.
diff --git a/src/third_party/angle/doc/Update20130618.md b/src/third_party/angle/doc/Update20130618.md
new file mode 100644
index 0000000..81beafd
--- /dev/null
+++ b/src/third_party/angle/doc/Update20130618.md
@@ -0,0 +1,27 @@
+# ANGLE Development Update - June 18, 2013
+
+This week brings some significant changes to ANGLE, which we think are worth
+covering in a development update.
+
+## Migration from svn to git
+
+We've changed our backing version control system from svn to git. Projects and
+contributors pulling from the svn repository will continue to be able to do so,
+but please note that this repository is now read-only, and no further updates
+will be made there. To continue tracking new development and issue fixes, you'll
+need to watch the git repository. Instructions on checking out code from the git
+repository can be found on the [Source Checkout]
+(https://code.google.com/p/angleproject/source/checkout) page.
+
+## DirectX 11 Support
+
+ANGLE now provides both a DirectX 9 and a DirectX 11-backed renderer in the same
+code base. By default, support for the DirectX 11 renderer is disabled, but it
+can be enabled by toggling the value of ANGLE\_ENABLE\_D3D11 as described on the
+DevSetup page. On systems without DirectX 11 support, ANGLE will fall back to
+DirectX 9.
+
+This work originally appeared in our dx11proto branch, which, with the move to
+the new repository, has been promoted to master. Code previously located in the
+trunk of the svn repository will now be located in the git legacy branch, and
+active development will now move to the newly promoted master.
diff --git a/src/third_party/angle/doc/Update20131120.md b/src/third_party/angle/doc/Update20131120.md
new file mode 100644
index 0000000..6a7ba98
--- /dev/null
+++ b/src/third_party/angle/doc/Update20131120.md
@@ -0,0 +1,16 @@
+# ANGLE Development Update - November 20, 2013
+
+ANGLE has undergone a few further migrations in the past week, which we thought
+it important to mention in a front-page update.
+
+The review process for contributed code has moved from [Rietveld]
+(https://codereview.appspot.com/) to [Gerrit]
+(https://chromium-review.googlesource.com). This migration allows us to more
+easily support a Git-centric workflow, and eases the process of accepting
+changes submitted by contributors without commit access to our repositories.
+
+As a result of this change, our repository has also moved from its prior
+location at code.google.com to https://chromium.googlesource.com/angle/angle.
+The repository may still be pulled from its old location, but no further changes
+will be committed there. Updates will be made only to the repository's new
+location.
diff --git a/src/third_party/angle/doc/Update20140325.md b/src/third_party/angle/doc/Update20140325.md
new file mode 100644
index 0000000..763b539
--- /dev/null
+++ b/src/third_party/angle/doc/Update20140325.md
@@ -0,0 +1,30 @@
+# ES 3.0 Development Branch merging
+
+ANGLE will soon be merging its ES 3.0 development branch to master, to make
+available (and more visible) the changes we've been making over the past several
+months in support of ES 3.0, and to remove divergence between the master and
+development branches.
+
+The previous master branch will still be available as the es2only-legacy branch,
+and SHAs will not change, so dependencies on individual commits of ANGLE will
+continue to work as expected. However, new contributions against es2only-legacy
+will generally not be considered, and future work should be done on master.
+
+This merge doesn't signify completion of ES 3.0, as we have some features still
+left to implement there, but interested developers can explore the work in
+progress. A significant portion of 3.0 features have been implemented,
+including:
+
+* 2D array textures, 3D textures
+* Expanded texture format support
+* Uniform Buffer Objects
+* Vertex Array Objects
+* Sampler objects, expanded sampler types
+* Transform Feedback
+* Texture Swizzle
+* GLSL integer support
+
+ES 3.0 features should not yet be considered stable, even where implemented, and
+some features are present only via naive implementation so far. There is still
+quite a bit of work ahead of us before ES 3.0 support is complete, but this
+merge should provide insight to those interested in what we've been working on!
diff --git a/src/third_party/angle/doc/Update20150105.md b/src/third_party/angle/doc/Update20150105.md
new file mode 100644
index 0000000..f5615c5
--- /dev/null
+++ b/src/third_party/angle/doc/Update20150105.md
@@ -0,0 +1,46 @@
+# Multiplatform ANGLE Refactor Complete
+
+ANGLE's multiplatform refactoring effort ([described here]
+(https://code.google.com/p/angleproject/wiki/MANGLE)) is now complete, paving
+the way for additional rendering backends, allowing ANGLE to enable OpenGL ES
+not just over Direct3D 9 and 11, but also desktop OpenGL.
+
+The refactoring we've done encapsulates D3D-related assumptions and API calls at
+the renderer level, so that no D3D calls are made in the renderer-agnostic
+portions of the codebase, and D3D-specific feature implementations won't be
+included on non-D3D platforms. For example, the creation and maintenance of
+CPU-side copies of texture data, which are required to enable GL-style
+per-mip-level texture creation over D3D's entire-mipchain texture creation API,
+is contained entirely within the D3D renderers, allowing a GL implementation to
+avoid this complication.
+
+Work will now begin within ANGLE to add a desktop OpenGL renderer, and EGL
+implementations compatible with OS X and Linux.
+
+# ES 3.0 Development Status
+
+Our ES 3.0 development branch was merged into mainline ANGLE in April 2014, but
+ES 3.0 support is not yet complete. The majority of API functionality has been
+implemented; features still pending include:
+
+* ETC2/EAC support
+* primitive restart index
+* drawRangeElements
+* full GetProgramBinary support in core
+
+Additional work remains in the compiler, including:
+
+* Array .length()
+* inf/nan detection
+* math utility functions, rounding
+* VertexID/InstanceID support
+* floating point packing functions
+* operators new in ES 3.0
+* name redeclaration
+* relaxed array indexing
+* switch statement support
+* loop & iteration improvements
+
+ES 3.0 features should not be considered stable, even where implemented, and
+some features are present only via naive implementation so far, but we welcome
+bugs filed against this functionality, and thank all our contributors!
diff --git a/src/third_party/angle/doc/VTF.md b/src/third_party/angle/doc/VTF.md
new file mode 100644
index 0000000..ebf3c56
--- /dev/null
+++ b/src/third_party/angle/doc/VTF.md
@@ -0,0 +1,76 @@
+# Vertex Texture Fetch
+
+This page details the steps necessary to implement vertex texture fetch in ANGLE
+and documents some of the pitfalls that may be encountered along the way.
+
+# Details
+
+Tasks to implement vertex texture support.
+
+1.  add/enable vertex shader texture look up functions in compiler & HLSL
+    translator.
+    *   add texture2DLod, texture2DProjLod (2 variants), textureCubeLod (these
+        are **only** valid in vertex shaders)
+    *   ensure other (non-bias/non-LOD) texture functions work in vertex shaders
+    *   non-mipmapped textures use the only level available
+    *   mipmapped textures use only the base level (ie level 0).
+2.  update implementation-dependent constants in Context.h
+    *   MAX\_VERTEX\_TEXTURE\_IMAGE\_UNITS = 4
+    *   MAX\_COMBINED\_TEXTURE\_IMAGE\_UNITS =
+        MAX\_VERTEX\_TEXTURE\_IMAGE\_UNITS + MAX\_TEXTURE\_IMAGE\_UNITS (ie 20).
+    *   these limits have to change based on the d3d device characteristics. For
+        example we likely don't want to advertise vertex image units on SM2.0
+        cards (unless we end up using software vertex processing).
+    *   detection of hardware support for various formats, types, etc.
+    *   As a first pass, use the "hasVertexTextures" check that Aras suggested
+        to only enable VTF on DX10 NVIDIA and AMD parts, and SM3 Intel parts.
+    *   If this proves insufficient, there are other things we can do, but it
+        involves using software vertex processing for unsupported formats and
+        system memory copies of textures -- all stuff which is rather annoying
+        and likely to hurt performance (see point 4. below).
+3.  add support and handling for vertex textures/samplers in the API.
+    *   any textures used in a vertex shader need to get assigned to the special
+        samplers in d3d9
+    *   there are only 4 of them (D3DVERTEXTEXTURESAMPLER0..
+        D3DVERTEXTEXTURESAMPLER3)
+    *   if a texture is used in both vertex & fragment it counts twice against
+        the "MAX\_COMBINED" limit (validated in Program::validateSamplers)
+    *   there are a number of places in our code where we have arrays of size,
+        or iterate over, MAX\_TEXTURE\_IMAGE\_UNITS. These will need to be
+        changed to operate on MAX\_COMBINED\_TEXTURE\_IMAGE\_UNITS instead. A
+        (possibly incomplete & outdated) list of areas that need to be updated
+        is as follows:
+    *   Program.h - increase size of mSamplers
+    *   Context.h - increase size of samplerTexture
+    *   glActiveTexture needs accept values in the range
+        0..MAX\_COMBINED\_TEXTURE\_IMAGE\_UNITS-1
+    *   Context::~Context
+    *   GetIntegerv (2D\_BINDING, CUBE\_BINDING)
+    *   Context::applyTextures
+    *   Context::detachTexture
+    *   Program::getSamplerMapping
+    *   Program::dirtyAllSamplers
+    *   Program::applyUniform1iv
+    *   Program::unlink
+    *   Program::validateSamplers
+4.  handling the nasty corner cases: texture formats, filtering and cube
+    textures.
+    *   OpenGL doesn't provide any restrictions on what formats and/or types of
+        textures can used for vertex textures, or if filtering can be enabled,
+        whereas D3D9 does.
+    *   Reference Rasterizer / Software Vertex Processing: all formats & types
+        supported (including filtering)
+    *   ATI R500 (on Google Code) cards do not support VTF (even though they are
+        SM 3.0)
+    *   ATI R600 (on Google Code) (and later) and in theory the Intel 965+,
+        claim to support all texture formats/types we care about and some with
+        filtering
+    *   NVIDIA cards fall into two camps:
+    *   dx9 SM3 (6&7 series): only R32F & A32B32G32R32F supported for 2D and no
+        filtering, CUBE or VOL texture support
+    *   dx10 (8+ series): only float texture formats for 2D, CUBE & VOLUME. no
+        filtering (according to caps)
+        *   further info from Aras P. suggests that all formats are supported on
+            DX10 hardware, but are just not advertised.
+    *   unsure what they do on these cards under OpenGL. Need to do more
+        testing, but suspect software fallback.
diff --git a/src/third_party/angle/doc/dEQP.md b/src/third_party/angle/doc/dEQP.md
new file mode 100644
index 0000000..8a293b2
--- /dev/null
+++ b/src/third_party/angle/doc/dEQP.md
@@ -0,0 +1,62 @@
+# ANGLE + dEQP
+
+drawElements (dEQP) is a very robust and comprehensive set of open-source
+tests for GLES2, GLES3+ and EGL. They provide a huge net of coverage for
+almost every GL API feature. ANGLE by default builds dEQP testing targets for
+testing against GLES 2, GLES 3, EGL, and GLES 3.1 (on supported platforms).
+
+## How to build dEQP
+
+You should have dEQP as a target if you followed the [DevSetup](DevSetup.md)
+instructions. Current targets:
+
+  * `angle_deqp_gles2_tests` for GLES 2.0 tests
+  * `angle_deqp_gles3_tests` for GLES 3.0 tests
+  * `angle_deqp_egl_tests` for EGL 1.x tests
+  * `angle_deqp_gles31_tests` for GLES 3.1 tests (currently very experimental)
+
+## How to use dEQP
+
+The `--deqp-case` flag allows you to run individual tests, with simple
+wildcard support. For example: `--deqp-case=dEQP-
+GLES2.functional.shaders.linkage.*`.
+
+The tests lists are sourced from the Android CTS masters in
+`third_party/deqp/src/android/cts/master`. See `gles2-master.txt`,
+`gles3-master.txt`, `gles31-master.txt` and `egl-master.txt`.
+
+If you're running a full test suite, it might take very long time. Running in
+Debug is only useful to isolate and fix particular failures, Release will give
+a better sense of total passing rate.
+
+### Choosing a Renderer on Windows
+
+By default Windows ANGLE tests with D3D11. To specify the exact platform for
+ANGLE + dEQP, use the arguments:
+
+  * `--deqp-egl-display-type=angle-d3d11` for D3D11 (highest available feature level)
+  * `--deqp-egl-display-type=angle-d3d9` for D3D9
+  * `--deqp-egl-display-type=angle-d3d11-fl93` for D3D11 Feature level 9_3
+  * `--deqp-egl-display-type=angle-gl` for OpenGL Desktop (OSX, Linux and Windows)
+  * `--deqp-egl-display-type=angle-gles` for OpenGL ES (Android/ChromeOS, some Windows platforms)
+
+### Check your results
+
+If run from Visual Studio 2015, dEQP generates a test log to
+`src/tests/TestResults.qpa`. To view the test log information, you'll need to
+use the open-source GUI
+[Cherry](https://android.googlesource.com/platform/external/cherry). ANGLE
+checks out a copy of Cherry to `angle/third_party/cherry` when you sync with
+gclient. Note, if you are using ninja or another build system, the qpa file
+will be located in your working directory.
+
+See the [official Cherry README](https://android.googlesource.com/platform/ext
+ernal/cherry/+/master/README) for instructions on how to run Cherry on Linux
+or Windows.
+
+### GoogleTest, ANGLE and dEQP
+
+ANGLE also supports the same set of targets built with GoogleTest, for running
+on the bots. We don't currently recommend using these for local debugging, but
+we do maintain lists of test expectations in `src/tests/deqp_support`. When
+you fix tests, please remove the suppression(s) from the relevant files!
diff --git a/src/third_party/angle/extensions/ANGLE_client_arrays.txt b/src/third_party/angle/extensions/ANGLE_client_arrays.txt
new file mode 100644
index 0000000..1922b34
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_client_arrays.txt
@@ -0,0 +1,100 @@
+Name
+
+    ANGLE_client_arrays
+
+Name Strings
+
+    GL_ANGLE_client_arrays
+
+Contributors
+
+    Geoff Lang
+
+Contact
+
+    Geoff Lang (geofflang 'at' google.com)
+
+Notice
+
+    Copyright (c) 2016 The Khronos Group Inc. Copyright terms at
+        http://www.khronos.org/registry/speccopyright.html
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, February 13, 2016
+
+Number
+
+    OpenGL ES Extension #??
+
+Dependencies
+
+    Requires OpenGL ES 2.0
+
+    Written against the OpenGL ES 2.0 specification.
+
+Overview
+
+    This extension allows the OpenGL context to indicate if it supports drawing
+    with client-side vertex or index data.  Client-side can be very inefficient
+    and unsafe, it is convenient for some users to completely disable its usage.
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted by the <cap> parameter to IsEnabled and the <pname> parameter to
+    GetBooleanv, GetIntegerv, GetFloatv, and GetInteger64v:
+
+    CLIENT_ARRAYS_ANGLE                 0x93AA
+
+Additions to the OpenGL ES Specification
+
+    Add after paragraph 3 of section 2.8 "Vertex Arrays":
+
+    If VertexAttribPointer is called while zero is bound to the ARRAY_BUFFER
+    buffer object binding point, the pointer argument is not NULL, and
+    CLIENT_ARRAYS_ANGLE is TRUE, an INVALID_OPERATION error is generated.
+
+    Add to the end of section 2.9.1 "Vertex Arrays in Buffer Objects":
+
+    Rendering commands that draw more than 0 primitives using enabled vertex
+    attributes with no buffer bound when CLIENT_ARRAYS_ANGLE is TRUE generate
+    an INVALID_OPERATION error.
+
+    Add to the end of section 2.9.2 "Array Indices in Buffer Objects":
+
+    Rendering commands that draw more than 0 primitives using index data when
+    no buffer is bound to the ELEMENT_ARRAY_BUFFER binding point when
+    CLIENT_ARRAYS_ANGLE is TRUE generate an INVALID_OPERATION error.
+
+New State
+
+    Modify Table 6.22, Miscellaneous
+
+    Add:
+
+                                          Initial
+    Get Value            Type Get Command Value   Description
+    -------------------- ---- ----------- ------- ---------------------
+    CLIENT_ARRAYS_ANGLE  B    IsEnabled   TRUE    Client arrays enabled
+
+Conformance Tests
+
+    TBD
+
+Issues
+
+    None
+
+Revision History
+
+    Rev.    Date         Author     Changes
+    ----  -------------  ---------  ----------------------------------------
+      1   Feb 13, 2016   geofflang  Initial version
diff --git a/src/third_party/angle/extensions/ANGLE_lossy_etc_decode.txt b/src/third_party/angle/extensions/ANGLE_lossy_etc_decode.txt
new file mode 100644
index 0000000..1488192
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_lossy_etc_decode.txt
@@ -0,0 +1,159 @@
+Name
+
+    ANGLE_lossy_etc_decode
+
+Name Strings
+
+    GL_ANGLE_lossy_etc_decode
+
+Contributors
+
+    Minmin Gong  (mgong 'at' microsoft.com)
+
+Contacts
+
+    Minmin Gong  (mgong 'at' microsoft.com)
+
+Status
+
+    Draft
+
+Version
+
+    Last Modified Date: Nov 25, 2015
+    Author Revision: 1
+
+Number
+
+    TBD
+
+Dependencies
+
+    Requires OpenGL ES 3.0 for ETC2 and EAC formats, or OpenGL ES 2.0 and
+    OES_compressed_ETC1_RGB8_texture for ETC1 format.
+    The extension is written against the OpenGL ES 2.0 specification.
+
+Overview
+
+    Both the OpenGL ES 3.0 specification and OES_compressed_ETC1_RGB8_texture
+    specify that Ericsson Texture Compression (ETC) decoding must not be lossy.
+    The goal of this extension is to allow a lossy decode of
+    compressed textures in the ETC formats in OpenGL ES, for lower memory
+    and bandwidth consumption.
+
+    This extension uses the same ETC compression format as OpenGL ES 3.0
+    and OES_compressed_ETC1_RGB8_texture, with the restriction that the texture
+    dimensions must be a multiple of four (except for mip levels where the
+    dimensions are either 2 or 1). And the requirement that ETC decoding must
+    not be lossy is relaxed.
+
+    See OES_compressed_ETC1_RGB8_texture for a description of the ETC1 format.
+    Also see OpenGL ES 3.0 specification appendix C.2 (ETC Compressed Texture
+    ImageFormats) for a description of ETC2 and EAC formats.
+
+IP Status
+
+    See Ericsson's "IP Statement"
+
+New Procedures and Functions
+
+    None.
+
+New Types
+
+    None.
+
+New Tokens
+
+    Accepted by the <internalformat> parameter of CompressedTexImage2D
+    and the <format> parameter of CompressedTexSubImage2D:
+
+    ETC1_RGB8_LOSSY_DECODE_ANGLE                                  0x9690
+    COMPRESSED_R11_LOSSY_DECODE_EAC_ANGLE                         0x9691
+    COMPRESSED_SIGNED_R11_LOSSY_DECODE_EAC_ANGLE                  0x9692
+    COMPRESSED_RG11_LOSSY_DECODE_EAC_ANGLE                        0x9693
+    COMPRESSED_SIGNED_RG11_LOSSY_DECODE_EAC_ANGLE                 0x9694
+    COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE                       0x9695
+    COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE                      0x9696
+    COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE   0x9697
+    COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE  0x9698
+    COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE                  0x9699
+    COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE           0x969A
+
+Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
+
+    Add the following to Section 3.7.3 (Compressed Texture Images)
+    (at the end of the description of the CompressedTexImage2D command):
+
+    Compressed Internal Format                                    Base Internal Format
+    ==========================                                    ====================
+    ETC1_RGB8_LOSSY_DECODE_ANGLE                                  RGB
+    COMPRESSED_R11_LOSSY_DECODE_EAC_ANGLE                         R
+    COMPRESSED_SIGNED_R11_LOSSY_DECODE_EAC_ANGLE                  R
+    COMPRESSED_RG11_LOSSY_DECODE_EAC_ANGLE                        RG
+    COMPRESSED_SIGNED_RG11_LOSSY_DECODE_EAC_ANGLE                 RG
+    COMPRESSED_RGB8_LOSSY_DECODE_ETC2_ANGLE                       RGB
+    COMPRESSED_SRGB8_LOSSY_DECODE_ETC2_ANGLE                      RGB
+    COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE   RGBA
+    COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_LOSSY_DECODE_ETC2_ANGLE  RGBA
+    COMPRESSED_RGBA8_LOSSY_DECODE_ETC2_EAC_ANGLE                  RGBA
+    COMPRESSED_SRGB8_ALPHA8_LOSSY_DECODE_ETC2_EAC_ANGLE           RGBA
+
+    Table 3.x: Specific Compressed Internal Formats
+
+    If <internalformat> is one of the ETC lossy decode formats listed in
+    Table 3.x, the compressed texture is stored in an unspecified compressed
+    texture format, that may introduce losses of precision in the texture data.
+    The GL and the ETC texture compression algorithm support only 2D images
+    without borders.
+
+    CompressedTexImage2D will produce the INVALID_OPERATION error when
+    <internalformat> is one of the lossy decode ETC-format values from
+    Table 3.x under the following conditions:
+
+      * <border> is non-zero.
+      * <width> is not one, two, nor a multiple of four.
+      * <height> is not one, two, nor a multiple of four.
+
+    Add the following to Section 3.7.3 (Compressed Texture Images)
+    (at the end of the description of the CompressedTexSubImage2D command):
+
+    If the internal format of the texture image being modified is an ETC-format
+    listed in Table 3.x, the compressed texture is stored in an unspecified
+    compressed texture format. The xoffset and yoffset must also be aligned to
+    4x4 texel block boundaries, since ETC encoding makes it difficult to modify
+    non-aligned regions. CompressedTexSubImage2D will result in an
+    INVALID_OPERATION error only if one of the following conditions occurs:
+
+      * <width> is not a multiple of four nor equal to TEXTURE_WIDTH.
+      * <height> is not a multiple of four nor equal to TEXTURE_HEIGHT.
+      * <xoffset> or <yoffset> is not a multiple of four.
+      * <format> does not match the internal format of the texture image
+        being modified.
+
+Errors
+
+    INVALID_OPERATION is generated by CompressedTexImage2D if
+    lossy decode ETC-format is used and <internalformat> is one of the
+    compressed internal formats from Table 3.x and any of the following apply:
+      - <border> is not equal to zero.
+      - <width> is not one, two, nor a multiple of four.
+      - <height> is not one, two, nor a multiple of four.
+
+    INVALID_OPERATION is generated by CompressedTexSubImage2D if
+    lossy decode ETC-format is used and <format> is one of the compressed
+    interal formats from Table 3.x and any of the following apply:
+      - <width> is not a multiple of four nor equal to TEXTURE_WIDTH;
+      - <height> is not a multiple of four nor equal to TEXTURE_HEIGHT;
+      - <xoffset> or <yoffset> is not a multiple of four;
+      - <format> does not match the internal format of the texture image
+      being modified.
+
+New State
+
+    None.
+
+Revision History
+
+    Revision 1, 2015/11/25 - mgong
+      - Initial revision
diff --git a/src/third_party/angle/extensions/ANGLE_platform_angle.txt b/src/third_party/angle/extensions/ANGLE_platform_angle.txt
new file mode 100644
index 0000000..b39815b
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_platform_angle.txt
@@ -0,0 +1,127 @@
+Name
+
+    ANGLE_platform_angle
+
+Name Strings
+
+    EGL_ANGLE_platform_angle
+
+Contributors
+
+    Scott Graham, Google
+    Shannon Woods, Google
+    Geoff Lang, Google
+
+Contacts
+
+    Scott Graham, Google (scottmg 'at' google 'dot' com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 3, 2014-10-20
+
+Number
+
+    EGL Extension XXX
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires EGL_EXT_client_extensions to query its existence without
+    a display.
+
+    Requires EGL_EXT_platform_base.
+
+    This extension is written against the wording of version 9 of the
+    EGL_EXT_platform_base specification.
+
+    ANGLE_platform_angle_d3d affects the definition of this extension.
+    ANGLE_platform_angle_opengl affects the definition of this extension.
+
+Overview
+
+    This extension defines how to create EGL resources from native resources
+    using the functions defined by EGL_EXT_platform_base.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as the <platform> argument of eglGetPlatformDisplayEXT:
+
+        EGL_PLATFORM_ANGLE_ANGLE                           0x3202
+
+    Accepted as an attribute name in the <attrib_list> argument of
+    eglGetPlatformDisplayEXT:
+
+        EGL_PLATFORM_ANGLE_TYPE_ANGLE                      0x3203
+        EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE         0x3204
+        EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE         0x3205
+
+    Accepted as values for the EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute:
+
+        EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE              0x3206
+
+Additions to the EGL Specification
+
+    None.
+
+New Behavior
+
+    To determine if the EGL implementation supports this extension, clients
+    should query the EGL_EXTENSIONS string of EGL_NO_DISPLAY.
+
+    To obtain an EGLDisplay backed by a ANGLE display, call
+    eglGetPlatformDisplayEXT with <platform> set to EGL_PLATFORM_ANGLE_ANGLE.
+
+    The <native_display> parameter is of type EGLNativeDisplayType. If
+    <native_display> is EGL_DEFAULT_DISPLAY a default display is returned.
+    Multiple calls with the same <native_display> will return the same
+    EGLDisplay handle. If <platform> is set to EGL_PLATFORM_ANGLE_ANGLE and
+    the returned display is in an uninitialized state, its attributes are
+    overwritten by those provided in the <attrib_list>, if any.
+
+    If no <attrib_list> is specified, the value of
+    EGL_PLATFORM_ANGLE_TYPE_ANGLE is implicitly set to
+    EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE.
+
+    If no <attrib_list> is specified, the values of
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE and
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE are implicitly set to
+    EGL_DONT_CARE.
+
+    If EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE is set to EGL_DONT_CARE and
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE is not set to EGL_DONT_CARE,
+    an EGL_BAD_ATTRIBUTE error is generated and EGL_NO_DISPLAY is returned.
+
+    If no display matching the requested <native_display> or of the type
+    requested by the value of EGL_PLATFORM_ANGLE_TYPE_ANGLE is available,
+    EGL_NO_DISPLAY is returned. No error condition is raised in this case.
+
+Issues
+
+    None
+
+Revision History
+
+    Version 1, 2014-02-04 (Scott Graham)
+      - Initial draft
+    Version 2, 2014-06-05 (Geoff Lang)
+      - Rename extension from ANGLE_platform_angle_d3d to ANGLE_platform_angle.
+      - Add sub-extensions for specific platforms.
+    Version 3, 2014-10-20 (Geoff Lang)
+      - Add attributes to request specific feature level and context versions.
+      - Moved descriptions of platforms to child extension specs.
diff --git a/src/third_party/angle/extensions/ANGLE_platform_angle_d3d.txt b/src/third_party/angle/extensions/ANGLE_platform_angle_d3d.txt
new file mode 100644
index 0000000..0c35005
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_platform_angle_d3d.txt
@@ -0,0 +1,140 @@
+Name
+
+    ANGLE_platform_angle_d3d
+
+Name Strings
+
+    EGL_ANGLE_platform_angle_d3d
+
+Contributors
+
+    Shannon Woods, Google
+    Geoff Lang, Google
+
+Contacts
+
+    Geoff Lang, Google (geofflang 'at' chromium 'dot' org)
+
+Status
+
+    Draft
+
+Version
+
+    Version 3, 2014-11-26
+
+Number
+
+    EGL Extension XXX
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires ANGLE_platform_angle.
+
+Overview
+
+    This extension enables selection of D3D display types.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as values for the EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute:
+
+        EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE                 0x3207
+        EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE                0x3208
+
+    Accepted as an attribute name in the <attrib_list> argument of
+    eglGetPlatformDisplayEXT:
+
+        EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE               0x3209
+        EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE     0x320F
+
+    Accepted as values for the EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE attribute:
+
+        EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE      0x320A
+        EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE          0x320B
+        EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE     0x320C
+
+Additions to the EGL Specification
+
+    None.
+
+New Behavior
+
+    To request a display that is backed by Direct3D resources, the value of
+    EGL_PLATFORM_ANGLE_TYPE_ANGLE should be:
+      - EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE for a D3D9 display,
+      - EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE for a D3D11 display.
+
+    To request a specific maximum feature level to be used by the D3D11
+    display, EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE and
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE can be used.  Only feature
+    levels that are capable of supporting all available client APIs will be
+    used unless explicitly requested.
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE and
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE have no effect when requesting
+    a D3D9 display.
+
+    If no <attrib_list> is specified to eglGetPlatformDisplayEXT, the value of
+    EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE is implicitly set to
+    EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE. Otherwise, the value of
+    EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE should be:
+      - EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE to request a hardware
+        accelerated device.
+      - EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE to request an
+        optimized software rasterizer.
+      - EGL_PLATFORM_ANGLE_DEVICE_TYPE_REFERENCE_ANGLE to request a
+        reference rasterizer.
+
+    If EGL_PLATFORM_ANGLE_TYPE_ANGLE is set to
+    EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, the display can automatically respond
+    to trim events from the operating system.  If the attribute
+    EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is unspecified, it is
+    implicitly set to EGL_FALSE.  Otherwise, the value of
+    EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE should be EGL_TRUE or
+    EGL_FALSE.
+
+    If EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE is set to
+    EGL_PLATFORM_ANGLE_DEVICE_TYPE_WARP_ANGLE and EGL_PLATFORM_ANGLE_TYPE_ANGLE
+    is not set to EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE, an EGL_BAD_ATTRIBUTE
+    error is generated and EGL_NO_DISPLAY is returned.
+
+    If EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE is specified when
+    EGL_PLATFORM_ANGLE_TYPE_ANGLE is not EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE
+    or a value other than EGL_TRUE or EGL_FALSE is used, an EGL_BAD_ATTRIBUTE
+    error is generated and EGL_NO_DISPLAY is returned.
+
+Issues
+
+    1) Some multithreaded applications can crash if the display automatically
+       responds to trim events while the application is rendering from another
+       thread.
+
+       RESOLVED: Added an EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE
+       enum to specify if the display should respond to trim events.
+       Applications that do multithreaded rendering should disable automatic
+       trim and handle the trim events on their own.
+
+Revision History
+
+    Version 1, 2014-06-05 (Geoff Lang)
+      - Initial draft
+    Version 2, 2014-10-27 (Geoff Lang)
+      - Separate WARP devices into a new attribute instead of a platform type.
+      - Moved descriptions of platforms and major/minor versions from
+        EGL_ANGLE_platform_angle spec to EGL_ANGLE_platform_angle_d3d.
+    Version 3, 2014-11-26 (Geoff Lang)
+      - Remove the USE_WARP bool and replace it with a DEVICE_TYPE enum.
+    Version 4, 2015-03-11 (Geoff Lang)
+      - Add the ENABLE_AUTOMATIC_TRIM enum.
diff --git a/src/third_party/angle/extensions/ANGLE_platform_angle_null.txt b/src/third_party/angle/extensions/ANGLE_platform_angle_null.txt
new file mode 100644
index 0000000..e9b8ee2
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_platform_angle_null.txt
@@ -0,0 +1,73 @@
+Name
+
+    ANGLE_platform_angle_null
+
+Name Strings
+
+    EGL_ANGLE_platform_angle_null
+
+Contributors
+
+    Geoff Lang, Google
+
+Contacts
+
+    Geoff Lang, Google (geofflang 'at' google 'dot' com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, September 23, 2016
+
+Number
+
+    EGL Extension #??
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires ANGLE_platform_angle.
+
+Overview
+
+    This extension enables selection of null display types which perform state
+    tracking and validation but do not render any content.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as values for the EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute:
+
+        EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE               0x33AE
+
+Additions to the EGL Specification
+
+    None.
+
+New Behavior
+
+    To request a display that performs no rendering and has no platform
+    dependencies, the value of EGL_PLATFORM_ANGLE_TYPE_ANGLE should be
+    EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE.
+
+Issues
+
+    None
+
+Revision History
+
+    Version 1, 2016-09-23 (Geoff Lang)
+      - Initial draft
diff --git a/src/third_party/angle/extensions/ANGLE_platform_angle_opengl.txt b/src/third_party/angle/extensions/ANGLE_platform_angle_opengl.txt
new file mode 100644
index 0000000..9768638
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_platform_angle_opengl.txt
@@ -0,0 +1,84 @@
+Name
+
+    ANGLE_platform_angle_opengl
+
+Name Strings
+
+    EGL_ANGLE_platform_angle_opengl
+
+Contributors
+
+    Shannon Woods, Google
+    Geoff Lang, Google
+
+Contacts
+
+    Geoff Lang, Google (geofflang 'at' chromium 'dot' org)
+
+Status
+
+    Draft
+
+Version
+
+    Version 3, 2014-11-26
+
+Number
+
+    EGL Extension XXX
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires ANGLE_platform_angle.
+
+Overview
+
+    This extension enables selection of OpenGL display types.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as values for the EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute:
+
+        EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE               0x320D
+        EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE             0x320E
+
+Additions to the EGL Specification
+
+    None.
+
+New Behavior
+
+    To request a display that translates to OpenGL or OpenGL ES, the value of
+    EGL_PLATFORM_ANGLE_TYPE_ANGLE should be:
+      - EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE for an OpenGL display,
+      - EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE for a native OpenGL ES display.
+
+    To request a specific maximum context version to use for the underlying
+    API, EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE and
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE can be used.
+
+Issues
+
+    None
+
+Revision History
+
+    Version 1, 2014-06-05 (Geoff Lang)
+      - Initial draft
+    Version 2, 2014-10-27 (Geoff Lang)
+      - Moved descriptions of platforms and major/minor versions from
+        EGL_ANGLE_platform_angle spec to EGL_ANGLE_platform_angle_opengl.
+    Version 3, 2014-11-26 (Geoff Lang)
+      - Updated enum values.
diff --git a/src/third_party/angle/extensions/ANGLE_platform_angle_vulkan.txt b/src/third_party/angle/extensions/ANGLE_platform_angle_vulkan.txt
new file mode 100644
index 0000000..7c426f7
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_platform_angle_vulkan.txt
@@ -0,0 +1,110 @@
+Name
+
+    ANGLE_platform_angle_vulkan
+
+Name Strings
+
+    EGL_ANGLE_platform_angle_vulkan
+
+Contributors
+
+    Jamie Madill, Google
+
+Contacts
+
+    Jamie Madill, Google (jmadill 'at' google 'dot' com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, 2016-11-17
+
+Number
+
+    EGL Extension XXX
+
+Extension Type
+
+    EGL client extension
+
+Dependencies
+
+    Requires ANGLE_platform_angle.
+
+Overview
+
+    This extension enables selection of Vulkan display types.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted as values for the EGL_PLATFORM_ANGLE_TYPE_ANGLE attribute:
+
+        EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE               0x3450
+
+    Accepted as an attribute name in the <attrib_list> argument of
+    eglGetPlatformDisplayEXT:
+
+        EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE   0x3451
+
+Additions to the EGL Specification
+
+    None.
+
+New Behavior
+
+    To request a display that is backed by a Vulkan driver, the value of
+    EGL_PLATFORM_ANGLE_TYPE_ANGLE should be
+    EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE.
+
+    If EGL_PLATFORM_ANGLE_ENABLE_VALIDATION_LAYER_ANGLE is specified, it
+    controls enabling the standard Vulkan validation layers. EGL_TRUE enables
+    the validation and EGL_FALSE disables it. Any value other than these will
+    result in an error. If the flag is not specified, validation may default
+    to either enabled or disabled, depending on compile-time parameters in the
+    implementation.
+
+    If EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE and
+    EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE are not specified, the
+    implementation will decide which version of Vulkan to instantiate. If they
+    are specified, it will choose a version that is lower or equal to the
+    specified major and minor versions. The only current values accepted for
+    major and minor version are 1 for major and 0 for minor.
+
+Issues
+
+    1) Would it be better to specify validation layers individually?
+
+       RESOLVED: It would give more fined grained control, but the layers
+       are sensitive to ordering, and there may be new ones added or old ones
+       removed, this abstracts the logic into a simpler form. The validation
+       layers maintainers are also moving towards a single-layer model from
+       the current multiple layers approach.
+
+    2) Should the validation layers default to on, off, or no guarantee?
+
+       Defaulting to off offers some consistency. However, it's customary for
+       some applications like ANGLE to turn on debugging features by default
+       in Debug builds.
+
+    3) Should ANGLE always instantiate the highest available version of Vulkan?
+
+       RESOLVED: It's possible that in a future implementation of Vulkan there
+       may be driver issues present only on some version of Vulkan, and there's
+       no explicit guarantee higher versions will be more stable. Hence, we should
+       give ANGLE some flexiblity in this regard and leave this unspecified.
+
+Revision History
+
+    Version 1, 2016-11-17 (Jamie Madill)
+      - Initial draft
diff --git a/src/third_party/angle/extensions/ANGLE_request_extension.txt b/src/third_party/angle/extensions/ANGLE_request_extension.txt
new file mode 100644
index 0000000..6536035
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_request_extension.txt
@@ -0,0 +1,116 @@
+Name
+
+    ANGLE_request_extension
+
+Name Strings
+
+    GL_ANGLE_request_extension
+
+Contributors
+
+    Geoff Lang
+
+Contact
+
+    Geoff Lang (geofflang 'at' google.com)
+
+Notice
+
+    Copyright (c) 2016 The Khronos Group Inc. Copyright terms at
+        http://www.khronos.org/registry/speccopyright.html
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, November 28, 2016
+
+Number
+
+    OpenGL ES Extension #??
+
+Dependencies
+
+    Requires OpenGL ES 2.0
+
+    Written against the OpenGL ES 3.0 specification.
+
+Overview
+
+    This extension allows the client to query extensions that can be enabled and
+    explicitly request than an extension be enabled.
+
+New Procedures and Functions
+
+    void RequestExtension(const char *name)
+
+New Tokens
+
+    Accepted by the <name> parameter of GetString and GetStringi:
+
+        REQUESTABLE_EXTENSIONS_ANGLE      0x93A8
+
+    Accepted by the <value> parameter of the GetInteger* functions:
+
+        NUM_REQUESTABLE_EXTENSIONS_ANGLE  0x93A9
+
+Additions to the OpenGL ES 3.0 Specification
+
+    Add the following paragraph to the end paragraph 4 of section 6.1.6, String
+    Queries:
+
+    "REQUESTABLE_EXTENSIONS_ANGLE returns a list of extensions that can be
+    enabled at runtime by calling RequestExtension."
+
+    Change the following section of paragraph 6 of section 6.1.6, String Queries:
+
+    - "name may only be EXTENSIONS, indicating that the extension name
+    - corresponding to the indexth supported extension should be returned.
+    - <index> may range from zero to the value of NUM_EXTENSIONS minus one"
+    + "name may be EXTENSIONS or REQUESTABLE_EXTENSIONS_ANGLE, indicating that
+    + the extension name corresponding to the indexth supported or requestable
+    + extension should be returned. <index> may range from zero to the value of
+    + NUM_EXTENSIONS and NUM_REQUESTABLE_EXTENSIONS_ANGLE minus one"
+
+    The command
+
+       void RequestExtension(const char *name)
+
+    enables the requestable OpenGL ES extension named <name>. If the extension
+    was not requestable, INVALID_OPERATION is generated.
+
+New State
+
+    Add to Table 6.30 (Implementation Dependent Version and Extension Support)
+
+    Get value                        Type Get Cmd     Min Value Description                      Sec.
+    -------------------------------- ---- ----------- --------- -------------------------------- -----
+    NUM_REQUESTABLE_EXTENSIONS_ANGLE Z+   GetIntegerv -         Number of individual requestable 6.1.6
+                                                                extension names
+
+Interactions with the OpenGL ES 2.0 specification:
+
+    Remove all references to GetStringi and NUM_REQUESTABLE_EXTENSIONS_ANGLE.
+
+Issues
+
+    (1) How can the user determine which extensions can be enabled without
+        potentially generating errors?
+
+      This can be solved by:
+      a) Never generate an error in EnableExtensions, simply return false when
+         the extension is not recognized or cannot be enabled.
+      b) Add another query for the extensions that the context supports
+         enabling.
+
+      RESOLVED: Use (b) because it allows the context to explicity advertise
+      which extensions support enabling and doesn't generate errors in the
+      normal use case.
+
+Revision History
+
+    Rev.    Date         Author     Changes
+    ----  -------------  ---------  ----------------------------------------
+      1    Nov 28, 2016  geofflang  Initial version
diff --git a/src/third_party/angle/extensions/ANGLE_robust_client_memory.txt b/src/third_party/angle/extensions/ANGLE_robust_client_memory.txt
new file mode 100644
index 0000000..933deb0
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_robust_client_memory.txt
@@ -0,0 +1,180 @@
+Name
+
+    ANGLE_robust_client_memory
+
+Name Strings
+
+    GL_ANGLE_robust_client_memory
+
+Contributors
+
+    Geoff Lang, Google
+
+Contacts
+
+    Geoff Lang, Google (geofflang 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 4, March 30, 2017
+
+Number
+
+    OpenGL ES Extension #??
+
+Dependencies
+
+    OpenGL ES 2.0 is required.
+
+    This extension is written against the wording of the OpenGL ES
+    3.2 specification.
+
+    Interacts with GL_KHR_debug, GL_EXT_disjoint_timer_queries,
+    GL_KHR_robustness.
+
+Overview
+
+    This extension adds overloads of many OpenGL ES functions that read from
+    and write to client memory to ensure that all reads and writes done by the
+    OpenGL ES implementation are safe.  When the OpenGL ES API is exposed to
+    users through complex bindings such as WebGL, allowing undefined behaviour
+    that may result in crashing the implementation is not acceptable.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    void GetBooleanvRobustANGLE(enum pname, sizei bufSize, sizei *length, boolean *data)
+    void GetBufferParameterivRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetFloatvRobustANGLE(enum pname, sizei bufSize, sizei *length, float *data)
+    void GetFramebufferAttachmentParameterivRobustANGLE(enum target, enum attachment, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetIntegervRobustANGLE(enum pname, sizei bufSize, sizei *length, int *data)
+    void GetProgramivRobustANGLE(uint program, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetRenderbufferParameterivRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetShaderivRobustANGLE(uint shader, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetTexParameterfvRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, float *params)
+    void GetTexParameterivRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetUniformfvRobustANGLE(uint program, int location, sizei bufSize, sizei *length, float *params)
+    void GetUniformivRobustANGLE(uint program, int location, sizei bufSize, sizei *length, int *params)
+    void GetVertexAttribfvRobustANGLE(uint index, enum pname, sizei bufSize, sizei *length, float *params)
+    void GetVertexAttribivRobustANGLE(uint index, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetVertexAttribPointervRobustANGLE(uint index, enum pname, sizei bufSize, sizei *length, void **pointer)
+    void ReadPixelsRobustANGLE(int x, int y, sizei width, sizei height, enum format, enum type, sizei bufSize, sizei *length, sizei *columns, sizei *rows, void *pixels)
+    void TexImage2DRobustANGLE(enum target, int level, int internalformat, sizei width, sizei height, int border, enum format, enum type, sizei bufSize, const void *pixels)
+    void TexParameterfvRobustANGLE(enum target, enum pname, sizei bufSize, const GLfloat *params)
+    void TexParameterivRobustANGLE(enum target, enum pname, sizei bufSize, const GLint *params)
+    void TexSubImage2DRobustANGLE(enum target, int level, int xoffset, int yoffset, sizei width, sizei height, enum format, enum type, sizei bufSize, const void *pixels)
+    void CompressedTexImage2D(enum target, int level, enum internalformat, sizei width, sizei height, int border, sizei imageSize, sizei bufSize, const void* data)
+    void CompressedTexSubImage2D(enum target, int level, int xoffset, int yoffset, sizei width, sizei height, enum format, sizei imageSize, sizei bufSize, const void* data)
+    void CompressedTexImage3D(enum target, int level, enum internalformat, sizei width, sizei height, sizei depth, int border, sizei imageSize, sizei bufSize, const void* data)
+    void CompressedTexSubImage3D(enum target, int level, int xoffset, int yoffset, int zoffset, sizei width, sizei height, sizei depth, enum format, sizei imageSize, sizei bufSize, const void* data)
+
+    void TexImage3DRobustANGLE(enum target, int level, int internalformat, sizei width, sizei height, sizei depth, int border, enum format, enum type, sizei bufSize, const void *pixels);
+    void TexSubImage3DRobustANGLE(enum target, int level, int xoffset, int yoffset, int zoffset, sizei width, sizei height, sizei depth, enum format, enum type, sizei bufSize, const void *pixels);
+    void GetQueryivRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetQueryObjectuivRobustANGLE(uint id, enum pname, sizei bufSize, sizei *length, uint *params)
+    void GetBufferPointervRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, void **params)
+    void GetIntegeri_vRobustANGLE(enum target, uint index, sizei bufSize, sizei *length, int *data)
+    void GetInternalformativRobustANGLE(enum target, enum internalformat, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetVertexAttribIivRobustANGLE(uint index, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetVertexAttribIuivRobustANGLE(uint index, enum pname, sizei bufSize, sizei *length, uint *params)
+    void GetUniformuivRobustANGLE(uint program, int location, sizei bufSize, sizei *length, uint *params)
+    void GetActiveUniformBlockivRobustANGLE(uint program, uint uniformBlockIndex, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetInteger64vRobustANGLE(enum pname, sizei bufSize, sizei *length, int64 *data)
+    void GetInteger64i_vRobustANGLE(enum target, uint index, sizei bufSize, sizei *length, int64 *data)
+    void GetBufferParameteri64vRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, int64 *params)
+    void SamplerParameterivRobustANGLE(uint sampler, enum pname, sizei bufSize, const GLint *param)
+    void SamplerParameterfvRobustANGLE(uint sampler, enum pname, sizei bufSize, const GLfloat *param)
+    void GetSamplerParameterivRobustANGLE(uint sampler, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetSamplerParameterfvRobustANGLE(uint sampler, enum pname, sizei bufSize, sizei *length, float *params)
+
+    void GetFramebufferParameterivRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetProgramInterfaceivRobustANGLE(uint program, enum programInterface, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetBooleani_vRobustANGLE(enum target, uint index, sizei bufSize, sizei *length, boolean *data)
+    void GetMultisamplefvRobustANGLE(enum pname, uint index, sizei bufSize, sizei *length, float *val)
+    void GetTexLevelParameterivRobustANGLE(enum target, int level, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetTexLevelParameterfvRobustANGLE(enum target, int level, enum pname, sizei bufSize, sizei *length, float *params)
+
+    void GetPointervRobustANGLERobustANGLE(enum pname, sizei bufSize, sizei *length, void **params)
+    void ReadnPixelsRobustANGLE(int x, int y, sizei width, sizei height, enum format, enum type, sizei bufSize, sizei *length, sizei *columns, sizei *rows, void *data)
+    void GetnUniformfvRobustANGLE(uint program, int location, sizei bufSize, sizei *length, float *params)
+    void GetnUniformivRobustANGLE(uint program, int location, sizei bufSize, sizei *length, int *params)
+    void GetnUniformuivRobustANGLE(uint program, int location, sizei bufSize, sizei *length, uint *params)
+    void TexParameterIivRobustANGLE(enum target, enum pname, sizei bufSize, const GLint *params)
+    void TexParameterIuivRobustANGLE(enum target, enum pname, sizei bufSize, const GLuint *params)
+    void GetTexParameterIivRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetTexParameterIuivRobustANGLE(enum target, enum pname, sizei bufSize, sizei *length, uint *params)
+    void SamplerParameterIivRobustANGLE(uint sampler, enum pname, sizei bufSize, const GLint *param)
+    void SamplerParameterIuivRobustANGLE(uint sampler, enum pname, sizei bufSize, const GLuint *param)
+    void GetSamplerParameterIivRobustANGLE(uint sampler, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetSamplerParameterIuivRobustANGLE(uint sampler, enum pname, sizei bufSize, sizei *length, uint *params)
+
+    void GetQueryObjectivRobustANGLE(uint id, enum pname, sizei bufSize, sizei *length, int *params)
+    void GetQueryObjecti64vRobustANGLE(uint id, enum pname, sizei bufSize, sizei *length, int64 *params)
+    void GetQueryObjectui64vRobustANGLE(uint id, enum pname, sizei bufSize, sizei *length, uint64 *params)
+
+New Tokens
+
+    None
+
+Additions to the OpenGL ES Specification:
+
+    The xRobustANGLE entry points perform additional validation using <bufSize>
+    to indicate the maximum number of values that can be read from or written
+    to the provided buffer.  INVALID_OPERATION is generated if <bufSize> is not
+    large enough.  The optional <length> specifies an address of a variable to
+    recieve the number of values written to the buffer.  When an error is
+    generated nothing will be written to <length>.
+
+    The <columns> and <rows> parameters of ReadPixelsRobustANGLE and
+    ReadnPixelsRobustANGLE specify addresses of variables to recieve the number
+    of columns and rows of pixels written to the buffer which may be less than
+    the <width> and <height> parameters if they would have read outside of the
+    framebuffer.
+
+    Calls to "xRobustANGLE" will generate errors under the same conditions as
+    "x". Any instances of undefined behaviour in "x" will also be undefined in
+    "xRobustANGLE".  For example, it is invalid to call
+    GetPointervRobustANGLERobustANGLE without first verifying that the context
+    is at least OpenGL ES version 3.2 or the GL_KHR_debug extension is present.
+
+Issues
+
+    1) Should additional entry points be added to specify sizes of client side
+       data provided to the VertexAttribPointer functions?
+
+    2) Should <length> be allowed to be null?
+
+       RESOLVED: Yes, <length> will not be written to when it is a null
+       pointer.
+
+    3) Should <bufSize> be specified in bytes or values (uint, int, float,
+       etc)?
+
+       There is no consistancy in current entry points for this.  For example,
+       glGetnUniformuiv indicates that bufSize is in bytes while GetSynciv
+       uses values despite GetnUniformuiv having a clear value type.
+
+       RESOLOVED: <bufSize> always indicates size in values. Functions that
+       specify data by void* such as TexImage2DRobustANGLE treat the client
+       data as bytes.
+
+    4) Should <length> be written to if an error is generated?
+
+       RESOLVED: No, using the prescedent set by glGetSynciv.
+
+Revision History
+
+    Rev.    Date         Author     Changes
+    ----  -------------  ---------  -------------------------------------------
+      1   Sept 26, 2016  geofflang  Initial version
+      2   Sept 28, 2016  geofflang  Changed name from ANGLE_robust_queries to
+                                    ANGLE_robust_client_memory, added issue 3.
+      3   Oct 7, 2016    geofflang  Added and resolved issue 4.
+      4   Mar 30, 2017   geofflang  Added columns and rows to ReadPixels.
diff --git a/src/third_party/angle/extensions/ANGLE_robust_resource_initialization.txt b/src/third_party/angle/extensions/ANGLE_robust_resource_initialization.txt
new file mode 100644
index 0000000..dbe2828
--- /dev/null
+++ b/src/third_party/angle/extensions/ANGLE_robust_resource_initialization.txt
@@ -0,0 +1,143 @@
+Name
+
+    ANGLE_robust_resource_initialization.txt
+
+Name Strings
+
+    ANGLE_robust_resource_intialization
+
+Contributors
+
+    Geoff Lang, Google
+    Ken Russell, Google
+
+Contacts
+
+    Shannon Woods, Google (shannonwoods 'at' google.com)
+
+Status
+
+    Draft
+
+Version
+
+    Version 1, January 7, 2015
+
+Number
+
+    OpenGL ES Extension TBD
+
+Dependencies
+
+    OpenGL ES 2.0 is required.
+
+    This extension is written against the wording of the OpenGL ES
+    3.1 specification.
+
+    EGL_ANGLE_create_context_robust_initialization is required to request a
+    context that supports this extension, and resource initialization.
+
+Overview
+
+    This extension specifies the behavior for initialization of
+    resources such as textures and buffers to default values. This
+    initialization ensures that access will not be provided by the
+    GL to previously allocated data not owned by the application.
+
+New Types
+
+    None
+
+New Procedures and Functions
+
+    None
+
+New Tokens
+
+    Accepted by the <value> parameter of GetBooleanv, GetIntegerv,
+    GetFloatv, GetDoublev, GetInteger64v, and IsEnabled:
+
+        CONTEXT_ROBUST_RESOURCE_INITIALIZATION_ANGLE    0x93A7
+
+Additions to Chapter 6 of the OpenGL ES 3.1 Specification (Buffer
+Objects)
+
+    Replace the last sentence of the first paragraph of section 6.2
+    "BufferData":
+
+    If <data> is NULL, and robust resource initialization is enabled,
+    the contents of the buffer object's data store are set to zero.
+    Otherwise, the contents of the buffer object's data store are
+    undefined.
+
+Additions to Chapter 8 of the OpenGL ES 3.1 Specification (Textures and
+Samplers)
+
+    Replace the first two sentances of the final paragraph in section
+    8.5.3 "Texture Image Structure":
+
+    If the <data> argument of TexImage2D or TexImage3D is NULL, and the
+    pixel unpack buffer object is zero, a two- or three-dimensional
+    texel array is created with the specified <target>, <level>,
+    <internalformat>, <border>, <width>, <height>, and <depth>. If
+    robust resource initialization is enabled, the contents of the image
+    are initialized as though a zero value were provided for each
+    component of each pixel, and processed and transferred to the GL
+    as described above. The components comprising this zero-filled data
+    are determined by <internalformat>. If robust resource
+    initialization is not enabled, the image contents are undefined, and
+    no pixel processing is performed. In either case, no pixel values
+    are accessed in client memory.
+
+    Replace the first sentence of the fifth paragraph in section 8.8
+    "Multisample Textures":
+
+    Upon success, TexStorage2DMultisample deletes any existing image
+    for target. If robust resource initialization is enabled, the
+    contents of each texel are initialized as though a zero value were
+    written to each channel of each sample; otherwise the contents of
+    texels are undefined.
+
+    Add to the final paragraph of section 8.17 "Immutable-Format Texture
+    Images":
+
+    If robust resource initialization is enabled, the contents of each
+    texel is initialized as though a zero value were provided for each
+    component of each pixel, and processed and transferred to the GL
+    as for a call to the appropriate TexSubImage* call for <target>.
+    Otherwise, the contents of texels are undefined.
+
+Additions to Chapter 9 of the OpenGL ES 3.1 Specification (Framebuffers
+and Framebuffer Objects)
+
+    Replace the sentence in section 9.2.4 "Renderbuffer Objects"
+    beginning "Upon success, RenderbufferStorageMultisample":
+
+    Upon success, RenderbufferStorageMultisample deletes any existing
+    data store for the renderbuffer image. If robust resource
+    initialization is enabled, the contents of each pixel in the data
+    store are initialized as though a zero value was written to each
+    channel of each sample; otherwise, the contents of the data store
+    are undefined.
+
+Interactions with EGL_ANGLE_create_context_robust_resource_initialization
+
+    If the EGL window-system binding API is used to create a context,
+    the EGL_ANGLE_create_context_robust_initialization extension is
+    supported, and the attribute
+    EGL_CONTEXT_ROBUST_RESOURCE_INITIALIZATION_ANGLE is set to
+    EGL_TRUE when eglCreateContext is called, the resulting context
+    will perform robust resource initialization as described above in
+    section <section>, and the
+    CONTEXT_ROBUST_RESOURCE_INITIALIZATION_ANGLE
+    query will return GL_TRUE as described above in section 2.6.1.1.
+    Otherwise queries will return GL_FALSE.
+
+Issues
+
+    None
+
+Revision History
+
+    Version 1, 2015/01/07 - first draft.
+    Version 2, 2017/03/07 - fixed EGL naming and added IsEnabled.
diff --git a/src/third_party/angle/extensions/ANGLE_timer_query.txt b/src/third_party/angle/extensions/ANGLE_timer_query.txt
index 3cc3858..c1371ad 100644
--- a/src/third_party/angle/extensions/ANGLE_timer_query.txt
+++ b/src/third_party/angle/extensions/ANGLE_timer_query.txt
@@ -1,591 +1,591 @@
-Name

-

-    ANGLE_timer_query

-

-Name Strings

-

-    GL_ANGLE_timer_query

-

-Contributors

-

-    Contributors to ARB_occlusion_query

-    Contributors to EXT_timer_query

-    Contributors to ARB_timer_query

-    Ben Vanik, Google Inc.

-    Daniel Koch, TransGaming Inc.

-

-Contact

-

-    Ben Vanik, Google Inc. (benvanik 'at' google 'dot' com)

-

-Status

-

-    Draft

-

-Version

-

-    Last Modified Date: Apr 28, 2011

-    Author Revision: 1

-

-Number

-

-    OpenGL ES Extension #??

-

-Dependencies

-

-    OpenGL ES 2.0 is required.

-

-    The extension is written against the OpenGL ES 2.0 specification.

-

-Overview

-

-    Applications can benefit from accurate timing information in a number of

-    different ways.  During application development, timing information can

-    help identify application or driver bottlenecks.  At run time,

-    applications can use timing information to dynamically adjust the amount

-    of detail in a scene to achieve constant frame rates.  OpenGL

-    implementations have historically provided little to no useful timing

-    information.  Applications can get some idea of timing by reading timers

-    on the CPU, but these timers are not synchronized with the graphics

-    rendering pipeline.  Reading a CPU timer does not guarantee the completion

-    of a potentially large amount of graphics work accumulated before the

-    timer is read, and will thus produce wildly inaccurate results.

-    glFinish() can be used to determine when previous rendering commands have

-    been completed, but will idle the graphics pipeline and adversely affect

-    application performance.

-

-    This extension provides a query mechanism that can be used to determine

-    the amount of time it takes to fully complete a set of GL commands, and

-    without stalling the rendering pipeline.  It uses the query object

-    mechanisms first introduced in the occlusion query extension, which allow

-    time intervals to be polled asynchronously by the application.

-

-IP Status

-

-    No known IP claims.

-

-New Procedures and Functions

-

-    void GenQueriesANGLE(sizei n, uint *ids);

-    void DeleteQueriesANGLE(sizei n, const uint *ids);

-    boolean IsQueryANGLE(uint id);

-    void BeginQueryANGLE(enum target, uint id);

-    void EndQueryANGLE(enum target);

-    void QueryCounterANGLE(uint id, enum target);

-    void GetQueryivANGLE(enum target, enum pname, int *params);

-    void GetQueryObjectivANGLE(uint id, enum pname, int *params);

-    void GetQueryObjectuivANGLE(uint id, enum pname, uint *params);

-    void GetQueryObjecti64vANGLE(uint id, enum pname, int64 *params);

-    void GetQueryObjectui64vANGLE(uint id, enum pname, uint64 *params);

-

-New Tokens

-

-    Accepted by the <pname> parameter of GetQueryivANGLE:

-

-        QUERY_COUNTER_BITS_ANGLE                       0x8864

-        CURRENT_QUERY_ANGLE                            0x8865

-

-    Accepted by the <pname> parameter of GetQueryObjectivANGLE,

-    GetQueryObjectuivANGLE, GetQueryObjecti64vANGLE, and

-    GetQueryObjectui64vANGLE:

-

-        QUERY_RESULT_ANGLE                             0x8866

-        QUERY_RESULT_AVAILABLE_ANGLE                   0x8867

-        

-    Accepted by the <target> parameter of BeginQueryANGLE, EndQueryANGLE, and

-    GetQueryivANGLE:

-

-        TIME_ELAPSED_ANGLE                             0x88BF

-

-    Accepted by the <target> parameter of GetQueryivANGLE and

-    QueryCounterANGLE:

-

-        TIMESTAMP_ANGLE                                0x8E28

-

-Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL ES Operation)

-

-    (Modify table 2.1, Correspondence of command suffix letters to GL argument)

-    Add two new types:

-    

-    Letter Corresponding GL Type

-    ------ ---------------------

-    i64    int64ANGLE

-    ui64   uint64ANGLE

-

-    (Modify table 2.2, GL data types) Add two new types:

-    

-    GL Type       Minimum Bit Width   Description

-    -------       -----------------   -----------------------------

-    int64ANGLE    64                  Signed 2's complement integer

-    uint64ANGLE   64                  Unsigned binary integer

-

-Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)

-

-    Add a new section 5.3 "Timer Queries":

-

-    "5.3  Timer Queries

-

-    Timer queries use query objects to track the amount of time needed to

-    fully complete a set of GL commands, or to determine the current time

-    of the GL.

-    

-    Timer queries are associated with query objects.  The command

-

-      void GenQueriesANGLE(sizei n, uint *ids);

-

-    returns <n> previously unused query object names in <ids>.  These

-    names are marked as used, but no object is associated with them until

-    the first time they are used by BeginQueryANGLE.  Query objects contain

-    one piece of state, an integer result value.  This result value is

-    initialized to zero when the object is created.  Any positive integer

-    except for zero (which is reserved for the GL) is a valid query

-    object name.

-

-    Query objects are deleted by calling

-

-      void DeleteQueriesANGLE(sizei n, const uint *ids);

-

-    <ids> contains <n> names of query objects to be deleted.  After a

-    query object is deleted, its name is again unused.  Unused names in

-    <ids> are silently ignored.

-    If an active query object is deleted its name immediately becomes unused,

-    but the underlying object is not deleted until it is no longer active.

-

-    A timer query can be started and finished by calling

-

-      void BeginQueryANGLE(enum target, uint id);

-      void EndQueryANGLE(enum target);

-

-    where <target> is TIME_ELAPSED_ANGLE.  If BeginQueryANGLE is called

-    with an unused <id>, that name is marked as used and associated with

-    a new query object.

-    

-    If BeginQueryANGLE is called with an <id> of zero, if the active query

-    object name for <target> is non-zero, if <id> is the name of an existing

-    query object whose type does not match <target>, or if <id> is the active

-    query object name for any query type, the error INVALID_OPERATION is

-    generated.  If EndQueryANGLE is called while no query with the same target

-    is in progress, an INVALID_OPERATION error is generated.

-

-    When BeginQueryANGLE and EndQueryANGLE are called with a <target> of

-    TIME_ELAPSED_ANGLE, the GL prepares to start and stop the timer used for

-    timer queries.  The timer is started or stopped when the effects from all

-    previous commands on the GL client and server state and the framebuffer

-    have been fully realized.  The BeginQueryANGLE and EndQueryANGLE commands

-    may return before the timer is actually started or stopped.  When the timer

-    query timer is finally stopped, the elapsed time (in nanoseconds) is

-    written to the corresponding query object as the query result value, and

-    the query result for that object is marked as available.

-

-    If the elapsed time overflows the number of bits, <n>, available to hold

-    elapsed time, its value becomes undefined.  It is recommended, but not

-    required, that implementations handle this overflow case by saturating at

-    2^n - 1.

-

-    The necessary state is a single bit indicating whether an timer

-    query is active, the identifier of the currently active timer

-    query, and a counter keeping track of the time that has passed.

-

-    When the command

-

-         void QueryCounterANGLE(uint id, enum target);

-

-    is called with <target> TIMESTAMP_ANGLE, the GL records the current time

-    into the corresponding query object. The time is recorded after all

-    previous commands on the GL client and server state and the framebuffer

-    have been fully realized. When the time is recorded, the query result for

-    that object is marked available. QueryCounterANGLE timer queries can be

-    used within a BeginQueryANGLE / EndQueryANGLE block where the <target> is

-    TIME_ELAPSED_ANGLE and it does not affect the result of that query object.

-    The error INVALID_OPERATION is generated if the <id> is already in use

-    within a BeginQueryANGLE/EndQueryANGLE block."

-

-Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State

-Requests)

-

-    Add a new section 6.1.9 "Timer Queries":

-

-    "The command

-

-      boolean IsQueryANGLE(uint id);

-

-    returns TRUE if <id> is the name of a query object.  If <id> is zero,

-    or if <id> is