Import Cobalt 10.51583
diff --git a/src/base/base_paths_starboard.cc b/src/base/base_paths_starboard.cc
index 6021b36..e02d2f4 100644
--- a/src/base/base_paths_starboard.cc
+++ b/src/base/base_paths_starboard.cc
@@ -89,6 +89,28 @@
     case base::DIR_HOME:
       // TODO: Add a home directory to SbSystemPathId and get it from there.
       return PathProviderStarboard(base::DIR_CACHE, result);
+
+    case base::DIR_SYSTEM_FONTS:
+#if SB_API_VERSION >= 4
+      if (SbSystemGetPath(kSbSystemPathFontDirectory, path,
+                          SB_ARRAY_SIZE_INT(path))) {
+        *result = FilePath(path);
+        return true;
+      }
+      DLOG(INFO) << "DIR_SYSTEM_FONTS not defined.";
+#endif  // SB_API_VERSION >= 4
+      return false;
+
+    case base::DIR_SYSTEM_FONTS_CONFIGURATION:
+#if SB_API_VERSION >= 4
+      if (SbSystemGetPath(kSbSystemPathFontConfigurationDirectory, path,
+                          SB_ARRAY_SIZE_INT(path))) {
+        *result = FilePath(path);
+        return true;
+      }
+      DLOG(INFO) << "DIR_SYSTEM_FONTS_CONFIGURATION not defined.";
+#endif  // SB_API_VERSION >= 4
+      return false;
   }
 
   return false;
diff --git a/src/base/base_paths_starboard.h b/src/base/base_paths_starboard.h
index cfa9099..c8c6ec1 100644
--- a/src/base/base_paths_starboard.h
+++ b/src/base/base_paths_starboard.h
@@ -31,6 +31,18 @@
   DIR_HOME,     // The root of the primary directory for a user (and their
                 // programs) to place their personal files.
 
+  DIR_SYSTEM_FONTS,                // Directory where system font files can be
+                                   // be found. This is only specified on
+                                   // platforms that provide fonts usable by
+                                   // Starboard applications.
+
+  DIR_SYSTEM_FONTS_CONFIGURATION,  // Directory where system font configuration
+                                   // metadata can be found. May be the same
+                                   // directory as DIR_SYSTEM_FONTS, but not
+                                   // necessarily. This is only specified on
+                                   // platforms that provide fonts usable by
+                                   // Starboard applications.
+
   PATH_STARBOARD_END
 };
 
diff --git a/src/cobalt/base/base.gyp b/src/cobalt/base/base.gyp
index 629d727..4753208 100644
--- a/src/cobalt/base/base.gyp
+++ b/src/cobalt/base/base.gyp
@@ -23,6 +23,7 @@
       'sources': [
         'accessibility_changed_event.h',
         'address_sanitizer.h',
+        'camera_transform.h',
         'clock.h',
         'cobalt_paths.h',
         'compiler.h',
diff --git a/src/cobalt/base/camera_transform.h b/src/cobalt/base/camera_transform.h
new file mode 100644
index 0000000..ef0fafa
--- /dev/null
+++ b/src/cobalt/base/camera_transform.h
@@ -0,0 +1,64 @@
+// 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_BASE_CAMERA_TRANSFORM_H_
+#define COBALT_BASE_CAMERA_TRANSFORM_H_
+
+#include "base/optional.h"
+#include "third_party/glm/glm/mat4x4.hpp"
+
+namespace base {
+
+// CameraTransform holds the affine transformations needed to apply a
+// camera viewing a 3D scene.
+class CameraTransform {
+ public:
+  struct ProjectionAndView {
+    glm::mat4 projection_matrix;
+    glm::mat4 view_matrix;
+  };
+
+  ProjectionAndView left_eye_or_mono;
+  base::optional<ProjectionAndView> right_eye;  // For stereoscopic cameras.
+
+  CameraTransform(glm::mat4 left_eye_or_mono_projection_matrix,
+                  glm::mat4 left_eye_or_mono_view_matrix,
+                  glm::mat4 right_eye_projection_matrix,
+                  glm::mat4 right_eye_view_matrix) {
+    left_eye_or_mono.projection_matrix = left_eye_or_mono_projection_matrix;
+    left_eye_or_mono.view_matrix = left_eye_or_mono_view_matrix;
+    right_eye = ProjectionAndView();
+    right_eye->projection_matrix = right_eye_projection_matrix;
+    right_eye->view_matrix = right_eye_view_matrix;
+  }
+
+  CameraTransform(glm::mat4 left_eye_or_mono_projection_matrix,
+                  glm::mat4 left_eye_or_mono_view_matrix) {
+    left_eye_or_mono.projection_matrix = left_eye_or_mono_projection_matrix;
+    left_eye_or_mono.view_matrix = left_eye_or_mono_view_matrix;
+  }
+};
+
+// Structure to keep track of the current orientation state.
+struct CameraOrientation {
+  CameraOrientation() : roll(0.0f), pitch(0.0f), yaw(0.0f) {}
+
+  float roll;
+  float pitch;
+  float yaw;
+};
+
+}  // namespace base
+
+#endif  // COBALT_BASE_CAMERA_TRANSFORM_H_
diff --git a/src/cobalt/browser/application.cc b/src/cobalt/browser/application.cc
index 77ecccd..108115a 100644
--- a/src/cobalt/browser/application.cc
+++ b/src/cobalt/browser/application.cc
@@ -363,9 +363,16 @@
   options->renderer_module_options.skia_cache_size_in_bytes =
       static_cast<int>(auto_mem.skia_cache_size_in_bytes()->value());
 
-  options->renderer_module_options.skia_texture_atlas_dimensions =
+  const memory_settings::TextureDimensions skia_glyph_atlas_texture_dimensions =
       auto_mem.skia_atlas_texture_dimensions()->value();
 
+  // Right now the bytes_per_pixel is assumed in the engine. Any other value
+  // is currently forbidden.
+  DCHECK_EQ(2, skia_glyph_atlas_texture_dimensions.bytes_per_pixel());
+  options->renderer_module_options.skia_glyph_texture_atlas_dimensions =
+      math::Size(skia_glyph_atlas_texture_dimensions.width(),
+                 skia_glyph_atlas_texture_dimensions.height());
+
   options->web_module_options.javascript_options.gc_threshold_bytes =
       static_cast<size_t>(auto_mem.javascript_gc_threshold_in_bytes()->value());
 
diff --git a/src/cobalt/browser/browser.gyp b/src/cobalt/browser/browser.gyp
index db75521..9ec2956 100644
--- a/src/cobalt/browser/browser.gyp
+++ b/src/cobalt/browser/browser.gyp
@@ -35,10 +35,14 @@
         'memory_settings/build_settings.h',
         'memory_settings/calculations.cc',
         'memory_settings/calculations.h',
+        'memory_settings/constants.h',
         'memory_settings/memory_settings.cc',
         'memory_settings/memory_settings.h',
         'memory_settings/pretty_print.cc',
         'memory_settings/pretty_print.h',
+        'memory_settings/table_printer.cc',
+        'memory_settings/table_printer.h',
+        'memory_settings/texture_dimensions.h',
         'memory_tracker/tool.cc',
         'memory_tracker/tool.h',
         'memory_tracker/tool/buffered_file_writer.cc',
@@ -200,6 +204,8 @@
         'memory_settings/calculations_test.cc',
         'memory_settings/pretty_print_test.cc',
         'memory_settings/memory_settings_test.cc',
+        'memory_settings/table_printer_test.cc',
+        'memory_settings/test_common.h',
         'memory_tracker/tool/tool_impl_test.cc',
         'memory_tracker/tool/util_test.cc',
       ],
diff --git a/src/cobalt/browser/browser_module.cc b/src/cobalt/browser/browser_module.cc
index fb03d85..50c5e80 100644
--- a/src/cobalt/browser/browser_module.cc
+++ b/src/cobalt/browser/browser_module.cc
@@ -198,6 +198,14 @@
       new h5vcc::H5vcc(settings, window, mutation_observer_task_manager));
 }
 
+renderer::RendererModule::Options RendererModuleWithCameraOptions(
+    renderer::RendererModule::Options options,
+    scoped_refptr<input::Camera3D> camera_3d) {
+  options.get_camera_transform = base::Bind(
+      &input::Camera3D::GetCameraTransformAndUpdateOrientation, camera_3d);
+  return options;  // Copy.
+}
+
 }  // namespace
 
 BrowserModule::BrowserModule(const GURL& url,
@@ -215,7 +223,13 @@
 #if defined(OS_STARBOARD)
       is_rendered_(false),
 #endif  // OS_STARBOARD
-      renderer_module_(system_window, options.renderer_module_options),
+      input_device_manager_(input::InputDeviceManager::CreateFromWindow(
+          base::Bind(&BrowserModule::OnKeyEventProduced,
+                     base::Unretained(this)),
+          system_window)),
+      renderer_module_(system_window, RendererModuleWithCameraOptions(
+                                          options.renderer_module_options,
+                                          input_device_manager_->camera_3d())),
 #if defined(ENABLE_GPU_ARRAY_BUFFER_ALLOCATOR)
       array_buffer_allocator_(new ResourceProviderArrayBufferAllocator(
           renderer_module_.pipeline()->GetResourceProvider())),
@@ -247,8 +261,7 @@
           kScreenshotCommandShortHelp, kScreenshotCommandLongHelp)),
 #endif  // defined(ENABLE_SCREENSHOT)
 #endif  // defined(ENABLE_DEBUG_CONSOLE)
-      ALLOW_THIS_IN_INITIALIZER_LIST(
-          h5vcc_url_handler_(this, system_window)),
+      ALLOW_THIS_IN_INITIALIZER_LIST(h5vcc_url_handler_(this, system_window)),
       web_module_options_(options.web_module_options),
       has_resumed_(true, false),
 #if defined(COBALT_CHECK_RENDER_TIMEOUT)
@@ -315,10 +328,6 @@
   }
 #endif  // ENABLE_DEBUG_CONSOLE && ENABLE_DEBUG_COMMAND_LINE_SWITCHES
 
-  input_device_manager_ = input::InputDeviceManager::CreateFromWindow(
-      base::Bind(&BrowserModule::OnKeyEventProduced, base::Unretained(this)),
-      system_window);
-
 #if defined(ENABLE_DEBUG_CONSOLE)
   debug_console_.reset(new DebugConsole(
       base::Bind(&BrowserModule::QueueOnDebugConsoleRenderTreeProduced,
@@ -433,7 +442,7 @@
 
   options.image_cache_capacity_multiplier_when_playing_video =
       COBALT_IMAGE_CACHE_CAPACITY_MULTIPLIER_WHEN_PLAYING_VIDEO;
-  options.input_poller = input_device_manager_->input_poller();
+  options.camera_3d = input_device_manager_->camera_3d();
   web_module_.reset(new WebModule(
       url, base::Bind(&BrowserModule::QueueOnRenderTreeProduced,
                       base::Unretained(this)),
diff --git a/src/cobalt/browser/browser_module.h b/src/cobalt/browser/browser_module.h
index fcb24ad..8147240 100644
--- a/src/cobalt/browser/browser_module.h
+++ b/src/cobalt/browser/browser_module.h
@@ -262,6 +262,10 @@
   bool is_rendered_;
 #endif  // OS_STARBOARD
 
+  // Wraps input device and produces input events that can be passed into
+  // the web module.
+  scoped_ptr<input::InputDeviceManager> input_device_manager_;
+
   // Sets up everything to do with graphics, from backend objects like the
   // display and graphics context to the rasterizer and rendering pipeline.
   renderer::RendererModule renderer_module_;
@@ -302,10 +306,6 @@
   // Will be signalled when the WebModule's Window.onload event is fired.
   base::WaitableEvent web_module_loaded_;
 
-  // Wraps input device and produces input events that can be passed into
-  // the web module.
-  scoped_ptr<input::InputDeviceManager> input_device_manager_;
-
   // This will be called after the WebModule has been destroyed and recreated,
   // which could occur on navigation.
   base::Closure web_module_recreated_callback_;
diff --git a/src/cobalt/browser/debug_console/console_values.js b/src/cobalt/browser/debug_console/console_values.js
index b0a7c79..2ed232e 100644
--- a/src/cobalt/browser/debug_console/console_values.js
+++ b/src/cobalt/browser/debug_console/console_values.js
@@ -20,7 +20,7 @@
   this.DEFAULT_KEY = 'default';
   // Reduced space-separated list of CVal prefixes to display at start-up.
   this.DEFAULT_ACTIVE_SET =
-      'Cobalt DevTools Memory.CPU Memory.MainWebModule Memory.JS ' +
+      'Cobalt DevTools Memory.CPU Memory.MainWebModule Memory.JS Memory.Font ' +
       'Event.Duration.MainWebModule.KeyDown Renderer.Rasterize.Duration';
 
   var names = window.debugHub.getConsoleValueNames();
diff --git a/src/cobalt/browser/memory_settings/auto_mem.cc b/src/cobalt/browser/memory_settings/auto_mem.cc
index 1c28846..a3df89c 100644
--- a/src/cobalt/browser/memory_settings/auto_mem.cc
+++ b/src/cobalt/browser/memory_settings/auto_mem.cc
@@ -16,6 +16,7 @@
 
 #include "cobalt/browser/memory_settings/auto_mem.h"
 
+#include <algorithm>
 #include <string>
 #include <vector>
 
@@ -23,9 +24,9 @@
 #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/pretty_print.h"
 #include "cobalt/browser/switches.h"
 
@@ -34,27 +35,55 @@
 namespace memory_settings {
 namespace {
 
+int64_t GetTotalCpuMemory() { return SbSystemGetTotalCPUMemory(); }
+
+base::optional<int64_t> GetTotalGpuMemory() {
+  base::optional<int64_t> total_gpu_memory;
+  if (SbSystemHasCapability(kSbSystemCapabilityCanQueryGPUMemoryStats)) {
+    total_gpu_memory = SbSystemGetTotalGPUMemory();
+  }
+  return total_gpu_memory;
+}
+
+// Determines if the string value signals "autoset".
+bool StringValueSignalsAutoset(const std::string& value) {
+  std::string value_lower_case = value;
+  std::transform(value_lower_case.begin(), value_lower_case.end(),
+                 value_lower_case.begin(), ::tolower);
+  bool is_autoset = (value_lower_case == "auto") ||
+                    (value_lower_case == "autoset") ||
+                    (value_lower_case == "-1");
+  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, const CommandLine& cmd_line,
+    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));
 
+  // True when the command line explicitly requests the variable to be autoset.
+  bool force_autoset = false;
+
   // The value is set according to importance:
   // 1) Command line switches are the most important, so set those if they
   //    exist.
   if (cmd_line.HasSwitch(setting_name)) {
     std::string value = cmd_line.GetSwitchValueNative(setting_name);
-    if (output->TryParseValue(MemorySetting::kCmdLine, value)) {
+    if (StringValueSignalsAutoset(value)) {
+      force_autoset = true;
+    } else if (output->TryParseValue(MemorySetting::kCmdLine, value)) {
       return output.Pass();
     }
   }
 
-  // 2) Is there a build setting? Then set to build_setting.
-  if (build_setting) {
+  // 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);
   } else {
     // 3) Otherwise bind to the autoset_value.
@@ -70,71 +99,119 @@
 }
 
 void EnsureValuePositive(DimensionSetting* setting) {
-  const math::Size value = setting->value();
-  if (value.width() < 0 || value.height() < 0) {
-    setting->set_value(setting->source_type(), math::Size(0, 0));
+  const TextureDimensions value = setting->value();
+  if (value.width() < 0 || value.height() < 0 || value.bytes_per_pixel() < 0) {
+    setting->set_value(setting->source_type(), TextureDimensions());
   }
 }
 
+void EnsureTwoBytesPerPixel(DimensionSetting* setting) {
+  TextureDimensions value = setting->value();
+  if (value.bytes_per_pixel() != 2) {
+    LOG(ERROR) << "Only two bytes per pixel are allowed for setting: "
+               << setting->name();
+    value.set_bytes_per_pixel(2);
+    setting->set_value(setting->source_type(), value);
+  }
+}
+
+// Sums up the memory consumption of all memory settings with of the input
+// memory type.
+int64_t SumMemoryConsumption(
+    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 == setting->memory_type()) {
+      sum += setting->MemoryConsumption();
+    }
+  }
+  return sum;
+}
+
 }  // namespace
 
 AutoMem::AutoMem(const math::Size& ui_resolution,
                  const CommandLine& command_line,
                  const BuildSettings& build_settings) {
+  // Set the misc cobalt engine 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);
+
   // Set the ImageCache
   image_cache_size_in_bytes_ = CreateMemorySetting<IntSetting, int64_t>(
-      switches::kImageCacheSizeInBytes, command_line,
+      switches::kImageCacheSizeInBytes,
+      command_line,
       build_settings.cobalt_image_cache_size_in_bytes,
       CalculateImageCacheSize(ui_resolution));
   EnsureValuePositive(image_cache_size_in_bytes_.get());
+  image_cache_size_in_bytes_->set_memory_type(MemorySetting::kGPU);
 
   // Set javascript gc threshold
   javascript_gc_threshold_in_bytes_ = CreateMemorySetting<IntSetting, int64_t>(
-      switches::kJavaScriptGcThresholdInBytes, command_line,
+      switches::kJavaScriptGcThresholdInBytes,
+      command_line,
       build_settings.javascript_garbage_collection_threshold_in_bytes,
       kDefaultJsGarbageCollectionThresholdSize);
   EnsureValuePositive(javascript_gc_threshold_in_bytes_.get());
 
   // Set skia_atlas_texture_dimensions
   skia_atlas_texture_dimensions_ =
-      CreateMemorySetting<DimensionSetting, math::Size>(
-          switches::kSkiaTextureAtlasDimensions, command_line,
+      CreateMemorySetting<DimensionSetting, TextureDimensions>(
+          switches::kSkiaTextureAtlasDimensions,
+          command_line,
           build_settings.skia_texture_atlas_dimensions,
           CalculateSkiaGlyphAtlasTextureSize(ui_resolution));
   // Not available for non-blitter platforms.
   if (build_settings.has_blitter) {
-    skia_atlas_texture_dimensions_->set_value(MemorySetting::kNotApplicable,
-                                              math::Size(0, 0));
+    skia_atlas_texture_dimensions_->set_memory_type(
+        MemorySetting::kNotApplicable);
+  } else {
+    // Skia always uses gpu memory, when enabled.
+    skia_atlas_texture_dimensions_->set_memory_type(MemorySetting::kGPU);
   }
   EnsureValuePositive(skia_atlas_texture_dimensions_.get());
+  EnsureTwoBytesPerPixel(skia_atlas_texture_dimensions_.get());
 
   // Set skia_cache_size_in_bytes
   skia_cache_size_in_bytes_ = CreateMemorySetting<IntSetting, int64_t>(
-      switches::kSkiaCacheSizeInBytes, command_line,
+      switches::kSkiaCacheSizeInBytes,
+      command_line,
       build_settings.skia_cache_size_in_bytes,
       CalculateSkiaCacheSize(ui_resolution));
   // Not available for blitter platforms.
   if (build_settings.has_blitter) {
-    skia_cache_size_in_bytes_->set_value(MemorySetting::kNotApplicable, 0);
+    skia_cache_size_in_bytes_->set_memory_type(MemorySetting::kNotApplicable);
+  } else {
+    // Skia always uses gpu memory, when enabled.
+    skia_cache_size_in_bytes_->set_memory_type(MemorySetting::kGPU);
   }
   EnsureValuePositive(skia_cache_size_in_bytes_.get());
 
   // Set software_surface_cache_size_in_bytes
   software_surface_cache_size_in_bytes_ =
       CreateMemorySetting<IntSetting, int64_t>(
-          switches::kSoftwareSurfaceCacheSizeInBytes, command_line,
+          switches::kSoftwareSurfaceCacheSizeInBytes,
+          command_line,
           build_settings.software_surface_cache_size_in_bytes,
           CalculateSoftwareSurfaceCacheSizeInBytes(ui_resolution));
   // Blitter only feature.
   if (!build_settings.has_blitter) {
-    software_surface_cache_size_in_bytes_->set_value(
-        MemorySetting::kNotApplicable, 0);
+    software_surface_cache_size_in_bytes_->set_memory_type(
+        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::image_cache_size_in_bytes() const {
   return image_cache_size_in_bytes_.get();
 }
@@ -155,11 +232,24 @@
   return software_surface_cache_size_in_bytes_.get();
 }
 
-std::vector<const MemorySetting*> AutoMem::AllMemorySetttings() const {
+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(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());
@@ -167,8 +257,20 @@
 }
 
 std::string AutoMem::ToPrettyPrintString() const {
-  std::vector<const MemorySetting*> all_settings = AllMemorySetttings();
-  return GeneratePrettyPrintTable(all_settings);
+  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(GetTotalCpuMemory(), GetTotalGpuMemory(),
+                            cpu_consumption, gpu_consumption);
+
+  std::string output_str = ss.str();
+  return output_str;
 }
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/auto_mem.h b/src/cobalt/browser/memory_settings/auto_mem.h
index 7d4bd2d..4d81db6 100644
--- a/src/cobalt/browser/memory_settings/auto_mem.h
+++ b/src/cobalt/browser/memory_settings/auto_mem.h
@@ -44,19 +44,23 @@
 
   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;
   const DimensionSetting* skia_atlas_texture_dimensions() const;
   const IntSetting* skia_cache_size_in_bytes() const;
   const IntSetting* software_surface_cache_size_in_bytes() const;
 
-  std::vector<const MemorySetting*> AllMemorySetttings() const;
+  std::vector<const MemorySetting*> AllMemorySettings() const;
+  std::vector<MemorySetting*> AllMemorySettingsMutable();
 
-  // Generates a string table of the memory settings. This is used during
-  // startup to display memory configuration information.
+  // 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;
 
  private:
   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<DimensionSetting> skia_atlas_texture_dimensions_;
   scoped_ptr<IntSetting> skia_cache_size_in_bytes_;
   scoped_ptr<IntSetting> software_surface_cache_size_in_bytes_;
diff --git a/src/cobalt/browser/memory_settings/auto_mem_test.cc b/src/cobalt/browser/memory_settings/auto_mem_test.cc
index 4f6d6d7..b5a2ba5 100644
--- a/src/cobalt/browser/memory_settings/auto_mem_test.cc
+++ b/src/cobalt/browser/memory_settings/auto_mem_test.cc
@@ -22,6 +22,7 @@
 #include "base/optional.h"
 #include "cobalt/browser/memory_settings/build_settings.h"
 #include "cobalt/browser/memory_settings/calculations.h"
+#include "cobalt/browser/memory_settings/test_common.h"
 #include "cobalt/browser/switches.h"
 #include "cobalt/math/size.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -32,8 +33,10 @@
 
 const math::Size kResolution1080p(1920, 1080);
 
-#define EXPECT_MEMORY_SETTING(SETTING, SOURCE, VALUE)                       \
+#define EXPECT_MEMORY_SETTING(SETTING, SOURCE, MEMORY_TYPE, VALUE)          \
   EXPECT_EQ(VALUE, SETTING->value()) << " failure for " << SETTING->name(); \
+  EXPECT_EQ(MEMORY_TYPE, SETTING->memory_type()) << "failure for "          \
+                                                 << SETTING->memory_type(); \
   EXPECT_EQ(SOURCE, SETTING->source_type()) << " failure for "              \
                                             << SETTING->name();
 
@@ -61,43 +64,61 @@
     // image_cache_size_in_bytes and javascript_gc_threshold_in_bytes settings
     // ignore the blitter type.
     EXPECT_MEMORY_SETTING(auto_mem.image_cache_size_in_bytes(),
-                          MemorySetting::kCmdLine, 1234);
+                          MemorySetting::kCmdLine, MemorySetting::kGPU, 1234);
 
     EXPECT_MEMORY_SETTING(auto_mem.javascript_gc_threshold_in_bytes(),
-                          MemorySetting::kCmdLine, 2345);
+                          MemorySetting::kCmdLine, MemorySetting::kCPU, 2345);
 
     // Certain features are only available for the blitter, and some features
     // are disabled, vice versa.
     if (builtin_settings.has_blitter) {
       // When blitter is active then skia_atlas_texture_dimensions are
       // not applicable because this is an OpenGl egl feature.
-      EXPECT_MEMORY_SETTING(auto_mem.skia_atlas_texture_dimensions(),
-                            MemorySetting::kNotApplicable, math::Size(0, 0));
-
+      EXPECT_MEMORY_SETTING(
+          auto_mem.skia_atlas_texture_dimensions(), MemorySetting::kCmdLine,
+          MemorySetting::kNotApplicable, TextureDimensions(0, 0, 0));
       // Skia cache is also an egl-only feature, which is not applicable
       // for blitter.
       EXPECT_MEMORY_SETTING(auto_mem.skia_cache_size_in_bytes(),
+                            MemorySetting::kCmdLine,
                             MemorySetting::kNotApplicable, 0);
 
       EXPECT_MEMORY_SETTING(auto_mem.software_surface_cache_size_in_bytes(),
-                            MemorySetting::kCmdLine, 4567);
+                            MemorySetting::kCmdLine, MemorySetting::kCPU, 4567);
     } else {
       // Skia atlas is an egl-only feature and therefore enabled.
       EXPECT_MEMORY_SETTING(auto_mem.skia_atlas_texture_dimensions(),
-                            MemorySetting::kCmdLine, math::Size(1234, 5678));
+                            MemorySetting::kCmdLine, MemorySetting::kGPU,
+                            TextureDimensions(1234, 5678, 2));
 
       // Skia cache is an egl-only feature therefore it is enabled for egl.
       EXPECT_MEMORY_SETTING(auto_mem.skia_cache_size_in_bytes(),
-                            MemorySetting::kCmdLine, 3456);
+                            MemorySetting::kCmdLine, MemorySetting::kGPU, 3456);
 
       // Software surface cache is a blitter-only feature, therefore disabled
       // in egl.
       EXPECT_MEMORY_SETTING(auto_mem.software_surface_cache_size_in_bytes(),
+                            MemorySetting::kCmdLine,
                             MemorySetting::kNotApplicable, 0);
     }
   }
 }
 
+// Tests the expectation that if the command line specifies that the variable
+// is "autoset" that the builtin setting is overriden.
+TEST(AutoMem, CommandLineSpecifiesAutoset) {
+  CommandLine command_line(CommandLine::NO_PROGRAM);
+  command_line.AppendSwitchASCII(switches::kImageCacheSizeInBytes, "autoset");
+  BuildSettings build_settings;
+  build_settings.cobalt_image_cache_size_in_bytes = 1234;
+
+  AutoMem auto_mem(kResolution1080p, command_line, build_settings);
+
+  EXPECT_MEMORY_SETTING(auto_mem.image_cache_size_in_bytes(),
+                        MemorySetting::kAutoSet, MemorySetting::kGPU,
+                        CalculateImageCacheSize(kResolution1080p));
+}
+
 // Tests that skia atlas texture will be bind to the built in value, iff it has
 // been set.
 TEST(AutoMem, SkiaAtlasTextureAtlasSize) {
@@ -106,7 +127,7 @@
   BuildSettings builtin_settings_with_default;
 
   builtin_settings_with_default.skia_texture_atlas_dimensions =
-      math::Size(1234, 5678);
+      TextureDimensions(1234, 5678, 2);
 
   AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
   AutoMem auto_mem_with_default(kResolution1080p, empty_command_line,
@@ -116,13 +137,14 @@
   // build settings that it will bind to the auto-set value (computed from
   // CalculateSkiaGlyphAtlasTextureSize(...)).
   EXPECT_MEMORY_SETTING(auto_mem.skia_atlas_texture_dimensions(),
-                        MemorySetting::kAutoSet,
+                        MemorySetting::kAutoSet, MemorySetting::kGPU,
                         CalculateSkiaGlyphAtlasTextureSize(kResolution1080p));
 
   // Expect that when the skia_atlas_texture_dimensions is specified in the
   // build settings that it will bind to the final value.
   EXPECT_MEMORY_SETTING(auto_mem_with_default.skia_atlas_texture_dimensions(),
-                        MemorySetting::kBuildSetting, math::Size(1234, 5678));
+                        MemorySetting::kBuildSetting, MemorySetting::kGPU,
+                        TextureDimensions(1234, 5678, 2));
 }
 
 // Tests that software surface cache will be bind to the built in value, iff
@@ -145,11 +167,12 @@
   // CalculateSoftwareSurfaceCacheSizeInBytes(...)).
   EXPECT_MEMORY_SETTING(
       auto_mem.software_surface_cache_size_in_bytes(), MemorySetting::kAutoSet,
+      MemorySetting::kCPU,
       CalculateSoftwareSurfaceCacheSizeInBytes(kResolution1080p));
 
   EXPECT_MEMORY_SETTING(
       auto_mem_with_surface_cache.software_surface_cache_size_in_bytes(),
-      MemorySetting::kBuildSetting, 1234);
+      MemorySetting::kBuildSetting, MemorySetting::kCPU, 1234);
 }
 
 // Tests that skia cache will be bind to the built in value, iff
@@ -165,11 +188,25 @@
                                    builtin_settings_with_default);
 
   EXPECT_MEMORY_SETTING(auto_mem.skia_cache_size_in_bytes(),
-                        MemorySetting::kAutoSet,
+                        MemorySetting::kAutoSet, MemorySetting::kGPU,
                         CalculateSkiaCacheSize(kResolution1080p));
 
   EXPECT_MEMORY_SETTING(auto_mem_with_skia_cache.skia_cache_size_in_bytes(),
-                        MemorySetting::kBuildSetting, 1234);
+                        MemorySetting::kBuildSetting, MemorySetting::kGPU,
+                        1234);
+}
+
+TEST(AutoMem, AllMemorySettingsAreOrderedByName) {
+  CommandLine empty_command_line(CommandLine::NO_PROGRAM);
+  BuildSettings builtin_settings;
+
+  AutoMem auto_mem(kResolution1080p, empty_command_line, builtin_settings);
+
+  std::vector<const MemorySetting*> settings = auto_mem.AllMemorySettings();
+
+  for (size_t i = 1; i < settings.size(); ++i) {
+    ASSERT_LT(settings[i-1]->name(), settings[i]->name());
+  }
 }
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/build_settings.cc b/src/cobalt/browser/memory_settings/build_settings.cc
index 65c646e..32c151e 100644
--- a/src/cobalt/browser/memory_settings/build_settings.cc
+++ b/src/cobalt/browser/memory_settings/build_settings.cc
@@ -16,6 +16,8 @@
 
 #include "cobalt/browser/memory_settings/build_settings.h"
 
+#include "cobalt/browser/memory_settings/constants.h"
+
 namespace cobalt {
 namespace browser {
 namespace memory_settings {
@@ -37,10 +39,10 @@
   return output;
 }
 
-base::optional<math::Size> MakeDimensionsIfPositive(int width, int height) {
-  base::optional<math::Size> output;
-  if ((width > 0) && (height > 0)) {
-    output = math::Size(width, height);
+base::optional<TextureDimensions> MakeDimensionsIfValid(TextureDimensions td) {
+  base::optional<TextureDimensions> output;
+  if ((td.width() > 0) && (td.height() > 0) && td.bytes_per_pixel() > 0) {
+    output = td;
   }
   return output;
 }
@@ -49,6 +51,7 @@
 BuildSettings GetDefaultBuildSettings() {
   BuildSettings settings;
   settings.has_blitter = HasBlitter();
+
   settings.cobalt_image_cache_size_in_bytes =
       MakeValidIfGreaterThanOrEqualToZero(COBALT_IMAGE_CACHE_SIZE_IN_BYTES);
   settings.javascript_garbage_collection_threshold_in_bytes =
@@ -56,8 +59,10 @@
           COBALT_JS_GARBAGE_COLLECTION_THRESHOLD_IN_BYTES);
   settings.skia_cache_size_in_bytes =
       MakeValidIfGreaterThanOrEqualToZero(COBALT_SKIA_CACHE_SIZE_IN_BYTES);
-  settings.skia_texture_atlas_dimensions = MakeDimensionsIfPositive(
-      COBALT_SKIA_GLYPH_ATLAS_WIDTH, COBALT_SKIA_GLYPH_ATLAS_HEIGHT);
+  settings.skia_texture_atlas_dimensions =
+      MakeDimensionsIfValid(TextureDimensions(COBALT_SKIA_GLYPH_ATLAS_WIDTH,
+                                              COBALT_SKIA_GLYPH_ATLAS_HEIGHT,
+                                              kSkiaGlyphAtlasTextureBytesPerPixel));
   settings.software_surface_cache_size_in_bytes =
       MakeValidIfGreaterThanOrEqualToZero(
           COBALT_SOFTWARE_SURFACE_CACHE_SIZE_IN_BYTES);
diff --git a/src/cobalt/browser/memory_settings/build_settings.h b/src/cobalt/browser/memory_settings/build_settings.h
index c57daea..3d71e31 100644
--- a/src/cobalt/browser/memory_settings/build_settings.h
+++ b/src/cobalt/browser/memory_settings/build_settings.h
@@ -18,6 +18,7 @@
 #define COBALT_BROWSER_MEMORY_SETTINGS_BUILD_SETTINGS_H_
 
 #include "base/optional.h"
+#include "cobalt/browser/memory_settings/texture_dimensions.h"
 #include "cobalt/math/size.h"
 #include "starboard/types.h"
 
@@ -31,7 +32,7 @@
   base::optional<int64_t> cobalt_image_cache_size_in_bytes;
   base::optional<int64_t> javascript_garbage_collection_threshold_in_bytes;
   base::optional<int64_t> skia_cache_size_in_bytes;
-  base::optional<math::Size> skia_texture_atlas_dimensions;
+  base::optional<TextureDimensions> skia_texture_atlas_dimensions;
   base::optional<int64_t> software_surface_cache_size_in_bytes;
 };
 
diff --git a/src/cobalt/browser/memory_settings/calculations.cc b/src/cobalt/browser/memory_settings/calculations.cc
index 6111d95..7da7d3e 100644
--- a/src/cobalt/browser/memory_settings/calculations.cc
+++ b/src/cobalt/browser/memory_settings/calculations.cc
@@ -18,6 +18,8 @@
 
 #include <algorithm>
 
+#include "cobalt/browser/memory_settings/build_settings.h"
+#include "cobalt/browser/memory_settings/constants.h"
 #include "cobalt/math/size.h"
 
 namespace cobalt {
@@ -95,7 +97,8 @@
                              kMinImageCacheSize, kMaxImageCacheSize);
 }
 
-math::Size CalculateSkiaGlyphAtlasTextureSize(const math::Size& ui_resolution) {
+TextureDimensions CalculateSkiaGlyphAtlasTextureSize(
+    const math::Size& ui_resolution) {
   // LinearRemap defines a mapping function which will map the number
   // of ui_resolution pixels to the number of texture atlas pixels such that:
   // 1080p (1920x1080) => maps to => 2048x2048 texture atlas pixels
@@ -113,9 +116,13 @@
 
   // Clamp the atlas texture to be within a minimum range.
   math::Size clamped_atlas_texture(
-      std::max<int>(kMinSkiaTextureAtlasWidth, atlas_texture.width()),
-      std::max<int>(kMinSkiaTextureAtlasWidth, atlas_texture.height()));
-  return clamped_atlas_texture;
+      std::max<int>(kMinSkiaGlyphTextureAtlasWidth, atlas_texture.width()),
+      std::max<int>(kMinSkiaGlyphTextureAtlasWidth, atlas_texture.height()));
+
+  TextureDimensions texture_dimensions(clamped_atlas_texture.width(),
+                                       clamped_atlas_texture.height(),
+                                       kSkiaGlyphAtlasTextureBytesPerPixel);
+  return texture_dimensions;
 }
 
 int64_t CalculateSoftwareSurfaceCacheSizeInBytes(
diff --git a/src/cobalt/browser/memory_settings/calculations.h b/src/cobalt/browser/memory_settings/calculations.h
index c90426a..cbb3afb 100644
--- a/src/cobalt/browser/memory_settings/calculations.h
+++ b/src/cobalt/browser/memory_settings/calculations.h
@@ -18,6 +18,7 @@
 #define COBALT_BROWSER_MEMORY_SETTINGS_CALCULATIONS_H_
 
 #include "base/optional.h"
+#include "cobalt/browser/memory_settings/texture_dimensions.h"
 #include "cobalt/math/size.h"
 #include "starboard/types.h"
 
@@ -41,7 +42,8 @@
 // and
 // kMinSkiaTextureAtlasHeight <= output.height() <= kMaxSkiaTextureAtlasHeight
 // will be true.
-math::Size CalculateSkiaGlyphAtlasTextureSize(const math::Size& ui_resolution);
+TextureDimensions CalculateSkiaGlyphAtlasTextureSize(
+    const math::Size& ui_resolution);
 
 // Calculates the SoftwareSurfaceCacheSize given the ui_resolution.
 int64_t CalculateSoftwareSurfaceCacheSizeInBytes(
@@ -51,19 +53,6 @@
 // to be 4MB @ 1080p and scales accordingly.
 int64_t CalculateSkiaCacheSize(const math::Size& ui_resolution);
 
-// These internal values are exposed for testing.
-enum MemorySizes {
-  kMinImageCacheSize = 20 * 1024 * 1024,  // 20mb.
-  kMaxImageCacheSize = 64 * 1024 * 1024,  // 64mb
-
-  kMinSkiaTextureAtlasWidth = 2048,
-  kMinSkiaTextureAtlasHeight = 2048,
-
-  kDefaultJsGarbageCollectionThresholdSize = 1 * 1024 * 1024,  // 1mb
-
-  kMinSkiaCacheSize = 4 * 1024 * 1024,  // 4mb.
-};
-
 }  // 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 935dc41..1d82f58 100644
--- a/src/cobalt/browser/memory_settings/calculations_test.cc
+++ b/src/cobalt/browser/memory_settings/calculations_test.cc
@@ -23,6 +23,9 @@
 
 #include "base/command_line.h"
 #include "base/logging.h"
+#include "cobalt/browser/memory_settings/build_settings.h"
+#include "cobalt/browser/memory_settings/constants.h"
+#include "cobalt/browser/memory_settings/test_common.h"
 #include "cobalt/browser/switches.h"
 #include "starboard/log.h"
 #include "starboard/memory.h"
@@ -111,14 +114,14 @@
 // function (side effect free) and will produce expected results.
 TEST(MemoryCalculations, CalculateSkiaGlyphAtlasTextureSize) {
   math::Size ui_dimensions;
-  math::Size atlas_texture_size;
+  TextureDimensions atlas_texture_size;
 
   // Test that the small resolution of 480p produces a texture atlas
   // that is minimal.
   ui_dimensions = GetDimensions(k480p);
   atlas_texture_size = CalculateSkiaGlyphAtlasTextureSize(ui_dimensions);
-  EXPECT_EQ(kMinSkiaTextureAtlasWidth, atlas_texture_size.width());
-  EXPECT_EQ(kMinSkiaTextureAtlasHeight, atlas_texture_size.height());
+  EXPECT_EQ(kMinSkiaGlyphTextureAtlasWidth, atlas_texture_size.width());
+  EXPECT_EQ(kMinSkiaGlyphTextureAtlasHeight, atlas_texture_size.height());
 
   // Test that expected resolution of 1080p produces a 2048x2048
   // atlas texture.
diff --git a/src/cobalt/browser/memory_settings/constants.h b/src/cobalt/browser/memory_settings/constants.h
new file mode 100644
index 0000000..2826296
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/constants.h
@@ -0,0 +1,45 @@
+/*
+ * 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_CONSTANTS_H_
+#define COBALT_BROWSER_MEMORY_SETTINGS_CONSTANTS_H_
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+// These internal values are exposed for testing.
+enum MemorySizes {
+  // Size of the engine, minus all caches.
+  kMiscCobaltSizeInBytes = 32 * 1024 * 1024,
+
+  kMinImageCacheSize = 20 * 1024 * 1024,  // 20mb.
+  kMaxImageCacheSize = 64 * 1024 * 1024,  // 64mb
+
+  kMinSkiaGlyphTextureAtlasWidth = 2048,
+  kMinSkiaGlyphTextureAtlasHeight = 2048,
+  kSkiaGlyphAtlasTextureBytesPerPixel = 2,
+
+  kDefaultJsGarbageCollectionThresholdSize = 1 * 1024 * 1024,  // 1mb
+
+  kMinSkiaCacheSize = 4 * 1024 * 1024,  // 4mb.
+};
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
+
+#endif  // COBALT_BROWSER_MEMORY_SETTINGS_CONSTANTS_H_
diff --git a/src/cobalt/browser/memory_settings/memory_settings.cc b/src/cobalt/browser/memory_settings/memory_settings.cc
index f6097c4..b71735b 100644
--- a/src/cobalt/browser/memory_settings/memory_settings.cc
+++ b/src/cobalt/browser/memory_settings/memory_settings.cc
@@ -25,6 +25,8 @@
 #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/constants.h"
 #include "cobalt/browser/switches.h"
 #include "nb/lexical_cast.h"
 
@@ -59,17 +61,22 @@
 }  // namespace
 
 MemorySetting::MemorySetting(ClassType type, const std::string& name)
-    : class_type_(type), name_(name), source_type_(kUnset) {}
+    : class_type_(type),
+      name_(name),
+      source_type_(kUnset),
+      memory_type_(kCPU) {}
 
 IntSetting::IntSetting(const std::string& name)
     : MemorySetting(kInt, name), value_() {}
 
 std::string IntSetting::ValueToString() const {
   std::stringstream ss;
-  ss << value_;
+  ss << value();
   return ss.str();
 }
 
+int64_t IntSetting::MemoryConsumption() const { return value(); }
+
 bool IntSetting::TryParseValue(SourceType source_type,
                                const std::string& string_value) {
   bool parse_ok = false;
@@ -89,23 +96,41 @@
 
 std::string DimensionSetting::ValueToString() const {
   std::stringstream ss;
-  ss << value_.width() << "x" << value_.height();
+  TextureDimensions value_data = value();
+  ss << value_data.width() << "x" << value_data.height() << "x"
+     << value_data.bytes_per_pixel();
   return ss.str();
 }
 
+int64_t DimensionSetting::MemoryConsumption() const {
+  return value().TotalBytes();
+}
+
 bool DimensionSetting::TryParseValue(SourceType source_type,
                                      const std::string& string_value) {
   std::vector<ParsedIntValue> int_values = ParseDimensions(string_value);
-  const bool parse_ok = (int_values.size() == 2) && (!int_values[0].error_) &&
-                        (!int_values[1].error_);
-  if (parse_ok) {
-    math::Size rectangle(int_values[0].value_, int_values[1].value_);
-    set_value(source_type, rectangle);
-    return true;
-  } else {
+
+  if ((int_values.size() < 2) || (int_values.size() > 3)) {
     LOG(ERROR) << "Invalid value for parse value setting: " << string_value;
-    return false;
+    return false;  // Parse failed.
   }
+
+  for (size_t i = 0; i < int_values.size(); ++i) {
+    if (int_values[i].error_) {
+      LOG(ERROR) << "Invalid value for parse value setting: " << string_value;
+      return false;  // Parse failed.
+    }
+  }
+
+  const int bytes_per_pixel =
+      int_values.size() == 3 ?
+      int_values[2].value_ : kSkiaGlyphAtlasTextureBytesPerPixel;
+
+  TextureDimensions tex_dimensions(int_values[0].value_, int_values[1].value_,
+                                   bytes_per_pixel);
+
+  set_value(source_type, tex_dimensions);
+  return true;
 }
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/memory_settings.h b/src/cobalt/browser/memory_settings/memory_settings.h
index 1d13aa7..c1e3d80 100644
--- a/src/cobalt/browser/memory_settings/memory_settings.h
+++ b/src/cobalt/browser/memory_settings/memory_settings.h
@@ -22,6 +22,7 @@
 
 #include "base/compiler_specific.h"
 #include "base/optional.h"
+#include "cobalt/browser/memory_settings/texture_dimensions.h"
 #include "cobalt/math/size.h"
 #include "starboard/configuration.h"
 #include "starboard/types.h"
@@ -38,8 +39,9 @@
   // 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, kCmdLine, kBuildSetting, kAutoSet, kNotApplicable };
+  enum SourceType { kUnset, kCmdLine, kBuildSetting, kAutoSet };
   enum ClassType { kInt, kDimensions };
+  enum MemoryType { kCPU, kGPU, kNotApplicable };
 
   virtual std::string ValueToString() const = 0;
   // Returns true if the TryParseValue() succeeded when converting the string
@@ -47,9 +49,17 @@
   virtual bool TryParseValue(SourceType source_type,
                              const std::string& string_value) = 0;
 
+  virtual int64_t MemoryConsumption() const = 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);
@@ -57,6 +67,7 @@
   const ClassType class_type_;
   const std::string name_;
   SourceType source_type_;
+  MemoryType memory_type_;  // Defaults to kCPU.
 
  private:
   // Default constructor for MemorySetting is forbidden. Do not use it.
@@ -70,7 +81,9 @@
   explicit IntSetting(const std::string& name);
 
   std::string ValueToString() const OVERRIDE;
-  int64_t value() const { return value_; }
+  virtual int64_t MemoryConsumption() const OVERRIDE;
+
+  int64_t value() const { return valid() ? value_ : 0; }
   void set_value(SourceType source_type, int64_t val) {
     source_type_ = source_type;
     value_ = val;
@@ -84,14 +97,19 @@
   SB_DISALLOW_COPY_AND_ASSIGN(IntSetting);
 };
 
-// A memory setting for dimensions type values like "2048x4096".
+// A memory setting for dimensions type values like "2048x4096x2" where
+// the first value is width, second is height, and third is bytes_per_pixel.
 class DimensionSetting : public MemorySetting {
  public:
   explicit DimensionSetting(const std::string& name);
 
   std::string ValueToString() const OVERRIDE;
-  math::Size value() const { return value_; }
-  void set_value(SourceType source_type, const math::Size& val) {
+  virtual int64_t MemoryConsumption() const OVERRIDE;
+
+  TextureDimensions value() const {
+    return valid() ? value_ : TextureDimensions();
+  }
+  void set_value(SourceType source_type, const TextureDimensions& val) {
     source_type_ = source_type;
     value_ = val;
   }
@@ -99,7 +117,7 @@
                      const std::string& string_value) OVERRIDE;
 
  private:
-  math::Size value_;
+  TextureDimensions value_;
 
   SB_DISALLOW_COPY_AND_ASSIGN(DimensionSetting);
 };
diff --git a/src/cobalt/browser/memory_settings/memory_settings_test.cc b/src/cobalt/browser/memory_settings/memory_settings_test.cc
index 565d1c1..956965f 100644
--- a/src/cobalt/browser/memory_settings/memory_settings_test.cc
+++ b/src/cobalt/browser/memory_settings/memory_settings_test.cc
@@ -22,6 +22,7 @@
 #include <vector>
 
 #include "base/memory/scoped_ptr.h"
+#include "cobalt/browser/memory_settings/test_common.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cobalt {
@@ -41,9 +42,18 @@
   scoped_ptr<DimensionSetting> rect_setting(new DimensionSetting("dummy"));
   ASSERT_TRUE(
       rect_setting->TryParseValue(MemorySetting::kCmdLine, "1234x5678"));
-  EXPECT_EQ(math::Size(1234, 5678), rect_setting->value());
+  EXPECT_EQ(TextureDimensions(1234, 5678, 2), rect_setting->value());
   EXPECT_EQ(MemorySetting::kCmdLine, rect_setting->source_type());
-  EXPECT_EQ(std::string("1234x5678"), rect_setting->ValueToString());
+  EXPECT_EQ(std::string("1234x5678x2"), rect_setting->ValueToString());
+}
+
+TEST(DimensionSetting, ParseFromStringWithBytesPerPixel) {
+  scoped_ptr<DimensionSetting> rect_setting(new DimensionSetting("dummy"));
+  ASSERT_TRUE(
+      rect_setting->TryParseValue(MemorySetting::kCmdLine, "1234x5678x12"));
+  EXPECT_EQ(TextureDimensions(1234, 5678, 12), rect_setting->value());
+  EXPECT_EQ(MemorySetting::kCmdLine, rect_setting->source_type());
+  EXPECT_EQ(std::string("1234x5678x12"), rect_setting->ValueToString());
 }
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/pretty_print.cc b/src/cobalt/browser/memory_settings/pretty_print.cc
index b153b5f..298fe3f 100644
--- a/src/cobalt/browser/memory_settings/pretty_print.cc
+++ b/src/cobalt/browser/memory_settings/pretty_print.cc
@@ -17,129 +17,25 @@
 #include "cobalt/browser/memory_settings/pretty_print.h"
 
 #include <algorithm>
+#include <string>
 #include <vector>
 
 #include "cobalt/browser/memory_settings/memory_settings.h"
+#include "cobalt/browser/memory_settings/table_printer.h"
 #include "starboard/log.h"
+#include "starboard/string.h"
 
 namespace cobalt {
 namespace browser {
 namespace memory_settings {
 namespace {
 
-class TablePrinter {
- public:
-  struct Row {
-    std::string name;
-    std::string value;
-    std::string source;
-  };
-
-  static std::string ToString(const std::vector<Row>& rows) {
-    // First column is the name, the second is the value, then source.
-    size_t name_col_width = 0;
-    size_t value_col_width = 0;
-    size_t source_col_width = 0;
-
-    for (size_t i = 0; i < rows.size(); ++i) {
-      const Row& row = rows[i];
-      name_col_width = std::max<size_t>(name_col_width, row.name.size());
-      value_col_width = std::max<size_t>(value_col_width, row.value.size());
-      source_col_width = std::max<size_t>(source_col_width, row.source.size());
-    }
-
-    TablePrinter printer(name_col_width, value_col_width, source_col_width);
-
-    std::stringstream output_ss;
-    std::string row_delimiter = printer.MakeDelimiterRow();
-
-    output_ss << printer.MakeHeaderRow() << "\n";
-    output_ss << row_delimiter << "\n";
-
-    for (size_t i = 0; i < rows.size(); ++i) {
-      const Row& row = rows[i];
-      std::string row_str =
-          printer.MakeDataRow(row.name, row.value, row.source);
-      output_ss << row_str << "\n";
-      output_ss << row_delimiter << "\n";
-    }
-
-    return output_ss.str();
+std::string StringifySourceType(const MemorySetting* setting) {
+  if (!setting->valid()) {
+    return "N/A";
   }
 
- private:
-  TablePrinter(size_t name_col_width, size_t value_col_width,
-               size_t source_col_width)
-      : name_col_width_(name_col_width),
-        value_col_width_(value_col_width),
-        source_col_width_(source_col_width) {
-    Init();
-  }
-
-  void Init() {
-    std::stringstream fmt_row_ss;
-    // Example: "| %-30s | %9s | %9s |\n"
-    fmt_row_ss << "| %-" << name_col_width_ << "s | %" << value_col_width_
-               << "s | %" << source_col_width_ << "s |";
-    fmt_data_row_ = fmt_row_ss.str();
-  }
-
-  std::string MakeHeaderRow() const {
-    std::string name_str = "NAME";
-    std::string value_str = "VALUE";
-    std::string source_str = "SOURCE";
-
-    std::stringstream ss;
-    ss << name_str;
-    for (size_t i = 0; i < name_col_width_ + 3 - name_str.size(); ++i) {
-      ss << " ";
-    }
-
-    ss << value_str;
-    for (size_t i = 0; i < value_col_width_ + 3 - value_str.size(); ++i) {
-      ss << " ";
-    }
-
-    ss << source_str;
-    for (size_t i = 0; i < source_col_width_ + 4 - source_str.size(); ++i) {
-      ss << " ";
-    }
-    return ss.str();
-  }
-
-  std::string MakeDataRow(const std::string& name, const std::string& value,
-                          const std::string& source) const {
-    std::string row_str = base::StringPrintf(
-        fmt_data_row_.c_str(), name.c_str(), value.c_str(), source.c_str());
-    return row_str;
-  }
-
-  std::string MakeDelimiterRow() const {
-    std::stringstream ss;
-    ss << "+";
-    for (size_t i = 0; i < name_col_width_ + 2; ++i) {
-      ss << "-";
-    }
-    ss << "+";
-    for (size_t i = 0; i < value_col_width_ + 2; ++i) {
-      ss << "-";
-    }
-    ss << "+";
-    for (size_t i = 0; i < source_col_width_ + 2; ++i) {
-      ss << "-";
-    }
-    ss << "+";
-    return ss.str();
-  }
-
-  const size_t name_col_width_;
-  const size_t value_col_width_;
-  const size_t source_col_width_;
-  std::string fmt_data_row_;
-};
-
-std::string StringifySourceType(MemorySetting::SourceType source_type) {
-  switch (source_type) {
+  switch (setting->source_type()) {
     case MemorySetting::kUnset: {
       return "Unset";
     }
@@ -147,41 +43,121 @@
       return "CmdLine";
     }
     case MemorySetting::kBuildSetting: {
-      return "BuildSetting";
+      return "Build";
     }
     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()) {
+    case MemorySetting::kCPU: {
+      return "CPU";
+    }
+    case MemorySetting::kGPU: {
+      return "GPU";
+    }
     case MemorySetting::kNotApplicable: {
       return "N/A";
     }
   }
 
-  SB_NOTIMPLEMENTED() << "Unimplemented string for type " << source_type;
+  SB_NOTIMPLEMENTED() << "Unimplemented string for memory type: "
+                      << setting->memory_type();
   return "UNKNOWN";
 }
 
+std::string StringifyValue(const MemorySetting* setting) {
+  if (!setting->valid()) {
+    return "N/A";
+  }
+  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);
+}
+
 }  // namespace
 
 std::string GeneratePrettyPrintTable(
     const std::vector<const MemorySetting*>& settings) {
-  std::vector<TablePrinter::Row> rows;
+  TablePrinter printer;
+
+  std::vector<std::string> header;
+  header.push_back("NAME");
+  header.push_back("VALUE");
+  header.push_back("");
+  header.push_back("TYPE");
+  header.push_back("SOURCE");
+  printer.AddRow(header);
 
   for (size_t i = 0; i < settings.size(); ++i) {
     const MemorySetting* setting = settings[i];
 
-    TablePrinter::Row row;
-    row.name = setting->name();
-    row.value = setting->ValueToString();
-    row.source = StringifySourceType(setting->source_type());
-
-    rows.push_back(row);
+    std::vector<std::string> row;
+    row.push_back(setting->name());
+    row.push_back(StringifyValue(setting));
+    if (setting->valid()) {
+      row.push_back(ToMegabyteString(setting->MemoryConsumption()));
+    } else {
+      row.push_back("N/A");
+    }
+    row.push_back(StringifyMemoryType(setting));
+    row.push_back(StringifySourceType(setting));
+    printer.AddRow(row);
   }
 
-  std::string table_string = TablePrinter::ToString(rows);
+  std::string table_string = printer.ToString();
   return table_string;
 }
 
+std::string GenerateMemoryTable(int64_t total_cpu_memory,
+                                base::optional<int64_t> total_gpu_memory,
+                                int64_t settings_cpu_consumption,
+                                int64_t settings_gpu_consumption) {
+  TablePrinter printer;
+  std::vector<std::string> header;
+  header.push_back("TYPE");
+  header.push_back("TOTAL");
+  header.push_back("SETTINGS");
+  printer.AddRow(header);
+
+  std::vector<std::string> data_row;
+  data_row.push_back("CPU");
+  data_row.push_back(ToMegabyteString(total_cpu_memory));
+  data_row.push_back(ToMegabyteString(settings_cpu_consumption));
+  printer.AddRow(data_row);
+  data_row.clear();
+
+  data_row.push_back("GPU");
+
+  std::string total_gpu_consumption_str;
+  if (!total_gpu_memory) {
+    total_gpu_consumption_str = "<UNKNOWN>";
+  } else {
+    total_gpu_consumption_str = ToMegabyteString(*total_gpu_memory);
+  }
+
+  data_row.push_back(total_gpu_consumption_str);
+  data_row.push_back(ToMegabyteString(settings_gpu_consumption));
+  printer.AddRow(data_row);
+  data_row.clear();
+
+  return printer.ToString();
+}
+
 }  // 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 dd533c0..be70421 100644
--- a/src/cobalt/browser/memory_settings/pretty_print.h
+++ b/src/cobalt/browser/memory_settings/pretty_print.h
@@ -17,35 +17,58 @@
 #ifndef COBALT_BROWSER_MEMORY_SETTINGS_PRETTY_PRINT_H_
 #define COBALT_BROWSER_MEMORY_SETTINGS_PRETTY_PRINT_H_
 
-#include <map>
 #include <string>
 #include <vector>
 
-#include "base/string_number_conversions.h"
-#include "base/string_split.h"
-#include "base/stringprintf.h"
 #include "cobalt/browser/memory_settings/memory_settings.h"
+#include "starboard/types.h"
 
 namespace cobalt {
 namespace browser {
 namespace memory_settings {
 
 // Generates a table, ie:
-//    "NAME                                   VALUE       SOURCE          \n"
-//    "+--------------------------------------+-----------+--------------+\n"
-//    "| image_cache_size_in_bytes            |      1234 |      CmdLine |\n"
-//    "+--------------------------------------+-----------+--------------+\n"
-//    "| javascript_gc_threshold_in_bytes     |      1112 |      AutoSet |\n"
-//    "+--------------------------------------+-----------+--------------+\n"
-//    "| skia_atlas_texture_dimensions        | 1234x4567 |      CmdLine |\n"
-//    "+--------------------------------------+-----------+--------------+\n"
-//    "| skia_cache_size_in_bytes             |         0 |          N/A |\n"
-//    "+--------------------------------------+-----------+--------------+\n"
-//    "| software_surface_cache_size_in_bytes |      8910 | BuildSetting |\n"
-//    "+--------------------------------------+-----------+--------------+\n";
+//
+//   NAME                                   VALUE                   TYPE   SOURCE
+//   _______________________________________________________________________________
+//  |                                      |             |         |      |         |
+//  | image_cache_size_in_bytes            |    33554432 | 32.0 MB |  GPU | AutoSet |
+//  |______________________________________|_____________|_________|______|_________|
+//  |                                      |             |         |      |         |
+//  | javascript_gc_threshold_in_bytes     |     8388608 |  8.0 MB |  CPU |   Build |
+//  |______________________________________|_____________|_________|______|_________|
+//  |                                      |             |         |      |         |
+//  | misc_cobalt_engine_size_in_bytes     |    33554432 | 32.0 MB |  CPU |   Build |
+//  |______________________________________|_____________|_________|______|_________|
+//  |                                      |             |         |      |         |
+//  | skia_atlas_texture_dimensions        | 4096x8192x2 | 64.0 MB |  GPU |   Build |
+//  |______________________________________|_____________|_________|______|_________|
+//  |                                      |             |         |      |         |
+//  | skia_cache_size_in_bytes             |     4194304 |  4.0 MB |  GPU |   Build |
+//  |______________________________________|_____________|_________|______|_________|
+//  |                                      |             |         |      |         |
+//  | software_surface_cache_size_in_bytes |         N/A |     N/A |  N/A |     N/A |
+//  |______________________________________|_____________|_________|______|_________|
 std::string GeneratePrettyPrintTable(
     const std::vector<const MemorySetting*>& memory_settings);
 
+// Generates a table, ie:
+//
+//   TYPE   TOTAL      SETTINGS
+//   ____________________________
+//  |      |          |          |
+//  | CPU  | 256.0 MB |  40.0 MB |
+//  |______|__________|__________|
+//  |      |          |          |
+//  | GPU  | 768.0 MB | 100.0 MB |
+//  |______|__________|__________|
+// When optional total_gpu_memory is null then the the value in the output
+// table will be <UNKNOWN>.
+std::string GenerateMemoryTable(int64_t total_cpu_memory,
+                                base::optional<int64_t> total_gpu_memory,
+                                int64_t settings_cpu_consumption,
+                                int64_t settings_gpu_consumption);
+
 }  // 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 079a099..ad5108e 100644
--- a/src/cobalt/browser/memory_settings/pretty_print_test.cc
+++ b/src/cobalt/browser/memory_settings/pretty_print_test.cc
@@ -17,6 +17,7 @@
 #include "cobalt/browser/memory_settings/pretty_print.h"
 
 #include <algorithm>
+#include <map>
 #include <sstream>
 #include <string>
 #include <vector>
@@ -36,77 +37,206 @@
 namespace browser {
 namespace memory_settings {
 
-scoped_ptr<MemorySetting> CreateMemorySetting(
-    MemorySetting::ClassType class_type, MemorySetting::SourceType source_type,
-    const std::string& name, const std::string& value) {
-  scoped_ptr<MemorySetting> setting;
+class TestSettingGroup {
+ public:
+  TestSettingGroup() {}
 
-  switch (class_type) {
-    case MemorySetting::kInt: {
-      setting.reset(new IntSetting(name));
-      break;
-    }
-    case MemorySetting::kDimensions: {
-      setting.reset(new DimensionSetting(name));
-      break;
-    }
-    default: {
-      EXPECT_TRUE(false) << "Unexpected type " << class_type;
-      setting.reset(new IntSetting(name));
-      break;
+  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;
     }
   }
-  EXPECT_TRUE(setting->TryParseValue(source_type, value));
-  return setting.Pass();
+
+  // 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());
+
+  const char* expected_string =
+      " NAME                                   VALUE                   TYPE   SOURCE    \n"
+      " _______________________________________________________________________________ \n"
+      "|                                      |             |         |      |         |\n"
+      "| image_cache_size_in_bytes            |        1234 |  0.0 MB |  GPU | CmdLine |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| javascript_gc_threshold_in_bytes     |        1112 |  0.0 MB |  CPU | AutoSet |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| skia_atlas_texture_dimensions        | 1234x4567x2 | 10.7 MB |  GPU | CmdLine |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| skia_cache_size_in_bytes             |    12345678 | 11.8 MB |  GPU | CmdLine |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| software_surface_cache_size_in_bytes |         N/A |     N/A |  N/A |     N/A |\n"
+      "|______________________________________|_____________|_________|______|_________|\n";
+
+  EXPECT_STREQ(expected_string, actual_string.c_str());
+}
+
+TEST(MemorySettingsPrettyPrint, GenerateMemoryTableWithNoGpuMemory) {
+  const base::optional<int64_t> no_gpu_memory;
+  std::string actual_output =
+      GenerateMemoryTable(256 * 1024 * 1024,  // 256 MB CPU available
+                          no_gpu_memory,
+                          128 * 1024 * 1024,  // 128 MB CPU consumption
+                          0);                 // 0 MB GPU consumption.
+
+  const char* expected_output =
+      " TYPE   TOTAL       SETTINGS   \n"
+      " _____________________________ \n"
+      "|      |           |          |\n"
+      "| CPU  |  256.0 MB | 128.0 MB |\n"
+      "|______|___________|__________|\n"
+      "|      |           |          |\n"
+      "| GPU  | <UNKNOWN> |   0.0 MB |\n"
+      "|______|___________|__________|\n";
+
+  EXPECT_STREQ(expected_output, actual_output.c_str()) << actual_output;
+}
+
+TEST(MemorySettingsPrettyPrint, GenerateMemoryTableWithGpuMemory) {
+  std::string actual_output =
+      GenerateMemoryTable(256 * 1024 * 1024,  // 256 MB CPU available.
+                          64 * 1024 * 1024,   // 64 MB GPU available.
+                          128 * 1024 * 1024,  // 128 MB CPU consumption.
+                          23592960);          // 22.5 MB GPU consumption.
+
+  const char* expected_output =
+      " TYPE   TOTAL      SETTINGS   \n"
+      " ____________________________ \n"
+      "|      |          |          |\n"
+      "| CPU  | 256.0 MB | 128.0 MB |\n"
+      "|______|__________|__________|\n"
+      "|      |          |          |\n"
+      "| GPU  |  64.0 MB |  22.5 MB |\n"
+      "|______|__________|__________|\n";
+
+  EXPECT_STREQ(expected_output, actual_output.c_str()) << actual_output;
 }
 
 TEST(MemorySettingsPrettyPrint, ToString) {
-  std::vector<const MemorySetting*> memory_settings_ptr;
-  scoped_ptr<MemorySetting> image_cache_setting =
-      CreateMemorySetting(MemorySetting::kInt, MemorySetting::kCmdLine,
-                          switches::kImageCacheSizeInBytes, "1234");
-  memory_settings_ptr.push_back(image_cache_setting.get());
+  TestSettingGroup test_setting_group;
+  test_setting_group.LoadDefault();
 
-  scoped_ptr<MemorySetting> js_gc_setting =
-      CreateMemorySetting(MemorySetting::kInt, MemorySetting::kAutoSet,
-                          switches::kJavaScriptGcThresholdInBytes, "1112");
-  memory_settings_ptr.push_back(js_gc_setting.get());
+  std::string actual_string = GeneratePrettyPrintTable(
+      test_setting_group.AsConstVector());
 
-  scoped_ptr<MemorySetting> skia_texture_setting =
-      CreateMemorySetting(MemorySetting::kDimensions, MemorySetting::kCmdLine,
-                          switches::kSkiaTextureAtlasDimensions, "1234x4567");
-  memory_settings_ptr.push_back(skia_texture_setting.get());
+  const char* expected_string =
+      " NAME                                   VALUE                   TYPE   SOURCE    \n"
+      " _______________________________________________________________________________ \n"
+      "|                                      |             |         |      |         |\n"
+      "| image_cache_size_in_bytes            |        1234 |  0.0 MB |  GPU | CmdLine |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| javascript_gc_threshold_in_bytes     |        1112 |  0.0 MB |  CPU | AutoSet |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| skia_atlas_texture_dimensions        | 1234x4567x2 | 10.7 MB |  GPU | CmdLine |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| skia_cache_size_in_bytes             |    12345678 | 11.8 MB |  GPU | CmdLine |\n"
+      "|______________________________________|_____________|_________|______|_________|\n"
+      "|                                      |             |         |      |         |\n"
+      "| software_surface_cache_size_in_bytes |         N/A |     N/A |  N/A |     N/A |\n"
+      "|______________________________________|_____________|_________|______|_________|\n";
 
-  scoped_ptr<MemorySetting> skia_cache_setting =
-      CreateMemorySetting(MemorySetting::kInt, MemorySetting::kNotApplicable,
-                          switches::kSkiaCacheSizeInBytes, "0");
-  memory_settings_ptr.push_back(skia_cache_setting.get());
+  EXPECT_STREQ(expected_string, actual_string.c_str()) << actual_string;
+}
 
-  scoped_ptr<MemorySetting> software_surface_setting =
-      CreateMemorySetting(MemorySetting::kInt, MemorySetting::kBuildSetting,
-                          switches::kSoftwareSurfaceCacheSizeInBytes, "8910");
-  memory_settings_ptr.push_back(software_surface_setting.get());
+TEST(MemorySettingsPrettyPrint, GenerateMemoryWithInvalidGpuMemoryConsumption) {
+  const base::optional<int64_t> no_gpu_memory;
+  std::string actual_output = GenerateMemoryTable(
+      256 * 1024 * 1024,  // 256 MB CPU available.
+      no_gpu_memory,      // Signals that no gpu memory is available
+                          //   on this system.
+      128 * 1024 * 1024,  // 128 MB CPU consumption.
+      16 * 1024 * 1024);  // 16 MB GPU consumption.
 
-  std::string actual_string = GeneratePrettyPrintTable(memory_settings_ptr);
+  const char* expected_output =
+      " TYPE   TOTAL       SETTINGS   \n"
+      " _____________________________ \n"
+      "|      |           |          |\n"
+      "| CPU  |  256.0 MB | 128.0 MB |\n"
+      "|______|___________|__________|\n"
+      "|      |           |          |\n"
+      "| GPU  | <UNKNOWN> |  16.0 MB |\n"
+      "|______|___________|__________|\n";
 
-  std::string expected_string =
-      "NAME                                   VALUE       SOURCE          \n"
-      "+--------------------------------------+-----------+--------------+\n"
-      "| image_cache_size_in_bytes            |      1234 |      CmdLine |\n"
-      "+--------------------------------------+-----------+--------------+\n"
-      "| javascript_gc_threshold_in_bytes     |      1112 |      AutoSet |\n"
-      "+--------------------------------------+-----------+--------------+\n"
-      "| skia_atlas_texture_dimensions        | 1234x4567 |      CmdLine |\n"
-      "+--------------------------------------+-----------+--------------+\n"
-      "| skia_cache_size_in_bytes             |         0 |          N/A |\n"
-      "+--------------------------------------+-----------+--------------+\n"
-      "| software_surface_cache_size_in_bytes |      8910 | BuildSetting |\n"
-      "+--------------------------------------+-----------+--------------+\n";
-
-  const bool strings_matched = (expected_string == actual_string);
-  EXPECT_TRUE(strings_matched) << "Strings Mismatched:\n\n"
-                               << "Actual:\n" << actual_string << "\n"
-                               << "Expected:\n" << expected_string << "\n";
+  EXPECT_STREQ(expected_output, actual_output.c_str()) << actual_output;
 }
 
 }  // namespace memory_settings
diff --git a/src/cobalt/browser/memory_settings/table_printer.cc b/src/cobalt/browser/memory_settings/table_printer.cc
new file mode 100644
index 0000000..ee85579
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/table_printer.cc
@@ -0,0 +1,300 @@
+/*
+ * 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/table_printer.h"
+
+#include <algorithm>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include "base/logging.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+namespace {
+
+std::string AddColor(TablePrinter::Color color, const std::string& value) {
+  const char* RED_START = "\x1b[31m";
+  const char* GREEN_START = "\x1b[32m";
+  const char* YELLOW_START = "\x1b[33m";
+  const char* BLUE_START = "\x1b[34m";
+  const char* MAGENTA_START = "\x1b[35m";
+  const char* CYAN_START = "\x1b[36m";
+
+  const char* COLOR_END = "\x1b[0m";
+
+  if (color == TablePrinter::kDefault) {
+    return value;
+  }
+
+  std::stringstream ss;
+  switch (color) {
+    case TablePrinter::kRed: { ss << RED_START; break; }
+    case TablePrinter::kGreen: { ss << GREEN_START; break; }
+    case TablePrinter::kYellow: { ss << YELLOW_START; break; }
+    case TablePrinter::kBlue: { ss << BLUE_START; break; }
+    case TablePrinter::kMagenta: { ss << MAGENTA_START; break; }
+    case TablePrinter::kCyan: { ss << CYAN_START; break; }
+    case TablePrinter::kDefault: { DCHECK(false) << "Unexpected"; break; }
+  }
+
+  ss << value;
+  ss << COLOR_END;
+  return ss.str();
+}
+
+class TablePrinterImpl {
+ public:
+  // First row is the header.
+  typedef std::vector<std::string> Row;
+  // table[i] gets row, table[i][j] gets row/col
+  typedef std::vector<Row> Table;
+  static std::string ToString(const Table& table,
+                              TablePrinter::Color text_color,
+                              TablePrinter::Color table_color);
+
+ private:
+  static bool CheckNotEmptyAndAllColumnsTheSame(const Table& rows);
+  static std::vector<size_t> MakeColumnSizeVector(const Table& table);
+  static size_t ColumnPrintSize(const Table& table, size_t which_col);
+  TablePrinterImpl(const std::vector<size_t>& column_sizes,
+                   TablePrinter::Color text_color,
+                   TablePrinter::Color table_printer);
+
+  // " col1     col2 "
+  std::string MakeHeaderRow(const Row& header_row) const;
+
+  // ex: "| value1 | value2 |"
+  std::string MakeDataRow(const Row& row) const;
+
+  // ex: "|________|________|"
+  std::string MakeRowDelimiter() const;
+
+  // Follows a data row to provide verticle space before a TopSeperatorRow().
+  // ex: "|        |        |"
+  std::string MakeTopSeperatorRowAbove() const;
+
+  // ex: " _________________ "
+  std::string MakeTopSeperatorRow() const;
+
+  const std::vector<size_t>& column_sizes_;
+  const TablePrinter::Color text_color_;
+  const TablePrinter::Color table_color_;
+};
+
+std::string TablePrinterImpl::ToString(const Table& rows,
+                                       TablePrinter::Color text_color,
+                                       TablePrinter::Color table_color) {
+  if (!CheckNotEmptyAndAllColumnsTheSame(rows)) {
+    std::string error_msg = "ERROR - NOT ALL COLUMNS ARE THE SAME";
+    DCHECK(false) << error_msg;
+    return error_msg;
+  }
+
+  std::vector<size_t> column_sizes = MakeColumnSizeVector(rows);
+  TablePrinterImpl printer(column_sizes, text_color, table_color);
+
+  std::stringstream output_ss;
+  output_ss << printer.MakeHeaderRow(rows[0]) << "\n";
+  output_ss << printer.MakeTopSeperatorRow() << "\n";
+
+  std::string seperator_row_above = printer.MakeTopSeperatorRowAbove();
+  std::string row_delimiter = printer.MakeRowDelimiter();
+
+  // Print body.
+  for (size_t i = 1; i < rows.size(); ++i) {
+    const Row& row = rows[i];
+
+    const std::string row_string = printer.MakeDataRow(row);
+
+    output_ss << seperator_row_above << "\n";
+    output_ss << row_string << "\n";
+    output_ss << row_delimiter << "\n";
+  }
+  return output_ss.str();
+}
+
+bool TablePrinterImpl::CheckNotEmptyAndAllColumnsTheSame(const Table& rows) {
+  if (rows.empty()) {
+    return false;
+  }
+  size_t num_columns = rows[0].size();
+  for (size_t i = 1; i < rows.size(); ++i) {
+    if (num_columns != rows[i].size()) {
+      return false;
+    }
+  }
+  return true;
+}
+
+// Given an input of rows, compute a column size vector. Each column size
+// is the MAX of all the same columns sizes, +2. The +2 will account for
+// padding on either side of the token during stringification.
+// Example:
+//   std::vector<Row> rows;
+//   Row row;
+//   row.push_back("first_column");
+//   row.push_back("second_column");
+//   rows.push_back(row);
+//   Row row2;
+//   row2.push_back("first_column-2");
+//   row2.push_back("second_column-2");
+//   rows.push_back(row2);
+//   std::vector<size_t> column_sizes = MakeColumnSizeVector(rows);
+//   EXPECT_EQ(2, column_sizes.size());
+//   EXPECT_EQ(16, column_sizes[0]);  // "first_column-2".size() + 2
+//   EXPECT_EQ(17, column_sizes[1]);  // "second_column-2".size() + 2
+std::vector<size_t> TablePrinterImpl::MakeColumnSizeVector(const Table& table) {
+  DCHECK(!table.empty());
+  const size_t num_cols = table[0].size();
+  std::vector<size_t> column_sizes;
+
+  for (size_t i = 0; i < num_cols; ++i) {
+    column_sizes.push_back(ColumnPrintSize(table, i));
+  }
+  return column_sizes;
+}
+
+size_t TablePrinterImpl::ColumnPrintSize(const Table& table, size_t which_col) {
+  size_t max_col_size = 0;
+  for (size_t i = 0; i < table.size(); ++i) {
+    size_t curr_col_size = table[i][which_col].size();
+    max_col_size = std::max<size_t>(max_col_size, curr_col_size);
+  }
+  return max_col_size + 2;  // +2 for padding on either side.
+}
+
+TablePrinterImpl::TablePrinterImpl(const std::vector<size_t>& column_sizes,
+                                   TablePrinter::Color text_color,
+                                   TablePrinter::Color table_printer)
+    : column_sizes_(column_sizes), text_color_(text_color),
+      table_color_(table_printer) {}
+
+std::string TablePrinterImpl::MakeHeaderRow(const Row& header_row) const {
+  std::stringstream ss;
+
+  for (size_t i = 0; i < header_row.size(); ++i) {
+    ss << " " << header_row[i];
+    const size_t name_size = header_row[i].size();
+    const size_t col_width = column_sizes_[i];
+
+    DCHECK_LT(name_size, col_width);
+
+    for (size_t j = 0; j < col_width - name_size; ++j) {
+      ss << " ";
+    }
+  }
+  ss << " ";
+  std::string output = AddColor(text_color_, ss.str());
+  return output;
+}
+
+std::string TablePrinterImpl::MakeDataRow(const Row& row) const {
+  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::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);
+    if (i == 0) {
+      row_ss << std::left;  // Left justification for first column.
+    } else {
+      row_ss << std::right;  // Right justification for all other columns.
+    }
+
+    row_ss << AddColor(text_color_, token);
+    output_ss << row_ss.str();
+  }
+  output_ss << vertical_bar;
+  return output_ss.str();
+}
+
+std::string TablePrinterImpl::MakeRowDelimiter() const {
+  std::stringstream ss;
+  for (size_t i = 0; i < column_sizes_.size(); ++i) {
+    ss << "|";
+    const size_t col_width = column_sizes_[i];
+    for (size_t j = 0; j < col_width; ++j) {
+      ss << "_";
+    }
+  }
+  ss << "|";
+
+  std::string output = AddColor(table_color_, ss.str());
+  return output;
+}
+
+std::string TablePrinterImpl::MakeTopSeperatorRow() const {
+  std::stringstream ss;
+  for (size_t i = 0; i < column_sizes_.size(); ++i) {
+    if (i == 0) {
+      ss << " ";
+    } else {
+      ss << "_";
+    }
+    const size_t col_width = column_sizes_[i];
+    for (size_t j = 0; j < col_width; ++j) {
+      ss << "_";
+    }
+  }
+  ss << " ";
+  std::string output = AddColor(table_color_, ss.str());
+  return output;
+}
+
+std::string TablePrinterImpl::MakeTopSeperatorRowAbove() const {
+  std::stringstream ss;
+  for (size_t i = 0; i < column_sizes_.size(); ++i) {
+    ss << "|";
+    const size_t col_width = column_sizes_[i];
+    for (size_t j = 0; j < col_width; ++j) {
+      ss << " ";
+    }
+  }
+  ss << "|";
+  std::string output = AddColor(table_color_, ss.str());
+  return output;
+}
+
+}  // namespace.
+
+TablePrinter::TablePrinter() : text_color_(kDefault), table_color_(kDefault) {
+}
+
+void TablePrinter::AddRow(const TablePrinter::Row& row) {
+  table_.push_back(row);
+}
+
+std::string TablePrinter::ToString() const {
+  return TablePrinterImpl::ToString(table_, text_color_, table_color_);
+}
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/table_printer.h b/src/cobalt/browser/memory_settings/table_printer.h
new file mode 100644
index 0000000..29d1d0f
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/table_printer.h
@@ -0,0 +1,75 @@
+/*
+ * 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_TABLE_PRINTER_H_
+#define COBALT_BROWSER_MEMORY_SETTINGS_TABLE_PRINTER_H_
+
+#include <string>
+#include <vector>
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+// TablePrinter takes in rows of strings and then converts them into
+// an ascii table that can be used to visualize information on stdout.
+// Example:
+//    table.AddRow({"col1", "col2"});
+//    table.AddRow({"value1", "value2"});
+//    std::cout << table.ToString();
+//
+//  --> outputs -->
+//
+//      "col1     col2      \n"
+//      "+--------+--------+\n"
+//      "| value1 | value2 |\n"
+//      "+--------+--------+\n";
+class TablePrinter {
+ public:
+  enum Color {
+    kDefault,
+    kRed,
+    kGreen,
+    kYellow,
+    kBlue,
+    kMagenta,
+    kCyan
+  };
+
+  typedef std::vector<std::string> Row;
+  TablePrinter();
+
+  void AddRow(const Row& row);
+  std::string ToString() const;
+
+  // Adds color to the string output. kDefault will omit any color value and
+  // just do straight text.
+  // Note: If SbLogIsTty() returns false then color output is disabled and its
+  //       recommended that these functions are not called.
+  void set_text_color(Color text_color) { text_color_ = text_color; }
+  void set_table_color(Color table_color) { table_color_ = table_color; }
+
+ private:
+  std::vector<Row> table_;
+  Color text_color_;
+  Color table_color_;
+};
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
+
+#endif  // COBALT_BROWSER_MEMORY_SETTINGS_TABLE_PRINTER_H_
diff --git a/src/cobalt/browser/memory_settings/table_printer_test.cc b/src/cobalt/browser/memory_settings/table_printer_test.cc
new file mode 100644
index 0000000..f03250f
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/table_printer_test.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/table_printer.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+#define RED_START "\x1b[31m"
+#define GREEN_START "\x1b[32m"
+#define COLOR_END "\x1b[0m"
+
+std::vector<std::string> MakeRow2(const std::string& col1,
+                                  const std::string& col2) {
+  std::vector<std::string> row;
+  row.push_back(col1);
+  row.push_back(col2);
+  return row;
+}
+
+TEST(TablePrinter, ToString) {
+  TablePrinter table;
+
+  // Add header.
+  table.AddRow(MakeRow2("col1", "col2"));
+  table.AddRow(MakeRow2("value1", "value2"));
+
+  std::string table_str = table.ToString();
+  std::string expected_table_str =
+      " col1     col2     \n"
+      " _________________ \n"
+      "|        |        |\n"
+      "| value1 | value2 |\n"
+      "|________|________|\n";
+
+  EXPECT_STREQ(expected_table_str.c_str(), table_str.c_str());
+}
+
+TEST(TablePrinter, ToStringWithColor) {
+  TablePrinter table;
+
+  // Adds color to table.
+  table.set_text_color(TablePrinter::kRed);
+  table.set_table_color(TablePrinter::kGreen);
+
+  // Add header.
+  table.AddRow(MakeRow2("col1", "col2"));
+  table.AddRow(MakeRow2("value1", "value2"));
+
+  // These defines will wrap color constants for string literals.
+#define R(STR) RED_START STR COLOR_END
+#define G(STR) GREEN_START STR COLOR_END
+
+  std::string table_str = table.ToString();
+  std::string expected_table_str =
+      R(" col1     col2     ") "\n"
+      G(" _________________ ") "\n"
+      G("|        |        |") "\n"
+      G("|") R(" value1 ") G("|") R(" value2 ") G("|") "\n"
+      G("|________|________|") "\n";
+
+#undef R
+#undef G
+
+  EXPECT_STREQ(expected_table_str.c_str(), table_str.c_str());
+}
+
+#undef RED_START
+#undef GREEN_START
+#undef COLOR_END
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
diff --git a/src/cobalt/browser/memory_settings/test_common.h b/src/cobalt/browser/memory_settings/test_common.h
new file mode 100644
index 0000000..7e489ff
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/test_common.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_TEST_COMMON_H_
+#define COBALT_BROWSER_MEMORY_SETTINGS_TEST_COMMON_H_
+
+#include <sstream>
+#include <string>
+
+#include "cobalt/browser/memory_settings/texture_dimensions.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 <>
+inline ::std::string PrintToString(const cobalt::math::Size& value) {
+  ::std::stringstream ss;
+  ss << "math::Size(" << value.width() << ", " << value.height() << ")";
+  return ss.str();
+}
+
+template <>
+inline ::std::string PrintToString(
+    const cobalt::browser::memory_settings::TextureDimensions& value) {
+  ::std::stringstream ss;
+  ss << "TextureDimensions(" << value.width() << "x" << value.height() << "x"
+     << value.bytes_per_pixel() << ")";
+  return ss.str();
+}
+
+}  // namespace testing
+
+#endif  // COBALT_BROWSER_MEMORY_SETTINGS_TEST_COMMON_H_
diff --git a/src/cobalt/browser/memory_settings/texture_dimensions.h b/src/cobalt/browser/memory_settings/texture_dimensions.h
new file mode 100644
index 0000000..0e6b9f7
--- /dev/null
+++ b/src/cobalt/browser/memory_settings/texture_dimensions.h
@@ -0,0 +1,70 @@
+/*
+ * 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_TEXTURE_DIMENSIONS_H_
+#define COBALT_BROWSER_MEMORY_SETTINGS_TEXTURE_DIMENSIONS_H_
+
+#include "starboard/types.h"
+
+namespace cobalt {
+namespace browser {
+namespace memory_settings {
+
+class TextureDimensions {
+ public:
+  TextureDimensions() : width_(), height_(), bytes_per_pixel_() {}
+  TextureDimensions(int w, int h, int d)
+      : width_(w), height_(h), bytes_per_pixel_(d) {}
+  TextureDimensions(const TextureDimensions& other)
+      : width_(other.width_),
+        height_(other.height_),
+        bytes_per_pixel_(other.bytes_per_pixel_) {}
+
+  bool operator==(const TextureDimensions& other) const {
+    return width_ == other.width_ && height_ == other.height_ &&
+           bytes_per_pixel_ == other.bytes_per_pixel_;
+  }
+
+  bool operator!=(const TextureDimensions& other) const {
+    return !(*this == other);
+  }
+
+  int width() const { return width_; }
+  int height() const { return height_; }
+  int bytes_per_pixel() const { return bytes_per_pixel_; }
+
+  int64_t TotalBytes() const {
+    int64_t out = width_;
+    out *= height_;
+    out *= bytes_per_pixel_;
+    return out;
+  }
+
+  void set_width(int width) { width_ = width; }
+  void set_height(int height) { height_ = height; }
+  void set_bytes_per_pixel(int bpp) { bytes_per_pixel_ = bpp; }
+
+ private:
+  int width_;
+  int height_;
+  int bytes_per_pixel_;
+};
+
+}  // namespace memory_settings
+}  // namespace browser
+}  // namespace cobalt
+
+#endif  // COBALT_BROWSER_MEMORY_SETTINGS_TEXTURE_DIMENSIONS_H_
diff --git a/src/cobalt/browser/web_module.cc b/src/cobalt/browser/web_module.cc
index f9cfc51..5087c2d 100644
--- a/src/cobalt/browser/web_module.cc
+++ b/src/cobalt/browser/web_module.cc
@@ -493,7 +493,7 @@
       base::Bind(&WebModule::Impl::OnRanAnimationFrameCallbacks,
                  base::Unretained(this)),
       data.window_close_callback, data.window_minimize_callback,
-      data.system_window_, data.options.input_poller,
+      data.system_window_, data.options.camera_3d,
       media_session_client_->GetMediaSession(),
       data.options.csp_insecure_allowed_token, data.dom_max_element_depth);
   DCHECK(window_);
diff --git a/src/cobalt/browser/web_module.h b/src/cobalt/browser/web_module.h
index 0054f19..3e29f72 100644
--- a/src/cobalt/browser/web_module.h
+++ b/src/cobalt/browser/web_module.h
@@ -165,9 +165,8 @@
     // default value is base::kThreadPriority_Low.
     base::ThreadPriority animated_image_decode_thread_priority;
 
-    // InputPoller to use for constantly polling the input key position or
-    // state. For example, this is used to support 3D camera movements.
-    scoped_refptr<input::InputPoller> input_poller;
+    // To support 3D camera movements.
+    scoped_refptr<input::Camera3D> camera_3d;
 
     script::JavaScriptEngine::Options javascript_options;
   };
diff --git a/src/cobalt/build/build.id b/src/cobalt/build/build.id
index aa6da0c..86bfd59 100644
--- a/src/cobalt/build/build.id
+++ b/src/cobalt/build/build.id
@@ -1 +1 @@
-49488
\ No newline at end of file
+51583
\ No newline at end of file
diff --git a/src/cobalt/build/config/base.gypi b/src/cobalt/build/config/base.gypi
index cc21f05..339b511 100644
--- a/src/cobalt/build/config/base.gypi
+++ b/src/cobalt/build/config/base.gypi
@@ -45,17 +45,19 @@
     #                 recommended that 'local_font_cache_size_in_bytes' be
     #                 increased to 24MB when using this package to account for
     #                 the extra memory required by bold CJK. This package is
-    #                 ~46.2MB.
-    #   'standard' -- The default package. It includes all non-CJK fallback
-    #                 fonts in both 'normal' and 'bold' weights, 'normal' weight
-    #                 CJK ('bold' weight CJK is synthesized from it), and all
-    #                 FCC fonts. This package is ~26.9MB.
+    #                 ~48.7MB.
+    #   'standard' -- The default package. It includes all sans-serif, serif,
+    #                 and FCC fonts, non-CJK fallback fonts in both 'normal' and
+    #                 'bold' weights, and 'normal' weight CJK ('bold' weight CJK
+    #                 is synthesized from it). This package is ~29.4MB.
     #   'limited_with_jp' -- A significantly smaller package than 'standard'.
-    #                 This package removes the 'bold' weighted non-CJK fallback
-    #                 fonts (the 'normal' weight is still included and is used
-    #                 to synthesize bold), removes the FCC fonts (which must be
-    #                 downloaded from the web), and replaces standard CJK with
-    #                 low quality CJK. However, higher quality Japanese is still
+    #                 This package removes all but 'normal' and 'bold' weighted
+    #                 sans-serif and serif, removes the FCC fonts (which must be
+    #                 provided by the system or downloaded from the web),
+    #                 removes the 'bold' weighted non-CJK fallback fonts (the
+    #                 'normal' weight is still included and is used to
+    #                 synthesize bold), and replaces standard CJK with low
+    #                 quality CJK. However, higher quality Japanese is still
     #                 included. Because low quality CJK cannot synthesize bold,
     #                 bold glyphs are unavailable in Chinese and Korean. This
     #                 package is ~10.9MB.
@@ -68,7 +70,8 @@
     #                 is ~7.7MB.
     #   'minimal'  -- The smallest possible font package. It only includes
     #                 Roboto's Basic Latin characters. Everything else must be
-    #                 downloaded from the web. This package is ~16.4KB.
+    #                 provided by the system or downloaded from the web. This
+    #                 package is ~16.4KB.
     # NOTE: When bold is needed, but unavailable, it is typically synthesized,
     #       resulting in lower quality glyphs than those generated directly from
     #       a bold font. However, this does not occur with low quality CJK,
diff --git a/src/cobalt/build/gyp_cobalt b/src/cobalt/build/gyp_cobalt
index 69180fb..e83ef44 100755
--- a/src/cobalt/build/gyp_cobalt
+++ b/src/cobalt/build/gyp_cobalt
@@ -239,7 +239,7 @@
         full_starboard_path = platforms[platform]
         assert full_starboard_path[:len(source_tree_dir)] == source_tree_dir
         starboard_path = full_starboard_path[len(source_tree_dir) + 1:]
-        starboard_path.replace(os.sep, '/')
+        starboard_path = starboard_path.replace(os.sep, '/')
         assert starboard_path[0] not in [ os.sep, os.altsep ]
         variables['starboard_path'] = starboard_path
     _AppendVariables(variables, self.common_args)
diff --git a/src/cobalt/content/fonts/README.md b/src/cobalt/content/fonts/README.md
index 3bd0d89..1181646 100644
--- a/src/cobalt/content/fonts/README.md
+++ b/src/cobalt/content/fonts/README.md
@@ -1,16 +1,34 @@
-## Description
+# Fonts
 
-This directory contains fonts that can be packaged with Cobalt.
+By default, Cobalt includes a robust set of fonts that support most characters
+encountered around the world. While this will likely meet many porters' needs,
+the font system is also extremely configurable when desired.
 
-## How to use
+It can be configured in the following ways:
+  1. The porter can select from a variety of font packages that Cobalt offers
+     and then override specific sections of those packages to add or remove
+     additional fonts.
+  2. The porter can use system fonts to complement or even replace Cobalt's
+     fonts. However, it is important to note that, given the extensive language
+     support that Cobalt provides in its font packages, care should be taken
+     when replacing Cobalt's fonts to not significantly degrade that support.
+
+Both font packages and system fonts are described in more detail below.
+
+## Font Packages
+
+While the fonts included in Cobalt's default font package should work well in
+most cases, Cobalt offers the ability to customize the fonts included in builds
+through package profile selection and package overrides.
+
+### How to use
 
 To use this:
-
-1.  Select one of the packages below.
-2.  Add a variable named `cobalt_font_package` in your platform's
-    `gyp_configuration.gypi` file.
-3.  Optional: Add package overrides, which can be used to add or remove fonts
-    from the package.
+  1.  Select one of the package profiles below.
+  2.  Add a variable named `cobalt_font_package` in your platform's
+      `gyp_configuration.gypi` file.
+  3.  Optional: Add package overrides, which can be used to add or remove fonts
+      from the package.
 
 Example:
     This example uses the 'limited' package, but overrides it to include bold
@@ -22,16 +40,16 @@
         'cobalt_font_package_override_fallback_lang_cjk_low_quality': 0,
     }
 
-## Packages
+### Package Profiles
 *  'expanded' -- The largest package. It includes everything in the 'standard'
                  package, along with 'bold' weight CJK. It is recommended that
                  'local_font_cache_size_in_bytes' be increased to 24MB when
                  using this package to account for the extra memory required by
-                 bold CJK. This package is ~46.2MB.
+                 bold CJK. This package is ~48.7MB.
 
                  Package category values:
                    'package_named_sans_serif': 4,
-                   'package_named_serif': 4,
+                   'package_named_serif': 3,
                    'package_named_fcc_fonts': 2,
                    'package_fallback_lang_non_cjk': 2,
                    'package_fallback_lang_cjk': 2,
@@ -40,13 +58,13 @@
                    'package_fallback_emoji': 1,
                    'package_fallback_symbols': 1,
 
-*  'standard' -- The default package. It includes all non-CJK fallback fonts in
-                 both 'normal' and 'bold' weights, 'normal' weight CJK ('bold'
-                 weight CJK is synthesized from it), and all FCC fonts. This
-                 package is ~26.9MB.
+*  'standard' -- The default package. It includes all sans-serif, serif, and FCC
+                 fonts, non-CJK fallback fonts in both 'normal' and 'bold'
+                 weights, and 'normal' weight CJK ('bold' weight CJK is
+                 synthesized from it). This package is ~29.4MB.
 
                  Package category values:
-                  'package_named_sans_serif': 3,
+                  'package_named_sans_serif': 4,
                   'package_named_serif': 3,
                   'package_named_fcc_fonts': 2,
                   'package_fallback_lang_non_cjk': 2,
@@ -57,13 +75,15 @@
                   'package_fallback_symbols': 1,
 
 *  'limited_with_jp' -- A significantly smaller package than 'standard'. This
-                 package removes the 'bold' weighted non-CJK fallback fonts (the
-                 'normal' weight is still included and is used to synthesize
-                 bold), removes the FCC fonts (which must be downloaded from the
-                 web), and replaces standard CJK with low quality CJK. However,
-                 higher quality Japanese is still included. Because low quality
-                 CJK cannot synthesize bold, bold glyphs are unavailable in
-                 Chinese and Korean. This package is ~10.9MB.
+                 package removes all but 'normal' and 'bold' weighted sans-serif
+                 and serif, removes the FCC fonts (which must be provided by the
+                 system or downloaded from the web), removes the 'bold' weighted
+                 non-CJK fallback fonts (the 'normal' weight is still included
+                 and is used to synthesize bold), and replaces standard CJK with
+                 low quality CJK. However, higher quality Japanese is still
+                 included. Because low quality CJK cannot synthesize bold, bold
+                 glyphs are unavailable in Chinese and Korean. This package is
+                 ~10.9MB.
 
                  Package category values:
                   'package_named_sans_serif': 2,
@@ -95,8 +115,8 @@
                   'package_fallback_symbols': 1,
 
 *  'minimal'  -- The smallest possible font package. It only includes Roboto's
-                 Basic Latin characters. Everything else must be downloaded from
-                 the web. This package is ~16.4KB.
+                 Basic Latin characters. Everything else must be provided by the
+                 system or downloaded from the web. This package is ~16.4KB.
 
                  Package category values:
                   'package_named_sans_serif': 0,
@@ -116,8 +136,8 @@
       weight.
 
 
-## Package font categories
-Each package contains values for the following categories, which specifies the
+### Package Font Categories
+Each package contains values for the following categories, which specify the
 fonts from each category included within the package:
   *  'package_named_sans_serif':
        Named sans-serif fonts.
@@ -151,7 +171,7 @@
        Symbol-related fallback fonts.
 
 
-## Package font category values
+### Package Font Category Values
 The following explains the meaning behind the values that packages use for each
 of the font categories:
   *  0 -- No fonts from the specified category are included.
@@ -165,7 +185,7 @@
           include additional weights beyond 'normal' and 'bold'.
 
 
-## Overriding packages
+### Overriding Packages
 Font package overrides can be used to modify the files included within the
 selected package. The following override values are available for each font
 category:
@@ -185,7 +205,7 @@
           beyond 'normal' and 'bold'.
 
 
-## Override mappings
+### Override Package Mappings
 The mapping between the override category name and the package category name:
   *  'cobalt_font_package_override_named_sans_serif' ==>
        'package_named_sans_serif'
@@ -205,3 +225,37 @@
        'package_fallback_emoji'
   *  'cobalt_font_package_override_fallback_symbols' ==>
        'package_fallback_symbols'
+
+
+## System Fonts
+
+Beyond simply providing the ability to configure the fonts that are included
+within its package, Cobalt supports the use of system fonts.
+
+### Starboard System Font Paths
+
+In order to enable system fonts, within SbSystemGetPath() porters must provide
+paths for kSbSystemPathFontDirectory, which contains the system font files, and
+for kSbSystemPathFontConfigurationDirectory, which contains the system font
+configuration file. These directories may be the same.
+
+### System Font Configuration File
+
+In addition to providing the directory paths, porters must implement a fonts.xml
+configuration file, which describes the system fonts that are available for use.
+
+The syntax of the system font configuration file is identical to that of
+Cobalt's font configuration file, which can be used as a reference. The system
+font configuration file can include both named font families and fallback font
+families. However, system fonts shouldn't duplicate any family, alias, or font
+names contained within Cobalt's font configuration, unless the corresponding
+font files are stripped from Cobalt's font package.
+
+For example: if any of Cobalt's "sans-serif" font files are included in the
+selected Cobalt font package, then the system font configuration cannot contain
+a family named "sans-serif"; however, if Cobalt's "sans-serif" font files are
+entirely stripped from the package, then the system may provide its own
+"sans-serif" family without issues.
+
+For more information on creating a font configuration, see
+[Cobalt's configuration file](config/common/fonts.xml).
diff --git a/src/cobalt/content/fonts/config/android/fonts.xml b/src/cobalt/content/fonts/config/android/fonts.xml
new file mode 100644
index 0000000..451441d
--- /dev/null
+++ b/src/cobalt/content/fonts/config/android/fonts.xml
@@ -0,0 +1,412 @@
+<!--
+ |==============================================================================
+ | OVERVIEW
+ | The font configuration files specify the local fonts available to Cobalt.
+ | They come in two flavors:
+ |   1. A required configuration file that Cobalt provides; it is loaded first
+ |      and specifies the superset of all fonts that can be included within the
+ |      Cobalt font package.
+ |   2. An optional configuration file that porters provide; it is loaded second
+ |      and specifies the system fonts available for use.
+ |
+ | There are two types of font families that the configurations can define:
+ | named families and fallback families.
+ |==============================================================================
+ | NAMED FAMILIES
+ | Named families are families that can be retrieved by name during font
+ | matching. Providing a family with the optional "name" attribute makes it a
+ | named family.
+ |
+ | Additionally, the alias tag can be used when more than one name needs to be
+ | mapped to the same same family. The alias's "name" attribute specifies an
+ | alternate name for the family and its "to" attribute specifies the specific
+ | family that it maps to. There is no limit to the number of aliases that can
+ | map to the same family. However, it is important to note that duplicate names
+ | are not allowed between aliases and families; they must all be unique.
+ |
+ | As an example, see the alias mapping "fantasy" to "serif" below. Because of
+ | the alias, whenever the font-family "fantasy" is encountered, the "serif"
+ | family is returned.
+ |
+ | System fonts shouldn't duplicate any family, alias, or font names contained
+ | within Cobalt's font configuration, unless the corresponding font files are
+ | stripped from Cobalt's font package.
+ |
+ | For example: if any of Cobalt's "sans-serif" font files are included in the
+ | selected Cobalt font package, then the system font configuration cannot
+ | contain a family named "sans-serif"; however, if Cobalt's "sans-serif" font
+ | files are entirely stripped from the package, then the system may provide its
+ | own "sans-serif" family without issues.
+ |==============================================================================
+ | FALLBACK FAMILIES
+ | Fallback families are used when none of the named families within a
+ | "font-family" property are found to support a character. When this occurs,
+ | Cobalt searches the fallback families for a font that supports the character.
+ |
+ | Families are included as fallback families if one of two conditions are met:
+ |  1. They do not have a "name" attribute.
+ |  2. They have a "fallback_priority" attribute.
+ | This allows named families to also be fallback families when they are
+ | explicitly given a fallback priority.
+ |
+ | When the optional family attribute "fallback_priority" is included, then its
+ | value, which is an integer, dictates the fallback priority of the family.
+ | When it is not present, then the family is given the default priority of 0.
+ |
+ | Fallback families are chosen based on a match: full BCP-47 language tag
+ | including script, then just language with no script, and then all fonts are
+ | considered regardless of language. Within each of these, the highest priority
+ | family that satisfies the constraints and supports the character is chosen.
+ | If more than one family has the same fallback priority, then order of
+ | appearance within the xml document is the final tiebreaker.
+ |
+ | Cobalt families are loaded before system families and, as a result, always
+ | win the order of appearance fallback tiebreaker with system families.
+ | However, Cobalt fallback families all have the default fallback priority of
+ | 0; if it is desired that a system family be chosen before a Cobalt family
+ | during fallback, then this can be accomplished by giving it a priority
+ | greater than 0.
+ |
+ | The optional family attribute "pages" indicates which character pages are
+ | contained within the family. It is used with character fallback to allow the
+ | system to quickly determine that a character cannot appear in a font without
+ | requiring the full character map to be loaded into memory. Character pages
+ | are zero-indexed, and each page contains 256 characters, so character 1000
+ | would be contained within page 3.
+ |
+ | For system families, it is safer not including "pages". When "pages" is
+ | included, the correct family may potentially be skipped if there is an error
+ | in the "pages" value. When "pages" is not included the correct fallback
+ | family is always selected. The cost of not including "pages" is that more
+ | full character maps will likely be loaded, which is a one-time performance
+ | hit per family, and results in a small increase in total memory usage.
+ |==============================================================================
+ | FONT ATTRIBUTES
+ | The optional font attributes "weight" and "style" are used to specify the
+ | weight and style that will be used during font matching within a family.
+ | "weight" must be a multiple of 100, between 100 and 900 inclusive; it
+ | defaults to 400 when not defined.
+ | "style" must have a value of either "normal" or "italic"; it defaults to
+ | "normal" when not defined.
+ |
+ | The optional font attributes "font_name" and "postscript_name" are used to
+ | allow the font to be matched during local src lookup with @font-face rules.
+ | https://www.w3.org/TR/css-fonts-3/#descdef-src
+ |
+ | The optional font attribute "disable_synthetic_bolding" prevents the font
+ | from being synthetically bolded. By default synthetic bolding is done when
+ | there is no bold font available and a bold weight (>500) is specified.
+ |==============================================================================
+ -->
+<familyset version="1">
+    <!-- first family is default -->
+    <family name="sans-serif">
+        <font weight="100" style="normal" font_name="Roboto Thin" postscript_name="Roboto-Thin">Roboto-Thin.ttf</font>
+        <font weight="100" style="italic" font_name="Roboto Thin Italic" postscript_name="Roboto-Thin-Italic">Roboto-ThinItalic.ttf</font>
+        <font weight="300" style="normal" font_name="Roboto Light" postscript_name="Roboto-Light">Roboto-Light.ttf</font>
+        <font weight="300" style="italic" font_name="Roboto Light Italic" postscript_name="Roboto-Light-Italic">Roboto-LightItalic.ttf</font>
+        <font weight="400" style="normal" font_name="Roboto Regular" postscript_name="Roboto-Regular">Roboto-Regular.ttf</font>
+        <font weight="400" style="italic" font_name="Roboto Regular Italic" postscript_name="Roboto-Italic">Roboto-Italic.ttf</font>
+        <font weight="500" style="normal" font_name="Roboto Medium" postscript_name="Roboto-Medium">Roboto-Medium.ttf</font>
+        <font weight="500" style="italic" font_name="Roboto Medium Italic" postscript_name="Roboto-Medium-Italic">Roboto-MediumItalic.ttf</font>
+        <font weight="700" style="normal" font_name="Roboto Bold" postscript_name="Roboto-Bold">Roboto-Bold.ttf</font>
+        <font weight="700" style="italic" font_name="Roboto Bold Italic" postscript_name="Roboto-BoldItalic">Roboto-BoldItalic.ttf</font>
+        <font weight="900" style="normal" font_name="Roboto Black" postscript_name="Roboto-Black">Roboto-Black.ttf</font>
+        <font weight="900" style="italic" font_name="Roboto Black Italic" postscript_name="Roboto-Black-Italic">Roboto-BlackItalic.ttf</font>
+    </family>
+    <!-- Note that aliases must come after the fonts they reference. -->
+    <alias name="roboto" to="sans-serif" />
+    <!-- This is the default font when Roboto is unavailable. -->
+    <family pages="0">
+        <font weight="400" style="normal">Roboto-Regular-Subsetted.ttf</font>
+    </family>
+    <family name="sans-serif-condensed">
+        <font weight="300" style="normal" font_name="Roboto Condensed Light" postscript_name="Roboto-Condensed-Light">RobotoCondensed-Light.ttf</font>
+        <font weight="300" style="italic" font_name="Roboto Condensed Light Italic" postscript_name="Roboto-Condensed-Light-Italic">RobotoCondensed-LightItalic.ttf</font>
+        <font weight="400" style="normal" font_name="Roboto Condensed Regular" postscript_name="Roboto-Condensed-Regular">RobotoCondensed-Regular.ttf</font>
+        <font weight="400" style="italic" font_name="Roboto Condensed Regular Italic" postscript_name="Roboto-Condensed-Regular-Italic">RobotoCondensed-Italic.ttf</font>
+        <font weight="700" style="normal" font_name="Roboto Condensed Bold" postscript_name="Roboto-Condensed-Bold">RobotoCondensed-Bold.ttf</font>
+        <font weight="700" style="italic" font_name="Roboto Condensed Bold Italic" postscript_name="Roboto-Condensed-Bold-Italic">RobotoCondensed-BoldItalic.ttf</font>
+    </family>
+    <family name="serif">
+        <font weight="400" style="normal" font_name="Noto Serif" postscript_name="NotoSerif">NotoSerif-Regular.ttf</font>
+        <font weight="400" style="italic" font_name="Noto Serif Italic" postscript_name="NotoSerif-Italic">NotoSerif-Italic.ttf</font>
+        <font weight="700" style="normal" font_name="Noto Serif Bold" postscript_name="NotoSerif-Bold">NotoSerif-Bold.ttf</font>
+        <font weight="700" style="italic" font_name="Noto Serif Bold Italic" postscript_name="NotoSerif-BoldItalic">NotoSerif-BoldItalic.ttf</font>
+    </family>
+    <alias name="fantasy" to="serif" />
+    <family name="monospace">
+        <font weight="400" style="normal" font_name="Droid Sans Mono" postscript_name="DroidSansMono">DroidSansMono.ttf</font>
+    </family>
+    <alias name="sans-serif-monospace" to="monospace" />
+    <family name="serif-monospace">
+        <font weight="400" style="normal" font_name="Cutive Mono" postscript_name="CutiveMono-Regular">CutiveMono.ttf</font>
+    </family>
+    <family name="casual">
+        <font weight="400" style="normal" font_name="Coming Soon" postscript_name="ComingSoon">ComingSoon.ttf</font>
+    </family>
+    <family name="cursive">
+        <font weight="400" style="normal" font_name="Dancing Script" postscript_name="DancingScript">DancingScript-Regular.ttf</font>
+        <font weight="700" style="normal" font_name="Dancing Script Bold" postscript_name="DancingScript-Bold">DancingScript-Bold.ttf</font>
+    </family>
+    <family name="sans-serif-smallcaps">
+        <font weight="400" style="normal" font_name="Carrois Gothic SC" postscript_name="CarroisGothicSC-Regular">CarroisGothicSC-Regular.ttf</font>
+    </family>
+    <!-- fallback fonts -->
+    <!-- "Noto Naskh Arabic UI" is given a fallback priority so that, in spite
+         of having a name, it will still be included as a fallback font.
+    -->
+    <family fallback_priority="0" name="Noto Naskh Arabic UI">
+        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
+        <font weight="400" style="normal">NotoNaskhUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
+        <font weight="700" style="normal">NotoNaskhUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
+    </family>
+    <!-- Gujarati should come after Devanagari -->
+    <family>
+        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
+    </family>
+    <!-- Gurmukhi should come after Devanagari -->
+    <family>
+        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">Lohit-Odia.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
+    </family>
+    <family lang="zh-Hans">
+        <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="zh-Hans">
+        <font weight="400" style="normal">NotoSansSC-Regular.otf</font>
+        <font weight="400" style="normal">NotoSansHans-Regular.otf</font>
+    </family>
+    <family lang="zh-Hant">
+        <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="zh-Hant">
+        <font weight="400" style="normal">NotoSansTC-Regular.otf</font>
+        <font weight="400" style="normal">NotoSansHant-Regular.otf</font>
+    </family>
+    <family lang="ja">
+        <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="ja">
+        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
+    </family>
+    <family lang="ko">
+        <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="ko">
+        <font weight="400" style="normal">NotoSansKR-Regular.otf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NanumGothic.ttf</font>
+    </family>
+    <!--
+        Pages are included for NotoEmoji-Regular because it is part of the
+        Cobalt font package. Font files that come from Android do not include
+        pages; this protects from subtle bugs that could be caused by Android
+        modifying the characters that a font supports.
+    -->
+    <family pages="0,32-33,35-39,41,43,48,50,254,496-502,4068,4072">
+        <font weight="400" style="normal">NotoEmoji-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
+    </family>
+    <!--
+        Synthetic bolding is explicitly disabled for DroidSansFallback. The
+        quality of its synthetically bolded glyphs are not good enough to meet
+        Cobalt's standards.
+    -->
+    <family>
+        <font weight="400" style="normal" disable_synthetic_bolding="true">DroidSansFallback.ttf</font>
+    </family>
+    <family lang="ja">
+        <font weight="400" style="normal">MTLmr3m.ttf</font>
+    </family>
+    <!--
+        Tai Le and Mongolian are intentionally kept last, to make sure they don't override
+        the East Asian punctuation for Chinese.
+    -->
+    <family>
+        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+    </family>
+    <family>
+        <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
+    </family>
+</familyset>
diff --git a/src/cobalt/content/fonts/config/common/fonts.xml b/src/cobalt/content/fonts/config/common/fonts.xml
new file mode 100644
index 0000000..b60cc92
--- /dev/null
+++ b/src/cobalt/content/fonts/config/common/fonts.xml
@@ -0,0 +1,376 @@
+<!--
+ |==============================================================================
+ | OVERVIEW
+ | The font configuration files specify the local fonts available to Cobalt.
+ | They come in two flavors:
+ |   1. A required configuration file that Cobalt provides; it is loaded first
+ |      and specifies the superset of all fonts that can be included within the
+ |      Cobalt font package.
+ |   2. An optional configuration file that porters provide; it is loaded second
+ |      and specifies the system fonts available for use.
+ |
+ | There are two types of font families that the configurations can define:
+ | named families and fallback families.
+ |==============================================================================
+ | NAMED FAMILIES
+ | Named families are families that can be retrieved by name during font
+ | matching. Providing a family with the optional "name" attribute makes it a
+ | named family.
+ |
+ | Additionally, the alias tag can be used when more than one name needs to be
+ | mapped to the same same family. The alias's "name" attribute specifies an
+ | alternate name for the family and its "to" attribute specifies the specific
+ | family that it maps to. There is no limit to the number of aliases that can
+ | map to the same family. However, it is important to note that duplicate names
+ | are not allowed between aliases and families; they must all be unique.
+ |
+ | As an example, see the alias mapping "fantasy" to "serif" below. Because of
+ | the alias, whenever the font-family "fantasy" is encountered, the "serif"
+ | family is returned.
+ |
+ | System fonts shouldn't duplicate any family, alias, or font names contained
+ | within Cobalt's font configuration, unless the corresponding font files are
+ | stripped from Cobalt's font package.
+ |
+ | For example: if any of Cobalt's "sans-serif" font files are included in the
+ | selected Cobalt font package, then the system font configuration cannot
+ | contain a family named "sans-serif"; however, if Cobalt's "sans-serif" font
+ | files are entirely stripped from the package, then the system may provide its
+ | own "sans-serif" family without issues.
+ |==============================================================================
+ | FALLBACK FAMILIES
+ | Fallback families are used when none of the named families within a
+ | "font-family" property are found to support a character. When this occurs,
+ | Cobalt searches the fallback families for a font that supports the character.
+ |
+ | Families are included as fallback families if one of two conditions are met:
+ |  1. They do not have a "name" attribute.
+ |  2. They have a "fallback_priority" attribute.
+ | This allows named families to also be fallback families when they are
+ | explicitly given a fallback priority.
+ |
+ | When the optional family attribute "fallback_priority" is included, then its
+ | value, which is an integer, dictates the fallback priority of the family.
+ | When it is not present, then the family is given the default priority of 0.
+ |
+ | Fallback families are chosen based on a match: full BCP-47 language tag
+ | including script, then just language with no script, and then all fonts are
+ | considered regardless of language. Within each of these, the highest priority
+ | family that satisfies the constraints and supports the character is chosen.
+ | If more than one family has the same fallback priority, then order of
+ | appearance within the xml document is the final tiebreaker.
+ |
+ | Cobalt families are loaded before system families and, as a result, always
+ | win the order of appearance fallback tiebreaker with system families.
+ | However, Cobalt fallback families all have the default fallback priority of
+ | 0; if it is desired that a system family be chosen before a Cobalt family
+ | during fallback, then this can be accomplished by giving it a priority
+ | greater than 0.
+ |
+ | The optional family attribute "pages" indicates which character pages are
+ | contained within the family. It is used with character fallback to allow the
+ | system to quickly determine that a character cannot appear in a font without
+ | requiring the full character map to be loaded into memory. Character pages
+ | are zero-indexed, and each page contains 256 characters, so character 1000
+ | would be contained within page 3.
+ |
+ | For system families, it is safer not including "pages". When "pages" is
+ | included, the correct family may potentially be skipped if there is an error
+ | in the "pages" value. When "pages" is not included the correct fallback
+ | family is always selected. The cost of not including "pages" is that more
+ | full character maps will likely be loaded, which is a one-time performance
+ | hit per family, and results in a small increase in total memory usage.
+ |==============================================================================
+ | FONT ATTRIBUTES
+ | The optional font attributes "weight" and "style" are used to specify the
+ | weight and style that will be used during font matching within a family.
+ | "weight" must be a multiple of 100, between 100 and 900 inclusive; it
+ | defaults to 400 when not defined.
+ | "style" must have a value of either "normal" or "italic"; it defaults to
+ | "normal" when not defined.
+ |
+ | The optional font attributes "font_name" and "postscript_name" are used to
+ | allow the font to be matched during local src lookup with @font-face rules.
+ | https://www.w3.org/TR/css-fonts-3/#descdef-src
+ |
+ | The optional font attribute "disable_synthetic_bolding" prevents the font
+ | from being synthetically bolded. By default synthetic bolding is done when
+ | there is no bold font available and a bold weight (>500) is specified.
+ |==============================================================================
+ -->
+<familyset version="1">
+    <!-- first family is default -->
+    <family name="sans-serif">
+        <font weight="100" style="normal" font_name="Roboto Thin" postscript_name="Roboto-Thin">Roboto-Thin.ttf</font>
+        <font weight="100" style="italic" font_name="Roboto Thin Italic" postscript_name="Roboto-Thin-Italic">Roboto-ThinItalic.ttf</font>
+        <font weight="300" style="normal" font_name="Roboto Light" postscript_name="Roboto-Light">Roboto-Light.ttf</font>
+        <font weight="300" style="italic" font_name="Roboto Light Italic" postscript_name="Roboto-Light-Italic">Roboto-LightItalic.ttf</font>
+        <font weight="400" style="normal" font_name="Roboto Regular" postscript_name="Roboto-Regular">Roboto-Regular.ttf</font>
+        <font weight="400" style="italic" font_name="Roboto Regular Italic" postscript_name="Roboto-Italic">Roboto-Italic.ttf</font>
+        <font weight="500" style="normal" font_name="Roboto Medium" postscript_name="Roboto-Medium">Roboto-Medium.ttf</font>
+        <font weight="500" style="italic" font_name="Roboto Medium Italic" postscript_name="Roboto-Medium-Italic">Roboto-MediumItalic.ttf</font>
+        <font weight="700" style="normal" font_name="Roboto Bold" postscript_name="Roboto-Bold">Roboto-Bold.ttf</font>
+        <font weight="700" style="italic" font_name="Roboto Bold Italic" postscript_name="Roboto-BoldItalic">Roboto-BoldItalic.ttf</font>
+        <font weight="900" style="normal" font_name="Roboto Black" postscript_name="Roboto-Black">Roboto-Black.ttf</font>
+        <font weight="900" style="italic" font_name="Roboto Black Italic" postscript_name="Roboto-Black-Italic">Roboto-BlackItalic.ttf</font>
+    </family>
+    <!-- Note that aliases must come after the fonts they reference. -->
+    <alias name="roboto" to="sans-serif" />
+    <!-- This is the default font when Roboto is unavailable. -->
+    <family pages="0">
+        <font weight="400" style="normal">Roboto-Regular-Subsetted.ttf</font>
+    </family>
+    <family name="serif">
+        <font weight="400" style="normal" font_name="Noto Serif" postscript_name="NotoSerif">NotoSerif-Regular.ttf</font>
+        <font weight="400" style="italic" font_name="Noto Serif Italic" postscript_name="NotoSerif-Italic">NotoSerif-Italic.ttf</font>
+        <font weight="700" style="normal" font_name="Noto Serif Bold" postscript_name="NotoSerif-Bold">NotoSerif-Bold.ttf</font>
+        <font weight="700" style="italic" font_name="Noto Serif Bold Italic" postscript_name="NotoSerif-BoldItalic">NotoSerif-BoldItalic.ttf</font>
+    </family>
+    <alias name="fantasy" to="serif" />
+    <family name="monospace">
+        <font weight="400" style="normal" font_name="Droid Sans Mono" postscript_name="DroidSansMono">DroidSansMono.ttf</font>
+    </family>
+    <alias name="sans-serif-monospace" to="monospace" />
+    <family name="serif-monospace">
+        <font weight="400" style="normal" font_name="Cutive Mono" postscript_name="CutiveMono-Regular">CutiveMono.ttf</font>
+    </family>
+    <family name="casual">
+        <font weight="400" style="normal" font_name="Coming Soon" postscript_name="ComingSoon">ComingSoon.ttf</font>
+    </family>
+    <family name="cursive">
+        <font weight="400" style="normal" font_name="Dancing Script" postscript_name="DancingScript">DancingScript-Regular.ttf</font>
+        <font weight="700" style="normal" font_name="Dancing Script Bold" postscript_name="DancingScript-Bold">DancingScript-Bold.ttf</font>
+    </family>
+    <family name="sans-serif-smallcaps">
+        <font weight="400" style="normal" font_name="Carrois Gothic SC" postscript_name="CarroisGothicSC-Regular">CarroisGothicSC-Regular.ttf</font>
+    </family>
+    <!-- fallback fonts -->
+    <!-- "Noto Naskh Arabic UI" is given a fallback priority so that, in spite
+         of having a name, it will still be included as a fallback font.
+    -->
+    <family fallback_priority="0" name="Noto Naskh Arabic UI" pages="0,6-8,32,37,46,251-254">
+        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
+    </family>
+    <family pages="0,18-19,45,171,254">
+        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
+    </family>
+    <family pages="0,5,32,37,251,254">
+        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
+    </family>
+    <family pages="0,2-3,14,32,37,254">
+        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
+    </family>
+    <family pages="0,5,251,254">
+        <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
+    </family>
+    <family pages="0,5,16,45,254">
+        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
+    </family>
+    <family pages="0,2,9,28,32,34,37,168,254">
+        <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
+    </family>
+    <!-- Gujarati should come after Devanagari -->
+    <family pages="0,9-10,32,34,37,168,254">
+        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
+    </family>
+    <!-- Gurmukhi should come after Devanagari -->
+    <family pages="0,9-10,32,34,37-38,168,254">
+        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
+    </family>
+    <family pages="0,9,11,32,34,37,254">
+        <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
+    </family>
+    <family pages="0,3,9,13,32,34,37,254">
+        <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
+    </family>
+    <family pages="0,9,32,34,37,254">
+        <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
+    </family>
+    <family pages="0,9,12,32,34,37,254">
+        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
+    </family>
+    <family pages="0,9,12,32,34,37,254">
+        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
+    </family>
+    <family pages="0,9,11,32,34,37,254">
+        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
+    </family>
+    <family pages="0,9,13,32,34,37,254">
+        <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
+    </family>
+    <family pages="0,23,25,32,37">
+        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
+    </family>
+    <family pages="0,3,14,32,37">
+        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
+    </family>
+    <family pages="0,16,32,37,169-170,254">
+        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
+    </family>
+    <family pages="0,6-7,32,37,253-254">
+        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
+    </family>
+    <family pages="0,3,170">
+        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
+    </family>
+    <family pages="0,27,32,37,254">
+        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
+    </family>
+    <family pages="0,166,254,360-362">
+        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
+    </family>
+    <family pages="0,27,254">
+        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
+    </family>
+    <family pages="0,26,32,37,169,254">
+        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
+    </family>
+    <family pages="0,23,254">
+        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
+    </family>
+    <family pages="0-3,20-22,24,254">
+        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
+    </family>
+    <family pages="0,19,254">
+        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
+    </family>
+    <family pages="0,3,29,37,44,254">
+        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
+    </family>
+    <family pages="0,44,254">
+        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
+    </family>
+    <family pages="0,23,254">
+        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
+    </family>
+    <family pages="0,32,37,169,254">
+        <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
+    </family>
+    <family pages="0,169,254">
+        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
+    </family>
+    <family pages="0,28,37,254">
+        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
+    </family>
+    <family pages="0,9,25,254">
+        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
+    </family>
+    <family pages="0,2,164,254">
+        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
+    </family>
+    <family pages="0,6,8,254">
+        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
+    </family>
+    <family pages="0,170-171,254">
+        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
+    </family>
+    <family pages="0,25,254">
+        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
+    </family>
+    <family pages="0,6-7,32,46,253-254">
+        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
+    </family>
+    <family pages="0,28,254">
+        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
+    </family>
+    <family pages="0,169,254">
+        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
+    </family>
+    <family pages="0,32,37,168,254">
+        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
+    </family>
+    <family pages="0,27-28,254">
+        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
+    </family>
+    <family pages="0,9,32,37,168,254">
+        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
+    </family>
+    <family pages="0,3,6-7,32,34,37-38,254">
+        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
+    </family>
+    <family pages="0,23,254">
+        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
+    </family>
+    <family pages="0,26,32,34,37,254">
+        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
+    </family>
+    <family pages="0,32,37,167,170,254">
+        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
+    </family>
+    <family pages="0,15,32,37,254">
+        <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
+    </family>
+    <family pages="0,3,32,45,254">
+        <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
+    </family>
+    <family pages="0,165-166,254">
+        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
+    </family>
+    <family pages="0,48,160-164,254-255">
+        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
+    </family>
+    <family pages="32-43,497-498">
+        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
+    </family>
+    <family lang="zh-Hans" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
+        <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="zh-Hant" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
+        <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="ja" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
+        <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="ko" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
+        <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
+    </family>
+    <family lang="ja" pages="0,32,34-35,46-159,249-250,254-255,498,512-523,525-527,530-538,540-543,545-547,550,552,554-559,561,563-568,570,572-573,575-579,582-584,586-594,596-608,610-612,614-618,620,622-625,627-628,630-631,633-638,640,642-646,649-655,658,660-664,666,669-678,681,695-696,760-761">
+        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
+    </family>
+    <family pages="0,32-33,35-39,41,43,48,50,254,496-502,4068,4072">
+        <font weight="400" style="normal">NotoEmoji-Regular.ttf</font>
+    </family>
+    <family pages="35,37-39,43,496,498">
+        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
+    </family>
+    <!--
+        Synthetic bolding is explicitly disabled for DroidSansFallback. The
+        quality of its synthetically bolded glyphs are not good enough to meet
+        Cobalt's standards.
+    -->
+    <family pages="0,14,17,32,48-51,77-159,172-215,249-250,254-255,260">
+        <font weight="400" style="normal" disable_synthetic_bolding="true">DroidSansFallback.ttf</font>
+    </family>
+    <!--
+        Tai Le and Mongolian are intentionally kept last, to make sure they don't override
+        the East Asian punctuation for Chinese.
+    -->
+    <family pages="0,3,16,25,48,254">
+        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
+    </family>
+    <family pages="0,24,32,36-37,48,254">
+        <font weight="400" style="normal" >NotoSansMongolian-Regular.ttf</font>
+    </family>
+</familyset>
diff --git a/src/cobalt/content/fonts/font_files/Roboto-Black.ttf b/src/cobalt/content/fonts/font_files/Roboto-Black.ttf
new file mode 100644
index 0000000..e8a835a
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-Black.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/Roboto-BlackItalic.ttf b/src/cobalt/content/fonts/font_files/Roboto-BlackItalic.ttf
new file mode 100644
index 0000000..49bc496
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-BlackItalic.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/Roboto-Light.ttf b/src/cobalt/content/fonts/font_files/Roboto-Light.ttf
new file mode 100644
index 0000000..e50ce97
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-Light.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/Roboto-LightItalic.ttf b/src/cobalt/content/fonts/font_files/Roboto-LightItalic.ttf
new file mode 100644
index 0000000..a2bfefe
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-LightItalic.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/Roboto-Medium.ttf b/src/cobalt/content/fonts/font_files/Roboto-Medium.ttf
new file mode 100644
index 0000000..f144b6d
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-Medium.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/Roboto-MediumItalic.ttf b/src/cobalt/content/fonts/font_files/Roboto-MediumItalic.ttf
new file mode 100644
index 0000000..e6e8319
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-MediumItalic.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/Roboto-Thin.ttf b/src/cobalt/content/fonts/font_files/Roboto-Thin.ttf
new file mode 100644
index 0000000..77b470e
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-Thin.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/font_files/Roboto-ThinItalic.ttf b/src/cobalt/content/fonts/font_files/Roboto-ThinItalic.ttf
new file mode 100644
index 0000000..5562612
--- /dev/null
+++ b/src/cobalt/content/fonts/font_files/Roboto-ThinItalic.ttf
Binary files differ
diff --git a/src/cobalt/content/fonts/xml/android/fonts.xml b/src/cobalt/content/fonts/xml/android/fonts.xml
deleted file mode 100644
index 6a714c9..0000000
--- a/src/cobalt/content/fonts/xml/android/fonts.xml
+++ /dev/null
@@ -1,329 +0,0 @@
-<familyset version="1">
-<!--
-    Fallback fonts are chosen based on a match: full BCP-47 language tag
-    including script, then just language, and finally order (the first font
-    containing the glyph). Order of appearance is also the tiebreaker for weight
-    matching.
-
-    NOTE: When the optional family attribute "fallback" is included for a
-    family, then it dictates whether or not that family is added to the fallback
-    list. However, when it is not included, then the lack of a "name" attribute
-    causes the family to be added to the fallback list.
-
-    The optional family attribute "pages" indicates which character pages are
-    contained within the family. It is used with character fallback to allow the
-    system to quickly determine that a character cannot appear in a font without
-    requiring the full character map to be loaded into memory. Character pages
-    are zero indexed, and each page contains 256 characters, so character 1000
-    would be contained within page 3.
-
-    The optional font attribute "disable_synthetic_bolding" prevents the font
-    from being synthetically bolded. By default synthetic bolding is done when
-    there is no bold font available and a bold weight (>500) is specified.
--->
-    <!-- first family is default -->
-    <family name="sans-serif">
-        <font weight="400" style="normal" font_name="Roboto Regular" postscript_name="Roboto-Regular">Roboto-Regular.ttf</font>
-        <font weight="400" style="italic" font_name="Roboto Regular Italic" postscript_name="Roboto-Italic">Roboto-Italic.ttf</font>
-        <font weight="700" style="normal" font_name="Roboto Bold" postscript_name="Roboto-Bold">Roboto-Bold.ttf</font>
-        <font weight="700" style="italic" font_name="Roboto Bold Italic" postscript_name="Roboto-BoldItalic">Roboto-BoldItalic.ttf</font>
-    </family>
-    <!-- Note that aliases must come after the fonts they reference. -->
-    <alias name="arial" to="sans-serif" />
-    <alias name="helvetica" to="sans-serif" />
-    <alias name="roboto" to="sans-serif" />
-    <alias name="tahoma" to="sans-serif" />
-    <alias name="verdana" to="sans-serif" />
-    <!-- This is the default font when Roboto is unavailable. -->
-    <family fallback="true" pages="0">
-        <font weight="400" style="normal">Roboto-Regular-Subsetted.ttf</font>
-    </family>
-    <family name="sans-serif-condensed">
-        <font weight="400" style="normal" font_name="Roboto Condensed Regular" postscript_name="Roboto-Condensed-Regular">RobotoCondensed-Regular.ttf</font>
-        <font weight="400" style="italic" font_name="Roboto Condensed Regular Italic" postscript_name="Roboto-Condensed-Regular-Italic">RobotoCondensed-Italic.ttf</font>
-        <font weight="700" style="normal" font_name="Roboto Condensed Bold" postscript_name="Roboto-Condensed-Bold">RobotoCondensed-Bold.ttf</font>
-        <font weight="700" style="italic" font_name="Roboto Condensed Bold Italic" postscript_name="Roboto-Condensed-Bold-Italic">RobotoCondensed-BoldItalic.ttf</font>
-    </family>
-    <family name="serif">
-        <font weight="400" style="normal" font_name="Noto Serif" postscript_name="NotoSerif">NotoSerif-Regular.ttf</font>
-        <font weight="400" style="italic" font_name="Noto Serif Italic" postscript_name="NotoSerif-Italic">NotoSerif-Italic.ttf</font>
-        <font weight="700" style="normal" font_name="Noto Serif Bold" postscript_name="NotoSerif-Bold">NotoSerif-Bold.ttf</font>
-        <font weight="700" style="italic" font_name="Noto Serif Bold Italic" postscript_name="NotoSerif-BoldItalic">NotoSerif-BoldItalic.ttf</font>
-    </family>
-    <alias name="times" to="serif" />
-    <alias name="times new roman" to="serif" />
-    <alias name="palatino" to="serif" />
-    <alias name="georgia" to="serif" />
-    <alias name="baskerville" to="serif" />
-    <alias name="goudy" to="serif" />
-    <alias name="fantasy" to="serif" />
-    <alias name="ITC Stone Serif" to="serif" />
-    <family name="monospace">
-        <font weight="400" style="normal" font_name="Droid Sans Mono" postscript_name="DroidSansMono">DroidSansMono.ttf</font>
-    </family>
-    <alias name="sans-serif-monospace" to="monospace" />
-    <alias name="monaco" to="monospace" />
-    <family name="serif-monospace">
-        <font weight="400" style="normal" font_name="Cutive Mono" postscript_name="CutiveMono-Regular">CutiveMono.ttf</font>
-    </family>
-    <alias name="courier" to="serif-monospace" />
-    <alias name="courier new" to="serif-monospace" />
-    <family name="casual">
-        <font weight="400" style="normal" font_name="Coming Soon" postscript_name="ComingSoon">ComingSoon.ttf</font>
-    </family>
-    <family name="cursive">
-        <font weight="400" style="normal" font_name="Dancing Script" postscript_name="DancingScript">DancingScript-Regular.ttf</font>
-        <font weight="700" style="normal" font_name="Dancing Script Bold" postscript_name="DancingScript-Bold">DancingScript-Bold.ttf</font>
-    </family>
-    <family name="sans-serif-smallcaps">
-        <font weight="400" style="normal" font_name="Carrois Gothic SC" postscript_name="CarroisGothicSC-Regular">CarroisGothicSC-Regular.ttf</font>
-    </family>
-    <!-- fallback fonts -->
-    <family fallback="true" name="Noto Naskh Arabic UI" pages="0,6-8,32,37,46,251-254">
-        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
-        <font weight="400" style="normal">NotoNaskhUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
-        <font weight="700" style="normal">NotoNaskhUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,18-19,45,171,254">
-        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,5,32,37,251,254">
-        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,2-3,14,32,37,254">
-        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,5,251,254">
-        <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,5,16,45,254">
-        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,2,9,28,32,34,37,168,254">
-        <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
-    </family>
-    <!-- Gujarati should come after Devanagari -->
-    <family fallback="true" pages="0,9-10,32,34,37,168,254">
-        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
-    </family>
-    <!-- Gurmukhi should come after Devanagari -->
-    <family fallback="true" pages="0,9-10,32,34,37-38,168,254">
-        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,11,32,34,37,254">
-        <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,9,13,32,34,37,254">
-        <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,32,34,37,254">
-        <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,12,32,34,37,254">
-        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,12,32,34,37,254">
-        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,11,32,34,37,254">
-        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,13,32,34,37,254">
-        <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,25,32,37">
-        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,14,32,37">
-        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,16,32,37,169-170,254">
-        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,6-7,32,37,253-254">
-        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,170">
-        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,27,32,37,254">
-        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,166,254,360-362">
-        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,27,254">
-        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,26,32,37,169,254">
-        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,254">
-        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0-3,20-22,24,254">
-        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,19,254">
-        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0-3,29,37,44,254">
-        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,44,254">
-        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,254">
-        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,32,37,169,254">
-        <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,169,254">
-        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,28,37,254">
-        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,25,254">
-        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,2,164,254">
-        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,6,8,254">
-        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,170-171,254">
-        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,25,254">
-        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,6-7,32,46,253-254">
-        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,28,254">
-        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,169,254">
-        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,32,37,168,254">
-        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,27-28,254">
-        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,32,37,168,254">
-        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,6-7,32,34,37-38,254">
-        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,254">
-        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,26,32,34,37,254">
-        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,32,37,167,170,254">
-        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,15,32,37,254">
-        <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,32,45,254">
-        <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,165-166,254">
-        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,48,160-164,254-255">
-        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,11,32,34,37">
-        <font weight="400" style="normal">Lohit-Odia.ttf</font>
-    </family>
-    <family fallback="true" pages="32-43,48,497-498">
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
-    </family>
-    <family fallback="true" lang="zh-Hans" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="zh-Hans" pages="0,2,32-39,41,43,46-159,249-250,254-255,497-498,512-513,518,524,531-533,553,565,572,574,577,584-586,597,602,606,610,612,614-615,617,619-620,632,639,644,646-647,651-652,654,662,664,671,679-682,687,689,691-696,698-702,704-718">
-        <font weight="400" style="normal">NotoSansSC-Regular.otf</font>
-        <font weight="400" style="normal">NotoSansHans-Regular.otf</font>
-    </family>
-    <family fallback="true" lang="zh-Hant" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="zh-Hant" pages="0,32,34,46-48,50,52-159,249-250,254-255,498,512-657,660-661,663-678,685,760-761">
-        <font weight="400" style="normal">NotoSansTC-Regular.otf</font>
-        <font weight="400" style="normal">NotoSansHant-Regular.otf</font>
-    </family>
-    <family fallback="true" lang="ja" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="ja" pages="0,32,34-35,46-159,249-250,254-255,498,512-523,525-527,530-538,540-543,545-547,550,552,554-559,561,563-568,570,572-573,575-579,582-584,586-594,596-608,610-612,614-618,620,622-625,627-628,630-631,633-638,640,642-646,649-655,658,660-664,666,669-678,681,695-696,760-761">
-        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
-    </family>
-    <family fallback="true" lang="ko" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="ko" pages="0,17,32,48-50,169,172-215,255">
-        <font weight="400" style="normal">NotoSansKR-Regular.otf</font>
-    </family>
-    <family fallback="true" pages="0,17,32,49-50,172-215">
-        <font weight="400" style="normal">NanumGothic.ttf</font>
-    </family>
-    <family fallback="true" pages="0,32-33,35-39,41,43,48,50,254,496-502,4068,4072">
-        <font weight="400" style="normal">NotoEmoji-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="35,37-39,43,496,498">
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
-    </family>
-    <!--
-        Synthetic bolding is explicitly disabled for DroidSansFallback. The
-        quality of its synthetically bolded glyphs are not good enough to meet
-        Cobalt's standards.
-    -->
-    <family fallback="true" pages="0,14,17,32,48-159,172-215,249-250,254-255,260">
-        <font weight="400" style="normal" disable_synthetic_bolding="true">DroidSansFallback.ttf</font>
-    </family>
-    <family fallback="true" lang="ja" pages="0,2-4,32-38,48,50-51,78-159,249-250,255">
-        <font weight="400" style="normal">MTLmr3m.ttf</font>
-    </family>
-    <!--
-        Tai Le and Mongolian are intentionally kept last, to make sure they don't override
-        the East Asian punctuation for Chinese.
-    -->
-    <family fallback="true" pages="0,3,16,25,48,254">
-        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,24,32,36-37,48,254">
-        <font weight="400" style="normal">NotoSansMongolian-Regular.ttf</font>
-    </family>
-</familyset>
diff --git a/src/cobalt/content/fonts/xml/common/fonts.xml b/src/cobalt/content/fonts/xml/common/fonts.xml
deleted file mode 100644
index 2ff5097..0000000
--- a/src/cobalt/content/fonts/xml/common/fonts.xml
+++ /dev/null
@@ -1,301 +0,0 @@
-<familyset version="1">
-<!--
-    Fallback fonts are chosen based on a match: full BCP-47 language tag
-    including script, then just language, and finally order (the first font
-    containing the glyph). Order of appearance is also the tiebreaker for weight
-    matching.
-
-    NOTE: When the optional family attribute "fallback" is included for a
-    family, then it dictates whether or not that family is added to the fallback
-    list. However, when it is not included, then the lack of a "name" attribute
-    causes the family to be added to the fallback list.
-
-    The optional family attribute "pages" indicates which character pages are
-    contained within the family. It is used with character fallback to allow the
-    system to quickly determine that a character cannot appear in a font without
-    requiring the full character map to be loaded into memory. Character pages
-    are zero indexed, and each page contains 256 characters, so character 1000
-    would be contained within page 3.
-
-    The optional font attribute "disable_synthetic_bolding" prevents the font
-    from being synthetically bolded. By default synthetic bolding is done when
-    there is no bold font available and a bold weight (>500) is specified.
--->
-    <!-- first family is default -->
-    <family name="sans-serif">
-        <font weight="400" style="normal" font_name="Roboto Regular" postscript_name="Roboto-Regular">Roboto-Regular.ttf</font>
-        <font weight="400" style="italic" font_name="Roboto Regular Italic" postscript_name="Roboto-Italic">Roboto-Italic.ttf</font>
-        <font weight="700" style="normal" font_name="Roboto Bold" postscript_name="Roboto-Bold">Roboto-Bold.ttf</font>
-        <font weight="700" style="italic" font_name="Roboto Bold Italic" postscript_name="Roboto-BoldItalic">Roboto-BoldItalic.ttf</font>
-    </family>
-    <!-- Note that aliases must come after the fonts they reference. -->
-    <alias name="arial" to="sans-serif" />
-    <alias name="helvetica" to="sans-serif" />
-    <alias name="roboto" to="sans-serif" />
-    <alias name="tahoma" to="sans-serif" />
-    <alias name="verdana" to="sans-serif" />
-    <!-- This is the default font when Roboto is unavailable. -->
-    <family fallback="true" pages="0">
-        <font weight="400" style="normal">Roboto-Regular-Subsetted.ttf</font>
-    </family>
-    <family name="serif">
-        <font weight="400" style="normal" font_name="Noto Serif" postscript_name="NotoSerif">NotoSerif-Regular.ttf</font>
-        <font weight="400" style="italic" font_name="Noto Serif Italic" postscript_name="NotoSerif-Italic">NotoSerif-Italic.ttf</font>
-        <font weight="700" style="normal" font_name="Noto Serif Bold" postscript_name="NotoSerif-Bold">NotoSerif-Bold.ttf</font>
-        <font weight="700" style="italic" font_name="Noto Serif Bold Italic" postscript_name="NotoSerif-BoldItalic">NotoSerif-BoldItalic.ttf</font>
-    </family>
-    <alias name="times" to="serif" />
-    <alias name="times new roman" to="serif" />
-    <alias name="palatino" to="serif" />
-    <alias name="georgia" to="serif" />
-    <alias name="baskerville" to="serif" />
-    <alias name="goudy" to="serif" />
-    <alias name="fantasy" to="serif" />
-    <alias name="ITC Stone Serif" to="serif" />
-    <family name="monospace">
-        <font weight="400" style="normal" font_name="Droid Sans Mono" postscript_name="DroidSansMono">DroidSansMono.ttf</font>
-    </family>
-    <alias name="sans-serif-monospace" to="monospace" />
-    <alias name="monaco" to="monospace" />
-    <family name="serif-monospace">
-        <font weight="400" style="normal" font_name="Cutive Mono" postscript_name="CutiveMono-Regular">CutiveMono.ttf</font>
-    </family>
-    <alias name="courier" to="serif-monospace" />
-    <alias name="courier new" to="serif-monospace" />
-    <family name="casual">
-        <font weight="400" style="normal" font_name="Coming Soon" postscript_name="ComingSoon">ComingSoon.ttf</font>
-    </family>
-    <family name="cursive">
-        <font weight="400" style="normal" font_name="Dancing Script" postscript_name="DancingScript">DancingScript-Regular.ttf</font>
-        <font weight="700" style="normal" font_name="Dancing Script Bold" postscript_name="DancingScript-Bold">DancingScript-Bold.ttf</font>
-    </family>
-    <family name="sans-serif-smallcaps">
-        <font weight="400" style="normal" font_name="Carrois Gothic SC" postscript_name="CarroisGothicSC-Regular">CarroisGothicSC-Regular.ttf</font>
-    </family>
-    <!-- fallback fonts -->
-    <family fallback="true" name="Noto Naskh Arabic UI" pages="0,6-8,32,37,46,251-254">
-        <font weight="400" style="normal">NotoNaskhArabicUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoNaskhArabicUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,18-19,45,171,254">
-        <font weight="400" style="normal">NotoSansEthiopic-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansEthiopic-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,5,32,37,251,254">
-        <font weight="400" style="normal">NotoSansHebrew-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansHebrew-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,2-3,14,32,37,254">
-        <font weight="400" style="normal">NotoSansThaiUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansThaiUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,5,251,254">
-        <font weight="400" style="normal">NotoSansArmenian-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansArmenian-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,5,16,45,254">
-        <font weight="400" style="normal">NotoSansGeorgian-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansGeorgian-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,2,9,28,32,34,37,168,254">
-        <font weight="400" style="normal">NotoSansDevanagariUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansDevanagariUI-Bold.ttf</font>
-    </family>
-    <!-- Gujarati should come after Devanagari -->
-    <family fallback="true" pages="0,9-10,32,34,37,168,254">
-        <font weight="400" style="normal">NotoSansGujaratiUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansGujaratiUI-Bold.ttf</font>
-    </family>
-    <!-- Gurmukhi should come after Devanagari -->
-    <family fallback="true" pages="0,9-10,32,34,37-38,168,254">
-        <font weight="400" style="normal">NotoSansGurmukhiUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansGurmukhiUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,11,32,34,37,254">
-        <font weight="400" style="normal">NotoSansTamilUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansTamilUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,9,13,32,34,37,254">
-        <font weight="400" style="normal">NotoSansMalayalamUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansMalayalamUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,32,34,37,254">
-        <font weight="400" style="normal">NotoSansBengaliUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansBengaliUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,12,32,34,37,254">
-        <font weight="400" style="normal">NotoSansTeluguUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansTeluguUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,12,32,34,37,254">
-        <font weight="400" style="normal">NotoSansKannadaUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansKannadaUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,11,32,34,37,254">
-        <font weight="400" style="normal">NotoSansOriyaUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansOriyaUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,13,32,34,37,254">
-        <font weight="400" style="normal">NotoSansSinhala-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansSinhala-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,25,32,37">
-        <font weight="400" style="normal">NotoSansKhmerUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansKhmerUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,14,32,37">
-        <font weight="400" style="normal">NotoSansLaoUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansLaoUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,16,32,37,169-170,254">
-        <font weight="400" style="normal">NotoSansMyanmarUI-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansMyanmarUI-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,6-7,32,37,253-254">
-        <font weight="400" style="normal">NotoSansThaana-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansThaana-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,170">
-        <font weight="400" style="normal">NotoSansCham-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansCham-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,27,32,37,254">
-        <font weight="400" style="normal">NotoSansBalinese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,166,254,360-362">
-        <font weight="400" style="normal">NotoSansBamum-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,27,254">
-        <font weight="400" style="normal">NotoSansBatak-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,26,32,37,169,254">
-        <font weight="400" style="normal">NotoSansBuginese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,254">
-        <font weight="400" style="normal">NotoSansBuhid-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0-3,20-22,24,254">
-        <font weight="400" style="normal">NotoSansCanadianAboriginal-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,19,254">
-        <font weight="400" style="normal">NotoSansCherokee-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,29,37,44,254">
-        <font weight="400" style="normal">NotoSansCoptic-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,44,254">
-        <font weight="400" style="normal">NotoSansGlagolitic-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,254">
-        <font weight="400" style="normal">NotoSansHanunoo-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,32,37,169,254">
-        <font weight="400" style="normal">NotoSansJavanese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,169,254">
-        <font weight="400" style="normal">NotoSansKayahLi-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,28,37,254">
-        <font weight="400" style="normal">NotoSansLepcha-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,25,254">
-        <font weight="400" style="normal">NotoSansLimbu-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,2,164,254">
-        <font weight="400" style="normal">NotoSansLisu-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,6,8,254">
-        <font weight="400" style="normal">NotoSansMandaic-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,170-171,254">
-        <font weight="400" style="normal">NotoSansMeeteiMayek-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,25,254">
-        <font weight="400" style="normal">NotoSansNewTaiLue-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,6-7,32,46,253-254">
-        <font weight="400" style="normal">NotoSansNKo-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,28,254">
-        <font weight="400" style="normal">NotoSansOlChiki-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,169,254">
-        <font weight="400" style="normal">NotoSansRejang-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,32,37,168,254">
-        <font weight="400" style="normal">NotoSansSaurashtra-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,27-28,254">
-        <font weight="400" style="normal">NotoSansSundanese-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,9,32,37,168,254">
-        <font weight="400" style="normal">NotoSansSylotiNagri-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,6-7,32,34,37-38,254">
-        <font weight="400" style="normal">NotoSansSyriacEstrangela-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,23,254">
-        <font weight="400" style="normal">NotoSansTagbanwa-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,26,32,34,37,254">
-        <font weight="400" style="normal">NotoSansTaiTham-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,32,37,167,170,254">
-        <font weight="400" style="normal">NotoSansTaiViet-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,15,32,37,254">
-        <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
-        <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
-    </family>
-    <family fallback="true" pages="0,3,32,45,254">
-        <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,165-166,254">
-        <font weight="400" style="normal">NotoSansVai-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,48,160-164,254-255">
-        <font weight="400" style="normal">NotoSansYi-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="32-43,497-498">
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted.ttf</font>
-    </family>
-    <family fallback="true" lang="zh-Hans" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="2">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="zh-Hant" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="3">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="ja" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="0">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="ko" pages="0-4,17,30,32-39,41,43,46-159,169,172-215,249-251,254-255,497-498,512-658,660-682,685,687,689,691-696,698-702,704-718,760-761">
-        <font weight="400" style="normal" index="1">NotoSansCJK-Regular.ttc</font>
-    </family>
-    <family fallback="true" lang="ja" pages="0,32,34-35,46-159,249-250,254-255,498,512-523,525-527,530-538,540-543,545-547,550,552,554-559,561,563-568,570,572-573,575-579,582-584,586-594,596-608,610-612,614-618,620,622-625,627-628,630-631,633-638,640,642-646,649-655,658,660-664,666,669-678,681,695-696,760-761">
-        <font weight="400" style="normal">NotoSansJP-Regular.otf</font>
-    </family>
-    <family fallback="true" pages="0,32-33,35-39,41,43,48,50,254,496-502,4068,4072">
-        <font weight="400" style="normal">NotoEmoji-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="35,37-39,43,496,498">
-        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
-    </family>
-    <!--
-        Synthetic bolding is explicitly disabled for DroidSansFallback. The
-        quality of its synthetically bolded glyphs are not good enough to meet
-        Cobalt's standards.
-    -->
-    <family fallback="true" pages="0,14,17,32,48-51,77-159,172-215,249-250,254-255,260">
-        <font weight="400" style="normal" disable_synthetic_bolding="true">DroidSansFallback.ttf</font>
-    </family>
-    <!--
-        Tai Le and Mongolian are intentionally kept last, to make sure they don't override
-        the East Asian punctuation for Chinese.
-    -->
-    <family fallback="true" pages="0,3,16,25,48,254">
-        <font weight="400" style="normal">NotoSansTaiLe-Regular.ttf</font>
-    </family>
-    <family fallback="true" pages="0,24,32,36-37,48,254">
-        <font weight="400" style="normal" >NotoSansMongolian-Regular.ttf</font>
-    </family>
-</familyset>
diff --git a/src/cobalt/dom/camera_3d.cc b/src/cobalt/dom/camera_3d.cc
index 376f981..297d1cd 100644
--- a/src/cobalt/dom/camera_3d.cc
+++ b/src/cobalt/dom/camera_3d.cc
@@ -19,8 +19,7 @@
 namespace cobalt {
 namespace dom {
 
-Camera3D::Camera3D(const scoped_refptr<input::InputPoller>& input_poller)
-    : impl_(new Camera3DImpl(input_poller)) {}
+Camera3D::Camera3D(const scoped_refptr<input::Camera3D>& impl) : impl_(impl) {}
 
 void Camera3D::CreateKeyMapping(int keycode, uint32 camera_axis,
                                 float degrees_per_second) {
diff --git a/src/cobalt/dom/camera_3d.h b/src/cobalt/dom/camera_3d.h
index 03d04cb..056683b 100644
--- a/src/cobalt/dom/camera_3d.h
+++ b/src/cobalt/dom/camera_3d.h
@@ -17,8 +17,7 @@
 #ifndef COBALT_DOM_CAMERA_3D_H_
 #define COBALT_DOM_CAMERA_3D_H_
 
-#include "cobalt/dom/camera_3d_impl.h"
-#include "cobalt/input/input_poller.h"
+#include "cobalt/input/camera_3d.h"
 #include "cobalt/script/wrappable.h"
 
 namespace cobalt {
@@ -29,14 +28,14 @@
  public:
   enum CameraAxes {
     // Restricted to [0deg, 360deg]
-    kDomCameraRoll = Camera3DImpl::kCameraRoll,
+    kDomCameraRoll = input::Camera3D::kCameraRoll,
     // Restricted to [-90deg, 90deg]
-    kDomCameraPitch = Camera3DImpl::kCameraPitch,
+    kDomCameraPitch = input::Camera3D::kCameraPitch,
     // Restricted to [0deg, 360deg]
-    kDomCameraYaw = Camera3DImpl::kCameraYaw,
+    kDomCameraYaw = input::Camera3D::kCameraYaw,
   };
 
-  explicit Camera3D(const scoped_refptr<input::InputPoller>& input_poller);
+  explicit Camera3D(const scoped_refptr<input::Camera3D>& impl);
 
   // Creates a mapping between the specified keyCode and the specified camera
   // axis, such that while the key is pressed, the cameraAxis will rotate at a
@@ -53,18 +52,18 @@
   void Reset();
 
   // Custom, not in any spec.
-  scoped_refptr<Camera3DImpl> impl() { return impl_; }
+  scoped_refptr<input::Camera3D> impl() { return impl_; }
 
   DEFINE_WRAPPABLE_TYPE(Camera3D);
 
  private:
-  // We delegate all calls to an Impl version of Camera3D so that all camera
-  // state is stored within an object that is *not* a script::Wrappable.  This
-  // is important because Camera3DImpl will typically be attached to a render
+  // We delegate all calls to the implementation of Camera3D so that all camera
+  // state is stored within an object that is *not* a script::Wrappable. This
+  // is important because input::Camera3D will typically be attached to a render
   // tree, and render trees passed to the rasterizer have the potential to
-  // outlive the WebModule that created them, and the Camera3DImpl class is
-  // designed for just this.
-  scoped_refptr<Camera3DImpl> impl_;
+  // outlive the WebModule that created them, and input::Camera3D is designed
+  // for just this.
+  scoped_refptr<input::Camera3D> impl_;
 
   DISALLOW_COPY_AND_ASSIGN(Camera3D);
 };
diff --git a/src/cobalt/dom/data_view.h b/src/cobalt/dom/data_view.h
index d6bfb21..15f645b 100644
--- a/src/cobalt/dom/data_view.h
+++ b/src/cobalt/dom/data_view.h
@@ -16,6 +16,7 @@
 #define COBALT_DOM_DATA_VIEW_H_
 
 #include <algorithm>
+#include <iterator>
 
 #include "build/build_config.h"
 #include "cobalt/dom/array_buffer.h"
diff --git a/src/cobalt/dom/document.cc b/src/cobalt/dom/document.cc
index 4869925..2f3ad0e 100644
--- a/src/cobalt/dom/document.cc
+++ b/src/cobalt/dom/document.cc
@@ -215,11 +215,11 @@
   TRACK_MEMORY_SCOPE("DOM");
   // https://www.w3.org/TR/2015/WD-dom-20150428/#dom-document-createevent
   // The match of interface name is case-insensitive.
-  if (strcasecmp(interface_name.c_str(), "event") == 0 ||
-      strcasecmp(interface_name.c_str(), "events") == 0) {
+  if (base::strcasecmp(interface_name.c_str(), "event") == 0 ||
+      base::strcasecmp(interface_name.c_str(), "events") == 0) {
     return new Event(Event::Uninitialized);
-  } else if (strcasecmp(interface_name.c_str(), "uievent") == 0 ||
-             strcasecmp(interface_name.c_str(), "uievents") == 0) {
+  } else if (base::strcasecmp(interface_name.c_str(), "uievent") == 0 ||
+             base::strcasecmp(interface_name.c_str(), "uievents") == 0) {
     return new UIEvent(Event::Uninitialized);
   }
 
diff --git a/src/cobalt/dom/font_face.cc b/src/cobalt/dom/font_face.cc
index 3b5e2ad..97f92cf 100644
--- a/src/cobalt/dom/font_face.cc
+++ b/src/cobalt/dom/font_face.cc
@@ -48,12 +48,12 @@
 size_t FontFaceStyleSet::GetClosestStyleEntryIndex(
     const render_tree::FontStyle& pattern) const {
   size_t closest_index = 0;
-  int min_score = std::numeric_limits<int>::max();
+  int max_score = std::numeric_limits<int>::min();
   for (size_t i = 0; i < entries_.size(); ++i) {
     int score = MatchScore(pattern, entries_[i].style);
-    if (score < min_score) {
+    if (score > max_score) {
       closest_index = i;
-      min_score = score;
+      max_score = score;
     }
   }
 
@@ -63,9 +63,43 @@
 int FontFaceStyleSet::MatchScore(
     const render_tree::FontStyle& pattern,
     const render_tree::FontStyle& candidate) const {
+  // This logic is taken from Skia and is based upon the algorithm specified
+  // within the spec:
+  //   https://www.w3.org/TR/css-fonts-3/#font-matching-algorithm
+
   int score = 0;
-  score += (pattern.slant == candidate.slant) ? 0 : 1000;
-  score += std::abs(pattern.weight - candidate.weight);
+
+  // CSS style (italic/oblique)
+  // Being italic trumps all valid weights which are not italic.
+  // Note that newer specs differentiate between italic and oblique.
+  if ((pattern.slant == render_tree::FontStyle::kItalicSlant) ==
+      (candidate.slant == render_tree::FontStyle::kItalicSlant)) {
+    score += 1001;
+  }
+
+  // The 'closer' to the target weight, the higher the score.
+  // 1000 is the 'heaviest' recognized weight
+  if (pattern.weight == candidate.weight) {
+    score += 1000;
+  } else if (pattern.weight <= 500) {
+    if (400 <= pattern.weight && pattern.weight < 450) {
+      if (450 <= candidate.weight && candidate.weight <= 500) {
+        score += 500;
+      }
+    }
+    if (candidate.weight <= pattern.weight) {
+      score += 1000 - pattern.weight + candidate.weight;
+    } else {
+      score += 1000 - candidate.weight;
+    }
+  } else if (pattern.weight > 500) {
+    if (candidate.weight > pattern.weight) {
+      score += 1000 + pattern.weight - candidate.weight;
+    } else {
+      score += candidate.weight;
+    }
+  }
+
   return score;
 }
 
diff --git a/src/cobalt/dom/media_source/media_source.cc b/src/cobalt/dom/media_source/media_source.cc
index 63abdec..c87fdb5 100644
--- a/src/cobalt/dom/media_source/media_source.cc
+++ b/src/cobalt/dom/media_source/media_source.cc
@@ -96,7 +96,7 @@
   }
   *mime = tokens[0];
   for (size_t i = 1; i < tokens.size(); ++i) {
-    if (strncasecmp(tokens[i].c_str(), kCodecs, strlen(kCodecs))) {
+    if (base::strncasecmp(tokens[i].c_str(), kCodecs, strlen(kCodecs))) {
       continue;
     }
     *codecs = tokens[i].substr(strlen("codecs="));
diff --git a/src/cobalt/dom/window.cc b/src/cobalt/dom/window.cc
index 16bdb99..665126d 100644
--- a/src/cobalt/dom/window.cc
+++ b/src/cobalt/dom/window.cc
@@ -95,7 +95,7 @@
                const base::Closure& window_close_callback,
                const base::Closure& window_minimize_callback,
                system_window::SystemWindow* system_window,
-               const scoped_refptr<input::InputPoller>& input_poller,
+               const scoped_refptr<input::Camera3D>& camera_3d,
                const scoped_refptr<MediaSession>& media_session,
                int csp_insecure_allowed_token, int dom_max_element_depth)
     : width_(width),
@@ -125,7 +125,7 @@
       ALLOW_THIS_IN_INITIALIZER_LIST(
           relay_on_load_event_(new RelayLoadEvent(this))),
       console_(new Console(execution_state)),
-      camera_3d_(new Camera3D(input_poller)),
+      camera_3d_(new Camera3D(camera_3d)),
       ALLOW_THIS_IN_INITIALIZER_LIST(window_timers_(new WindowTimers(this))),
       ALLOW_THIS_IN_INITIALIZER_LIST(animation_frame_request_callback_list_(
           new AnimationFrameRequestCallbackList(this))),
diff --git a/src/cobalt/dom/window.h b/src/cobalt/dom/window.h
index d162f0a..36eddab 100644
--- a/src/cobalt/dom/window.h
+++ b/src/cobalt/dom/window.h
@@ -38,7 +38,7 @@
 #include "cobalt/dom/test_runner.h"
 #endif  // ENABLE_TEST_RUNNER
 #include "cobalt/dom/window_timers.h"
-#include "cobalt/input/input_poller.h"
+#include "cobalt/input/camera_3d.h"
 #include "cobalt/loader/decoder.h"
 #include "cobalt/loader/fetcher_factory.h"
 #include "cobalt/loader/font/remote_typeface_cache.h"
@@ -131,7 +131,7 @@
       const base::Closure& window_close_callback,
       const base::Closure& window_minimize_callback,
       system_window::SystemWindow* system_window,
-      const scoped_refptr<input::InputPoller>& input_poller,
+      const scoped_refptr<input::Camera3D>& camera_3d,
       const scoped_refptr<cobalt::media_session::MediaSession>& media_session,
       int csp_insecure_allowed_token = 0, int dom_max_element_depth = 0);
 
diff --git a/src/cobalt/input/camera_3d.h b/src/cobalt/input/camera_3d.h
new file mode 100644
index 0000000..5138c80
--- /dev/null
+++ b/src/cobalt/input/camera_3d.h
@@ -0,0 +1,82 @@
+// 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_INPUT_CAMERA_3D_H_
+#define COBALT_INPUT_CAMERA_3D_H_
+
+#include "base/memory/ref_counted.h"
+#include "cobalt/base/camera_transform.h"
+#include "cobalt/input/input_poller.h"
+#include "starboard/window.h"
+
+namespace cobalt {
+namespace input {
+
+// Obtains camera parameters from hardware input to render a 3D scene.
+// Interface to the Web module and Renderer module. Some settings may not apply
+// depending on the specfic hardware implementation, so their setter methods
+// have empty default implementations.
+class Camera3D : public base::RefCountedThreadSafe<Camera3D> {
+ public:
+  enum CameraAxes {
+    // Restricted to [0deg, 360deg]
+    kCameraRoll = 0x00,
+    // Restricted to [-90deg, 90deg]
+    kCameraPitch = 0x01,
+    // Restricted to [0deg, 360deg]
+    kCameraYaw = 0x02,
+  };
+
+  // Functions to map input keys to camera controls.
+  virtual void CreateKeyMapping(int keycode, uint32 camera_axis,
+                                float degrees_per_second) {
+    UNREFERENCED_PARAMETER(keycode);
+    UNREFERENCED_PARAMETER(camera_axis);
+    UNREFERENCED_PARAMETER(degrees_per_second);
+  }
+  virtual void ClearKeyMapping(int keycode) { UNREFERENCED_PARAMETER(keycode); }
+  virtual void ClearAllKeyMappings() {}
+
+  // Return the camera's current view direction.
+  virtual base::CameraOrientation GetOrientation() const = 0;
+
+  // The above methods are meant as an interface for the Camera3D's WebAPI on
+  // the WebModule thread, but the methods below will be accessed on the
+  // renderer thread. So, all the methods on this class may be synchronized to
+  // guard against these potentially parallel accesses. It is expected that the
+  // renderer will call them at a higher frequency than the WebModule.
+
+  // Updates the camera's perspective parameters.
+  virtual void UpdatePerspective(float width_to_height_aspect_ratio,
+                                 float vertical_fov) {
+    UNREFERENCED_PARAMETER(width_to_height_aspect_ratio);
+    UNREFERENCED_PARAMETER(vertical_fov);
+  }
+
+  // Returns the camera's view and projection matrices, setup according to the
+  // latest available orientation and perspective information. This queries the
+  // orientation from hardware inputs, and leaves it in the state of the class
+  // to be queried by GetOrientation().
+  virtual base::CameraTransform GetCameraTransformAndUpdateOrientation() = 0;
+
+  // Resets camera to default orientation.
+  virtual void Reset() {}
+
+  virtual ~Camera3D() {}
+};
+
+}  // namespace input
+}  // namespace cobalt
+
+#endif  // COBALT_INPUT_CAMERA_3D_H_
diff --git a/src/cobalt/input/camera_3d_input_poller.cc b/src/cobalt/input/camera_3d_input_poller.cc
new file mode 100644
index 0000000..95447a6
--- /dev/null
+++ b/src/cobalt/input/camera_3d_input_poller.cc
@@ -0,0 +1,165 @@
+/*
+ * 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/input/camera_3d_input_poller.h"
+
+#include <algorithm>
+#include <cmath>
+
+#include "cobalt/input/create_default_camera_3d.h"
+#include "third_party/glm/glm/gtc/matrix_transform.hpp"
+#include "third_party/glm/glm/gtx/transform.hpp"
+
+namespace cobalt {
+namespace input {
+
+Camera3DInputPoller::Camera3DInputPoller(
+    const scoped_refptr<input::InputPoller>& input_poller)
+    : input_poller_(input_poller),
+      width_to_height_aspect_ratio_(16.0f / 9.0f),
+      vertical_fov_(60.0f) {}
+
+void Camera3DInputPoller::CreateKeyMapping(int keycode, uint32 camera_axis,
+                                           float degrees_per_second) {
+  base::AutoLock lock(mutex_);
+  keycode_map_[keycode] = KeycodeMappingInfo(camera_axis, degrees_per_second);
+}
+
+void Camera3DInputPoller::ClearKeyMapping(int keycode) {
+  base::AutoLock lock(mutex_);
+  keycode_map_.erase(keycode);
+}
+
+void Camera3DInputPoller::ClearAllKeyMappings() {
+  base::AutoLock lock(mutex_);
+  keycode_map_.clear();
+}
+
+base::CameraOrientation Camera3DInputPoller::GetOrientation() const {
+  base::AutoLock lock(mutex_);
+  return orientation_;
+}
+
+namespace {
+
+const float kPiF = static_cast<float>(M_PI);
+
+float DegreesToRadians(float degrees) { return (degrees / 360.0f) * 2 * kPiF; }
+
+}  // namespace
+
+base::CameraTransform
+Camera3DInputPoller::GetCameraTransformAndUpdateOrientation() {
+  base::AutoLock lock(mutex_);
+  AccumulateOrientation();
+
+  // Note that we invert the rotation angles since this matrix is applied to
+  // the objects in our scene, and if the camera moves right, the objects,
+  // relatively, would move right.
+  glm::mat4 view_matrix =
+      glm::rotate(-DegreesToRadians(orientation_.roll), glm::vec3(0, 0, 1)) *
+      glm::rotate(-DegreesToRadians(orientation_.pitch), glm::vec3(1, 0, 0)) *
+      glm::rotate(-DegreesToRadians(orientation_.yaw), glm::vec3(0, 1, 0));
+
+  // Setup a (right-handed) perspective projection matrix.
+  const float kNearZ = 0.01f;
+  const float kFarZ = 1000.0f;
+  glm::mat4 projection_matrix = glm::perspectiveRH(
+      vertical_fov_, width_to_height_aspect_ratio_, kNearZ, kFarZ);
+
+  return base::CameraTransform(projection_matrix, view_matrix);
+}
+
+void Camera3DInputPoller::UpdatePerspective(float width_to_height_aspect_ratio,
+                                            float vertical_fov) {
+  width_to_height_aspect_ratio_ = width_to_height_aspect_ratio;
+  vertical_fov_ = vertical_fov;
+}
+
+void Camera3DInputPoller::Reset() {
+  base::AutoLock lock(mutex_);
+  orientation_ = base::CameraOrientation();
+}
+
+void Camera3DInputPoller::AccumulateOrientation() {
+  if (!input_poller_) {
+    // Nothing to do if no input poller was provided.
+    return;
+  }
+
+  base::TimeTicks now = base::TimeTicks::Now();
+  if (last_update_) {
+    base::TimeDelta delta = now - *last_update_;
+    // Cap out the maximum time delta that we will accumulate changes over, to
+    // avoid a random extra long time delta that completely changes the camera
+    // orientation.
+    const base::TimeDelta kMaxTimeDelta = base::TimeDelta::FromMilliseconds(40);
+    if (delta > kMaxTimeDelta) {
+      delta = kMaxTimeDelta;
+    }
+
+    for (KeycodeMap::const_iterator iter = keycode_map_.begin();
+         iter != keycode_map_.end(); ++iter) {
+      // If the key does not have analog output, the AnalogInput() method will
+      // always return 0.0f, so check this first, and if it is indeed 0,
+      // fallback to a check to see if the button is digital and pressed.
+      float value = input_poller_->AnalogInput(static_cast<SbKey>(iter->first));
+      if (value == 0.0f) {
+        value = input_poller_->IsPressed(static_cast<SbKey>(iter->first))
+                    ? 1.0f
+                    : 0.0f;
+      }
+
+      // Get a pointer to the camera axis angle that this key is bound to.
+      float* target_angle;
+      switch (iter->second.axis) {
+        case kCameraRoll:
+          target_angle = &orientation_.roll;
+          break;
+        case kCameraPitch:
+          target_angle = &orientation_.pitch;
+          break;
+        case kCameraYaw:
+          target_angle = &orientation_.yaw;
+          break;
+      }
+
+      // Apply the angle adjustment from the key.
+      *target_angle += value * iter->second.degrees_per_second *
+                       static_cast<float>(delta.InSecondsF());
+
+      // Apply any clamping or wrapping to the resulting camera angles.
+      if (iter->second.axis == kCameraPitch) {
+        *target_angle = std::min(90.0f, std::max(-90.0f, *target_angle));
+      } else {
+        *target_angle = static_cast<float>(fmod(*target_angle, 360));
+        if (*target_angle < 0) {
+          *target_angle += 360;
+        }
+      }
+    }
+  }
+  last_update_ = now;
+}
+
+scoped_refptr<Camera3D> CreatedDefaultCamera3D(
+    SbWindow window, const scoped_refptr<InputPoller>& input_poller) {
+  UNREFERENCED_PARAMETER(window);
+  return new Camera3DInputPoller(input_poller);
+}
+
+}  // namespace input
+}  // namespace cobalt
diff --git a/src/cobalt/input/camera_3d_input_poller.h b/src/cobalt/input/camera_3d_input_poller.h
new file mode 100644
index 0000000..bd89ad5
--- /dev/null
+++ b/src/cobalt/input/camera_3d_input_poller.h
@@ -0,0 +1,91 @@
+/*
+ * 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_INPUT_CAMERA_3D_INPUT_POLLER_H_
+#define COBALT_INPUT_CAMERA_3D_INPUT_POLLER_H_
+
+#include <map>
+#include <utility>
+
+#include "base/optional.h"
+#include "base/synchronization/lock.h"
+#include "cobalt/input/camera_3d.h"
+#include "cobalt/input/input_poller.h"
+#include "third_party/glm/glm/mat4x4.hpp"
+
+namespace cobalt {
+namespace input {
+
+// Implements a camera that gets its orientation information from hand-
+// controlled inputs.
+class Camera3DInputPoller : public Camera3D {
+ public:
+  explicit Camera3DInputPoller(
+      const scoped_refptr<input::InputPoller>& input_poller);
+
+  void CreateKeyMapping(int keycode, uint32 camera_axis,
+                        float degrees_per_second) OVERRIDE;
+  void ClearKeyMapping(int keycode) OVERRIDE;
+  void ClearAllKeyMappings() OVERRIDE;
+  base::CameraOrientation GetOrientation() const OVERRIDE;
+
+  // Returns the camera transforms based on hand-controlled inputs mapped
+  // by the functions above
+  base::CameraTransform GetCameraTransformAndUpdateOrientation() OVERRIDE;
+
+  virtual void UpdatePerspective(float width_to_height_aspect_ratio,
+                                 float vertical_fov) OVERRIDE;
+
+  virtual void Reset() OVERRIDE;
+
+ private:
+  struct KeycodeMappingInfo {
+    KeycodeMappingInfo() : axis(0), degrees_per_second(0.0f) {}
+    KeycodeMappingInfo(uint32 axis, float degrees_per_second)
+        : axis(axis), degrees_per_second(degrees_per_second) {}
+
+    uint32 axis;
+    float degrees_per_second;
+  };
+
+  typedef std::map<int, KeycodeMappingInfo> KeycodeMap;
+
+  void AccumulateOrientation();
+
+  mutable base::Lock mutex_;
+
+  // The current accumulated camera orientation state.
+  base::CameraOrientation orientation_;
+
+  // The time that the last update to the camera's state has occurred.
+  base::optional<base::TimeTicks> last_update_;
+
+  // A map of keys bound to camera movements.
+  KeycodeMap keycode_map_;
+
+  // The input poller from which we can check the state of a given key.
+  scoped_refptr<input::InputPoller> input_poller_;
+
+  float width_to_height_aspect_ratio_;
+  float vertical_fov_;
+
+  DISALLOW_COPY_AND_ASSIGN(Camera3DInputPoller);
+};
+
+}  // namespace input
+}  // namespace cobalt
+
+#endif  // COBALT_INPUT_CAMERA_3D_INPUT_POLLER_H_
diff --git a/src/cobalt/input/create_default_camera_3d.h b/src/cobalt/input/create_default_camera_3d.h
new file mode 100644
index 0000000..a9859a4
--- /dev/null
+++ b/src/cobalt/input/create_default_camera_3d.h
@@ -0,0 +1,32 @@
+// 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_INPUT_CREATE_DEFAULT_CAMERA_3D_H_
+#define COBALT_INPUT_CREATE_DEFAULT_CAMERA_3D_H_
+
+#include "base/memory/ref_counted.h"
+#include "cobalt/input/camera_3d.h"
+#include "cobalt/input/input_poller.h"
+#include "starboard/window.h"
+
+namespace cobalt {
+namespace input {
+
+scoped_refptr<Camera3D> CreatedDefaultCamera3D(
+    SbWindow window, const scoped_refptr<InputPoller>& input_poller);
+
+}  // namespace input
+}  // namespace cobalt
+
+#endif  // COBALT_INPUT_CREATE_DEFAULT_CAMERA_3D_H_
diff --git a/src/cobalt/input/input.gyp b/src/cobalt/input/input.gyp
index 27a850e..b220f36 100644
--- a/src/cobalt/input/input.gyp
+++ b/src/cobalt/input/input.gyp
@@ -18,6 +18,8 @@
       'target_name': 'input',
       'type': 'static_library',
       'sources': [
+        'camera_3d.h',
+        'create_default_camera_3d.h',
         'input_device_manager.h',
         'input_device_manager_fuzzer.cc',
         'input_device_manager_fuzzer.h',
@@ -52,6 +54,17 @@
             'input_device_manager_desktop.h',
           ],
         }],
+        ['enable_vr==1', {
+          'sources': [
+            'private/camera_3d_vr.cc',
+            'private/camera_3d_vr.h',
+          ],
+        }, { # enable_vr!=1
+          'sources': [
+            'camera_3d_input_poller.cc',
+            'camera_3d_input_poller.h',
+          ],
+        }],
       ],
     },
   ],
diff --git a/src/cobalt/input/input_device_manager.h b/src/cobalt/input/input_device_manager.h
index ccd0991..4dae106 100644
--- a/src/cobalt/input/input_device_manager.h
+++ b/src/cobalt/input/input_device_manager.h
@@ -15,6 +15,7 @@
 #ifndef COBALT_INPUT_INPUT_DEVICE_MANAGER_H_
 #define COBALT_INPUT_INPUT_DEVICE_MANAGER_H_
 
+#include "cobalt/input/camera_3d.h"
 #include "cobalt/input/input_poller.h"
 #include "cobalt/input/key_event_handler.h"
 
@@ -41,12 +42,16 @@
   virtual ~InputDeviceManager() {}
 
   scoped_refptr<InputPoller> input_poller() { return input_poller_; }
+  scoped_refptr<Camera3D> camera_3d() { return camera_3d_; }
 
  protected:
   InputDeviceManager() {}
 
   // Used for polling the input outside of InputDeviceManager.
   scoped_refptr<InputPoller> input_poller_;
+
+  // Used for holding the 3D camera state.
+  scoped_refptr<Camera3D> camera_3d_;
 };
 
 }  // namespace input
diff --git a/src/cobalt/input/input_device_manager_desktop.cc b/src/cobalt/input/input_device_manager_desktop.cc
index 7d291ac..5925fe8 100644
--- a/src/cobalt/input/input_device_manager_desktop.cc
+++ b/src/cobalt/input/input_device_manager_desktop.cc
@@ -16,6 +16,7 @@
 
 #include <string>
 
+#include "cobalt/input/create_default_camera_3d.h"
 #include "cobalt/input/input_poller_impl.h"
 #include "cobalt/system_window/input_event.h"
 
@@ -31,6 +32,10 @@
                      base::Unretained(this))),
       keypress_generator_filter_(callback) {
   input_poller_ = new InputPollerImpl();
+  DCHECK(system_window_);
+  camera_3d_ =
+      CreatedDefaultCamera3D(system_window->GetSbWindow(), input_poller_);
+
   if (system_window_) {
     // Add this object's keyboard event callback to the system window.
     system_window_->event_dispatcher()->AddEventCallback(
diff --git a/src/cobalt/layout/layout_manager.cc b/src/cobalt/layout/layout_manager.cc
index 88f5a41..c5be2b6 100644
--- a/src/cobalt/layout/layout_manager.cc
+++ b/src/cobalt/layout/layout_manager.cc
@@ -14,6 +14,7 @@
 
 #include "cobalt/layout/layout_manager.h"
 
+#include <algorithm>
 #include <cmath>
 #include <string>
 
@@ -104,14 +105,22 @@
 namespace {
 
 void UpdateCamera(
-    float width_to_height_aspect_ratio, scoped_refptr<dom::Camera3DImpl> camera,
+    float width_to_height_aspect_ratio, scoped_refptr<input::Camera3D> camera,
     float max_horizontal_fov_rad, float max_vertical_fov_rad,
     render_tree::MatrixTransform3DNode::Builder* transform_node_builder,
     base::TimeDelta time) {
   UNREFERENCED_PARAMETER(time);
-  transform_node_builder->transform = camera->QueryViewPerspectiveMatrix(
-      width_to_height_aspect_ratio, max_horizontal_fov_rad,
-      max_vertical_fov_rad);
+  float vertical_fov_rad =
+      std::min(max_vertical_fov_rad,
+               2 * static_cast<float>(atan(tan(max_horizontal_fov_rad * 0.5f) /
+                                           width_to_height_aspect_ratio)));
+  camera->UpdatePerspective(width_to_height_aspect_ratio, vertical_fov_rad);
+  base::CameraTransform transform(
+      camera->GetCameraTransformAndUpdateOrientation());
+  DCHECK(!transform.right_eye);
+  transform_node_builder->transform =
+      transform.left_eye_or_mono.projection_matrix *
+      transform.left_eye_or_mono.view_matrix;
 }
 
 scoped_refptr<render_tree::Node> AttachCameraNodes(
diff --git a/src/cobalt/layout/replaced_box.cc b/src/cobalt/layout/replaced_box.cc
index 4811118..c687b10 100644
--- a/src/cobalt/layout/replaced_box.cc
+++ b/src/cobalt/layout/replaced_box.cc
@@ -657,11 +657,21 @@
   scoped_refptr<render_tree::Node> filter_node =
       new FilterNode(MapToMeshFilter(stereo_mode, builder), animate_node);
 
-  // Attach a 3D camera to the map-to-mesh node.
+#if !SB_HAS(VIRTUAL_REALITY)
+  // Attach a 3D camera to the map-to-mesh node, so the rendering of its
+  // content can be transformed.
   border_node_builder->AddChild(
       used_style_provider()->attach_camera_node_function().Run(
           filter_node, mtm_function->horizontal_fov_in_radians(),
           mtm_function->vertical_fov_in_radians()));
+#else
+  // Camera node unnecessary in VR, since the 3D scene is completely immersive,
+  // and the whole render tree is placed within it and subject to camera
+  // transforms, not just the map-to-mesh node.
+  // TODO: Reconcile both paths with respect to this if Cobalt adopts a global
+  // camera or a document-wide notion of 3D space layout.
+  border_node_builder->AddChild(filter_node);
+#endif
 }
 
 void ReplacedBox::RenderAndAnimateContentWithLetterboxing(
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-negative-spread-blur-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-negative-spread-blur-and-rounded-corners-expected.png
new file mode 100644
index 0000000..7a6e6eb
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-negative-spread-blur-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-negative-spread-blur-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-negative-spread-blur-and-rounded-corners.html
new file mode 100644
index 0000000..962cc4b
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-negative-spread-blur-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 150px;
+      box-shadow: -15px 20px 10px -10px rgb(0, 0, 0) inset;
+      border-radius: 75px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-spread-blur-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-spread-blur-and-rounded-corners-expected.png
new file mode 100644
index 0000000..72b9bc4
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-spread-blur-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-spread-blur-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-spread-blur-and-rounded-corners.html
new file mode 100644
index 0000000..b23b31e
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-inset-spread-blur-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 150px;
+      box-shadow: -10px 10px 25px 25px rgb(0, 0, 0) inset;
+      border-radius: 75px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-negative-spread-blur-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-negative-spread-blur-and-rounded-corners-expected.png
new file mode 100644
index 0000000..59ab8f9
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-negative-spread-blur-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-negative-spread-blur-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-negative-spread-blur-and-rounded-corners.html
new file mode 100644
index 0000000..fde861b
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-negative-spread-blur-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 150px;
+      box-shadow: -15px 20px 10px -10px rgb(0, 0, 0);
+      border-radius: 75px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-spread-blur-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-spread-blur-and-rounded-corners-expected.png
new file mode 100644
index 0000000..37dad12
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-spread-blur-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-spread-blur-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-spread-blur-and-rounded-corners.html
new file mode 100644
index 0000000..a50cd60
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-circle-with-spread-blur-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 150px;
+      box-shadow: -10px 10px 25px 25px rgb(0, 0, 0);
+      border-radius: 75px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-negative-spread-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-negative-spread-and-rounded-corners-expected.png
new file mode 100644
index 0000000..d5224b4
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-negative-spread-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-negative-spread-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-negative-spread-and-rounded-corners.html
new file mode 100644
index 0000000..5ca1fd3
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-negative-spread-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 100px;
+      box-shadow: -15px 20px 10px -10px rgb(0, 0, 0) inset;
+      border-radius: 20px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-and-rounded-corners-expected.png
new file mode 100644
index 0000000..c66a8f7
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-and-rounded-corners.html
new file mode 100644
index 0000000..ed1a91b
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 100px;
+      box-shadow: -10px 10px 0px 5px rgb(0, 0, 0) inset;
+      border-radius: 20px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-blur-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-blur-and-rounded-corners-expected.png
new file mode 100644
index 0000000..7951ab2
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-blur-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-blur-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-blur-and-rounded-corners.html
new file mode 100644
index 0000000..4723bb4
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-inset-spread-blur-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 100px;
+      box-shadow: -10px 10px 25px 5px rgb(0, 0, 0) inset;
+      border-radius: 20px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-negative-spread-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-negative-spread-and-rounded-corners-expected.png
new file mode 100644
index 0000000..2619297
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-negative-spread-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-negative-spread-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-negative-spread-and-rounded-corners.html
new file mode 100644
index 0000000..df40829
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-negative-spread-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 100px;
+      box-shadow: -15px 20px 10px -10px rgb(0, 0, 0);
+      border-radius: 20px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-and-rounded-corners-expected.png
new file mode 100644
index 0000000..0ca9935
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-and-rounded-corners.html
new file mode 100644
index 0000000..33a9f70
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 100px;
+      box-shadow: 10px 10px 0px 25px rgb(0, 0, 0);
+      border-radius: 20px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-blur-and-rounded-corners-expected.png b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-blur-and-rounded-corners-expected.png
new file mode 100644
index 0000000..7e22074
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-blur-and-rounded-corners-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-blur-and-rounded-corners.html b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-blur-and-rounded-corners.html
new file mode 100644
index 0000000..42edb67
--- /dev/null
+++ b/src/cobalt/layout_tests/testdata/css3-background/7-1-box-shadow-with-spread-blur-and-rounded-corners.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<!--
+ | Tests that a box shadow works with both spread, blur and rounded corners.
+ -->
+<html>
+<head>
+  <style>
+    div {
+      position: absolute;
+      left: 20px;
+      top: 20px;
+      width: 150px;
+      height: 100px;
+      box-shadow: 10px 10px 25px 25px rgb(0, 0, 0);
+      border-radius: 20px;
+    }
+  </style>
+</head>
+<body>
+  <div></div>
+</body>
+</html>
diff --git a/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt b/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt
index 2d35370..2c12a56 100644
--- a/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt
+++ b/src/cobalt/layout_tests/testdata/css3-background/layout_tests.txt
@@ -60,9 +60,9 @@
 14-2-1-background-with-repeat-position-image-color
 14-2-1-multiple-layers-background-image
 3-10-background-none-declares-initial-value-for-background-color
+3-11-2-body-background-can-be-set-to-transparent-later
 3-11-2-propagate-computed-value-of-background-from-body-to-root
 3-11-2-propagate-computed-value-of-background-from-html-to-root
-3-11-2-body-background-can-be-set-to-transparent-later
 4-0-border-color-with-solid-border-style
 4-0-border-color-with-solid-border-style-and-background-color
 4-0-border-set-using-border-color-and-border-style
@@ -87,11 +87,22 @@
 7-1-1-outset-box-shadow-applies-to-border-box
 7-1-2-box-shadow-with-blur
 7-1-box-shadow-appears-even-with-overflow-hidden
+7-1-box-shadow-circle-with-inset-negative-spread-blur-and-rounded-corners
+7-1-box-shadow-circle-with-inset-spread-blur-and-rounded-corners
+7-1-box-shadow-circle-with-negative-spread-blur-and-rounded-corners
+7-1-box-shadow-circle-with-spread-blur-and-rounded-corners
 7-1-box-shadow-offset-top-left
 7-1-box-shadow-with-inset-and-outset-blur
+7-1-box-shadow-with-inset-negative-spread-and-rounded-corners
+7-1-box-shadow-with-inset-spread-and-rounded-corners
+7-1-box-shadow-with-inset-spread-blur-and-rounded-corners
+7-1-box-shadow-with-negative-spread-and-rounded-corners
 7-1-box-shadow-with-spread-and-blur
+7-1-box-shadow-with-spread-and-rounded-corners
+7-1-box-shadow-with-spread-blur-and-rounded-corners
 7-1-circle-box-shadow-offset-top-left
 7-1-circle-box-shadow-with-inset
 7-1-circle-box-shadow-with-spread
 7-1-simple-black-box-shadow
 7-1-simple-red-box-shadow
+
diff --git a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-numerical-font-weights-in-family-face-matching-expected.png b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-numerical-font-weights-in-family-face-matching-expected.png
index 2b69abe..c0f8d5e 100644
--- a/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-numerical-font-weights-in-family-face-matching-expected.png
+++ b/src/cobalt/layout_tests/testdata/css3-fonts/5-2-use-numerical-font-weights-in-family-face-matching-expected.png
Binary files differ
diff --git a/src/cobalt/layout_tests/testdata/web-platform-tests/XMLHttpRequest/web_platform_tests.txt b/src/cobalt/layout_tests/testdata/web-platform-tests/XMLHttpRequest/web_platform_tests.txt
index 8363eef..87dab78 100644
--- a/src/cobalt/layout_tests/testdata/web-platform-tests/XMLHttpRequest/web_platform_tests.txt
+++ b/src/cobalt/layout_tests/testdata/web-platform-tests/XMLHttpRequest/web_platform_tests.txt
@@ -142,7 +142,7 @@
 send-conditional.htm,FAIL
 send-content-type-charset.htm,FAIL
 send-content-type-string.htm,FAIL
-send-data-arraybuffer.htm,FAIL
+send-data-arraybuffer.htm,PASS
 send-data-blob.htm,FAIL
 send-data-es-object.htm,DISABLE
 send-data-unexpected-tostring.htm,FAIL
diff --git a/src/cobalt/render_tree/resource_provider.h b/src/cobalt/render_tree/resource_provider.h
index aa716d7..69e0f6c 100644
--- a/src/cobalt/render_tree/resource_provider.h
+++ b/src/cobalt/render_tree/resource_provider.h
@@ -97,7 +97,7 @@
   // Return the associated SbDecodeTargetProvider with the ResourceProvider,
   // if it exists.  Returns NULL if SbDecodeTarget is not supported.
   virtual SbDecodeTargetProvider* GetSbDecodeTargetProvider() = 0;
-#endif  // SB_VERSION(3) && SB_HAS(GRAPHICS)
+#endif  // SB__API_VERSION >= 4
 #endif  // SB_HAS(GRAPHICS)
 
   // Returns a raw chunk of memory that can later be passed into a function like
diff --git a/src/cobalt/render_tree/resource_provider_stub.h b/src/cobalt/render_tree/resource_provider_stub.h
index 84658d8..5d33cd0 100644
--- a/src/cobalt/render_tree/resource_provider_stub.h
+++ b/src/cobalt/render_tree/resource_provider_stub.h
@@ -223,6 +223,7 @@
   bool SupportsSbDecodeTarget() OVERRIDE { return false; }
 #endif  // SB_API_VERSION >= 3 && SB_HAS(GRAPHICS)
 
+#if SB_HAS(GRAPHICS)
 #if SB_API_VERSION >= 4
   SbDecodeTargetGraphicsContextProvider*
   GetSbDecodeTargetGraphicsContextProvider() OVERRIDE {
@@ -231,6 +232,7 @@
 #elif SB_API_VERSION >= 3
   SbDecodeTargetProvider* GetSbDecodeTargetProvider() OVERRIDE { return NULL; }
 #endif  // SB_API_VERSION >= 4
+#endif  // SB_HAS(GRAPHICS)
 
   scoped_ptr<RawImageMemory> AllocateRawImageMemory(size_t size_in_bytes,
                                                     size_t alignment) OVERRIDE {
diff --git a/src/cobalt/renderer/copy_font_data.gypi b/src/cobalt/renderer/copy_font_data.gypi
index 971f550..b62574e 100644
--- a/src/cobalt/renderer/copy_font_data.gypi
+++ b/src/cobalt/renderer/copy_font_data.gypi
@@ -22,10 +22,10 @@
 
     'conditions': [
       [ 'cobalt_font_package == "expanded"', {
-        'source_xml_file_dir': '<(static_contents_source_dir)/fonts/xml/common',
+        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
 
         'package_named_sans_serif': 4,
-        'package_named_serif': 4,
+        'package_named_serif': 3,
         'package_named_fcc_fonts': 2,
         'package_fallback_lang_non_cjk': 2,
         'package_fallback_lang_cjk': 2,
@@ -37,9 +37,9 @@
 
       # 'unlimited' is deprecated but is mapped to 'standard'
       [ 'cobalt_font_package == "standard" or cobalt_font_package == "unlimited"', {
-        'source_xml_file_dir': '<(static_contents_source_dir)/fonts/xml/common',
+        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
 
-        'package_named_sans_serif': 3,
+        'package_named_sans_serif': 4,
         'package_named_serif': 3,
         'package_named_fcc_fonts': 2,
         'package_fallback_lang_non_cjk': 2,
@@ -50,9 +50,9 @@
         'package_fallback_symbols': 1,
       }],
 
-      # '10megabytes' is deprecated but is mapped to 'limited_with_noto_jp'
+      # '10megabytes' is deprecated but is mapped to 'limited_with_jp'
       [ 'cobalt_font_package == "limited_with_jp" or cobalt_font_package == "10megabytes"', {
-        'source_xml_file_dir': '<(static_contents_source_dir)/fonts/xml/common',
+        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
 
         'package_named_sans_serif': 2,
         'package_named_serif': 0,
@@ -66,7 +66,7 @@
       }],
 
       [ 'cobalt_font_package == "limited"', {
-        'source_xml_file_dir': '<(static_contents_source_dir)/fonts/xml/common',
+        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
 
         'package_named_sans_serif': 2,
         'package_named_serif': 0,
@@ -80,7 +80,7 @@
       }],
 
       [ 'cobalt_font_package == "minimal"', {
-        'source_xml_file_dir': '<(static_contents_source_dir)/fonts/xml/common',
+        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/common',
 
         'package_named_sans_serif': 0,
         'package_named_serif': 0,
@@ -97,7 +97,7 @@
         # fonts.xml contains a superset of what we expect to find on Android
         # devices. The Android SbFile implementation falls back to system font
         # files for those not in cobalt content.
-        'source_xml_file_dir': '<(static_contents_source_dir)/fonts/xml/android',
+        'source_font_config_dir': '<(static_contents_source_dir)/fonts/config/android',
 
         # Emojis are currently included because Cobalt's version of Skia does
         # not support Android's color emojis and will be removed when Skia is
@@ -147,7 +147,7 @@
     {
       'destination': '<(static_contents_output_data_dir)/fonts/',
       'files': [
-        '<(source_xml_file_dir)/fonts.xml',
+        '<(source_font_config_dir)/fonts.xml',
       ],
       'conditions': [
         [ 'package_named_sans_serif == 0', {
@@ -171,6 +171,18 @@
             '<(source_font_files_dir)/Roboto-BoldItalic.ttf',
           ],
         }],
+        [ 'package_named_sans_serif >= 4', {
+          'files+': [
+            '<(source_font_files_dir)/Roboto-Thin.ttf',
+            '<(source_font_files_dir)/Roboto-ThinItalic.ttf',
+            '<(source_font_files_dir)/Roboto-Light.ttf',
+            '<(source_font_files_dir)/Roboto-LightItalic.ttf',
+            '<(source_font_files_dir)/Roboto-Medium.ttf',
+            '<(source_font_files_dir)/Roboto-MediumItalic.ttf',
+            '<(source_font_files_dir)/Roboto-Black.ttf',
+            '<(source_font_files_dir)/Roboto-BlackItalic.ttf',
+          ],
+        }],
         [ 'package_named_serif >= 1', {
           'files+': [
             '<(source_font_files_dir)/NotoSerif-Regular.ttf',
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_alpha_texcoords_and_color.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_alpha_texcoords_and_color.glsl
new file mode 100644
index 0000000..418d2b8
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_alpha_texcoords_and_color.glsl
@@ -0,0 +1,26 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec3 ucircle_Stage1;

+uniform float uRTHeight;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+void main() 

+{

+  vec4 fragCoordYDown =

+      vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+  vec4 output_Stage0;

+  {

+    // Stage 0: Texture

+    output_Stage0 =

+        (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0).aaaa);

+  }

+  vec4 output_Stage1;

+  {

+    // Stage 1: Circle

+    float d = length(ucircle_Stage1.xy - fragCoordYDown.xy) - ucircle_Stage1.z;

+    d = clamp(d, 0.0, 1.0);

+    output_Stage1 = (output_Stage0 * d);

+  }

+  gl_FragColor = output_Stage1;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_alpha_texcoords_and_color_negative.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_alpha_texcoords_and_color_negative.glsl
new file mode 100644
index 0000000..00529b7
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_alpha_texcoords_and_color_negative.glsl
@@ -0,0 +1,26 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec3 ucircle_Stage1;

+uniform float uRTHeight;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+void main() 

+{

+  vec4 fragCoordYDown =

+      vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+  vec4 output_Stage0;

+  {

+    // Stage 0: Texture

+    output_Stage0 =

+        (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0).aaaa);

+  }

+  vec4 output_Stage1;

+  {

+    // Stage 1: Circle

+    float d = ucircle_Stage1.z - length(fragCoordYDown.xy - ucircle_Stage1.xy);

+    d = clamp(d, 0.0, 1.0);

+    output_Stage1 = (output_Stage0 * d);

+  }

+  gl_FragColor = output_Stage1;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_circle_edge.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_circle_edge.glsl
new file mode 100644
index 0000000..2bfdc7f
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_circle_edge.glsl
@@ -0,0 +1,33 @@
+#version 100

+precision mediump float;

+uniform vec3 ucircle_Stage1;

+uniform float uRTHeight;

+uniform vec3 ucircle_Stage2;

+varying vec4 vColor;

+varying vec4 vCircleEdge_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: CircleEdge

+		float d = length(vCircleEdge_Stage0.xy);

+		float edgeAlpha = clamp(vCircleEdge_Stage0.z - d, 0.0, 1.0);

+		output_Stage0 = vec4(edgeAlpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: Circle

+		float d = length(ucircle_Stage1.xy - fragCoordYDown.xy) - ucircle_Stage1.z;

+		d = clamp(d, 0.0, 1.0);

+		output_Stage1 = (output_Stage0 * d);

+	}

+	vec4 output_Stage2;

+	{

+		// Stage 2: Circle

+		float d = ucircle_Stage2.z - length(fragCoordYDown.xy - ucircle_Stage2.xy);

+		d = clamp(d, 0.0, 1.0);

+		output_Stage2 = (output_Stage1 * d);

+	}

+	gl_FragColor = (vColor * output_Stage2);

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_texture_negative.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_texture_negative.glsl
new file mode 100644
index 0000000..9d74546
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circle_masked_texture_negative.glsl
@@ -0,0 +1,24 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec3 ucircle_Stage1;

+uniform float uRTHeight;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: Texture

+		output_Stage0 = (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0));

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: Circle

+		float d = length(ucircle_Stage1.xy - fragCoordYDown.xy) - ucircle_Stage1.z;

+		d = clamp(d, 0.0, 1.0);

+		output_Stage1 = (output_Stage0 * d);

+	}

+	gl_FragColor = output_Stage1;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_circle_edge.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_circle_edge.glsl
new file mode 100644
index 0000000..81428de
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_circle_edge.glsl
@@ -0,0 +1,29 @@
+#version 100

+precision mediump float;

+uniform vec4 uinnerRect_Stage1;

+uniform float uradiusPlusHalf_Stage1;

+uniform float uRTHeight;

+varying vec4 vColor;

+varying vec4 vCircleEdge_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: CircleEdge

+		float d = length(vCircleEdge_Stage0.xy);

+		float edgeAlpha = clamp(vCircleEdge_Stage0.z - d, 0.0, 1.0);

+		output_Stage0 = vec4(edgeAlpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage1 - length(dxy), 0.0, 1.0);

+		alpha = 1.0 - alpha;

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = (vColor * output_Stage1);

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_gr_rrect_blur.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_gr_rrect_blur.glsl
new file mode 100644
index 0000000..78f115b
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_gr_rrect_blur.glsl
@@ -0,0 +1,52 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec4 uproxyRect_Stage0;

+uniform float ucornerRadius_Stage0;

+uniform float ublurRadius_Stage0;

+uniform float uRTHeight;

+uniform vec4 uinnerRect_Stage1;

+uniform float uradiusPlusHalf_Stage1;

+varying vec4 vColor;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: GrRRectBlur

+		vec2 rectCenter = (uproxyRect_Stage0.xy + uproxyRect_Stage0.zw)/2.0;

+		vec2 translatedFragPos = fragCoordYDown.xy - uproxyRect_Stage0.xy;

+		float threshold = ucornerRadius_Stage0 + 2.0*ublurRadius_Stage0;

+		vec2 middle = uproxyRect_Stage0.zw - uproxyRect_Stage0.xy - 2.0*threshold;

+		if (translatedFragPos.x >= threshold && translatedFragPos.x < (middle.x+threshold)) 

+		{

+			translatedFragPos.x = threshold;

+		}

+		else if (translatedFragPos.x >= (middle.x + threshold)) 

+		{

+			translatedFragPos.x -= middle.x - 1.0;

+		}

+		if (translatedFragPos.y > threshold && translatedFragPos.y < (middle.y+threshold)) 

+		{

+			translatedFragPos.y = threshold;

+		}

+		else if (translatedFragPos.y >= (middle.y + threshold)) 

+		{

+			translatedFragPos.y -= middle.y - 1.0;

+		}

+		vec2 proxyDims = vec2(2.0*threshold+1.0);

+		vec2 texCoord = translatedFragPos / proxyDims;

+		output_Stage0 = (vColor * texture2D(uSampler0_Stage0, texCoord).aaaa);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage1 - length(dxy), 0.0, 1.0);

+		alpha = 1.0 - alpha;

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = output_Stage1;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_rect_blur.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_rect_blur.glsl
new file mode 100644
index 0000000..c363929
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_rect_blur.glsl
@@ -0,0 +1,47 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec4 uproxyRect_Stage0;

+uniform float uprofileSize_Stage0;

+uniform float uRTHeight;

+uniform vec4 uinnerRect_Stage1;

+uniform float uradiusPlusHalf_Stage1;

+varying vec4 vColor;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: RectBlur

+		vec4 src=vColor;

+		vec2 translatedPos = fragCoordYDown.xy - uproxyRect_Stage0.xy;

+		float width = uproxyRect_Stage0.z - uproxyRect_Stage0.x;

+		float height = uproxyRect_Stage0.w - uproxyRect_Stage0.y;

+		vec2 smallDims = vec2(width - uprofileSize_Stage0, height-uprofileSize_Stage0);

+		float center = 2.0 * floor(uprofileSize_Stage0/2.0 + .25) - 1.0;

+		vec2 wh = smallDims - vec2(center,center);

+		float horiz_lookup;

+		{

+			float coord = (0.5 * (abs(2.0*translatedPos.x - width) - wh.x))/uprofileSize_Stage0;

+			horiz_lookup = texture2D(uSampler0_Stage0, vec2(coord,0.5)).aaaa.a;

+		}

+		float vert_lookup;

+		{

+			float coord = (0.5 * (abs(2.0*translatedPos.y - height) - wh.y))/uprofileSize_Stage0;

+			vert_lookup = texture2D(uSampler0_Stage0, vec2(coord,0.5)).aaaa.a;

+		}

+		float final = horiz_lookup * vert_lookup;

+		output_Stage0 = src * vec4(final);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage1 - length(dxy), 0.0, 1.0);

+		alpha = 1.0 - alpha;

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = output_Stage1;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_rect_ring.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_rect_ring.glsl
new file mode 100644
index 0000000..d76962f
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_rect_ring.glsl
@@ -0,0 +1,45 @@
+#version 100

+precision mediump float;

+uniform vec4 urect_Stage0;

+uniform float uRTHeight;

+uniform vec4 urect_Stage1;

+uniform vec4 uinnerRect_Stage2;

+uniform float uradiusPlusHalf_Stage2;

+varying vec4 vColor;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: AARect

+		float xSub, ySub;

+		xSub = min(fragCoordYDown.x - urect_Stage0.x, 0.0);

+		xSub += min(urect_Stage0.z - fragCoordYDown.x, 0.0);

+		ySub = min(fragCoordYDown.y - urect_Stage0.y, 0.0);

+		ySub += min(urect_Stage0.w - fragCoordYDown.y, 0.0);

+		float alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));

+		alpha = 1.0 - alpha;

+		output_Stage0 = (vColor * alpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: AARect

+		float xSub, ySub;

+		xSub = min(fragCoordYDown.x - urect_Stage1.x, 0.0);

+		xSub += min(urect_Stage1.z - fragCoordYDown.x, 0.0);

+		ySub = min(fragCoordYDown.y - urect_Stage1.y, 0.0);

+		ySub += min(urect_Stage1.w - fragCoordYDown.y, 0.0);

+		float alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	vec4 output_Stage2;

+	{

+		// Stage 2: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage2.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage2.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage2 - length(dxy), 0.0, 1.0);

+		output_Stage2 = (output_Stage1 * alpha);

+	}

+	gl_FragColor = output_Stage2;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_texture.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_texture.glsl
new file mode 100644
index 0000000..17a7770
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_texture.glsl
@@ -0,0 +1,27 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec4 uinnerRect_Stage1;

+uniform float uradiusPlusHalf_Stage1;

+uniform float uRTHeight;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: Texture

+		output_Stage0 = (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0));

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage1 - length(dxy), 0.0, 1.0);

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = output_Stage1;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_texture_negative.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_texture_negative.glsl
new file mode 100644
index 0000000..0c3de5d
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_circular_rrect_masked_texture_negative.glsl
@@ -0,0 +1,28 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec4 uinnerRect_Stage1;

+uniform float uradiusPlusHalf_Stage1;

+uniform float uRTHeight;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: Texture

+		output_Stage0 = (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0));

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage1 - length(dxy), 0.0, 1.0);

+		alpha = 1.0 - alpha;

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = output_Stage1;

+}

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
new file mode 100644
index 0000000..411e72a
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_rrect.glsl
@@ -0,0 +1,39 @@
+#version 100

+precision mediump float;

+uniform vec4 uinnerRect_Stage1;

+uniform float uRTHeight;

+uniform vec2 uinvRadiiXY_Stage1;

+varying vec4 vColor;

+varying vec2 vEllipseOffsets_Stage0;

+varying vec4 vEllipseRadii_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: EllipseEdge

+		vec2 scaledOffset = vEllipseOffsets_Stage0*vEllipseRadii_Stage0.xy;

+		float test = dot(scaledOffset, scaledOffset) - 1.0;

+		vec2 grad = 2.0*scaledOffset*vEllipseRadii_Stage0.xy;

+		float grad_dot = dot(grad, grad);

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

+		float invlen = inversesqrt(grad_dot);

+		float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);

+		output_Stage0 = vec4(edgeAlpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: EllipticalRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		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);

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

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = (vColor * output_Stage1);

+}

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
new file mode 100644
index 0000000..0c57707
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_masked_texture_negative.glsl
@@ -0,0 +1,33 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec4 uellipse_Stage1;

+uniform float uRTHeight;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+

+void main() {

+  vec4 fragCoordYDown =

+      vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+

+  vec4 output_Stage0;

+  {

+    // Stage 0: Texture

+    output_Stage0 = (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0));

+  }

+

+  vec4 output_Stage1;

+  {

+    // Stage 1: Ellipse

+    vec2 d = fragCoordYDown.xy - uellipse_Stage1.xy;

+    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);

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

+    output_Stage1 = (output_Stage0 * alpha);

+  }

+

+  gl_FragColor = output_Stage1;

+}
\ No newline at end of file
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
new file mode 100644
index 0000000..6616121
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_ellipse_ring_masked_color.glsl
@@ -0,0 +1,49 @@
+#version 100

+precision mediump float;

+uniform vec4 uellipse_Stage1;

+uniform float uRTHeight;

+uniform vec4 uellipse_Stage2;

+varying vec4 vColor;

+varying vec2 vEllipseOffsets_Stage0;

+varying vec4 vEllipseRadii_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: EllipseEdge

+		vec2 scaledOffset = vEllipseOffsets_Stage0*vEllipseRadii_Stage0.xy;

+		float test = dot(scaledOffset, scaledOffset) - 1.0;

+		vec2 grad = 2.0*scaledOffset*vEllipseRadii_Stage0.xy;

+		float grad_dot = dot(grad, grad);

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

+		float invlen = inversesqrt(grad_dot);

+		float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);

+		output_Stage0 = vec4(edgeAlpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: Ellipse

+		vec2 d = fragCoordYDown.xy - uellipse_Stage1.xy;

+		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);

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

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	vec4 output_Stage2;

+	{

+		// Stage 2: Ellipse

+		vec2 d = fragCoordYDown.xy - uellipse_Stage2.xy;

+		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);

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

+		output_Stage2 = (output_Stage1 * alpha);

+	}

+	gl_FragColor = (vColor * output_Stage2);

+}

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
new file mode 100644
index 0000000..054570a
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rect_edge_masked_ellipse.glsl
@@ -0,0 +1,50 @@
+#version 100

+precision mediump float;

+uniform vec4 urect_Stage0;

+uniform float uRTHeight;

+uniform vec4 urect_Stage1;

+uniform vec4 uinnerRect_Stage2;

+uniform vec2 uinvRadiiXY_Stage2;

+varying vec4 vColor;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: AARect

+		float xSub, ySub;

+		xSub = min(fragCoordYDown.x - urect_Stage0.x, 0.0);

+		xSub += min(urect_Stage0.z - fragCoordYDown.x, 0.0);

+		ySub = min(fragCoordYDown.y - urect_Stage0.y, 0.0);

+		ySub += min(urect_Stage0.w - fragCoordYDown.y, 0.0);

+		float alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));

+		alpha = 1.0 - alpha;

+		output_Stage0 = (vColor * alpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: AARect

+		float xSub, ySub;

+		xSub = min(fragCoordYDown.x - urect_Stage1.x, 0.0);

+		xSub += min(urect_Stage1.z - fragCoordYDown.x, 0.0);

+		ySub = min(fragCoordYDown.y - urect_Stage1.y, 0.0);

+		ySub += min(urect_Stage1.w - fragCoordYDown.y, 0.0);

+		float alpha = (1.0 + max(xSub, -1.0)) * (1.0 + max(ySub, -1.0));

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	vec4 output_Stage2;

+	{

+		// Stage 2: EllipticalRRect

+		vec2 dxy0 = uinnerRect_Stage2.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage2.zw;

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

+		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);

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

+		output_Stage2 = (output_Stage1 * alpha);

+	}

+	gl_FragColor = output_Stage2;

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_circle_edge.glsl b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_circle_edge.glsl
new file mode 100644
index 0000000..a74961c
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_circle_edge.glsl
@@ -0,0 +1,40 @@
+#version 100

+precision mediump float;

+uniform vec4 uinnerRect_Stage1;

+uniform float uradiusPlusHalf_Stage1;

+uniform float uRTHeight;

+uniform vec4 uinnerRect_Stage2;

+uniform float uradiusPlusHalf_Stage2;

+varying vec4 vColor;

+varying vec4 vCircleEdge_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: CircleEdge

+		float d = length(vCircleEdge_Stage0.xy);

+		float edgeAlpha = clamp(vCircleEdge_Stage0.z - d, 0.0, 1.0);

+		output_Stage0 = vec4(edgeAlpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage1 - length(dxy), 0.0, 1.0);

+		alpha = 1.0 - alpha;

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	vec4 output_Stage2;

+	{

+		// Stage 2: CircularRRect

+		vec2 dxy0 = uinnerRect_Stage2.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage2.zw;

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

+		float alpha = clamp(uradiusPlusHalf_Stage2 - length(dxy), 0.0, 1.0);

+		output_Stage2 = (output_Stage1 * alpha);

+	}

+	gl_FragColor = (vColor * output_Stage2);

+}

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
new file mode 100644
index 0000000..2a2574d
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture.glsl
@@ -0,0 +1,32 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec4 uinnerRect_Stage1;

+uniform float uRTHeight;

+uniform vec2 uinvRadiiXY_Stage1;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: Texture

+		output_Stage0 = (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0));

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: EllipticalRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		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);

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

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = output_Stage1;

+}

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
new file mode 100644
index 0000000..b2f1111
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_masked_texture_negative.glsl
@@ -0,0 +1,32 @@
+#version 100

+precision mediump float;

+uniform sampler2D uSampler0_Stage0;

+uniform vec4 uinnerRect_Stage1;

+uniform float uRTHeight;

+uniform vec2 uinvRadiiXY_Stage1;

+varying vec4 vColor;

+varying vec2 vMatrixCoord_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: Texture

+		output_Stage0 = (vColor * texture2D(uSampler0_Stage0, vMatrixCoord_Stage0));

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: EllipticalRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		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);

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

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	gl_FragColor = output_Stage1;

+}

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
new file mode 100644
index 0000000..97428cf
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/fragment_skia_rrect_ring_masked_ellipse_edge.glsl
@@ -0,0 +1,55 @@
+#version 100

+precision mediump float;

+uniform vec4 uinnerRect_Stage1;

+uniform float uRTHeight;

+uniform vec2 uinvRadiiXY_Stage1;

+uniform vec4 uinnerRect_Stage2;

+uniform vec2 uinvRadiiXY_Stage2;

+varying vec4 vColor;

+varying vec2 vEllipseOffsets_Stage0;

+varying vec4 vEllipseRadii_Stage0;

+void main() 

+{

+	vec4 fragCoordYDown = vec4(gl_FragCoord.x, uRTHeight - gl_FragCoord.y, 1.0, 1.0);

+	vec4 output_Stage0;

+	{

+		// Stage 0: EllipseEdge

+		vec2 scaledOffset = vEllipseOffsets_Stage0*vEllipseRadii_Stage0.xy;

+		float test = dot(scaledOffset, scaledOffset) - 1.0;

+		vec2 grad = 2.0*scaledOffset*vEllipseRadii_Stage0.xy;

+		float grad_dot = dot(grad, grad);

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

+		float invlen = inversesqrt(grad_dot);

+		float edgeAlpha = clamp(0.5-test*invlen, 0.0, 1.0);

+		output_Stage0 = vec4(edgeAlpha);

+	}

+	vec4 output_Stage1;

+	{

+		// Stage 1: EllipticalRRect

+		vec2 dxy0 = uinnerRect_Stage1.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage1.zw;

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

+		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);

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

+		output_Stage1 = (output_Stage0 * alpha);

+	}

+	vec4 output_Stage2;

+	{

+		// Stage 2: EllipticalRRect

+		vec2 dxy0 = uinnerRect_Stage2.xy - fragCoordYDown.xy;

+		vec2 dxy1 = fragCoordYDown.xy - uinnerRect_Stage2.zw;

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

+		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);

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

+		output_Stage2 = (output_Stage1 * alpha);

+	}

+	gl_FragColor = (vColor * output_Stage2);

+}

diff --git a/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi b/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi
index 7f7455c..2740656 100644
--- a/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi
+++ b/src/cobalt/renderer/glimp_shaders/glsl/shaders.gypi
@@ -32,18 +32,31 @@
       'fragment_skia_antialiased_oval.glsl',
       'fragment_skia_bounded_x_convolution_filtered_texture.glsl',
       'fragment_skia_bounded_y_convolution_filtered_texture.glsl',
+      'fragment_skia_circle_masked_alpha_texcoords_and_color.glsl',
+      'fragment_skia_circle_masked_alpha_texcoords_and_color_negative.glsl',
+      'fragment_skia_circle_masked_circle_edge.glsl',
       'fragment_skia_circle_masked_texture.glsl',
       'fragment_skia_circle_masked_texture_domain.glsl',
+      'fragment_skia_circle_masked_texture_negative.glsl',
       'fragment_skia_circle_outside_masked_circle.glsl',
+      'fragment_skia_circular_rrect_masked_circle_edge.glsl',
+      'fragment_skia_circular_rrect_masked_gr_rrect_blur.glsl',
+      'fragment_skia_circular_rrect_masked_rect_blur.glsl',
+      'fragment_skia_circular_rrect_masked_rect_ring.glsl',
+      'fragment_skia_circular_rrect_masked_texture.glsl',
+      'fragment_skia_circular_rrect_masked_texture_negative.glsl',
       'fragment_skia_color_filtered_texture.glsl',
       'fragment_skia_color_only.glsl',
       'fragment_skia_color_with_coverage.glsl',
       'fragment_skia_convolution_filtered_texture.glsl',
       'fragment_skia_distance_field_texture.glsl',
       'fragment_skia_distance_field_texture_non_similar.glsl',
+      'fragment_skia_ellipse_masked_rrect.glsl',
       'fragment_skia_ellipse_masked_texture.glsl',
       'fragment_skia_ellipse_masked_texture_domain.glsl',
+      'fragment_skia_ellipse_masked_texture_negative.glsl',
       'fragment_skia_ellipse_outside_masked_ellipse.glsl',
+      'fragment_skia_ellipse_ring_masked_color.glsl',
       'fragment_skia_linear_gradient_many_colors.glsl',
       'fragment_skia_linear_gradient_three_colors.glsl',
       'fragment_skia_linear_gradient_two_colors.glsl',
@@ -52,9 +65,14 @@
       'fragment_skia_radial_gradient_three_colors.glsl',
       'fragment_skia_radial_gradient_two_colors.glsl',
       'fragment_skia_rect_blur.glsl',
+      'fragment_skia_rect_edge_masked_ellipse.glsl',
       'fragment_skia_rect_outside_masked_color.glsl',
       'fragment_skia_rect_outside_masked_rect_blur.glsl',
       'fragment_skia_rect_outside_masked_texture.glsl',
+      'fragment_skia_rrect_masked_circle_edge.glsl',
+      'fragment_skia_rrect_masked_texture.glsl',
+      'fragment_skia_rrect_masked_texture_negative.glsl',
+      'fragment_skia_rrect_ring_masked_ellipse_edge.glsl',
       'fragment_skia_texcoords_and_color.glsl',
       'fragment_skia_texcoords_and_color_with_edge_clamped_texels.glsl',
       'fragment_skia_texture_domain.glsl',
@@ -68,6 +86,7 @@
       'vertex_skia_antialiased_oval.glsl',
       'vertex_skia_color_only.glsl',
       'vertex_skia_color_with_coverage.glsl',
+      'vertex_skia_ellipse_edge.glsl',
       'vertex_skia_texcoords_and_color.glsl',
       'vertex_skia_texcoords_and_color_with_texcoord_matrix.glsl',
       'vertex_skia_texcoords_derived_from_position.glsl',
diff --git a/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_ellipse_edge.glsl b/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_ellipse_edge.glsl
new file mode 100644
index 0000000..358da94
--- /dev/null
+++ b/src/cobalt/renderer/glimp_shaders/glsl/vertex_skia_ellipse_edge.glsl
@@ -0,0 +1,27 @@
+#version 100

+uniform mat3 uViewM;

+uniform vec4 urtAdjustment;

+attribute vec2 inPosition;

+attribute vec4 inColor;

+attribute vec2 inEllipseOffset;

+attribute vec4 inEllipseRadii;

+varying vec4 vColor;

+varying vec2 vEllipseOffsets_Stage0;

+varying vec4 vEllipseRadii_Stage0;

+void main() 

+{

+	vec3 pos3 = uViewM * vec3(inPosition, 1);

+	vColor = inColor;

+	{

+		// Stage 0: EllipseEdge

+		vEllipseOffsets_Stage0 = inEllipseOffset;

+		vEllipseRadii_Stage0 = inEllipseRadii;

+	}

+	{

+		// Stage 1: Ellipse

+	}

+	{

+		// Stage 2: Ellipse

+	}

+	gl_Position = vec4(dot(pos3.xz, urtAdjustment.xy), dot(pos3.yz, urtAdjustment.zw), 0, pos3.z);

+}

diff --git a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc
index 664edb4..8f932a9 100644
--- a/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc
+++ b/src/cobalt/renderer/rasterizer/egl/textured_mesh_renderer.cc
@@ -182,7 +182,7 @@
 
     GL_CALL(glAttachShader(result.gl_program_id, blit_vertex_shader));
 
-    std::string sampler_type = "sampler";
+    std::string sampler_type = "sampler2D";
     if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
       sampler_type = "samplerExternalOES";
     }
diff --git a/src/cobalt/renderer/rasterizer/pixel_test.cc b/src/cobalt/renderer/rasterizer/pixel_test.cc
index 5700075..16b0c2a 100644
--- a/src/cobalt/renderer/rasterizer/pixel_test.cc
+++ b/src/cobalt/renderer/rasterizer/pixel_test.cc
@@ -2674,13 +2674,438 @@
       Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 0.0f));
 }
 
-TEST_F(PixelTest, BoxShadowWithInsetSpreadAndBlur) {
+TEST_F(PixelTest, BoxShadowWithInset25pxSpreadAndBlur) {
   TestTree(CreateShadowRectWithBackground(
       output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
       ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
       Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f));
 }
 
+TEST_F(PixelTest, BoxShadowCircleWithInset25pxSpreadAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest, BoxShadowCircleWithOutset25pxSpreadAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest, BoxShadowCircleWithInset25pxSpread1pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowCircleWithInset25pxSpread1pxBlurRoundedCornersAndNoOffset) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(0.0f, 0.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest, BoxShadowCircleWithOutset25pxSpread1pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest, BoxShadowCircleWithInset25pxSpread8pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest, BoxShadowCircleWithOutset25pxSpread8pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest, BoxShadowCircleWithInset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowBigCircleWithInset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 25, 150, 150),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(75, 75)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowCircleWithOutset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 50, 50),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(25, 25)));
+}
+
+TEST_F(PixelTest, BoxShadowEllipseWithInset25pxSpreadAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest, BoxShadowEllipseWithOutset25pxSpreadAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest, BoxShadowEllipseWithInset25pxSpread1pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowEllipseWithOutset25pxSpread1pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest, BoxShadowEllipseWithInset25pxSpread8pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowEllipseWithOutset25pxSpread8pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowEllipseWithInset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowBigEllipseWithInset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 25, 190, 150),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(95, 75)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowEllipseWithOutset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 140, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(70, 50)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset5pxSpreadAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(20, 20)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset5pxSpreadAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(20, 20)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset25pxSpreadAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(20, 20)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset25pxSpreadAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), false,
+      25.0f, RoundedCorners(20, 20)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset5pxSpread5pxBlurAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(0.0f, 0.0f), 5.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset5pxSpread5pxBlurAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(0.0f, 0.0f), 5.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset5pxSpreadAndDifferentRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(20, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset5pxSpreadAndDifferentRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), false, 5.0f,
+      RoundedCorners(20, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset5pxSpread25pxBlurAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 25.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(20, 20)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset5pxSpread25pxBlurAndSameRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 25.0f, ColorRGBA(0, 0, 0, 1)), false,
+      5.0f, RoundedCorners(20, 20)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithInset5pxSpread25pxBlurAndDifferentRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 25.0f, ColorRGBA(0, 0, 0, 1)), true, 5.0f,
+      RoundedCorners(20, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithOutset5pxSpread25pxBlurAndDifferentRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(10.0f, 10.0f), 25.0f, ColorRGBA(0, 0, 0, 1)), false,
+      5.0f, RoundedCorners(20, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset25pxSpreadAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset25pxSpreadAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset25pxSpread1pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset25pxSpread1pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset25pxSpread8pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset25pxSpread8pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset25pxSpread50pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(25, 50, 150, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(5, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInset25pxSpreadAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutset25pxSpreadAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 0.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithInset25pxSpread1pxBlurAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithOutset25pxSpread1pxBlurAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 1.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithInset25pxSpread8pxBlurAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithOutset25pxSpread8pxBlurAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 8.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithInset25pxSpread50pxBlurAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), true, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithOutset25pxSpread50pxBlurAndIsometricRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(8.0f, 8.0f), 50.0f, ColorRGBA(0, 0, 0, 1)), false, 25.0f,
+      RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(-15.0f, 20.0f), 10.0f, ColorRGBA(0, 0, 0, 1)), true,
+      -10.0f, RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest,
+       BoxShadowWithOutsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(-15.0f, 20.0f), 10.0f, ColorRGBA(0, 0, 0, 1)), false,
+      -10.0f, RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithInsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(-15.0f, 20.0f), 2.0f, ColorRGBA(0, 0, 0, 1)), true,
+      -10.0f, RoundedCorners(10, 10)));
+}
+
+TEST_F(PixelTest, BoxShadowWithOutsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners) {
+  TestTree(CreateShadowRectWithBackground(
+      output_surface_size(), ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f),
+      ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), RectF(50, 50, 100, 100),
+      Shadow(Vector2dF(-15.0f, 20.0f), 2.0f, ColorRGBA(0, 0, 0, 1)), false,
+      -10.0f, RoundedCorners(10, 10)));
+}
+
 TEST_F(PixelTest, FilterBlurred0Point1PxText) {
   TestTree(new FilterNode(
       BlurFilter(0.1f),
diff --git a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
index 2554c09..a892498 100644
--- a/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/hardware_resource_provider.cc
@@ -302,7 +302,7 @@
   SkAutoTUnref<SkTypeface_Cobalt> typeface(
       base::polymorphic_downcast<SkTypeface_Cobalt*>(
           font_manager->matchFamilyStyleCharacter(
-              0, CobaltFontStyleToSkFontStyle(font_style), language.c_str(),
+              NULL, CobaltFontStyleToSkFontStyle(font_style), language.c_str(),
               character)));
   return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
 }
diff --git a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
index 1e2f1cf..f8b34ab 100644
--- a/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
+++ b/src/cobalt/renderer/rasterizer/skia/render_tree_node_visitor.cc
@@ -1442,35 +1442,54 @@
 
 void DrawRoundedRectShadowNode(render_tree::RectShadowNode* node,
                                SkCanvas* canvas) {
-  if (node->data().shadow.blur_sigma > 0.0f) {
-    NOTIMPLEMENTED() << "Cobalt doesn't currently support rendering blurred "
-                        "box shadows on rounded rectangles.";
-    return;
-  }
-  if (!IsCircle(node->data().rect.size(), *node->data().rounded_corners)) {
-    NOTIMPLEMENTED() << "Cobalt does not support box shadows with rounded "
-                        "corners that are not circles.";
-    return;
-  }
-
   RRect shadow_rrect = GetShadowRect(*node);
 
-  SkRRect skia_clip_rrect =
-      RoundedRectToSkia(node->data().rect, *node->data().rounded_corners);
-  SkRRect skia_draw_rrect =
-      RoundedRectToSkia(shadow_rrect.rect, *shadow_rrect.rounded_corners);
-
-  if (node->data().inset) {
-    std::swap(skia_clip_rrect, skia_draw_rrect);
-  }
-
   canvas->save();
 
-  canvas->clipRRect(skia_clip_rrect, SkRegion::kDifference_Op, true);
+  SkRRect skia_clip_rrect =
+      RoundedRectToSkia(node->data().rect, *node->data().rounded_corners);
+  SkRRect skia_shadow_rrect =
+      RoundedRectToSkia(shadow_rrect.rect, *shadow_rrect.rounded_corners);
 
-  SkPaint paint = GetPaintForBoxShadow(node->data().shadow);
-  paint.setAntiAlias(true);
-  canvas->drawRRect(skia_draw_rrect, paint);
+  if (node->data().inset) {
+    // Calculate the outer rect to be large enough such that blurring the outer
+    // unseen edge will not affect the visible inner region of the shadow.
+    math::RectF outer_rect = shadow_rrect.rect;
+    math::Vector2dF common_outer_rect_outset =
+        node->data().shadow.BlurExtent() +
+        math::Vector2dF(node->data().spread, node->data().spread);
+    math::InsetsF outer_rect_outset(
+        common_outer_rect_outset.x() + node->data().shadow.offset.x(),
+        common_outer_rect_outset.y() + node->data().shadow.offset.y(),
+        common_outer_rect_outset.x() - node->data().shadow.offset.x(),
+        common_outer_rect_outset.y() - node->data().shadow.offset.y());
+    outer_rect_outset.set_left(std::max(0.0f, outer_rect_outset.left()));
+    outer_rect_outset.set_top(std::max(0.0f, outer_rect_outset.top()));
+    outer_rect_outset.set_right(std::max(0.0f, outer_rect_outset.right()));
+    outer_rect_outset.set_bottom(std::max(0.0f, outer_rect_outset.bottom()));
+    outer_rect.Outset(outer_rect_outset);
+
+    SkRRect skia_outer_draw_rrect =
+        RoundedRectToSkia(outer_rect, *shadow_rrect.rounded_corners);
+
+    canvas->clipRRect(skia_clip_rrect, SkRegion::kIntersect_Op, true);
+
+    SkPaint paint = GetPaintForBoxShadow(node->data().shadow);
+    paint.setAntiAlias(true);
+
+    // Draw a rounded rect "ring".  We draw a ring whose outer rectangle is
+    // larger than the clip rectangle so that we can blur it without the outer
+    // edge's blur reaching the visible region.
+    canvas->drawDRRect(skia_outer_draw_rrect, skia_shadow_rrect, paint);
+  } else {
+    // Draw a rounded rectangle, possibly blurred, as the shadow rectangle,
+    // clipped by node->data().rect.
+    canvas->clipRRect(skia_clip_rrect, SkRegion::kDifference_Op, true);
+
+    SkPaint paint = GetPaintForBoxShadow(node->data().shadow);
+    paint.setAntiAlias(true);
+    canvas->drawRRect(skia_shadow_rrect, paint);
+  }
 
   canvas->restore();
 }
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi b/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
index 41bb8a1..71ac5a6 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
+++ b/src/cobalt/renderer/rasterizer/skia/skia/skia_cobalt.gypi
@@ -41,7 +41,7 @@
   ],
 
   'defines': [
-    'COBALT_SYSTEM_TYPEFACE_CACHE_CAPACITY_IN_BYTES=<(local_font_cache_size_in_bytes)',
+    'COBALT_LOCAL_TYPEFACE_CACHE_SIZE_IN_BYTES=<(local_font_cache_size_in_bytes)',
   ],
 
   'include_dirs': [
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
index be914e6..206c6e3 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontConfigParser_cobalt.cc
@@ -19,6 +19,7 @@
 #include <stack>
 #include <string>
 
+#include "base/logging.h"
 #include "base/memory/scoped_ptr.h"
 #include "base/string_util.h"
 #include "base/stringprintf.h"
@@ -29,7 +30,7 @@
 
 namespace {
 
-const char* kSystemFontsFile = "fonts.xml";
+const char* kConfigFile = "fonts.xml";
 
 /////////////////////////////////////////////////////////////////////////////
 // Helpers
@@ -59,7 +60,7 @@
     int d = *s - '0';
     // Check for overflow
     if (n > n_max || (n == n_max && d > d_max)) {
-      SkDebugf("---- ParseNonNegativeInteger error: overflow)");
+      LOG(ERROR) << "---- ParseNonNegativeInteger error: overflow";
       return false;
     }
     n = (n * 10) + d;
@@ -68,6 +69,36 @@
   return true;
 }
 
+template <typename T>
+bool ParseInteger(const char* s, T* value) {
+  SK_COMPILE_ASSERT(std::numeric_limits<T>::is_signed, T_must_be_signed);
+  T multiplier = 1;
+  if (*s && *s == '-') {
+    multiplier = -1;
+    ++s;
+  }
+  if (!ParseNonNegativeInteger(s, value)) {
+    return false;
+  }
+  *value *= multiplier;
+  return true;
+}
+
+template <typename T>
+bool ParseFontWeight(const char* s, T* value) {
+  T n = 0;
+  if (!ParseNonNegativeInteger(s, &n)) {
+    return false;
+  }
+  // Verify that the weight is a multiple of 100 between 100 and 900.
+  // https://www.w3.org/TR/css-fonts-3/#font-weight-prop
+  if (n < 100 || n > 900 || n % 100 != 0) {
+    return false;
+  }
+  *value = n;
+  return true;
+}
+
 // The page range list is a comma-delimited list of character page ranges. Each
 // page range can either consist of either a single integer value, or a pair of
 // values separated by a hyphen (representing the min and max value of the
@@ -93,7 +124,8 @@
 
     for (int i = 0; i <= 1; ++i) {
       if (!IsAsciiDigit(*s)) {
-        SkDebugf("---- ParsePageRangeList error: non-ascii digit page range");
+        LOG(ERROR)
+            << "---- ParsePageRangeList error: non-ascii digit page range";
         return false;
       }
 
@@ -105,7 +137,7 @@
         int d = *s - '0';
         // Check for overflow
         if (n > n_max || (n == n_max && d > d_max)) {
-          SkDebugf("---- ParsePageRangeList error: page range overflow");
+          LOG(ERROR) << "---- ParsePageRangeList error: page range overflow";
           return false;
         }
 
@@ -117,7 +149,7 @@
         // max. Ranges must appear in order. If it isn't, then the parsing has
         // failed.
         if (last_max >= n) {
-          SkDebugf("---- ParsePageRangeList error: pages unordered");
+          LOG(ERROR) << "---- ParsePageRangeList error: pages unordered";
           return false;
         }
 
@@ -138,7 +170,7 @@
           range_value.second = n;
           ranges->push_back(range_value);
         } else {
-          SkDebugf("---- ParsePageRangeList error: page range flipped");
+          LOG(ERROR) << "---- ParsePageRangeList error: page range flipped";
           return false;
         }
       }
@@ -156,7 +188,7 @@
       if (*s == ',') {
         ++s;
       } else {
-        SkDebugf("---- ParsePageRangeList error: invalid character");
+        LOG(ERROR) << "---- ParsePageRangeList error: invalid character";
         return false;
       }
     }
@@ -243,13 +275,16 @@
   }
 
   // A <family> may have the following attributes:
-  // name (string), fallback (true, false), lang (string), pages (comma
+  // name (string), fallback_priority (int), lang (string), pages (comma
   // delimited int ranges)
   // A <family> tag must have a canonical name attribute or be a fallback
   // family in order to be usable, unless it is the default family.
-  // If the fallback attribute exists, then it alone determines whether the
-  // family is a fallback family.  However, if it does not exist, then the
-  // lack of a name attribute makes it a fallback family.
+  // A family is a fallback family if one of two conditions are met:
+  //   1. It does not have a "name" attribute.
+  //   2. It has a "fallback_priority" attribute.
+  // If the fallback_priority attribute exists, then the family is given the
+  // fallback priority specified by the value. If it does not exist, then the
+  // fallback priority defaults to 0.
   // The lang and pages attributes are only used by fallback families.
 
   bool encountered_fallback_attribute = false;
@@ -273,13 +308,20 @@
       family->language = SkLanguage(value);
     } else if (name_len == 5 && strncmp("pages", name, name_len) == 0) {
       if (!ParsePageRangeList(value, &family->page_ranges)) {
-        SkDebugf("---- Page ranges %s (INVALID)", value);
+        LOG(ERROR) << "---- Invalid page ranges [" << value << "]";
+        NOTREACHED();
         family->page_ranges.reset();
       }
-    } else if (name_len == 8 && strncmp("fallback", name, name_len) == 0) {
+    } else if (name_len == 17 &&
+               strncmp("fallback_priority", name, name_len) == 0) {
       encountered_fallback_attribute = true;
-      family->is_fallback_family =
-          strcmp("true", value) == 0 || strcmp("1", value) == 0;
+      if (!ParseInteger(value, &family->fallback_priority)) {
+        LOG(ERROR) << "---- Invalid fallback priority [" << value << "]";
+        NOTREACHED();
+      }
+    } else {
+      LOG(ERROR) << "---- Unsupported family attribute [" << name << "]";
+      NOTREACHED();
     }
   }
 }
@@ -301,7 +343,8 @@
       case 5:
         if (strncmp("index", name, 5) == 0) {
           if (!ParseNonNegativeInteger(value, &file->index)) {
-            DLOG(WARNING) << "Invalid font index [" << value << "]";
+            LOG(ERROR) << "---- Invalid font index [" << value << "]";
+            NOTREACHED();
           }
           continue;
         } else if (strncmp("style", name, 5) == 0) {
@@ -312,14 +355,16 @@
             file->style = FontFileInfo::kNormal_FontStyle;
             continue;
           } else {
-            NOTREACHED() << "Unsupported style [" << value << "]";
+            LOG(ERROR) << "---- Unsupported style [" << value << "]";
+            NOTREACHED();
           }
         }
         break;
       case 6:
         if (strncmp("weight", name, 6) == 0) {
-          if (!ParseNonNegativeInteger(value, &file->weight)) {
-            DLOG(WARNING) << "Invalid font weight [" << value << "]";
+          if (!ParseFontWeight(value, &file->weight)) {
+            LOG(ERROR) << "---- Invalid font weight [" << value << "]";
+            NOTREACHED();
           }
           continue;
         }
@@ -349,7 +394,8 @@
         break;
     }
 
-    NOTREACHED() << "Unsupported attribute [" << name << "]";
+    LOG(ERROR) << "---- Unsupported font attribute [" << name << "]";
+    NOTREACHED();
   }
 }
 
@@ -390,60 +436,19 @@
   // Assumes that the named family is already declared
   FontFamily* target_family = FindFamily(family_data, to.c_str());
   if (!target_family) {
-    SkDebugf("---- Font alias target %s (NOT FOUND)", to.c_str());
+    LOG(ERROR) << "---- Invalid alias target [name: " << alias_name.c_str()
+               << ", to: " << to.c_str() << "]";
+    NOTREACHED();
     return;
   } else if (alias_name.size() == 0) {
-    SkDebugf("---- Font alias name for %s (NOT SET)", to.c_str());
+    LOG(ERROR) << "---- Invalid alias name [to: " << to.c_str() << "]";
+    NOTREACHED();
     return;
   }
 
   target_family->names.push_back().set(alias_name);
 }
 
-bool FindWeight400(FontFamily* family) {
-  for (int i = 0; i < family->fonts.count(); i++) {
-    if (family->fonts[i].weight == 400) {
-      return true;
-    }
-  }
-  return false;
-}
-
-bool DesiredWeight(int weight) { return (weight == 400 || weight == 700); }
-
-int CountDesiredWeight(FontFamily* family) {
-  int count = 0;
-  for (int i = 0; i < family->fonts.count(); i++) {
-    if (DesiredWeight(family->fonts[i].weight)) {
-      count++;
-    }
-  }
-  return count;
-}
-
-// To meet Skia's expectations, any family that contains weight=400
-// fonts should *only* contain {400,700}
-void PurgeUndesiredWeights(FontFamily* family) {
-  int count = CountDesiredWeight(family);
-  for (int i = 1, j = 0; i < family->fonts.count(); i++) {
-    if (DesiredWeight(family->fonts[j].weight)) {
-      j++;
-    }
-    if ((i != j) && DesiredWeight(family->fonts[i].weight)) {
-      family->fonts[j] = family->fonts[i];
-    }
-  }
-  family->fonts.resize_back(count);
-}
-
-void FamilySetElementEndHandler(FamilyData* familyData) {
-  for (int i = 0; i < familyData->families->count(); i++) {
-    if (FindWeight400((*familyData->families)[i])) {
-      PurgeUndesiredWeights((*familyData->families)[i]);
-    }
-  }
-}
-
 void StartElement(void* data, const xmlChar* xml_tag,
                   const xmlChar** xml_attribute_pairs) {
   FamilyData* family_data = reinterpret_cast<FamilyData*>(data);
@@ -474,13 +479,12 @@
   const char* tag = reinterpret_cast<const char*>(xml_tag);
   size_t tag_len = strlen(tag);
 
-  if (tag_len == 9 && strncmp("familyset", tag, tag_len) == 0) {
-    FamilySetElementEndHandler(family_data);
-  } else if (tag_len == 6 && strncmp("family", tag, tag_len) == 0) {
+  if (tag_len == 6 && strncmp("family", tag, tag_len) == 0) {
     if (family_data->current_family != NULL) {
       *family_data->families->append() = family_data->current_family.release();
     } else {
-      SkDebugf("---- Encountered end family tag with no current family");
+      LOG(ERROR) << "---- Encountered end family tag with no current family";
+      NOTREACHED();
     }
   }
 
@@ -501,42 +505,43 @@
   va_list arguments;
   va_start(arguments, message);
 
-  SkDebugf("---- Parsing warning: %s",
-           StringPrintVAndTrim(message, arguments).c_str());
+  DLOG(WARNING) << "---- Parsing warning: "
+                << StringPrintVAndTrim(message, arguments).c_str();
 }
 
 void ParserError(void* context, const char* message, ...) {
   va_list arguments;
   va_start(arguments, message);
 
-  SkDebugf("---- Parsing error: %s",
-           StringPrintVAndTrim(message, arguments).c_str());
+  LOG(ERROR) << "---- Parsing error: "
+             << StringPrintVAndTrim(message, arguments).c_str();
+  NOTREACHED();
 }
 
 void ParserFatal(void* context, const char* message, ...) {
   va_list arguments;
   va_start(arguments, message);
 
-  SkDebugf("---- Parsing fatal error: %s",
-           StringPrintVAndTrim(message, arguments).c_str());
+  LOG(ERROR) << "---- Parsing fatal error: "
+             << StringPrintVAndTrim(message, arguments).c_str();
+  NOTREACHED();
 }
 
 // This function parses the given filename and stores the results in the given
 // families array.
-void ParseConfigFile(const char* directory, const char* filename,
-                     SkTDArray<FontFamily*>* families) {
-  SkString file_path = SkOSPath::Join(directory, filename);
+void ParseConfigFile(const char* directory, SkTDArray<FontFamily*>* families) {
+  SkString file_path = SkOSPath::Join(directory, kConfigFile);
 
   SkAutoTUnref<SkStream> file_stream(SkStream::NewFromFile(file_path.c_str()));
   if (file_stream == NULL) {
-    SkDebugf("---- Failed to open %s", file_path.c_str());
+    LOG(ERROR) << "---- Failed to open %s", file_path.c_str();
     return;
   }
 
   SkAutoDataUnref file_data(
       SkData::NewFromStream(file_stream, file_stream->getLength()));
   if (file_data == NULL) {
-    SkDebugf("---- Failed to read %s", file_path.c_str());
+    LOG(ERROR) << "---- Failed to read %s", file_path.c_str();
     return;
   }
 
@@ -546,11 +551,6 @@
                         static_cast<int>(file_data->size()));
 }
 
-void GetSystemFontFamilies(const char* directory,
-                           SkTDArray<FontFamily*>* font_families) {
-  ParseConfigFile(directory, kSystemFontsFile, font_families);
-}
-
 }  // namespace
 
 namespace SkFontConfigParser {
@@ -559,7 +559,7 @@
 // is returned in the given fontFamilies array.
 void GetFontFamilies(const char* directory,
                      SkTDArray<FontFamily*>* font_families) {
-  GetSystemFontFamilies(directory, font_families);
+  ParseConfigFile(directory, font_families);
 }
 
 }  // namespace SkFontConfigParser
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
index d77460a..850a112 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.cc
@@ -23,21 +23,39 @@
 #include "SkTSearch.h"
 
 SkFontMgr_Cobalt::SkFontMgr_Cobalt(
-    const char* directory, const SkTArray<SkString, true>& default_families)
-    : system_typeface_stream_manager_(
-          "Font.SystemTypeface",
-          COBALT_SYSTEM_TYPEFACE_CACHE_CAPACITY_IN_BYTES),
+    const char* cobalt_font_config_directory,
+    const char* cobalt_font_files_directory,
+    const char* system_font_config_directory,
+    const char* system_font_files_directory,
+    const SkTArray<SkString, true>& default_families)
+    : local_typeface_stream_manager_("Font.LocalTypefaceCache",
+                                     COBALT_LOCAL_TYPEFACE_CACHE_SIZE_IN_BYTES),
       default_family_(NULL) {
   TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::SkFontMgr_Cobalt()");
 
-  SkTDArray<FontFamily*> font_families;
-  {
-    TRACE_EVENT0("cobalt::renderer", "SkFontConfigParser::GetFontFamilies()");
-    SkFontConfigParser::GetFontFamilies(directory, &font_families);
-  }
-  BuildNameToFamilyMap(directory, &font_families);
-  font_families.deleteAll();
+  PriorityStyleSetArrayMap priority_fallback_families;
 
+  // Cobalt fonts are loaded first.
+  {
+    TRACE_EVENT0("cobalt::renderer", "LoadCobaltFontFamilies");
+    ParseConfigAndBuildFamilies(cobalt_font_config_directory,
+                                cobalt_font_files_directory,
+                                &priority_fallback_families);
+  }
+
+  // Only attempt to load the system font families if the system directories
+  // have been populated.
+  if (system_font_config_directory != NULL &&
+      *system_font_config_directory != '\0' &&
+      system_font_files_directory != NULL &&
+      *system_font_files_directory != '\0') {
+    TRACE_EVENT0("cobalt::renderer", "LoadSystemFontFamilies");
+    ParseConfigAndBuildFamilies(system_font_config_directory,
+                                system_font_files_directory,
+                                &priority_fallback_families);
+  }
+
+  GeneratePriorityOrderedFallbackFamilies(priority_fallback_families);
   FindDefaultFamily(default_families);
 }
 
@@ -232,26 +250,42 @@
   return matchFamilyStyle(family_name, style);
 }
 
-void SkFontMgr_Cobalt::BuildNameToFamilyMap(const char* base_path,
-                                            SkTDArray<FontFamily*>* families) {
+void SkFontMgr_Cobalt::ParseConfigAndBuildFamilies(
+    const char* font_config_directory, const char* font_files_directory,
+    PriorityStyleSetArrayMap* priority_fallback_families) {
+  SkTDArray<FontFamily*> font_families;
+  {
+    TRACE_EVENT0("cobalt::renderer", "SkFontConfigParser::GetFontFamilies()");
+    SkFontConfigParser::GetFontFamilies(font_config_directory, &font_families);
+  }
+  BuildNameToFamilyMap(font_files_directory, &font_families,
+                       priority_fallback_families);
+  font_families.deleteAll();
+}
+
+void SkFontMgr_Cobalt::BuildNameToFamilyMap(
+    const char* font_files_directory, SkTDArray<FontFamily*>* families,
+    PriorityStyleSetArrayMap* priority_fallback_families) {
   TRACE_EVENT0("cobalt::renderer", "SkFontMgr_Cobalt::BuildNameToFamilyMap()");
   for (int i = 0; i < families->count(); i++) {
     FontFamily& family = *(*families)[i];
     bool named_family = family.names.count() > 0;
 
-    if (family.is_fallback_family) {
-      if (!named_family) {
-        SkString& fallback_name = family.names.push_back();
-        fallback_name.printf("%.2x##fallback", i);
-      }
+    if (!named_family) {
+      // Unnamed families should always be fallback families.
+      DCHECK(family.is_fallback_family);
+      SkString& fallback_name = family.names.push_back();
+      fallback_name.printf("%.2x##fallback", font_style_sets_.count());
     }
 
     SkAutoTUnref<SkFontStyleSet_Cobalt> new_set(
         SkNEW_ARGS(SkFontStyleSet_Cobalt,
-                   (family, base_path, &system_typeface_stream_manager_,
-                    &style_sets_mutex_)));
+                   (family, font_files_directory,
+                    &local_typeface_stream_manager_, &style_sets_mutex_)));
 
-    // Verify that the set successfully added entries.
+    // Do not add the set if none of its fonts were available. This allows the
+    // config file to specify a superset of all fonts, and ones that are not
+    // included in the final package are stripped out.
     if (new_set->styles_.count() == 0) {
       continue;
     }
@@ -260,14 +294,26 @@
 
     if (named_family) {
       for (int j = 0; j < family.names.count(); j++) {
-        family_names_.push_back(family.names[j]);
-        name_to_family_map_.insert(
-            std::make_pair(family.names[j].c_str(), new_set.get()));
+        // Verify that the name was not previously added.
+        if (name_to_family_map_.find(family.names[j].c_str()) ==
+            name_to_family_map_.end()) {
+          family_names_.push_back(family.names[j]);
+          name_to_family_map_.insert(
+              std::make_pair(family.names[j].c_str(), new_set.get()));
+        } else {
+          NOTREACHED() << "Duplicate Font name: \"" << family.names[j].c_str()
+                       << "\"";
+        }
       }
     }
 
+    // If this is a fallback family, add it to the fallback family array
+    // that corresponds to its priority. This will be used to generate a
+    // priority-ordered fallback families list once the family map is fully
+    // built.
     if (family.is_fallback_family) {
-      fallback_families_.push_back(new_set.get());
+      (*priority_fallback_families)[family.fallback_priority].push_back(
+          new_set.get());
     }
 
     for (SkAutoTUnref<SkFontStyleSet_Cobalt::SkFontStyleSetEntry_Cobalt>*
@@ -290,23 +336,43 @@
             i == 0 ? full_font_name_to_style_set_map_
                    : font_postscript_name_to_style_set_map_;
 
+        // Verify that the font face name was not already added.
         if (font_face_name_style_set_map.find(font_face_name) ==
             font_face_name_style_set_map.end()) {
           font_face_name_style_set_map[font_face_name] = new_set.get();
         } else {
-          // Purposely, not overwriting the entry gives priority to the
-          // earlier entry.  This is consistent with how fonts.xml gives
-          // priority to fonts that are specified earlier in the file.
           const std::string font_face_name_type =
               i == 0 ? "Full Font" : "Postscript";
-          NOTREACHED() << font_face_name_type << " name [" << font_face_name
-                       << "] already registered in BuildNameToFamilyMap.";
+          NOTREACHED() << "Duplicate " << font_face_name_type << " name: \""
+                       << font_face_name << "\"";
         }
       }
     }
   }
 }
 
+void SkFontMgr_Cobalt::GeneratePriorityOrderedFallbackFamilies(
+    const PriorityStyleSetArrayMap& priority_fallback_families) {
+  // Reserve the combined size of the priority fallback families.
+  size_t reserve_size = 0;
+  for (PriorityStyleSetArrayMap::const_iterator iter =
+           priority_fallback_families.begin();
+       iter != priority_fallback_families.end(); ++iter) {
+    reserve_size += iter->second.size();
+  }
+  fallback_families_.reserve(reserve_size);
+
+  // Add each of the priority fallback families to |fallback_families_| in
+  // reverse order, so that higher priorities are added first. This results in
+  // |fallback_families_| being ordered by priority.
+  for (PriorityStyleSetArrayMap::const_reverse_iterator iter =
+           priority_fallback_families.rbegin();
+       iter != priority_fallback_families.rend(); ++iter) {
+    fallback_families_.insert(fallback_families_.end(), iter->second.begin(),
+                              iter->second.end());
+  }
+}
+
 void SkFontMgr_Cobalt::FindDefaultFamily(
     const SkTArray<SkString, true>& default_families) {
   CHECK(!font_style_sets_.empty());
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
index 081408e..5ea8eec 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h
@@ -15,6 +15,7 @@
 #ifndef COBALT_RENDERER_RASTERIZER_SKIA_SKIA_SRC_PORTS_SKFONTMGR_COBALT_H_
 #define COBALT_RENDERER_RASTERIZER_SKIA_SKIA_SRC_PORTS_SKFONTMGR_COBALT_H_
 
+#include <map>
 #include <string>
 #include <vector>
 
@@ -43,8 +44,12 @@
 class SkFontMgr_Cobalt : public SkFontMgr {
  public:
   typedef std::vector<SkFontStyleSet_Cobalt*> StyleSetArray;
+  typedef std::map<int, StyleSetArray> PriorityStyleSetArrayMap;
 
-  SkFontMgr_Cobalt(const char* directory,
+  SkFontMgr_Cobalt(const char* cobalt_font_config_directory,
+                   const char* cobalt_font_files_directory,
+                   const char* system_font_config_directory,
+                   const char* system_font_files_directory,
                    const SkTArray<SkString, true>& default_fonts);
 
   // NOTE: This returns NULL if a match is not found.
@@ -102,8 +107,14 @@
   typedef base::SmallMap<base::hash_map<std::string, StyleSetArray*> >
       NameToStyleSetArrayMap;
 
-  void BuildNameToFamilyMap(const char* base_path,
-                            SkTDArray<FontFamily*>* families);
+  void ParseConfigAndBuildFamilies(
+      const char* font_config_directory, const char* font_files_directory,
+      PriorityStyleSetArrayMap* priority_fallback_families);
+  void BuildNameToFamilyMap(
+      const char* font_files_directory, SkTDArray<FontFamily*>* families,
+      PriorityStyleSetArrayMap* priority_fallback_families);
+  void GeneratePriorityOrderedFallbackFamilies(
+      const PriorityStyleSetArrayMap& priority_fallback_families);
   void FindDefaultFamily(const SkTArray<SkString, true>& default_families);
 
   // Returns the first encountered fallback family that matches the language tag
@@ -118,7 +129,7 @@
   // NOTE: |style_sets_mutex_| should be locked prior to calling this function.
   StyleSetArray* GetMatchingFallbackFamilies(const SkString& language_tag);
 
-  SkFileMemoryChunkStreamManager system_typeface_stream_manager_;
+  SkFileMemoryChunkStreamManager local_typeface_stream_manager_;
 
   SkTArray<SkAutoTUnref<SkFontStyleSet_Cobalt>, true> font_style_sets_;
 
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt_factory.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt_factory.cc
index 9722f21..c323ed8 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt_factory.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt_factory.cc
@@ -14,17 +14,30 @@
 
 #include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontMgr_cobalt.h"
 
+#include "base/base_paths_starboard.h"
 #include "base/file_path.h"
 #include "base/file_util.h"
 #include "base/path_service.h"
 
 SkFontMgr* SkFontMgr::Factory() {
-  FilePath font_directory;
-  CHECK(PathService::Get(base::DIR_EXE, &font_directory));
-  font_directory = font_directory.Append(FILE_PATH_LITERAL("fonts"));
+  FilePath cobalt_font_directory;
+  CHECK(PathService::Get(base::DIR_EXE, &cobalt_font_directory));
+  cobalt_font_directory =
+      cobalt_font_directory.Append(FILE_PATH_LITERAL("fonts"));
+
+  FilePath system_font_config_directory;
+  PathService::Get(base::DIR_SYSTEM_FONTS_CONFIGURATION,
+                   &system_font_config_directory);
+
+  FilePath system_font_files_directory;
+  PathService::Get(base::DIR_SYSTEM_FONTS, &system_font_files_directory);
 
   SkTArray<SkString, true> default_families;
   default_families.push_back(SkString("sans-serif"));
 
-  return new SkFontMgr_Cobalt(font_directory.value().c_str(), default_families);
+  return new SkFontMgr_Cobalt(cobalt_font_directory.value().c_str(),
+                              cobalt_font_directory.value().c_str(),
+                              system_font_config_directory.value().c_str(),
+                              system_font_files_directory.value().c_str(),
+                              default_families);
 }
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
index 4a4f6c1..4774f00 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.cc
@@ -14,9 +14,10 @@
 
 #include "cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h"
 
-#include <cmath>
 #include <ft2build.h>
 #include FT_FREETYPE_H
+
+#include <cmath>
 #include <limits>
 
 #include "base/debug/trace_event.h"
@@ -28,10 +29,42 @@
 namespace {
 
 int MatchScore(const SkFontStyle& pattern, const SkFontStyle& candidate) {
+  // This logic is taken from Skia and is based upon the algorithm specified
+  // within the spec:
+  //   https://www.w3.org/TR/css-fonts-3/#font-matching-algorithm
+
   int score = 0;
-  score += std::abs((pattern.width() - candidate.width()) * 100);
-  score += (pattern.isItalic() == candidate.isItalic()) ? 0 : 1000;
-  score += std::abs(pattern.weight() - candidate.weight());
+
+  // CSS style (italic/oblique)
+  // Being italic trumps all valid weights which are not italic.
+  // Note that newer specs differentiate between italic and oblique.
+  if (pattern.isItalic() == candidate.isItalic()) {
+    score += 1001;
+  }
+
+  // The 'closer' to the target weight, the higher the score.
+  // 1000 is the 'heaviest' recognized weight
+  if (pattern.weight() == candidate.weight()) {
+    score += 1000;
+  } else if (pattern.weight() <= 500) {
+    if (400 <= pattern.weight() && pattern.weight() < 450) {
+      if (450 <= candidate.weight() && candidate.weight() <= 500) {
+        score += 500;
+      }
+    }
+    if (candidate.weight() <= pattern.weight()) {
+      score += 1000 - pattern.weight() + candidate.weight();
+    } else {
+      score += 1000 - candidate.weight();
+    }
+  } else if (pattern.weight() > 500) {
+    if (candidate.weight() > pattern.weight()) {
+      score += 1000 + pattern.weight() - candidate.weight();
+    } else {
+      score += candidate.weight();
+    }
+  }
+
   return score;
 }
 
@@ -53,13 +86,11 @@
 static void sk_cobalt_ft_stream_close(FT_Stream) {}
 }
 
-//  This class is used by SkFontMgr_Cobalt to hold SkTypeface_CobaltSystem
-//  families.
 SkFontStyleSet_Cobalt::SkFontStyleSet_Cobalt(
     const FontFamily& family, const char* base_path,
-    SkFileMemoryChunkStreamManager* const system_typeface_stream_manager,
+    SkFileMemoryChunkStreamManager* const local_typeface_stream_manager,
     SkMutex* const manager_owned_mutex)
-    : system_typeface_stream_manager_(system_typeface_stream_manager),
+    : local_typeface_stream_manager_(local_typeface_stream_manager),
       manager_owned_mutex_(manager_owned_mutex),
       is_fallback_family_(family.is_fallback_family),
       language_(family.language),
@@ -80,9 +111,10 @@
 
     SkString file_path(SkOSPath::Join(base_path, font_file.file_name.c_str()));
 
-    // Sanity check that something exists at this location.
+    // Validate that the file exists at this location. If it does not, then skip
+    // over it; it isn't being added to the set.
     if (!sk_exists(file_path.c_str(), kRead_SkFILE_Flag)) {
-      LOG(ERROR) << "Failed to find font file: " << file_path.c_str();
+      DLOG(INFO) << "Failed to find font file: " << file_path.c_str();
       continue;
     }
 
@@ -170,7 +202,7 @@
   SkFontStyleSetEntry_Cobalt* style = styles_[style_index];
   // If the typeface doesn't already exist, then attempt to create it.
   if (style->typeface == NULL) {
-    CreateSystemTypeface(style);
+    CreateStreamProviderTypeface(style);
     // If the creation attempt failed and the typeface is still NULL, then
     // remove the entry from the set's styles.
     if (style->typeface == NULL) {
@@ -236,7 +268,7 @@
       SkFontStyleSetEntry_Cobalt* closest_style = styles_[style_index];
 
       SkFileMemoryChunkStreamProvider* stream_provider =
-          system_typeface_stream_manager_->GetStreamProvider(
+          local_typeface_stream_manager_->GetStreamProvider(
               closest_style->font_file_path.c_str());
 
       // Create a snapshot prior to loading any additional memory chunks. In the
@@ -250,7 +282,7 @@
           stream_provider->OpenStream());
       if (GenerateStyleFaceInfo(closest_style, stream)) {
         if (CharacterMapContainsCharacter(character)) {
-          CreateSystemTypeface(closest_style, stream_provider);
+          CreateStreamProviderTypeface(closest_style, stream_provider);
           return true;
         } else {
           // If a typeface was not created, destroy the stream and purge any
@@ -359,25 +391,25 @@
 
 int SkFontStyleSet_Cobalt::GetClosestStyleIndex(const SkFontStyle& pattern) {
   int closest_index = 0;
-  int min_score = std::numeric_limits<int>::max();
+  int max_score = std::numeric_limits<int>::min();
   for (int i = 0; i < styles_.count(); ++i) {
     int score = MatchScore(pattern, styles_[i]->font_style);
-    if (score < min_score) {
+    if (score > max_score) {
       closest_index = i;
-      min_score = score;
+      max_score = score;
     }
   }
   return closest_index;
 }
 
-void SkFontStyleSet_Cobalt::CreateSystemTypeface(
+void SkFontStyleSet_Cobalt::CreateStreamProviderTypeface(
     SkFontStyleSetEntry_Cobalt* style_entry,
     SkFileMemoryChunkStreamProvider* stream_provider /*=NULL*/) {
   TRACE_EVENT0("cobalt::renderer",
-               "SkFontStyleSet_Cobalt::CreateSystemTypeface()");
+               "SkFontStyleSet_Cobalt::CreateStreamProviderTypeface()");
 
   if (!stream_provider) {
-    stream_provider = system_typeface_stream_manager_->GetStreamProvider(
+    stream_provider = local_typeface_stream_manager_->GetStreamProvider(
         style_entry->font_file_path.c_str());
   }
 
@@ -386,7 +418,7 @@
     LOG(ERROR) << "Scanned font from file: " << style_entry->face_name.c_str()
                << "(" << style_entry->face_style << ")";
     style_entry->typeface.reset(
-        SkNEW_ARGS(SkTypeface_CobaltSystem,
+        SkNEW_ARGS(SkTypeface_CobaltStreamProvider,
                    (stream_provider, style_entry->face_index,
                     style_entry->face_style, style_entry->face_is_fixed_pitch,
                     family_name_, style_entry->disable_synthetic_bolding)));
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h
index da1b701..3d1f7c7 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontStyleSet_cobalt.h
@@ -25,15 +25,12 @@
 #include "SkTArray.h"
 #include "SkTypeface.h"
 
-//  This class is used by SkFontMgr_Cobalt to hold SkTypeface_Cobalt families.
+// This class is used by SkFontMgr_Cobalt to store families of
+// SkTypeface_Cobalt objects.
 //
-//  To avoid the memory hit from keeping all fonts around, both the full
-//  character map for fonts and the font faces for fonts are lazily loaded
-//  when needed. After this, they are retained in memory.
-//
-//  The style sets contain an array of page ranges, providing information on
-//  characters that are potentially contained. To determine whether or not a
-//  character is actually contained, the full character map is generated.
+// Both the full character map of the style set and the typeface of each
+// individual entry are lazily loaded the first time that they are needed. After
+// this, they are retained in memory.
 class SkFontStyleSet_Cobalt : public SkFontStyleSet {
  public:
   struct SkFontStyleSetEntry_Cobalt : public SkRefCnt {
@@ -76,7 +73,7 @@
 
   SkFontStyleSet_Cobalt(
       const FontFamily& family, const char* base_path,
-      SkFileMemoryChunkStreamManager* const system_typeface_stream_manager,
+      SkFileMemoryChunkStreamManager* const local_typeface_stream_manager,
       SkMutex* const manager_owned_mutex);
 
   // From SkFontStyleSet
@@ -110,12 +107,12 @@
                              SkStreamAsset* stream);
 
   int GetClosestStyleIndex(const SkFontStyle& pattern);
-  void CreateSystemTypeface(
+  void CreateStreamProviderTypeface(
       SkFontStyleSetEntry_Cobalt* style,
       SkFileMemoryChunkStreamProvider* stream_provider = NULL);
 
   // NOTE: The following variables can safely be accessed outside of the mutex.
-  SkFileMemoryChunkStreamManager* const system_typeface_stream_manager_;
+  SkFileMemoryChunkStreamManager* const local_typeface_stream_manager_;
   SkMutex* const manager_owned_mutex_;
 
   SkString family_name_;
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
index ef1af47..5aeb2c8 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkFontUtil_cobalt.h
@@ -126,12 +126,13 @@
 // cannot possible contain a character, without needing to load the font file
 // and generate a full mapping of the font's characters.
 struct FontFamily {
-  FontFamily() : is_fallback_family(true) {}
+  FontFamily() : is_fallback_family(true), fallback_priority(0) {}
 
   SkTArray<SkString> names;
   SkTArray<FontFileInfo> fonts;
   SkLanguage language;
   bool is_fallback_family;
+  int fallback_priority;
   font_character_map::PageRanges page_ranges;
 };
 
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc
index 9d9f0de..4bec9d0 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.cc
@@ -35,7 +35,7 @@
                                                  const SkString family_name)
     : INHERITED(face_index, style, is_fixed_pitch, family_name),
       stream_(SkRef(stream)) {
-  LOG(INFO) << "Created SkTypeface_CobaltMemory: " << family_name.c_str() << "("
+  LOG(INFO) << "Created SkTypeface_CobaltStream: " << family_name.c_str() << "("
             << style << "); Size: " << stream_->getLength() << " bytes";
 }
 
@@ -54,7 +54,7 @@
   return stream_->duplicate();
 }
 
-SkTypeface_CobaltSystem::SkTypeface_CobaltSystem(
+SkTypeface_CobaltStreamProvider::SkTypeface_CobaltStreamProvider(
     SkFileMemoryChunkStreamProvider* stream_provider, int face_index,
     Style style, bool is_fixed_pitch, const SkString family_name,
     bool disable_synthetic_bolding)
@@ -63,10 +63,13 @@
   if (disable_synthetic_bolding) {
     synthesizes_bold_ = false;
   }
+  LOG(INFO) << "Created SkTypeface_CobaltStreamProvider: "
+            << family_name.c_str() << "(" << style << "); File: \""
+            << stream_provider->file_path() << "\"";
 }
 
-void SkTypeface_CobaltSystem::onGetFontDescriptor(SkFontDescriptor* descriptor,
-                                                  bool* serialize) const {
+void SkTypeface_CobaltStreamProvider::onGetFontDescriptor(
+    SkFontDescriptor* descriptor, bool* serialize) const {
   SkASSERT(descriptor);
   SkASSERT(serialize);
   descriptor->setFamilyName(family_name_.c_str());
@@ -75,7 +78,8 @@
   *serialize = false;
 }
 
-SkStreamAsset* SkTypeface_CobaltSystem::onOpenStream(int* face_index) const {
+SkStreamAsset* SkTypeface_CobaltStreamProvider::onOpenStream(
+    int* face_index) const {
   *face_index = face_index_;
   return stream_provider_->OpenStream();
 }
diff --git a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h
index 0299cf2..4fcbda5 100644
--- a/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h
+++ b/src/cobalt/renderer/rasterizer/skia/skia/src/ports/SkTypeface_cobalt.h
@@ -57,12 +57,12 @@
   SkAutoTUnref<SkStreamAsset> stream_;
 };
 
-class SkTypeface_CobaltSystem : public SkTypeface_Cobalt {
+class SkTypeface_CobaltStreamProvider : public SkTypeface_Cobalt {
  public:
-  SkTypeface_CobaltSystem(SkFileMemoryChunkStreamProvider* stream_provider,
-                          int face_index, Style style, bool is_fixed_pitch,
-                          const SkString family_name,
-                          bool disable_synthetic_bolding);
+  SkTypeface_CobaltStreamProvider(
+      SkFileMemoryChunkStreamProvider* stream_provider, int face_index,
+      Style style, bool is_fixed_pitch, const SkString family_name,
+      bool disable_synthetic_bolding);
 
   virtual void onGetFontDescriptor(SkFontDescriptor* descriptor,
                                    bool* serialize) const SK_OVERRIDE;
diff --git a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
index 05e9723..e4db0c1 100644
--- a/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
+++ b/src/cobalt/renderer/rasterizer/skia/software_resource_provider.cc
@@ -156,7 +156,7 @@
   SkAutoTUnref<SkTypeface_Cobalt> typeface(
       base::polymorphic_downcast<SkTypeface_Cobalt*>(
           font_manager->matchFamilyStyleCharacter(
-              0, CobaltFontStyleToSkFontStyle(font_style), language.c_str(),
+              NULL, CobaltFontStyleToSkFontStyle(font_style), language.c_str(),
               character)));
   return scoped_refptr<render_tree::Typeface>(new SkiaTypeface(typeface));
 }
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowBigCircleWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowBigCircleWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..ea5b4e4
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowBigCircleWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowBigEllipseWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowBigEllipseWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..3703a08
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowBigEllipseWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..6fa5660
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread1pxBlurRoundedCornersAndNoOffset-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread1pxBlurRoundedCornersAndNoOffset-expected.png
new file mode 100644
index 0000000..f0f7ced
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread1pxBlurRoundedCornersAndNoOffset-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..972251c
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..1ce7f87
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpreadAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpreadAndRoundedCorners-expected.png
new file mode 100644
index 0000000..fdb1ab5
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithInset25pxSpreadAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..c8a5658
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..cd1622d
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..6f29c1b
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpreadAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpreadAndRoundedCorners-expected.png
new file mode 100644
index 0000000..4414735
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowCircleWithOutset25pxSpreadAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..c326226
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..e4edc94
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..1135b9e
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpreadAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpreadAndRoundedCorners-expected.png
new file mode 100644
index 0000000..eb92cb0
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithInset25pxSpreadAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..b48173a
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..5f0d31b
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..9858145
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpreadAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpreadAndRoundedCorners-expected.png
new file mode 100644
index 0000000..feb36f8
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowEllipseWithOutset25pxSpreadAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread1pxBlurAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread1pxBlurAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..3ed1914
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread1pxBlurAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..3e9dcec
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread1pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread50pxBlurAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread50pxBlurAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..f52bd50
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread50pxBlurAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..231ea75
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread8pxBlurAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread8pxBlurAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..6abbaea
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread8pxBlurAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..8aede5c
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpread8pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndBlur-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndBlur-expected.png
new file mode 100644
index 0000000..d56f9e7
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndBlur-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..97a82a7
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndRoundedCorners-expected.png
new file mode 100644
index 0000000..40d0cb8
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..fe6139d
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset25pxSpreadAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread25pxBlurAndDifferentRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread25pxBlurAndDifferentRoundedCorners-expected.png
new file mode 100644
index 0000000..4bae443
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread25pxBlurAndDifferentRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread25pxBlurAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread25pxBlurAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..bc32f8b
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread25pxBlurAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread5pxBlurAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread5pxBlurAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..4a22bfe
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpread5pxBlurAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpreadAndDifferentRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpreadAndDifferentRoundedCorners-expected.png
new file mode 100644
index 0000000..2a2bad9
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpreadAndDifferentRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpreadAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpreadAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..62e395b
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInset5pxSpreadAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..c0e1add
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..a96d677
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetSpreadAndBlur-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetSpreadAndBlur-expected.png
deleted file mode 100644
index 717f915..0000000
--- a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithInsetSpreadAndBlur-expected.png
+++ /dev/null
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread1pxBlurAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread1pxBlurAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..debca65
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread1pxBlurAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..9e0f04e
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread1pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread50pxBlurAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread50pxBlurAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..3c9930d
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread50pxBlurAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..f1ffda8
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread50pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread8pxBlurAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread8pxBlurAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..24b1a05
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread8pxBlurAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..92e9577
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpread8pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndIsometricRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndIsometricRoundedCorners-expected.png
new file mode 100644
index 0000000..9501789
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndIsometricRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndRoundedCorners-expected.png
new file mode 100644
index 0000000..d989a78
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..d567767
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset25pxSpreadAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread25pxBlurAndDifferentRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread25pxBlurAndDifferentRoundedCorners-expected.png
new file mode 100644
index 0000000..a8b1437
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread25pxBlurAndDifferentRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread25pxBlurAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread25pxBlurAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..a06eaf1
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread25pxBlurAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread5pxBlurAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread5pxBlurAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..4a22bfe
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpread5pxBlurAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpreadAndDifferentRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpreadAndDifferentRoundedCorners-expected.png
new file mode 100644
index 0000000..c77b7f7
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpreadAndDifferentRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpreadAndSameRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpreadAndSameRoundedCorners-expected.png
new file mode 100644
index 0000000..4db2929
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutset5pxSpreadAndSameRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..300b031
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutsetNeg10pxSpreadAnd10pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners-expected.png b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners-expected.png
new file mode 100644
index 0000000..00b6797
--- /dev/null
+++ b/src/cobalt/renderer/rasterizer/testdata/BoxShadowWithOutsetNeg10pxSpreadAnd2pxBlurAndRoundedCorners-expected.png
Binary files differ
diff --git a/src/cobalt/renderer/renderer_module.cc b/src/cobalt/renderer/renderer_module.cc
index 04d18b9..28cbe93 100644
--- a/src/cobalt/renderer/renderer_module.cc
+++ b/src/cobalt/renderer/renderer_module.cc
@@ -24,7 +24,7 @@
 namespace renderer {
 
 RendererModule::Options::Options()
-    : skia_texture_atlas_dimensions(2048, 2048) {
+    : skia_glyph_texture_atlas_dimensions(2048, 2048) {
   // Call into platform-specific code for setting up render module options.
   SetPerPlatformDefaultOptions();
 }
diff --git a/src/cobalt/renderer/renderer_module.h b/src/cobalt/renderer/renderer_module.h
index 8446117..0e92c82 100644
--- a/src/cobalt/renderer/renderer_module.h
+++ b/src/cobalt/renderer/renderer_module.h
@@ -15,6 +15,7 @@
 #ifndef COBALT_RENDERER_RENDERER_MODULE_H_
 #define COBALT_RENDERER_RENDERER_MODULE_H_
 
+#include "cobalt/base/camera_transform.h"
 #include "cobalt/render_tree/node.h"
 #include "cobalt/renderer/backend/display.h"
 #include "cobalt/renderer/backend/graphics_context.h"
@@ -35,6 +36,8 @@
         backend::GraphicsContext*, const Options& options)>
         CreateRasterizerCallback;
 
+    typedef base::Callback<base::CameraTransform()> GetCameraTransformCallback;
+
     // The rasterizer must be created, accessed, and destroyed within the same
     // thread, and so to facilitate that a rasterizer factory function must
     // be provided here instead of the rasterizer itself.
@@ -48,7 +51,7 @@
 
     // Represents the dimensions of the skia texture atlas which holds all of
     // the glyph textures used during rendering.
-    math::Size skia_texture_atlas_dimensions;
+    math::Size skia_glyph_texture_atlas_dimensions;
 
     // Determines the capacity of the skia cache.  The Skia cache is maintained
     // within Skia and is used to cache the results of complicated effects such
@@ -74,6 +77,10 @@
     // buffer will not be frequently swapped.
     bool submit_even_if_render_tree_is_unchanged;
 
+    // On modes with a 3D camera controllable by user input, fetch the affine
+    // transforms needed to render the scene from the camera's view.
+    GetCameraTransformCallback get_camera_transform;
+
    private:
     // Implemented per-platform, and allows each platform to customize
     // the renderer options.
diff --git a/src/cobalt/renderer/renderer_module_default_options_starboard.cc b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
index 443c212..fc3f3e0 100644
--- a/src/cobalt/renderer/renderer_module_default_options_starboard.cc
+++ b/src/cobalt/renderer/renderer_module_default_options_starboard.cc
@@ -42,16 +42,16 @@
 #elif defined(COBALT_FORCE_DIRECT_GLES_RASTERIZER)
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::egl::HardwareRasterizer(
-          graphics_context, options.skia_texture_atlas_dimensions.width(),
-          options.skia_texture_atlas_dimensions.height(),
+          graphics_context, options.skia_glyph_texture_atlas_dimensions.width(),
+          options.skia_glyph_texture_atlas_dimensions.height(),
           options.skia_cache_size_in_bytes,
           options.scratch_surface_cache_size_in_bytes,
           options.surface_cache_size_in_bytes));
 #else
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::skia::HardwareRasterizer(
-          graphics_context, options.skia_texture_atlas_dimensions.width(),
-          options.skia_texture_atlas_dimensions.height(),
+          graphics_context, options.skia_glyph_texture_atlas_dimensions.width(),
+          options.skia_glyph_texture_atlas_dimensions.height(),
           options.skia_cache_size_in_bytes,
           options.scratch_surface_cache_size_in_bytes,
           options.surface_cache_size_in_bytes));
@@ -64,8 +64,8 @@
 #else
   return scoped_ptr<rasterizer::Rasterizer>(
       new rasterizer::blitter::HardwareRasterizer(
-          graphics_context, options.skia_texture_atlas_dimensions.width(),
-          options.skia_texture_atlas_dimensions.height(),
+          graphics_context, options.skia_glyph_texture_atlas_dimensions.width(),
+          options.skia_glyph_texture_atlas_dimensions.height(),
           options.scratch_surface_cache_size_in_bytes,
           options.surface_cache_size_in_bytes,
           options.software_surface_cache_size_in_bytes));
diff --git a/src/cobalt/script/mozjs/util/algorithm_helpers.cc b/src/cobalt/script/mozjs/util/algorithm_helpers.cc
index 30ae90a..5d08029 100644
--- a/src/cobalt/script/mozjs/util/algorithm_helpers.cc
+++ b/src/cobalt/script/mozjs/util/algorithm_helpers.cc
@@ -134,7 +134,7 @@
 bool Call0(JSContext* context, JS::HandleFunction function,
            JS::HandleObject value, JS::MutableHandleValue out_result) {
   const size_t kNumArguments = 0;
-  JS::Value args[kNumArguments];
+  JS::Value *args = NULL;
   js::SetValueRangeToNull(args, kNumArguments);
   js::AutoValueArray auto_array_rooter(context, args, kNumArguments);
 
diff --git a/src/cobalt/speech/speech_synthesis.cc b/src/cobalt/speech/speech_synthesis.cc
index 3fd8db6..5e3e1bb 100644
--- a/src/cobalt/speech/speech_synthesis.cc
+++ b/src/cobalt/speech/speech_synthesis.cc
@@ -50,6 +50,9 @@
     (*utterance_iterator)->DispatchErrorCancelledEvent();
   }
   utterances_.clear();
+#if SB_HAS(SPEECH_SYNTHESIS)
+  SbSpeechSynthesisCancel();
+#endif
 }
 
 void SpeechSynthesis::Resume() {
diff --git a/src/cobalt/xhr/xml_http_request.cc b/src/cobalt/xhr/xml_http_request.cc
index 84bb0d3..806c7c5 100644
--- a/src/cobalt/xhr/xml_http_request.cc
+++ b/src/cobalt/xhr/xml_http_request.cc
@@ -345,6 +345,13 @@
         request_body_text.assign(start + view->byte_offset(),
                                  view->byte_length());
       }
+    } else if (request_body->IsType<scoped_refptr<dom::ArrayBuffer> >()) {
+      scoped_refptr<dom::ArrayBuffer> array_buffer =
+          request_body->AsType<scoped_refptr<dom::ArrayBuffer> >();
+      if (array_buffer->byte_length()) {
+        const char* start = reinterpret_cast<const char*>(array_buffer->data());
+        request_body_text.assign(start, array_buffer->byte_length());
+      }
     }
   } else {
     upload_complete_ = true;
diff --git a/src/cobalt/xhr/xml_http_request.h b/src/cobalt/xhr/xml_http_request.h
index 8d5843c..5e10595 100644
--- a/src/cobalt/xhr/xml_http_request.h
+++ b/src/cobalt/xhr/xml_http_request.h
@@ -59,8 +59,8 @@
   typedef script::UnionType2<std::string, scoped_refptr<dom::ArrayBuffer> >
       ResponseType;
 
-  typedef script::UnionType2<std::string, scoped_refptr<dom::ArrayBufferView> >
-      RequestBodyType;
+  typedef script::UnionType3<std::string, scoped_refptr<dom::ArrayBufferView>,
+                             scoped_refptr<dom::ArrayBuffer> > RequestBodyType;
 
   enum State {
     kUnsent = 0,
diff --git a/src/cobalt/xhr/xml_http_request.idl b/src/cobalt/xhr/xml_http_request.idl
index 7c1b0df..3b164d6 100644
--- a/src/cobalt/xhr/xml_http_request.idl
+++ b/src/cobalt/xhr/xml_http_request.idl
@@ -40,8 +40,10 @@
     attribute unsigned long timeout;
     [RaisesException=Setter] attribute boolean withCredentials;
     readonly attribute XMLHttpRequestUpload upload;
-    [RaisesException] void send(optional (DOMString or ArrayBufferView)? request_body);
-    // void send(optional (ArrayBufferView or Blob or Document or DOMString or FormData)? data);
+    // TODO: Upgrade to void send(optional (Document or BodyInit)? body = null);
+    //       See https://xhr.spec.whatwg.org/#interface-xmlhttprequest.
+    [RaisesException] void send(
+        optional (DOMString or ArrayBufferView or ArrayBuffer)? request_body);
     void abort();
 
     // response
diff --git a/src/crypto/ghash.cc b/src/crypto/ghash.cc
index 939dd0b..99eae03 100644
--- a/src/crypto/ghash.cc
+++ b/src/crypto/ghash.cc
@@ -4,6 +4,8 @@
 
 #include "crypto/ghash.h"
 
+#include <algorithm>
+
 #include "base/logging.h"
 #include "base/sys_byteorder.h"
 
diff --git a/src/nb/reuse_allocator_benchmark.cc b/src/nb/reuse_allocator_benchmark.cc
index 299b7f7..7fe94d4 100644
--- a/src/nb/reuse_allocator_benchmark.cc
+++ b/src/nb/reuse_allocator_benchmark.cc
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <algorithm>
 #include <map>
 #include <sstream>
 #include <string>
diff --git a/src/nb/simple_thread.cc b/src/nb/simple_thread.cc
index 7bfea39..b8c50d2 100644
--- a/src/nb/simple_thread.cc
+++ b/src/nb/simple_thread.cc
@@ -18,6 +18,7 @@
 

 #include "starboard/mutex.h"

 #include "starboard/thread.h"

+#include "starboard/time.h"

 #include "starboard/types.h"

 #include "starboard/log.h"

 

@@ -45,6 +46,14 @@
   return;

 }

 

+void SimpleThread::Sleep(SbTime microseconds) {

+  SbThreadSleep(microseconds);

+}

+

+void SimpleThread::SleepMilliseconds(int value) {

+  return Sleep(value * kSbTimeMillisecond);

+}

+

 void* SimpleThread::ThreadEntryPoint(void* context) {

   SimpleThread* this_ptr = static_cast<SimpleThread*>(context);

   this_ptr->Run();

diff --git a/src/nb/simple_thread.h b/src/nb/simple_thread.h
index ce3bbfe..6bc2d97 100644
--- a/src/nb/simple_thread.h
+++ b/src/nb/simple_thread.h
@@ -21,6 +21,7 @@
 

 #include "nb/atomic.h"

 #include "starboard/thread.h"

+#include "starboard/time.h"

 #include "starboard/types.h"

 

 namespace nb {

@@ -42,6 +43,12 @@
   // Destroys the threads resources.

   void Join();

 

+  bool join_called() const { return join_called_.load(); }

+

+ protected:

+  static void Sleep(SbTime microseconds);

+  static void SleepMilliseconds(int value);

+

  private:

   static void* ThreadEntryPoint(void* context);

 

diff --git a/src/starboard/creator/shared/configuration_public.h b/src/starboard/creator/shared/configuration_public.h
index 1a587d9..f8b220e 100644
--- a/src/starboard/creator/shared/configuration_public.h
+++ b/src/starboard/creator/shared/configuration_public.h
@@ -119,6 +119,9 @@
 // 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 1
+
 // Whether the current platform has microphone supported.
 #define SB_HAS_MICROPHONE 0
 
diff --git a/src/starboard/linux/shared/configuration_public.h b/src/starboard/linux/shared/configuration_public.h
index b4bed14..b7c9e2f 100644
--- a/src/starboard/linux/shared/configuration_public.h
+++ b/src/starboard/linux/shared/configuration_public.h
@@ -56,6 +56,9 @@
 // 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 1
+
 // Whether the current platform has microphone supported.
 #define SB_HAS_MICROPHONE 0
 
diff --git a/src/starboard/linux/shared/starboard_platform.gypi b/src/starboard/linux/shared/starboard_platform.gypi
index 3750233..9ac2033 100644
--- a/src/starboard/linux/shared/starboard_platform.gypi
+++ b/src/starboard/linux/shared/starboard_platform.gypi
@@ -291,6 +291,7 @@
       '<(DEPTH)/starboard/shared/stub/image_decode.cc',
       '<(DEPTH)/starboard/shared/stub/image_is_decode_supported.cc',
       '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
+      '<(DEPTH)/starboard/shared/stub/media_is_transfer_characteristics_supported.cc',
       '<(DEPTH)/starboard/shared/stub/microphone_close.cc',
       '<(DEPTH)/starboard/shared/stub/microphone_create.cc',
       '<(DEPTH)/starboard/shared/stub/microphone_destroy.cc',
diff --git a/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi b/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi
index 1210a68..3bd32d7 100644
--- a/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi
+++ b/src/starboard/linux/x64x11/cpp11/compiler_flags.gypi
@@ -128,6 +128,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/nplb/once_test.cc b/src/starboard/nplb/once_test.cc
index c94993d..79853fa 100644
--- a/src/starboard/nplb/once_test.cc
+++ b/src/starboard/nplb/once_test.cc
@@ -106,8 +106,8 @@
     RunSbOnceContext context;
 
     s_global_value = 0;
-    for (int i = 0; i < kMany; ++i) {
-      threads[i] =
+    for (int j = 0; j < kMany; ++j) {
+      threads[j] =
           SbThreadCreate(0, kSbThreadNoPriority, kSbThreadNoAffinity, true,
                          kThreadName, RunSbOnceEntryPoint, &context);
     }
@@ -115,7 +115,7 @@
     // Wait for all threads to finish initializing and become ready, then
     // broadcast the signal to begin.  We do this to increase the chances that
     // threads will call SbOnce() at the same time as each other.
-    for (int i = 0; i < kMany; ++i) {
+    for (int j = 0; j < kMany; ++j) {
       context.semaphore.Take();
     }
     {
diff --git a/src/starboard/raspi/shared/starboard_platform.gypi b/src/starboard/raspi/shared/starboard_platform.gypi
index 65951fd..dd195e1 100644
--- a/src/starboard/raspi/shared/starboard_platform.gypi
+++ b/src/starboard/raspi/shared/starboard_platform.gypi
@@ -334,6 +334,7 @@
         '<(DEPTH)/starboard/shared/stub/drm_system_internal.h',
         '<(DEPTH)/starboard/shared/stub/drm_update_session.cc',
         '<(DEPTH)/starboard/shared/stub/media_is_supported.cc',
+        '<(DEPTH)/starboard/shared/stub/media_is_transfer_characteristics_supported.cc',
         '<(DEPTH)/starboard/shared/stub/system_clear_platform_error.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_total_gpu_memory.cc',
         '<(DEPTH)/starboard/shared/stub/system_get_used_gpu_memory.cc',
diff --git a/src/starboard/shared/starboard/application.h b/src/starboard/shared/starboard/application.h
index 2469a6e..1137712 100644
--- a/src/starboard/shared/starboard/application.h
+++ b/src/starboard/shared/starboard/application.h
@@ -292,6 +292,12 @@
   // kSbTimeMax if there are no queued TimedEvents.
   virtual SbTimeMonotonic GetNextTimedEventTargetTime() = 0;
 
+  // Sets the command-line parameters for the application. Used to support
+  // system message pump-based implementations, which don't call |Run()|.
+  void SetCommandLine(int argc, const char** argv) {
+    command_line_.reset(new CommandLine(argc, argv));
+  }
+
   // Sets the launch deep link string, if any, which is passed in the start
   // event that initializes and starts Cobalt.
   void SetStartLink(const char* start_link);
@@ -304,6 +310,10 @@
   // Returns the current application state.
   State state() const { return state_; }
 
+  // Returns the error level that the application has been stopped with. |0|
+  // means "success" or at least "no error."
+  int error_level() const { return error_level_; }
+
   // Returns true if the Start event should be sent in |Run| before entering the
   // event loop. Derived classes that return false must call |DispatchStart|.
   virtual bool IsStartImmediate() { return true; }
@@ -317,9 +327,11 @@
   // i.e. false means to abort the event queue.
   bool DispatchAndDelete(Application::Event* event);
 
- private:
+  // Calls registered Starboard teardown callbacks. This is called only by
+  // |Run()| or directly by system message pump implementations at teardown.
   void CallTeardownCallbacks();
 
+ private:
   // The single application instance.
   static Application* g_instance;
 
diff --git a/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc b/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
index 390abe4..0a96110 100644
--- a/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
+++ b/src/starboard/shared/starboard/media/media_can_play_mime_and_key_system.cc
@@ -96,6 +96,7 @@
 #include "starboard/shared/starboard/media/media_util.h"
 
 using starboard::shared::starboard::media::GetAudioCodecFromString;
+using starboard::shared::starboard::media::GetTransferIdFromString;
 using starboard::shared::starboard::media::GetVideoCodecFromString;
 using starboard::shared::starboard::media::IsAudioOutputSupported;
 using starboard::shared::starboard::media::MimeType;
@@ -248,6 +249,14 @@
       }
     }
 
+    std::string eotf = mime_type.GetParamStringValue("eotf", "");
+    if (!eotf.empty()) {
+      SbMediaTransferId transfer_id = GetTransferIdFromString(eotf);
+      if (!SbMediaIsTransferCharacteristicsSupported(transfer_id)) {
+        return kSbMediaSupportTypeNotSupported;
+      }
+    }
+
     int width = 0;
     int height = 0;
     int fps = 0;
diff --git a/src/starboard/shared/starboard/media/media_support_internal.h b/src/starboard/shared/starboard/media/media_support_internal.h
index 8ad5b21..ff42fd6 100644
--- a/src/starboard/shared/starboard/media/media_support_internal.h
+++ b/src/starboard/shared/starboard/media/media_support_internal.h
@@ -54,6 +54,14 @@
 SB_EXPORT bool SbMediaIsAudioSupported(SbMediaAudioCodec audio_codec,
                                        int64_t bitrate);
 
+// Indicates whether this platform supports |transfer_id| as a transfer
+// characteristics.  If |transfer_id| is not supported under any condition, this
+// function returns |false|.
+//
+// |transfer_id|: The id of transfer charateristics listed in SbMediaTransferId.
+SB_EXPORT bool SbMediaIsTransferCharacteristicsSupported(
+    SbMediaTransferId transfer_id);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif
diff --git a/src/starboard/shared/starboard/media/media_util.cc b/src/starboard/shared/starboard/media/media_util.cc
index b6fd9d7..bac646d 100644
--- a/src/starboard/shared/starboard/media/media_util.cc
+++ b/src/starboard/shared/starboard/media/media_util.cc
@@ -37,6 +37,17 @@
   return false;
 }
 
+SbMediaTransferId GetTransferIdFromString(const std::string& eotf) {
+  if (eotf == "bt709") {
+    return kSbMediaTransferIdBt709;
+  } else if (eotf == "smpte2084") {
+    return kSbMediaTransferIdSmpteSt2084;
+  } else if (eotf == "arib-std-b67") {
+    return kSbMediaTransferIdAribStdB67;
+  }
+  return kSbMediaTransferIdUnknown;
+}
+
 }  // namespace media
 }  // namespace starboard
 }  // namespace shared
diff --git a/src/starboard/shared/starboard/media/media_util.h b/src/starboard/shared/starboard/media/media_util.h
index 293a34e..51c793c 100644
--- a/src/starboard/shared/starboard/media/media_util.h
+++ b/src/starboard/shared/starboard/media/media_util.h
@@ -15,6 +15,8 @@
 #ifndef STARBOARD_SHARED_STARBOARD_MEDIA_MEDIA_UTIL_H_
 #define STARBOARD_SHARED_STARBOARD_MEDIA_MEDIA_UTIL_H_
 
+#include <string>
+
 #include "starboard/media.h"
 #include "starboard/shared/internal_only.h"
 
@@ -25,6 +27,12 @@
 
 bool IsAudioOutputSupported(SbMediaAudioCodingType coding_type, int channels);
 
+// Turns |eotf| into value of SbMediaTransferId.  If |eotf| isn't recognized the
+// function returns kSbMediaTransferIdReserved0.
+// This function supports all eotfs required by YouTube TV HTML5 Technical
+// Requirements (2018).
+SbMediaTransferId GetTransferIdFromString(const std::string& eotf);
+
 }  // namespace media
 }  // namespace starboard
 }  // namespace shared
diff --git a/src/starboard/shared/starboard/microphone/microphone_internal.h b/src/starboard/shared/starboard/microphone/microphone_internal.h
index d34215a..f14e734 100644
--- a/src/starboard/shared/starboard/microphone/microphone_internal.h
+++ b/src/starboard/shared/starboard/microphone/microphone_internal.h
@@ -18,6 +18,8 @@
 #include "starboard/microphone.h"
 #include "starboard/shared/internal_only.h"
 
+#if SB_HAS(MICROPHONE) && SB_VERSION(2)
+
 struct SbMicrophonePrivate {
   virtual ~SbMicrophonePrivate() {}
   virtual bool Open() = 0;
@@ -34,4 +36,6 @@
   static void DestroyMicrophone(SbMicrophone microphone);
 };
 
+#endif  // SB_HAS(MICROPHONE) && SB_VERSION(2)
+
 #endif  // STARBOARD_SHARED_STARBOARD_MICROPHONE_MICROPHONE_INTERNAL_H_
diff --git a/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_cancel.cc b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_cancel.cc
new file mode 100644
index 0000000..aa77349
--- /dev/null
+++ b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_cancel.cc
@@ -0,0 +1,29 @@
+// 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/speech_recognizer.h"
+
+#if SB_HAS(SPEECH_RECOGNIZER) && \
+    SB_API_VERSION >= SB_SPEECH_RECOGNIZER_API_VERSION
+
+#include "starboard/log.h"
+#include "starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h"
+
+void SbSpeechRecognizerCancel(SbSpeechRecognizer recognizer) {
+  SB_DCHECK(SbSpeechRecognizerIsValid(recognizer));
+  recognizer->Cancel();
+}
+
+#endif  // SB_HAS(SPEECH_RECOGNIZER) && SB_API_VERSION >=
+        // SB_SPEECH_RECOGNIZER_API_VERSION
diff --git a/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_create.cc b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_create.cc
new file mode 100644
index 0000000..875726f
--- /dev/null
+++ b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_create.cc
@@ -0,0 +1,28 @@
+// 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/speech_recognizer.h"
+
+#if SB_HAS(SPEECH_RECOGNIZER) && \
+    SB_API_VERSION >= SB_SPEECH_RECOGNIZER_API_VERSION
+
+#include "starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h"
+
+SbSpeechRecognizer SbSpeechRecognizerCreate(
+    const SbSpeechRecognizerHandler* handler) {
+  return SbSpeechRecognizerPrivate::CreateSpeechRecognizer(handler);
+}
+
+#endif  // SB_HAS(SPEECH_RECOGNIZER) && SB_API_VERSION >=
+        // SB_SPEECH_RECOGNIZER_API_VERSION
diff --git a/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_destroy.cc b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_destroy.cc
new file mode 100644
index 0000000..b7b052b
--- /dev/null
+++ b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_destroy.cc
@@ -0,0 +1,27 @@
+// 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/speech_recognizer.h"
+
+#if SB_HAS(SPEECH_RECOGNIZER) && \
+    SB_API_VERSION >= SB_SPEECH_RECOGNIZER_API_VERSION
+
+#include "starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h"
+
+void SbSpeechRecognizerDestroy(SbSpeechRecognizer recognizer) {
+  SbSpeechRecognizerPrivate::DestroySpeechRecognizer(recognizer);
+}
+
+#endif  // SB_HAS(SPEECH_RECOGNIZER) && SB_API_VERSION >=
+        // SB_SPEECH_RECOGNIZER_API_VERSION
diff --git a/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h
new file mode 100644
index 0000000..a69a05c
--- /dev/null
+++ b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h
@@ -0,0 +1,35 @@
+// 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_SHARED_STARBOARD_SPEECH_RECOGNIZER_SPEECH_RECOGNIZER_INTERNAL_H_
+#define STARBOARD_SHARED_STARBOARD_SPEECH_RECOGNIZER_SPEECH_RECOGNIZER_INTERNAL_H_
+
+#include "starboard/shared/internal_only.h"
+#include "starboard/speech_recognizer.h"
+
+#if SB_HAS(SPEECH_RECOGNIZER) && \
+    SB_API_VERSION >= SB_SPEECH_RECOGNIZER_API_VERSION
+struct SbSpeechRecognizerPrivate {
+  virtual ~SbSpeechRecognizerPrivate() {}
+  virtual bool Start(const SbSpeechConfiguration* configuration) = 0;
+  virtual void Stop() = 0;
+  virtual void Cancel() = 0;
+  static SbSpeechRecognizer CreateSpeechRecognizer(
+      const SbSpeechRecognizerHandler* handler);
+  static void DestroySpeechRecognizer(SbSpeechRecognizer speech_recognizer);
+};
+#endif  // SB_HAS(SPEECH_RECOGNIZER) && SB_API_VERSION >=
+        // SB_SPEECH_RECOGNIZER_API_VERSION
+
+#endif  // STARBOARD_SHARED_STARBOARD_SPEECH_RECOGNIZER_SPEECH_RECOGNIZER_INTERNAL_H_
diff --git a/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_start.cc b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_start.cc
new file mode 100644
index 0000000..2fd1002
--- /dev/null
+++ b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_start.cc
@@ -0,0 +1,30 @@
+// 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/speech_recognizer.h"
+
+#if SB_HAS(SPEECH_RECOGNIZER) && \
+    SB_API_VERSION >= SB_SPEECH_RECOGNIZER_API_VERSION
+
+#include "starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h"
+
+bool SbSpeechRecognizerStart(SbSpeechRecognizer recognizer,
+                             const SbSpeechConfiguration* configuration) {
+  return SbSpeechRecognizerIsValid(recognizer)
+             ? recognizer->Start(configuration)
+             : false;
+}
+
+#endif  // SB_HAS(SPEECH_RECOGNIZER) && SB_API_VERSION >=
+        // SB_SPEECH_RECOGNIZER_API_VERSION
diff --git a/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_stop.cc b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_stop.cc
new file mode 100644
index 0000000..e8cadfd
--- /dev/null
+++ b/src/starboard/shared/starboard/speech_recognizer/speech_recognizer_stop.cc
@@ -0,0 +1,29 @@
+// 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/speech_recognizer.h"
+
+#if SB_HAS(SPEECH_RECOGNIZER) && \
+    SB_API_VERSION >= SB_SPEECH_RECOGNIZER_API_VERSION
+
+#include "starboard/log.h"
+#include "starboard/shared/starboard/speech_recognizer/speech_recognizer_internal.h"
+
+void SbSpeechRecognizerStop(SbSpeechRecognizer recognizer) {
+  SB_DCHECK(SbSpeechRecognizerIsValid(recognizer));
+  recognizer->Stop();
+}
+
+#endif  // SB_HAS(SPEECH_RECOGNIZER) && SB_API_VERSION >=
+        // SB_SPEECH_RECOGNIZER_API_VERSION
diff --git a/src/starboard/shared/stub/media_is_transfer_characteristics_supported.cc b/src/starboard/shared/stub/media_is_transfer_characteristics_supported.cc
new file mode 100644
index 0000000..e0ed7eb
--- /dev/null
+++ b/src/starboard/shared/stub/media_is_transfer_characteristics_supported.cc
@@ -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.
+
+#include "starboard/shared/starboard/media/media_support_internal.h"
+
+#include "starboard/media.h"
+
+SB_EXPORT bool SbMediaIsTransferCharacteristicsSupported(
+    SbMediaTransferId /*transfer_id*/) {
+  return false;
+}
diff --git a/src/starboard/shared/stub/system_break_into_debugger.cc b/src/starboard/shared/stub/system_break_into_debugger.cc
index 59d081e..2fa0f6a 100644
--- a/src/starboard/shared/stub/system_break_into_debugger.cc
+++ b/src/starboard/shared/stub/system_break_into_debugger.cc
@@ -15,5 +15,7 @@
 #include "starboard/system.h"
 
 void SbSystemBreakIntoDebugger() {
+#if SB_IS(COMPILER_GCC)
   __builtin_unreachable();
+#endif
 }
diff --git a/src/starboard/stub/configuration_public.h b/src/starboard/stub/configuration_public.h
index edf093a..5786638 100644
--- a/src/starboard/stub/configuration_public.h
+++ b/src/starboard/stub/configuration_public.h
@@ -131,6 +131,9 @@
 // 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 1
+
 // Whether the current platform has microphone supported.
 #define SB_HAS_MICROPHONE 1
 
diff --git a/src/starboard/stub/starboard_platform.gyp b/src/starboard/stub/starboard_platform.gyp
index e2ab6dc..7dfd774 100644
--- a/src/starboard/stub/starboard_platform.gyp
+++ b/src/starboard/stub/starboard_platform.gyp
@@ -96,6 +96,7 @@
         '<(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_transfer_characteristics_supported.cc',
         '<(DEPTH)/starboard/shared/stub/media_is_video_supported.cc',
         '<(DEPTH)/starboard/shared/stub/media_set_output_protection.cc',
         '<(DEPTH)/starboard/shared/stub/memory_allocate_aligned_unchecked.cc',
diff --git a/src/starboard/tizen/shared/configuration_public.h b/src/starboard/tizen/shared/configuration_public.h
index 16c4066..ff7d28d 100644
--- a/src/starboard/tizen/shared/configuration_public.h
+++ b/src/starboard/tizen/shared/configuration_public.h
@@ -49,6 +49,9 @@
 // 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 1
+
 // Type detection for wchar_t.
 #if defined(__WCHAR_MAX__) && \
     (__WCHAR_MAX__ == 0x7fffffff || __WCHAR_MAX__ == 0xffffffff)
diff --git a/src/starboard/types.h b/src/starboard/types.h
index 64a27c0..37d9e3a 100644
--- a/src/starboard/types.h
+++ b/src/starboard/types.h
@@ -83,6 +83,14 @@
 typedef SB_UINTPTR uintptr_t;
 #endif  // !SB_HAS(STDINT_H) && !SB_HAS(INTTYPES_H)
 
+#if !SB_HAS(SSIZE_T)
+#if SB_IS(32_BIT)
+typedef int32_t ssize_t;
+#elif SB_IS(64_BIT)
+typedef int64_t ssize_t;
+#endif
+#endif  // !SB_HAS(SSIZE_T)
+
 // Simulate stdbool.h for platforms that don't provide it.
 #if !SB_HAS(STDBOOL_H) && !defined(__cplusplus)
 #if __STDC_VERSION__ >= 199901L
diff --git a/src/third_party/icu/icu.gyp b/src/third_party/icu/icu.gyp
index 7162895..bad1c71 100644
--- a/src/third_party/icu/icu.gyp
+++ b/src/third_party/icu/icu.gyp
@@ -154,8 +154,10 @@
           'type': 'static_library',
           'defines': [
             'U_HIDE_DATA_SYMBOL',
+            'U_ICUDATAENTRY_IN_COMMON',
           ],
           'sources': [
+            'source/stubdata/stubdata.c',
           ],
           'conditions': [
             [ 'use_system_icu==1 and want_separate_host_toolset==1', {
@@ -304,9 +306,6 @@
                 'U_HAVE_NL_LANGINFO_CODESET=0',
                 'U_HAVE_NL_LANGINFO=0'
               ],
-              'sources': [
-                'source/stubdata/stubdata.c',
-              ],
             }],
             ['OS=="lb_shell"', {
               'dependencies': [
diff --git a/src/third_party/libwebp/dec/alpha.c b/src/third_party/libwebp/dec/alpha.c
index b5e6891..c81c481 100644
--- a/src/third_party/libwebp/dec/alpha.c
+++ b/src/third_party/libwebp/dec/alpha.c
@@ -11,7 +11,12 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <stdlib.h>
+#endif
 #include "./vp8i.h"
 #include "./vp8li.h"
 #include "../utils/filters.h"
@@ -42,8 +47,8 @@
   const uint8_t* const alpha_data = data + ALPHA_HEADER_LEN;
   const size_t alpha_data_size = data_size - ALPHA_HEADER_LEN;
 
-  assert(width > 0 && height > 0);
-  assert(data != NULL && output != NULL);
+  SB_DCHECK(width > 0 && height > 0);
+  SB_DCHECK(data != NULL && output != NULL);
 
   if (data_size <= ALPHA_HEADER_LEN) {
     return 0;
@@ -64,7 +69,7 @@
   if (method == ALPHA_NO_COMPRESSION) {
     const size_t alpha_decoded_size = height * width;
     ok = (alpha_data_size >= alpha_decoded_size);
-    if (ok) memcpy(output, alpha_data, alpha_decoded_size);
+    if (ok) SbMemoryCopy(output, alpha_data, alpha_decoded_size);
   } else {
     ok = VP8LDecodeAlphaImageStream(width, height, alpha_data, alpha_data_size,
                                     output);
@@ -98,7 +103,7 @@
 
   if (row == 0) {
     // Decode everything during the first call.
-    assert(!dec->is_alpha_decoded_);
+    SB_DCHECK(!dec->is_alpha_decoded_);
     if (!DecodeAlpha(dec->alpha_data_, (size_t)dec->alpha_data_size_,
                      width, height, dec->alpha_plane_)) {
       return NULL;  // Error.
diff --git a/src/third_party/libwebp/dec/buffer.c b/src/third_party/libwebp/dec/buffer.c
index 3855715..24e8abb 100644
--- a/src/third_party/libwebp/dec/buffer.c
+++ b/src/third_party/libwebp/dec/buffer.c
@@ -17,6 +17,10 @@
 #include "./webpi.h"
 #include "../utils/utils.h"
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#endif
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -176,14 +180,14 @@
     return 0;  // version mismatch
   }
   if (buffer == NULL) return 0;
-  memset(buffer, 0, sizeof(*buffer));
+  SbMemorySet(buffer, 0, sizeof(*buffer));
   return 1;
 }
 
 void WebPFreeDecBuffer(WebPDecBuffer* buffer) {
   if (buffer != NULL) {
     if (!buffer->is_external_memory)
-      free(buffer->private_memory);
+      SbMemoryDeallocate(buffer->private_memory);
     buffer->private_memory = NULL;
   }
 }
diff --git a/src/third_party/libwebp/dec/frame.c b/src/third_party/libwebp/dec/frame.c
index 5f6a7d9..d73528a 100644
--- a/src/third_party/libwebp/dec/frame.c
+++ b/src/third_party/libwebp/dec/frame.c
@@ -11,7 +11,12 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <stdlib.h>
+#endif
 #include "./vp8i.h"
 #include "../utils/utils.h"
 
@@ -92,7 +97,7 @@
 static void FilterRow(const VP8Decoder* const dec) {
   int mb_x;
   const int mb_y = dec->thread_ctx_.mb_y_;
-  assert(dec->thread_ctx_.filter_row_);
+  SB_DCHECK(dec->thread_ctx_.filter_row_);
   for (mb_x = dec->tl_mb_x_; mb_x < dec->br_mb_x_; ++mb_x) {
     DoFilter(dec, mb_x, mb_y);
   }
@@ -215,7 +220,7 @@
     if (y_start < io->crop_top) {
       const int delta_y = io->crop_top - y_start;
       y_start = io->crop_top;
-      assert(!(delta_y & 1));
+      SB_DCHECK(!(delta_y & 1));
       io->y += dec->cache_y_stride_ * delta_y;
       io->u += dec->cache_uv_stride_ * (delta_y >> 1);
       io->v += dec->cache_uv_stride_ * (delta_y >> 1);
@@ -239,9 +244,9 @@
   // rotate top samples if needed
   if (ctx->id_ + 1 == dec->num_caches_) {
     if (!last_row) {
-      memcpy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize);
-      memcpy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize);
-      memcpy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize);
+      SbMemoryCopy(dec->cache_y_ - ysize, ydst + 16 * dec->cache_y_stride_, ysize);
+      SbMemoryCopy(dec->cache_u_ - uvsize, udst + 8 * dec->cache_uv_stride_, uvsize);
+      SbMemoryCopy(dec->cache_v_ - uvsize, vdst + 8 * dec->cache_uv_stride_, uvsize);
     }
   }
 
@@ -264,7 +269,7 @@
     WebPWorker* const worker = &dec->worker_;
     // Finish previous job *before* updating context
     ok &= WebPWorkerSync(worker);
-    assert(worker->status_ == OK);
+    SB_DCHECK(worker->status_ == OK);
     if (ok) {   // spawn a new deblocking/output job
       ctx->io_ = *io;
       ctx->id_ = dec->cache_id_;
@@ -434,7 +439,7 @@
 
   if (needed != (size_t)needed) return 0;  // check for overflow
   if (needed > dec->mem_size_) {
-    free(dec->mem_);
+    SbMemoryDeallocate(dec->mem_);
     dec->mem_size_ = 0;
     dec->mem_ = WebPSafeMalloc(needed, sizeof(uint8_t));
     if (dec->mem_ == NULL) {
@@ -471,7 +476,7 @@
   }
 
   mem = (uint8_t*)((uintptr_t)(mem + ALIGN_MASK) & ~ALIGN_MASK);
-  assert((yuv_size & ALIGN_MASK) == 0);
+  SB_DCHECK((yuv_size & ALIGN_MASK) == 0);
   dec->yuv_b_ = (uint8_t*)mem;
   mem += yuv_size;
 
@@ -496,13 +501,13 @@
   // alpha plane
   dec->alpha_plane_ = alpha_size ? (uint8_t*)mem : NULL;
   mem += alpha_size;
-  assert(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
+  SB_DCHECK(mem <= (uint8_t*)dec->mem_ + dec->mem_size_);
 
   // note: left-info is initialized once for all.
-  memset(dec->mb_info_ - 1, 0, mb_info_size);
+  SbMemorySet(dec->mb_info_ - 1, 0, mb_info_size);
 
   // initialize top
-  memset(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
+  SbMemorySet(dec->intra_t_, B_DC_PRED, intra_pred_mode_size);
 
   return 1;
 }
@@ -589,15 +594,15 @@
     int n;
 
     if (dec->mb_y_ > 0) {
-      memcpy(y_dst - BPS, top_y, 16);
-      memcpy(u_dst - BPS, top_u, 8);
-      memcpy(v_dst - BPS, top_v, 8);
+      SbMemoryCopy(y_dst - BPS, top_y, 16);
+      SbMemoryCopy(u_dst - BPS, top_u, 8);
+      SbMemoryCopy(v_dst - BPS, top_v, 8);
     } else if (dec->mb_x_ == 0) {
       // we only need to do this init once at block (0,0).
       // Afterward, it remains valid for the whole topmost row.
-      memset(y_dst - BPS - 1, 127, 16 + 4 + 1);
-      memset(u_dst - BPS - 1, 127, 8 + 1);
-      memset(v_dst - BPS - 1, 127, 8 + 1);
+      SbMemorySet(y_dst - BPS - 1, 127, 16 + 4 + 1);
+      SbMemorySet(u_dst - BPS - 1, 127, 8 + 1);
+      SbMemorySet(v_dst - BPS - 1, 127, 8 + 1);
     }
 
     // predict and add residuals
@@ -609,7 +614,7 @@
         if (dec->mb_x_ >= dec->mb_w_ - 1) {    // on rightmost border
           top_right[0] = top_y[15] * 0x01010101u;
         } else {
-          memcpy(top_right, top_y + 16, sizeof(*top_right));
+          SbMemoryCopy(top_right, top_y + 16, sizeof(*top_right));
         }
       }
       // replicate the top-right pixels below
@@ -664,9 +669,9 @@
 
       // stash away top samples for next block
       if (dec->mb_y_ < dec->mb_h_ - 1) {
-        memcpy(top_y, y_dst + 15 * BPS, 16);
-        memcpy(top_u, u_dst +  7 * BPS,  8);
-        memcpy(top_v, v_dst +  7 * BPS,  8);
+        SbMemoryCopy(top_y, y_dst + 15 * BPS, 16);
+        SbMemoryCopy(top_u, u_dst +  7 * BPS,  8);
+        SbMemoryCopy(top_v, v_dst +  7 * BPS,  8);
       }
     }
   }
@@ -678,11 +683,11 @@
     uint8_t* const u_out = dec->cache_u_ + dec->mb_x_ * 8 + uv_offset;
     uint8_t* const v_out = dec->cache_v_ + dec->mb_x_ * 8 + uv_offset;
     for (j = 0; j < 16; ++j) {
-      memcpy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16);
+      SbMemoryCopy(y_out + j * dec->cache_y_stride_, y_dst + j * BPS, 16);
     }
     for (j = 0; j < 8; ++j) {
-      memcpy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8);
-      memcpy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8);
+      SbMemoryCopy(u_out + j * dec->cache_uv_stride_, u_dst + j * BPS, 8);
+      SbMemoryCopy(v_out + j * dec->cache_uv_stride_, v_dst + j * BPS, 8);
     }
   }
 }
diff --git a/src/third_party/libwebp/dec/idec.c b/src/third_party/libwebp/dec/idec.c
index 5bf79d3..4c01ba2 100644
--- a/src/third_party/libwebp/dec/idec.c
+++ b/src/third_party/libwebp/dec/idec.c
@@ -12,7 +12,8 @@
 // Author: somnath@google.com (Somnath Banerjee)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <string.h>
@@ -115,7 +116,7 @@
     return 0;  // ALPH chunk is not present for lossless images.
   } else {
     const VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
-    assert(dec != NULL);  // Must be true as idec->state_ != STATE_PRE_VP8.
+    SB_DCHECK(dec != NULL);  // Must be true as idec->state_ != STATE_PRE_VP8.
     return (dec->alpha_data_ != NULL) && !dec->is_alpha_decoded_;
   }
 }
@@ -143,7 +144,7 @@
           RemapBitReader(&dec->br_, offset);
         }
       }
-      assert(last_part >= 0);
+      SB_DCHECK(last_part >= 0);
       dec->parts_[last_part].buf_end_ = mem->buf_ + mem->end_;
       if (NeedCompressedAlpha(idec)) dec->alpha_data_ += offset;
     } else {    // Resize lossless bitreader
@@ -163,7 +164,7 @@
   const uint8_t* const old_start = mem->buf_ + mem->start_;
   const uint8_t* const old_base =
       need_compressed_alpha ? dec->alpha_data_ : old_start;
-  assert(mem->mode_ == MEM_MODE_APPEND);
+  SB_DCHECK(mem->mode_ == MEM_MODE_APPEND);
   if (data_size > MAX_CHUNK_PAYLOAD) {
     // security safeguard: trying to allocate more than what the format
     // allows for a chunk should be considered a smoke smell.
@@ -178,17 +179,17 @@
     uint8_t* const new_buf =
         (uint8_t*)WebPSafeMalloc(extra_size, sizeof(*new_buf));
     if (new_buf == NULL) return 0;
-    memcpy(new_buf, old_base, current_size);
-    free(mem->buf_);
+    SbMemoryCopy(new_buf, old_base, current_size);
+    SbMemoryDeallocate(mem->buf_);
     mem->buf_ = new_buf;
     mem->buf_size_ = (size_t)extra_size;
     mem->start_ = new_mem_start;
     mem->end_ = current_size;
   }
 
-  memcpy(mem->buf_ + mem->end_, data, data_size);
+  SbMemoryCopy(mem->buf_ + mem->end_, data, data_size);
   mem->end_ += data_size;
-  assert(mem->end_ <= mem->buf_size_);
+  SB_DCHECK(mem->end_ <= mem->buf_size_);
 
   DoRemap(idec, mem->buf_ + mem->start_ - old_start);
   return 1;
@@ -199,7 +200,7 @@
   MemBuffer* const mem = &idec->mem_;
   const uint8_t* const old_buf = mem->buf_;
   const uint8_t* const old_start = old_buf + mem->start_;
-  assert(mem->mode_ == MEM_MODE_MAP);
+  SB_DCHECK(mem->mode_ == MEM_MODE_MAP);
 
   if (data_size < mem->buf_size_) return 0;  // can't remap to a shorter buffer!
 
@@ -219,10 +220,10 @@
 }
 
 static void ClearMemBuffer(MemBuffer* const mem) {
-  assert(mem);
+  SB_DCHECK(mem);
   if (mem->mode_ == MEM_MODE_APPEND) {
-    free(mem->buf_);
-    free((void*)mem->part0_buf_);
+    SbMemoryDeallocate(mem->buf_);
+    SbMemoryDeallocate((void*)mem->part0_buf_);
   }
 }
 
@@ -232,7 +233,7 @@
   } else if (mem->mode_ != expected) {
     return 0;         // we mixed the modes => error
   }
-  assert(mem->mode_ == expected);   // mode is ok
+  SB_DCHECK(mem->mode_ == expected);   // mode is ok
   return 1;
 }
 
@@ -249,8 +250,8 @@
   context->info_ = *info;
   context->br_ = *br;
   context->token_br_ = *token_br;
-  memcpy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4);
-  memcpy(context->intra_l_, dec->intra_l_, 4);
+  SbMemoryCopy(context->intra_t_, dec->intra_t_ + 4 * dec->mb_x_, 4);
+  SbMemoryCopy(context->intra_l_, dec->intra_l_, 4);
 }
 
 static void RestoreContext(const MBContext* context, VP8Decoder* const dec,
@@ -263,8 +264,8 @@
   *info = context->info_;
   *br = context->br_;
   *token_br = context->token_br_;
-  memcpy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4);
-  memcpy(dec->intra_l_, context->intra_l_, 4);
+  SbMemoryCopy(dec->intra_t_ + 4 * dec->mb_x_, context->intra_t_, 4);
+  SbMemoryCopy(dec->intra_l_, context->intra_l_, 4);
 }
 
 //------------------------------------------------------------------------------
@@ -285,7 +286,7 @@
   MemBuffer* const mem = &idec->mem_;
   idec->state_ = new_state;
   mem->start_ += consumed_bytes;
-  assert(mem->start_ <= mem->end_);
+  SB_DCHECK(mem->start_ <= mem->end_);
   idec->io_.data = mem->buf_ + mem->start_;
   idec->io_.data_size = MemDataSize(mem);
 }
@@ -363,17 +364,17 @@
   VP8BitReader* const br = &dec->br_;
   const size_t psize = br->buf_end_ - br->buf_;
   MemBuffer* const mem = &idec->mem_;
-  assert(!idec->is_lossless_);
-  assert(mem->part0_buf_ == NULL);
-  assert(psize > 0);
-  assert(psize <= mem->part0_size_);  // Format limit: no need for runtime check
+  SB_DCHECK(!idec->is_lossless_);
+  SB_DCHECK(mem->part0_buf_ == NULL);
+  SB_DCHECK(psize > 0);
+  SB_DCHECK(psize <= mem->part0_size_);  // Format limit: no need for runtime check
   if (mem->mode_ == MEM_MODE_APPEND) {
     // We copy and grab ownership of the partition #0 data.
-    uint8_t* const part0_buf = (uint8_t*)malloc(psize);
+    uint8_t* const part0_buf = (uint8_t*)SbMemoryAllocate(psize);
     if (part0_buf == NULL) {
       return 0;
     }
-    memcpy(part0_buf, br->buf_, psize);
+    SbMemoryCopy(part0_buf, br->buf_, psize);
     mem->part0_buf_ = part0_buf;
     br->buf_ = part0_buf;
     br->buf_end_ = part0_buf + psize;
@@ -436,7 +437,7 @@
   VP8Decoder* const dec = (VP8Decoder*)idec->dec_;
   VP8Io* const io = &idec->io_;
 
-  assert(dec->ready_);
+  SB_DCHECK(dec->ready_);
 
   for (; dec->mb_y_ < dec->mb_h_; ++dec->mb_y_) {
     VP8BitReader* token_br = &dec->parts_[dec->mb_y_ & (dec->num_parts_ - 1)];
@@ -461,7 +462,7 @@
       // Release buffer only if there is only one partition
       if (dec->num_parts_ == 1) {
         idec->mem_.start_ = token_br->buf_ - idec->mem_.buf_;
-        assert(idec->mem_.start_ <= idec->mem_.end_);
+        SB_DCHECK(idec->mem_.start_ <= idec->mem_.end_);
       }
     }
     if (!VP8ProcessRow(dec, io)) {
@@ -492,7 +493,7 @@
   const WebPDecParams* const params = &idec->params_;
   WebPDecBuffer* const output = params->output;
   size_t curr_size = MemDataSize(&idec->mem_);
-  assert(idec->is_lossless_);
+  SB_DCHECK(idec->is_lossless_);
 
   // Wait until there's enough data for decoding header.
   if (curr_size < (idec->chunk_size_ >> 3)) {
@@ -515,7 +516,7 @@
 static VP8StatusCode DecodeVP8LData(WebPIDecoder* const idec) {
   VP8LDecoder* const dec = (VP8LDecoder*)idec->dec_;
   const size_t curr_size = MemDataSize(&idec->mem_);
-  assert(idec->is_lossless_);
+  SB_DCHECK(idec->is_lossless_);
 
   // At present Lossless decoder can't decode image incrementally. So wait till
   // all the image data is aggregated before image can be decoded.
@@ -565,7 +566,7 @@
 // Public functions
 
 WebPIDecoder* WebPINewDecoder(WebPDecBuffer* output_buffer) {
-  WebPIDecoder* idec = (WebPIDecoder*)calloc(1, sizeof(*idec));
+  WebPIDecoder* idec = (WebPIDecoder*)SbMemoryCalloc(1, sizeof(*idec));
   if (idec == NULL) {
     return NULL;
   }
@@ -617,7 +618,7 @@
   }
   ClearMemBuffer(&idec->mem_);
   WebPFreeDecBuffer(&idec->output_);
-  free(idec);
+  SbMemoryDeallocate(idec);
 }
 
 //------------------------------------------------------------------------------
@@ -702,7 +703,7 @@
 //------------------------------------------------------------------------------
 
 static VP8StatusCode IDecCheckStatus(const WebPIDecoder* const idec) {
-  assert(idec);
+  SB_DCHECK(idec);
   if (idec->state_ == STATE_ERROR) {
     return VP8_STATUS_BITSTREAM_ERROR;
   }
diff --git a/src/third_party/libwebp/dec/io.c b/src/third_party/libwebp/dec/io.c
index dea517e..60a6865 100644
--- a/src/third_party/libwebp/dec/io.c
+++ b/src/third_party/libwebp/dec/io.c
@@ -12,7 +12,8 @@
 // Author: Skal (pascal.massimino@gmail.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -42,11 +43,11 @@
   const int uv_h = (mb_h + 1) / 2;
   int j;
   for (j = 0; j < mb_h; ++j) {
-    memcpy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
+    SbMemoryCopy(y_dst + j * buf->y_stride, io->y + j * io->y_stride, mb_w);
   }
   for (j = 0; j < uv_h; ++j) {
-    memcpy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
-    memcpy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
+    SbMemoryCopy(u_dst + j * buf->u_stride, io->u + j * io->uv_stride, uv_w);
+    SbMemoryCopy(v_dst + j * buf->v_stride, io->v + j * io->uv_stride, uv_w);
   }
   return io->mb_h;
 }
@@ -147,9 +148,9 @@
   cur_y += io->y_stride;
   if (io->crop_top + y_end < io->crop_bottom) {
     // Save the unfinished samples for next call (as we're not done yet).
-    memcpy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y));
-    memcpy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u));
-    memcpy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v));
+    SbMemoryCopy(p->tmp_y, cur_y, mb_w * sizeof(*p->tmp_y));
+    SbMemoryCopy(p->tmp_u, cur_u, uv_w * sizeof(*p->tmp_u));
+    SbMemoryCopy(p->tmp_v, cur_v, uv_w * sizeof(*p->tmp_v));
     // The fancy upsampler leaves a row unfinished behind
     // (except for the very last row)
     num_lines_out--;
@@ -177,14 +178,14 @@
 
   if (alpha != NULL) {
     for (j = 0; j < mb_h; ++j) {
-      memcpy(dst, alpha, mb_w * sizeof(*dst));
+      SbMemoryCopy(dst, alpha, mb_w * sizeof(*dst));
       alpha += io->width;
       dst += buf->a_stride;
     }
   } else if (buf->a != NULL) {
     // the user requested alpha, but there is none, set it to opaque.
     for (j = 0; j < mb_h; ++j) {
-      memset(dst, 0xff, mb_w * sizeof(*dst));
+      SbMemorySet(dst, 0xff, mb_w * sizeof(*dst));
       dst += buf->a_stride;
     }
   }
@@ -329,7 +330,7 @@
   if (has_alpha) {
     tmp_size += work_size;
   }
-  p->memory = calloc(1, tmp_size * sizeof(*work));
+  p->memory = SbMemoryCalloc(1, tmp_size * sizeof(*work));
   if (p->memory == NULL) {
     return 0;   // memory error
   }
@@ -373,8 +374,8 @@
   // U/V can be +1/-1 line from the Y one.  Hence the double test.
   while (WebPRescalerHasPendingOutput(&p->scaler_y) &&
          WebPRescalerHasPendingOutput(&p->scaler_u)) {
-    assert(p->last_y + y_pos + num_lines_out < p->output->height);
-    assert(p->scaler_u.y_accum == p->scaler_v.y_accum);
+    SB_DCHECK(p->last_y + y_pos + num_lines_out < p->output->height);
+    SB_DCHECK(p->scaler_u.y_accum == p->scaler_v.y_accum);
     WebPRescalerExportRow(&p->scaler_y);
     WebPRescalerExportRow(&p->scaler_u);
     WebPRescalerExportRow(&p->scaler_v);
@@ -402,7 +403,7 @@
         WebPRescalerImport(&p->scaler_v, uv_mb_h - uv_j,
                            io->v + uv_j * io->uv_stride, io->uv_stride);
     (void)v_lines_in;   // remove a gcc warning
-    assert(u_lines_in == v_lines_in);
+    SB_DCHECK(u_lines_in == v_lines_in);
     j += y_lines_in;
     uv_j += u_lines_in;
     num_lines_out += ExportRGB(p, num_lines_out);
@@ -424,7 +425,7 @@
 
   while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
     int i;
-    assert(p->last_y + y_pos + num_lines_out < p->output->height);
+    SB_DCHECK(p->last_y + y_pos + num_lines_out < p->output->height);
     WebPRescalerExportRow(&p->scaler_a);
     for (i = 0; i < width; ++i) {
       const uint32_t alpha_value = p->scaler_a.dst[i];
@@ -453,7 +454,7 @@
 
   while (WebPRescalerHasPendingOutput(&p->scaler_a)) {
     int i;
-    assert(p->last_y + y_pos + num_lines_out < p->output->height);
+    SB_DCHECK(p->last_y + y_pos + num_lines_out < p->output->height);
     WebPRescalerExportRow(&p->scaler_a);
     for (i = 0; i < width; ++i) {
       // Fill in the alpha value (converted to 4 bits).
@@ -501,7 +502,7 @@
     tmp_size1 += work_size;
     tmp_size2 += out_width;
   }
-  p->memory = calloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
+  p->memory = SbMemoryCalloc(1, tmp_size1 * sizeof(*work) + tmp_size2 * sizeof(*tmp));
   if (p->memory == NULL) {
     return 0;   // memory error
   }
@@ -565,7 +566,7 @@
 #ifdef FANCY_UPSAMPLING
       if (io->fancy_upsampling) {
         const int uv_width = (io->mb_w + 1) >> 1;
-        p->memory = malloc(io->mb_w + 2 * uv_width);
+        p->memory = SbMemoryAllocate(io->mb_w + 2 * uv_width);
         if (p->memory == NULL) {
           return 0;   // memory error.
         }
@@ -602,7 +603,7 @@
   const int mb_w = io->mb_w;
   const int mb_h = io->mb_h;
   int num_lines_out;
-  assert(!(io->mb_y & 1));
+  SB_DCHECK(!(io->mb_y & 1));
 
   if (mb_w <= 0 || mb_h <= 0) {
     return 0;
@@ -619,7 +620,7 @@
 
 static void CustomTeardown(const VP8Io* io) {
   WebPDecParams* const p = (WebPDecParams*)io->opaque;
-  free(p->memory);
+  SbMemoryDeallocate(p->memory);
   p->memory = NULL;
 }
 
diff --git a/src/third_party/libwebp/dec/layer.c b/src/third_party/libwebp/dec/layer.c
index ccb036a..3a7042f 100644
--- a/src/third_party/libwebp/dec/layer.c
+++ b/src/third_party/libwebp/dec/layer.c
@@ -12,7 +12,7 @@
 // Author: Skal (pascal.massimino@gmail.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -27,8 +27,8 @@
 //------------------------------------------------------------------------------
 
 int VP8DecodeLayer(VP8Decoder* const dec) {
-  assert(dec);
-  assert(dec->layer_data_size_ > 0);
+  SB_DCHECK(dec);
+  SB_DCHECK(dec->layer_data_size_ > 0);
   (void)dec;
 
   // TODO: handle enhancement layer here.
diff --git a/src/third_party/libwebp/dec/tree.c b/src/third_party/libwebp/dec/tree.c
index 3f02efe..dcb32fc 100644
--- a/src/third_party/libwebp/dec/tree.c
+++ b/src/third_party/libwebp/dec/tree.c
@@ -15,6 +15,10 @@
 
 #define USE_GENERIC_TREE
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#endif
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -327,12 +331,12 @@
 };
 
 void VP8ResetProba(VP8Proba* const proba) {
-  memset(proba->segments_, 255u, sizeof(proba->segments_));
-  memcpy(proba->coeffs_, CoeffsProba0, sizeof(CoeffsProba0));
+  SbMemorySet(proba->segments_, 255u, sizeof(proba->segments_));
+  SbMemoryCopy(proba->coeffs_, CoeffsProba0, sizeof(CoeffsProba0));
 #ifndef ONLY_KEYFRAME_CODE
-  memcpy(proba->mv_, kMVProba0, sizeof(kMVProba0));
-  memcpy(proba->ymode_, kYModeProbaInter0, sizeof(kYModeProbaInter0));
-  memcpy(proba->uvmode_, kUVModeProbaInter0, sizeof(kUVModeProbaInter0));
+  SbMemoryCopy(proba->mv_, kMVProba0, sizeof(kMVProba0));
+  SbMemoryCopy(proba->ymode_, kYModeProbaInter0, sizeof(kYModeProbaInter0));
+  SbMemoryCopy(proba->uvmode_, kUVModeProbaInter0, sizeof(kUVModeProbaInter0));
 #endif
 }
 
@@ -346,8 +350,8 @@
         VP8GetBit(br, 156) ? (VP8GetBit(br, 128) ? TM_PRED : H_PRED)
                            : (VP8GetBit(br, 163) ? V_PRED : DC_PRED);
     dec->imodes_[0] = ymode;
-    memset(top, ymode, 4 * sizeof(top[0]));
-    memset(left, ymode, 4 * sizeof(left[0]));
+    SbMemorySet(top, ymode, 4 * sizeof(top[0]));
+    SbMemorySet(left, ymode, 4 * sizeof(left[0]));
   } else {
     uint8_t* modes = dec->imodes_;
     int y;
diff --git a/src/third_party/libwebp/dec/vp8.c b/src/third_party/libwebp/dec/vp8.c
index 8632e48..ad3ae29 100644
--- a/src/third_party/libwebp/dec/vp8.c
+++ b/src/third_party/libwebp/dec/vp8.c
@@ -11,7 +11,12 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <stdlib.h>
+#endif
 
 #include "./vp8i.h"
 #include "./vp8li.h"
@@ -41,13 +46,13 @@
     return 0;  // mismatch error
   }
   if (io != NULL) {
-    memset(io, 0, sizeof(*io));
+    SbMemorySet(io, 0, sizeof(*io));
   }
   return 1;
 }
 
 VP8Decoder* VP8New(void) {
-  VP8Decoder* const dec = (VP8Decoder*)calloc(1, sizeof(*dec));
+  VP8Decoder* const dec = (VP8Decoder*)SbMemoryCalloc(1, sizeof(*dec));
   if (dec != NULL) {
     SetOk(dec);
     WebPWorkerInit(&dec->worker_);
@@ -71,7 +76,7 @@
 void VP8Delete(VP8Decoder* const dec) {
   if (dec != NULL) {
     VP8Clear(dec);
-    free(dec);
+    SbMemoryDeallocate(dec);
   }
 }
 
@@ -139,19 +144,19 @@
 // Header parsing
 
 static void ResetSegmentHeader(VP8SegmentHeader* const hdr) {
-  assert(hdr != NULL);
+  SB_DCHECK(hdr != NULL);
   hdr->use_segment_ = 0;
   hdr->update_map_ = 0;
   hdr->absolute_delta_ = 1;
-  memset(hdr->quantizer_, 0, sizeof(hdr->quantizer_));
-  memset(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_));
+  SbMemorySet(hdr->quantizer_, 0, sizeof(hdr->quantizer_));
+  SbMemorySet(hdr->filter_strength_, 0, sizeof(hdr->filter_strength_));
 }
 
 // Paragraph 9.3
 static int ParseSegmentHeader(VP8BitReader* br,
                               VP8SegmentHeader* hdr, VP8Proba* proba) {
-  assert(br != NULL);
-  assert(hdr != NULL);
+  SB_DCHECK(br != NULL);
+  SB_DCHECK(hdr != NULL);
   hdr->use_segment_ = VP8Get(br);
   if (hdr->use_segment_) {
     hdr->update_map_ = VP8Get(br);
@@ -273,7 +278,7 @@
   }
 
   if (dec->alpha_data_ == NULL) {
-    assert(dec->alpha_data_size_ == 0);
+    SB_DCHECK(dec->alpha_data_size_ == 0);
     // We have NOT set alpha data yet. Set it now.
     // (This is to ensure that dec->alpha_data_ is NOT reset to NULL if
     // WebPParseHeaders() is called more than once, as in incremental decoding
@@ -285,7 +290,7 @@
   // Process the VP8 frame header.
   buf = headers.data + headers.offset;
   buf_size = headers.data_size - headers.offset;
-  assert(headers.data_size >= headers.offset);  // WebPParseHeaders' guarantee
+  SB_DCHECK(headers.data_size >= headers.offset);  // WebPParseHeaders' guarantee
   if (buf_size < 4) {
     return VP8SetError(dec, VP8_STATUS_NOT_ENOUGH_DATA,
                        "Truncated header.");
@@ -563,7 +568,7 @@
   int x, y, ch;
 
   nz_dc.i32 = nz_ac.i32 = 0;
-  memset(dst, 0, 384 * sizeof(*dst));
+  SbMemorySet(dst, 0, 384 * sizeof(*dst));
   if (!dec->is_i4x4_) {    // parse DC
     int16_t dc[16] = { 0 };
     const int ctx = mb->dc_nz_ + left_mb->dc_nz_;
@@ -676,7 +681,7 @@
   VP8MB* const left = dec->mb_info_ - 1;
   left->nz_ = 0;
   left->dc_nz_ = 0;
-  memset(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
+  SbMemorySet(dec->intra_l_, B_DC_PRED, sizeof(dec->intra_l_));
   dec->filter_row_ =
     (dec->filter_type_ > 0) &&
     (dec->mb_y_ >= dec->tl_mb_y_) && (dec->mb_y_ <= dec->br_mb_y_);
@@ -737,7 +742,7 @@
       return 0;
     }
   }
-  assert(dec->ready_);
+  SB_DCHECK(dec->ready_);
 
   // Finish setting up the decoding parameter. Will call io->setup().
   ok = (VP8EnterCritical(dec, io) == VP8_STATUS_OK);
@@ -769,11 +774,11 @@
     WebPWorkerEnd(&dec->worker_);
   }
   if (dec->mem_) {
-    free(dec->mem_);
+    SbMemoryDeallocate(dec->mem_);
   }
   dec->mem_ = NULL;
   dec->mem_size_ = 0;
-  memset(&dec->br_, 0, sizeof(dec->br_));
+  SbMemorySet(&dec->br_, 0, sizeof(dec->br_));
   dec->ready_ = 0;
 }
 
diff --git a/src/third_party/libwebp/dec/vp8i.h b/src/third_party/libwebp/dec/vp8i.h
index 1d0d407..91d27f1 100644
--- a/src/third_party/libwebp/dec/vp8i.h
+++ b/src/third_party/libwebp/dec/vp8i.h
@@ -14,7 +14,12 @@
 #ifndef WEBP_DEC_VP8I_H_
 #define WEBP_DEC_VP8I_H_
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#else
 #include <string.h>     // for memcpy()
+#endif
+
 #include "./vp8li.h"
 #include "../utils/bit_reader.h"
 #include "../utils/thread.h"
diff --git a/src/third_party/libwebp/dec/vp8l.c b/src/third_party/libwebp/dec/vp8l.c
index 89b5b4b..83ea9e2 100644
--- a/src/third_party/libwebp/dec/vp8l.c
+++ b/src/third_party/libwebp/dec/vp8l.c
@@ -12,8 +12,14 @@
 // Authors: Vikas Arora (vikaas.arora@gmail.com)
 //          Jyrki Alakuijala (jyrki@google.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <stdio.h>
 #include <stdlib.h>
+#endif
+
 #include "./vp8li.h"
 #include "../dsp/lossless.h"
 #include "../dsp/yuv.h"
@@ -157,7 +163,7 @@
   const HuffmanTreeNode* node = tree->root_;
   int num_bits = 0;
   uint32_t bits = VP8LPrefetchBits(br);
-  assert(node != NULL);
+  SB_DCHECK(node != NULL);
   while (!HuffmanTreeNodeIsLeaf(node)) {
     node = HuffmanTreeNextNode(node, bits & 1);
     bits >>= 1;
@@ -274,7 +280,7 @@
     if (ok) {
       ok = HuffmanTreeBuildImplicit(tree, code_lengths, alphabet_size);
     }
-    free(code_lengths);
+    SbMemoryDeallocate(code_lengths);
   }
   ok = ok && !br->error_;
   if (!ok) {
@@ -293,7 +299,7 @@
         HuffmanTreeRelease(&htrees[j]);
       }
     }
-    free(htree_groups);
+    SbMemoryDeallocate(htree_groups);
   }
 }
 
@@ -330,7 +336,7 @@
 
   if (br->error_) goto Error;
 
-  assert(num_htree_groups <= 0x10000);
+  SB_DCHECK(num_htree_groups <= 0x10000);
   htree_groups =
       (HTreeGroup*)WebPSafeCalloc((uint64_t)num_htree_groups,
                                   sizeof(*htree_groups));
@@ -357,7 +363,7 @@
   return 1;
 
  Error:
-  free(huffman_image);
+  SbMemoryDeallocate(huffman_image);
   DeleteHtreeGroups(htree_groups, num_htree_groups);
   return 0;
 }
@@ -383,7 +389,7 @@
     dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
     return 0;
   }
-  assert(dec->rescaler_memory == NULL);
+  SB_DCHECK(dec->rescaler_memory == NULL);
   dec->rescaler_memory = memory;
 
   dec->rescaler = (WebPRescaler*)memory;
@@ -567,8 +573,8 @@
 // Returns true if the crop window is not empty.
 static int SetCropWindow(VP8Io* const io, int y_start, int y_end,
                          const uint32_t** const in_data, int pixel_stride) {
-  assert(y_start < y_end);
-  assert(io->crop_left < io->crop_right);
+  SB_DCHECK(y_start < y_end);
+  SB_DCHECK(io->crop_left < io->crop_right);
   if (y_end > io->crop_bottom) {
     y_end = io->crop_bottom;  // make sure we don't overflow on last row.
   }
@@ -599,7 +605,7 @@
                                                    int x, int y) {
   const int meta_index = GetMetaIndex(hdr->huffman_image_, hdr->huffman_xsize_,
                                       hdr->huffman_subsample_bits_, x, y);
-  assert(meta_index < hdr->num_htree_groups_);
+  SB_DCHECK(meta_index < hdr->num_htree_groups_);
   return hdr->htree_groups_ + meta_index;
 }
 
@@ -619,7 +625,7 @@
 
   // Inverse transforms.
   // TODO: most transforms only need to operate on the cropped region only.
-  memcpy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
+  SbMemoryCopy(rows_out, rows_in, cache_pixs * sizeof(*rows_out));
   while (n-- > 0) {
     VP8LTransform* const transform = &dec->transforms_[n];
     VP8LInverseTransform(transform, start_row, end_row, rows_in, rows_out);
@@ -635,8 +641,8 @@
   const uint8_t* rows_in = rows;
   uint8_t* rows_out = (uint8_t*)dec->io_->opaque + dec->io_->width * start_row;
   VP8LTransform* const transform = &dec->transforms_[0];
-  assert(dec->next_transform_ == 1);
-  assert(transform->type_ == COLOR_INDEXING_TRANSFORM);
+  SB_DCHECK(dec->next_transform_ == 1);
+  SB_DCHECK(transform->type_ == COLOR_INDEXING_TRANSFORM);
   VP8LColorIndexInverseTransformAlpha(transform, start_row, end_row, rows_in,
                                       rows_out);
 }
@@ -674,13 +680,13 @@
             EmitRescaledRowsYUVA(dec, rows_data, in_stride, io->mb_h) :
             EmitRowsYUVA(dec, rows_data, in_stride, io->mb_w, io->mb_h);
       }
-      assert(dec->last_out_row_ <= output->height);
+      SB_DCHECK(dec->last_out_row_ <= output->height);
     }
   }
 
   // Update 'last_row_'.
   dec->last_row_ = row;
-  assert(dec->last_row_ <= dec->height_);
+  SB_DCHECK(dec->last_row_ <= dec->height_);
 }
 
 #define DECODE_DATA_FUNC(FUNC_NAME, TYPE, STORE_PIXEL)                         \
@@ -699,7 +705,7 @@
   VP8LColorCache* const color_cache =                                          \
       (hdr->color_cache_size_ > 0) ? &hdr->color_cache_ : NULL;                \
   const int mask = hdr->huffman_mask_;                                         \
-  assert(htree_group != NULL);                                                 \
+  SB_DCHECK(htree_group != NULL);                                                 \
   while (!br->eos_ && src < src_end) {                                         \
     int code;                                                                  \
     /* Only update when changing tile. Note we could use this test:        */  \
@@ -768,7 +774,7 @@
       }                                                                        \
     } else if (code < color_cache_limit) {  /* Color cache */                  \
       const int key = code - len_code_limit;                                   \
-      assert(color_cache != NULL);                                             \
+      SB_DCHECK(color_cache != NULL);                                             \
       while (last_cached < src) {                                              \
         VP8LColorCacheInsert(color_cache, *last_cached++);                     \
       }                                                                        \
@@ -816,7 +822,7 @@
 // VP8LTransform
 
 static void ClearTransform(VP8LTransform* const transform) {
-  free(transform->data_);
+  SbMemoryDeallocate(transform->data_);
   transform->data_ = NULL;
 }
 
@@ -840,7 +846,7 @@
     }
     for (; i < 4 * final_num_colors; ++i)
       new_data[i] = 0;  // black tail.
-    free(transform->data_);
+    SbMemoryDeallocate(transform->data_);
     transform->data_ = new_color_map;
   }
   return 1;
@@ -865,7 +871,7 @@
   transform->ysize_ = *ysize;
   transform->data_ = NULL;
   ++dec->next_transform_;
-  assert(dec->next_transform_ <= NUM_TRANSFORMS);
+  SB_DCHECK(dec->next_transform_ <= NUM_TRANSFORMS);
 
   switch (type) {
     case PREDICTOR_TRANSFORM:
@@ -892,7 +898,7 @@
     case SUBTRACT_GREEN:
       break;
     default:
-      assert(0);    // can't happen
+      SB_DCHECK(0);    // can't happen
       break;
   }
 
@@ -903,14 +909,14 @@
 // VP8LMetadata
 
 static void InitMetadata(VP8LMetadata* const hdr) {
-  assert(hdr);
-  memset(hdr, 0, sizeof(*hdr));
+  SB_DCHECK(hdr);
+  SbMemorySet(hdr, 0, sizeof(*hdr));
 }
 
 static void ClearMetadata(VP8LMetadata* const hdr) {
-  assert(hdr);
+  SB_DCHECK(hdr);
 
-  free(hdr->huffman_image_);
+  SbMemoryDeallocate(hdr->huffman_image_);
   DeleteHtreeGroups(hdr->htree_groups_, hdr->num_htree_groups_);
   VP8LColorCacheClear(&hdr->color_cache_);
   InitMetadata(hdr);
@@ -920,7 +926,7 @@
 // VP8LDecoder
 
 VP8LDecoder* VP8LNew(void) {
-  VP8LDecoder* const dec = (VP8LDecoder*)calloc(1, sizeof(*dec));
+  VP8LDecoder* const dec = (VP8LDecoder*)SbMemoryCalloc(1, sizeof(*dec));
   if (dec == NULL) return NULL;
   dec->status_ = VP8_STATUS_OK;
   dec->action_ = READ_DIM;
@@ -933,7 +939,7 @@
   if (dec == NULL) return;
   ClearMetadata(&dec->hdr_);
 
-  free(dec->pixels_);
+  SbMemoryDeallocate(dec->pixels_);
   dec->pixels_ = NULL;
   for (i = 0; i < dec->next_transform_; ++i) {
     ClearTransform(&dec->transforms_[i]);
@@ -941,7 +947,7 @@
   dec->next_transform_ = 0;
   dec->transforms_seen_ = 0;
 
-  free(dec->rescaler_memory);
+  SbMemoryDeallocate(dec->rescaler_memory);
   dec->rescaler_memory = NULL;
 
   dec->output_ = NULL;   // leave no trace behind
@@ -950,7 +956,7 @@
 void VP8LDelete(VP8LDecoder* const dec) {
   if (dec != NULL) {
     VP8LClear(dec);
-    free(dec);
+    SbMemoryDeallocate(dec);
   }
 }
 
@@ -1036,7 +1042,7 @@
  End:
 
   if (!ok) {
-    free(data);
+    SbMemoryDeallocate(data);
     ClearMetadata(hdr);
     // If not enough data (br.eos_) resulted in BIT_STREAM_ERROR, update the
     // status appropriately.
@@ -1049,8 +1055,8 @@
     } else {
       // We allocate image data in this function only for transforms. At level 0
       // (that is: not the transforms), we shouldn't have allocated anything.
-      assert(data == NULL);
-      assert(is_level0);
+      SB_DCHECK(data == NULL);
+      SB_DCHECK(is_level0);
     }
     if (!is_level0) ClearMetadata(hdr);  // Clean up temporary data behind.
   }
@@ -1073,7 +1079,7 @@
   const uint64_t total_num_pixels =
       num_pixels + cache_top_pixels + cache_pixels;
 
-  assert(dec->width_ <= final_width);
+  SB_DCHECK(dec->width_ <= final_width);
   dec->pixels_ = (uint32_t*)WebPSafeMalloc(total_num_pixels, bytes_per_pixel);
   if (dec->pixels_ == NULL) {
     dec->argb_cache_ = NULL;    // for sanity check
@@ -1195,7 +1201,7 @@
 
  Error:
   VP8LClear(dec);
-  assert(dec->status_ != VP8_STATUS_OK);
+  SB_DCHECK(dec->status_ != VP8_STATUS_OK);
   return 0;
 }
 
@@ -1208,11 +1214,11 @@
   if (dec == NULL) return 0;
 
   io = dec->io_;
-  assert(io != NULL);
+  SB_DCHECK(io != NULL);
   params = (WebPDecParams*)io->opaque;
-  assert(params != NULL);
+  SB_DCHECK(params != NULL);
   dec->output_ = params->output;
-  assert(dec->output_ != NULL);
+  SB_DCHECK(dec->output_ != NULL);
 
   // Initialization.
   if (!WebPIoInitFromOptions(params->options, io, MODE_BGRA)) {
@@ -1238,7 +1244,7 @@
 
  Err:
   VP8LClear(dec);
-  assert(dec->status_ != VP8_STATUS_OK);
+  SB_DCHECK(dec->status_ != VP8_STATUS_OK);
   return 0;
 }
 
diff --git a/src/third_party/libwebp/dec/vp8li.h b/src/third_party/libwebp/dec/vp8li.h
index 543a767..dbdd9c1 100644
--- a/src/third_party/libwebp/dec/vp8li.h
+++ b/src/third_party/libwebp/dec/vp8li.h
@@ -15,7 +15,12 @@
 #ifndef WEBP_DEC_VP8LI_H_
 #define WEBP_DEC_VP8LI_H_
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#else
 #include <string.h>     // for memcpy()
+#endif
+
 #include "./webpi.h"
 #include "../utils/bit_reader.h"
 #include "../utils/color_cache.h"
diff --git a/src/third_party/libwebp/dec/webp.c b/src/third_party/libwebp/dec/webp.c
index 97e79b6..3364ab8 100644
--- a/src/third_party/libwebp/dec/webp.c
+++ b/src/third_party/libwebp/dec/webp.c
@@ -11,7 +11,12 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <stdlib.h>
+#endif
 
 #include "./vp8i.h"
 #include "./vp8li.h"
@@ -64,13 +69,13 @@
 static VP8StatusCode ParseRIFF(const uint8_t** const data,
                                size_t* const data_size,
                                size_t* const riff_size) {
-  assert(data != NULL);
-  assert(data_size != NULL);
-  assert(riff_size != NULL);
+  SB_DCHECK(data != NULL);
+  SB_DCHECK(data_size != NULL);
+  SB_DCHECK(riff_size != NULL);
 
   *riff_size = 0;  // Default: no RIFF present.
-  if (*data_size >= RIFF_HEADER_SIZE && !memcmp(*data, "RIFF", TAG_SIZE)) {
-    if (memcmp(*data + 8, "WEBP", TAG_SIZE)) {
+  if (*data_size >= RIFF_HEADER_SIZE && !SbMemoryCompare(*data, "RIFF", TAG_SIZE)) {
+    if (SbMemoryCompare(*data + 8, "WEBP", TAG_SIZE)) {
       return VP8_STATUS_BITSTREAM_ERROR;  // Wrong image file signature.
     } else {
       const uint32_t size = get_le32(*data + TAG_SIZE);
@@ -103,9 +108,9 @@
                                int* const width_ptr, int* const height_ptr,
                                uint32_t* const flags_ptr) {
   const uint32_t vp8x_size = CHUNK_HEADER_SIZE + VP8X_CHUNK_SIZE;
-  assert(data != NULL);
-  assert(data_size != NULL);
-  assert(found_vp8x != NULL);
+  SB_DCHECK(data != NULL);
+  SB_DCHECK(data_size != NULL);
+  SB_DCHECK(found_vp8x != NULL);
 
   *found_vp8x = 0;
 
@@ -113,7 +118,7 @@
     return VP8_STATUS_NOT_ENOUGH_DATA;  // Insufficient data.
   }
 
-  if (!memcmp(*data, "VP8X", TAG_SIZE)) {
+  if (!SbMemoryCompare(*data, "VP8X", TAG_SIZE)) {
     int width, height;
     uint32_t flags;
     const uint32_t chunk_size = get_le32(*data + TAG_SIZE);
@@ -160,13 +165,13 @@
   uint32_t total_size = TAG_SIZE +           // "WEBP".
                         CHUNK_HEADER_SIZE +  // "VP8Xnnnn".
                         VP8X_CHUNK_SIZE;     // data.
-  assert(data != NULL);
-  assert(data_size != NULL);
+  SB_DCHECK(data != NULL);
+  SB_DCHECK(data_size != NULL);
   buf = *data;
   buf_size = *data_size;
 
-  assert(alpha_data != NULL);
-  assert(alpha_size != NULL);
+  SB_DCHECK(alpha_data != NULL);
+  SB_DCHECK(alpha_size != NULL);
   *alpha_data = NULL;
   *alpha_size = 0;
 
@@ -198,8 +203,8 @@
     // parsed all the optional chunks.
     // Note: This check must occur before the check 'buf_size < disk_chunk_size'
     // below to allow incomplete VP8/VP8L chunks.
-    if (!memcmp(buf, "VP8 ", TAG_SIZE) ||
-        !memcmp(buf, "VP8L", TAG_SIZE)) {
+    if (!SbMemoryCompare(buf, "VP8 ", TAG_SIZE) ||
+        !SbMemoryCompare(buf, "VP8L", TAG_SIZE)) {
       return VP8_STATUS_OK;
     }
 
@@ -207,7 +212,7 @@
       return VP8_STATUS_NOT_ENOUGH_DATA;
     }
 
-    if (!memcmp(buf, "ALPH", TAG_SIZE)) {         // A valid ALPH header.
+    if (!SbMemoryCompare(buf, "ALPH", TAG_SIZE)) {         // A valid ALPH header.
       *alpha_data = buf + CHUNK_HEADER_SIZE;
       *alpha_size = chunk_size;
     }
@@ -232,15 +237,15 @@
                                     size_t* const chunk_size,
                                     int* const is_lossless) {
   const uint8_t* const data = *data_ptr;
-  const int is_vp8 = !memcmp(data, "VP8 ", TAG_SIZE);
-  const int is_vp8l = !memcmp(data, "VP8L", TAG_SIZE);
+  const int is_vp8 = !SbMemoryCompare(data, "VP8 ", TAG_SIZE);
+  const int is_vp8l = !SbMemoryCompare(data, "VP8L", TAG_SIZE);
   const uint32_t minimal_size =
       TAG_SIZE + CHUNK_HEADER_SIZE;  // "WEBP" + "VP8 nnnn" OR
                                      // "WEBP" + "VP8Lnnnn"
-  assert(data != NULL);
-  assert(data_size != NULL);
-  assert(chunk_size != NULL);
-  assert(is_lossless != NULL);
+  SB_DCHECK(data != NULL);
+  SB_DCHECK(data_size != NULL);
+  SB_DCHECK(chunk_size != NULL);
+  SB_DCHECK(is_lossless != NULL);
 
   if (*data_size < CHUNK_HEADER_SIZE) {
     return VP8_STATUS_NOT_ENOUGH_DATA;  // Insufficient data.
@@ -294,7 +299,7 @@
   if (data == NULL || data_size < RIFF_HEADER_SIZE) {
     return VP8_STATUS_NOT_ENOUGH_DATA;
   }
-  memset(&hdrs, 0, sizeof(hdrs));
+  SbMemorySet(&hdrs, 0, sizeof(hdrs));
   hdrs.data = data;
   hdrs.data_size = data_size;
 
@@ -328,7 +333,7 @@
 
   // Skip over optional chunks if data started with "RIFF + VP8X" or "ALPH".
   if ((found_riff && found_vp8x) ||
-      (!found_riff && !found_vp8x && !memcmp(data, "ALPH", TAG_SIZE))) {
+      (!found_riff && !found_vp8x && !SbMemoryCompare(data, "ALPH", TAG_SIZE))) {
     status = ParseOptionalChunks(&data, &data_size, hdrs.riff_size,
                                  &hdrs.alpha_data, &hdrs.alpha_data_size);
     if (status != VP8_STATUS_OK) {
@@ -373,8 +378,8 @@
   if (headers != NULL) {
     *headers = hdrs;
     headers->offset = data - headers->data;
-    assert((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
-    assert(headers->offset == headers->data_size - data_size);
+    SB_DCHECK((uint64_t)(data - headers->data) < MAX_CHUNK_PAYLOAD);
+    SB_DCHECK(headers->offset == headers->data_size - data_size);
   }
   return VP8_STATUS_OK;  // Return features from VP8 header.
 }
@@ -382,7 +387,7 @@
 VP8StatusCode WebPParseHeaders(WebPHeaderStructure* const headers) {
   VP8StatusCode status;
   int has_animation = 0;
-  assert(headers != NULL);
+  SB_DCHECK(headers != NULL);
   // fill out headers, ignore width/height/has_alpha.
   status = ParseHeadersInternal(headers->data, headers->data_size,
                                 NULL, NULL, NULL, &has_animation, headers);
@@ -400,7 +405,7 @@
 
 void WebPResetDecParams(WebPDecParams* const params) {
   if (params) {
-    memset(params, 0, sizeof(*params));
+    SbMemorySet(params, 0, sizeof(*params));
   }
 }
 
@@ -421,7 +426,7 @@
     return status;
   }
 
-  assert(params != NULL);
+  SB_DCHECK(params != NULL);
   VP8InitIo(&io);
   io.data = headers.data + headers.offset;
   io.data_size = headers.data_size - headers.offset;
@@ -626,14 +631,14 @@
     *v = buf->v;
     *stride = buf->y_stride;
     *uv_stride = buf->u_stride;
-    assert(buf->u_stride == buf->v_stride);
+    SB_DCHECK(buf->u_stride == buf->v_stride);
   }
   return out;
 }
 
 static void DefaultFeatures(WebPBitstreamFeatures* const features) {
-  assert(features != NULL);
-  memset(features, 0, sizeof(*features));
+  SB_DCHECK(features != NULL);
+  SbMemorySet(features, 0, sizeof(*features));
   features->bitstream_version = 0;
 }
 
@@ -683,7 +688,7 @@
   if (config == NULL) {
     return 0;
   }
-  memset(config, 0, sizeof(*config));
+  SbMemorySet(config, 0, sizeof(*config));
   DefaultFeatures(&config->input);
   WebPInitDecBuffer(&config->output);
   return 1;
diff --git a/src/third_party/libwebp/demux/demux.c b/src/third_party/libwebp/demux/demux.c
index d825d9b..8bca6c6 100644
--- a/src/third_party/libwebp/demux/demux.c
+++ b/src/third_party/libwebp/demux/demux.c
@@ -15,7 +15,8 @@
 #endif
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -123,7 +124,7 @@
 
 static int InitMemBuffer(MemBuffer* const mem,
                          const uint8_t* data, size_t size) {
-  memset(mem, 0, sizeof(*mem));
+  SbMemorySet(mem, 0, sizeof(*mem));
   return RemapMemBuffer(mem, data, size);
 }
 
@@ -299,7 +300,7 @@
   if (actual_size < min_size) return PARSE_ERROR;
   if (MemDataSize(mem) < min_size)  return PARSE_NEED_MORE_DATA;
 
-  *frame = (Frame*)calloc(1, sizeof(**frame));
+  *frame = (Frame*)SbMemoryCalloc(1, sizeof(**frame));
   return (*frame == NULL) ? PARSE_ERROR : PARSE_OK;
 }
 
@@ -323,7 +324,7 @@
   frame->duration_       = ReadLE24s(mem);
   frame->dispose_method_ = (WebPMuxAnimDispose)(ReadByte(mem) & 1);
   if (frame->width_ * (uint64_t)frame->height_ >= MAX_IMAGE_AREA) {
-    free(frame);
+    SbMemoryDeallocate(frame);
     return PARSE_ERROR;
   }
 
@@ -340,7 +341,7 @@
     }
   }
 
-  if (!added_frame) free(frame);
+  if (!added_frame) SbMemoryDeallocate(frame);
   return status;
 }
 
@@ -375,7 +376,7 @@
     }
   }
 
-  if (!added_fragment) free(frame);
+  if (!added_fragment) SbMemoryDeallocate(frame);
   return status;
 }
 #endif  // WEBP_EXPERIMENTAL_FEATURES
@@ -386,7 +387,7 @@
 // Returns true on success, false otherwise.
 static int StoreChunk(WebPDemuxer* const dmux,
                       size_t start_offset, uint32_t size) {
-  Chunk* const chunk = (Chunk*)calloc(1, sizeof(*chunk));
+  Chunk* const chunk = (Chunk*)SbMemoryCalloc(1, sizeof(*chunk));
   if (chunk == NULL) return 0;
 
   chunk->data_.offset_ = start_offset;
@@ -404,8 +405,8 @@
 
   // Basic file level validation.
   if (MemDataSize(mem) < min_size) return 0;
-  if (memcmp(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) ||
-      memcmp(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) {
+  if (SbMemoryCompare(GetBuffer(mem), "RIFF", CHUNK_SIZE_BYTES) ||
+      SbMemoryCompare(GetBuffer(mem) + CHUNK_HEADER_SIZE, "WEBP", CHUNK_SIZE_BYTES)) {
     return 0;
   }
 
@@ -434,7 +435,7 @@
   if (SizeIsInvalid(mem, min_size)) return PARSE_ERROR;
   if (MemDataSize(mem) < min_size) return PARSE_NEED_MORE_DATA;
 
-  frame = (Frame*)calloc(1, sizeof(*frame));
+  frame = (Frame*)SbMemoryCalloc(1, sizeof(*frame));
   if (frame == NULL) return PARSE_ERROR;
 
   // For the single image case we allow parsing of a partial frame, but we need
@@ -460,7 +461,7 @@
     AddFrame(dmux, frame);
     dmux->num_frames_ = 1;
   } else {
-    free(frame);
+    SbMemoryDeallocate(frame);
   }
 
   return status;
@@ -686,12 +687,12 @@
   partial = (mem.buf_size_ < mem.riff_end_);
   if (!allow_partial && partial) return NULL;
 
-  dmux = (WebPDemuxer*)calloc(1, sizeof(*dmux));
+  dmux = (WebPDemuxer*)SbMemoryCalloc(1, sizeof(*dmux));
   if (dmux == NULL) return NULL;
   InitDemux(dmux, &mem);
 
   for (parser = kMasterChunks; parser->parse != NULL; ++parser) {
-    if (!memcmp(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) {
+    if (!SbMemoryCompare(parser->id, GetBuffer(&dmux->mem_), TAG_SIZE)) {
       status = parser->parse(dmux);
       if (status == PARSE_OK) dmux->state_ = WEBP_DEMUX_DONE;
       if (status == PARSE_NEED_MORE_DATA && !partial) status = PARSE_ERROR;
@@ -716,14 +717,14 @@
   for (f = dmux->frames_; f != NULL;) {
     Frame* const cur_frame = f;
     f = f->next_;
-    free(cur_frame);
+    SbMemoryDeallocate(cur_frame);
   }
   for (c = dmux->chunks_; c != NULL;) {
     Chunk* const cur_chunk = c;
     c = c->next_;
-    free(cur_chunk);
+    SbMemoryDeallocate(cur_chunk);
   }
-  free(dmux);
+  SbMemoryDeallocate(dmux);
 }
 
 // -----------------------------------------------------------------------------
@@ -806,7 +807,7 @@
   const uint8_t* const payload =
       GetFramePayload(mem_buf, fragment, &payload_size);
   if (payload == NULL) return 0;
-  assert(first_frame != NULL);
+  SB_DCHECK(first_frame != NULL);
 
   iter->frame_num      = first_frame->frame_num_;
   iter->num_frames     = dmux->num_frames_;
@@ -841,7 +842,7 @@
 int WebPDemuxGetFrame(const WebPDemuxer* dmux, int frame, WebPIterator* iter) {
   if (iter == NULL) return 0;
 
-  memset(iter, 0, sizeof(*iter));
+  SbMemorySet(iter, 0, sizeof(*iter));
   iter->private_ = (void*)dmux;
   return SetFrame(frame, iter);
 }
@@ -881,7 +882,7 @@
   int count = 0;
   for (c = dmux->chunks_; c != NULL; c = c->next_) {
     const uint8_t* const header = mem_buf + c->data_.offset_;
-    if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
+    if (!SbMemoryCompare(header, fourcc, TAG_SIZE)) ++count;
   }
   return count;
 }
@@ -893,7 +894,7 @@
   int count = 0;
   for (c = dmux->chunks_; c != NULL; c = c->next_) {
     const uint8_t* const header = mem_buf + c->data_.offset_;
-    if (!memcmp(header, fourcc, TAG_SIZE)) ++count;
+    if (!SbMemoryCompare(header, fourcc, TAG_SIZE)) ++count;
     if (count == chunk_num) break;
   }
   return c;
@@ -926,7 +927,7 @@
                       WebPChunkIterator* iter) {
   if (iter == NULL) return 0;
 
-  memset(iter, 0, sizeof(*iter));
+  SbMemorySet(iter, 0, sizeof(*iter));
   iter->private_ = (void*)dmux;
   return SetChunk(fourcc, chunk_num, iter);
 }
diff --git a/src/third_party/libwebp/dsp/dec.c b/src/third_party/libwebp/dsp/dec.c
index 2fbd6b1..ce32ee3 100644
--- a/src/third_party/libwebp/dsp/dec.c
+++ b/src/third_party/libwebp/dsp/dec.c
@@ -14,6 +14,10 @@
 #include "./dsp.h"
 #include "../dec/vp8i.h"
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#endif
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -196,14 +200,14 @@
 static void VE16(uint8_t *dst) {     // vertical
   int j;
   for (j = 0; j < 16; ++j) {
-    memcpy(dst + j * BPS, dst - BPS, 16);
+    SbMemoryCopy(dst + j * BPS, dst - BPS, 16);
   }
 }
 
 static void HE16(uint8_t *dst) {     // horizontal
   int j;
   for (j = 16; j > 0; --j) {
-    memset(dst, dst[-1], 16);
+    SbMemorySet(dst, dst[-1], 16);
     dst += BPS;
   }
 }
@@ -211,7 +215,7 @@
 static WEBP_INLINE void Put16(int v, uint8_t* dst) {
   int j;
   for (j = 0; j < 16; ++j) {
-    memset(dst + j * BPS, v, 16);
+    SbMemorySet(dst + j * BPS, v, 16);
   }
 }
 
@@ -262,7 +266,7 @@
   };
   int i;
   for (i = 0; i < 4; ++i) {
-    memcpy(dst + i * BPS, vals, sizeof(vals));
+    SbMemoryCopy(dst + i * BPS, vals, sizeof(vals));
   }
 }
 
@@ -283,7 +287,7 @@
   int i;
   for (i = 0; i < 4; ++i) dc += dst[i - BPS] + dst[-1 + i * BPS];
   dc >>= 3;
-  for (i = 0; i < 4; ++i) memset(dst + i * BPS, dc, 4);
+  for (i = 0; i < 4; ++i) SbMemorySet(dst + i * BPS, dc, 4);
 }
 
 static void RD4(uint8_t *dst) {   // Down-right
@@ -415,14 +419,14 @@
 static void VE8uv(uint8_t *dst) {    // vertical
   int j;
   for (j = 0; j < 8; ++j) {
-    memcpy(dst + j * BPS, dst - BPS, 8);
+    SbMemoryCopy(dst + j * BPS, dst - BPS, 8);
   }
 }
 
 static void HE8uv(uint8_t *dst) {    // horizontal
   int j;
   for (j = 0; j < 8; ++j) {
-    memset(dst, dst[-1], 8);
+    SbMemorySet(dst, dst[-1], 8);
     dst += BPS;
   }
 }
@@ -436,7 +440,7 @@
     *(uint64_t*)(dst + j * BPS) = v;
   }
 #else
-  for (j = 0; j < 8; ++j) memset(dst + j * BPS, value, 8);
+  for (j = 0; j < 8; ++j) SbMemorySet(dst + j * BPS, value, 8);
 #endif
 }
 
diff --git a/src/third_party/libwebp/dsp/enc.c b/src/third_party/libwebp/dsp/enc.c
index 552807a..fae8d93 100644
--- a/src/third_party/libwebp/dsp/enc.c
+++ b/src/third_party/libwebp/dsp/enc.c
@@ -11,7 +11,13 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/client_porting/poem/stdlib_poem.h"
+#include "starboard/memory.h"
+#else
 #include <stdlib.h>  // for abs()
+#endif
+
 #include "./dsp.h"
 #include "../enc/vp8enci.h"
 
@@ -229,7 +235,7 @@
 static WEBP_INLINE void Fill(uint8_t* dst, int value, int size) {
   int j;
   for (j = 0; j < size; ++j) {
-    memset(dst + j * BPS, value, size);
+    SbMemorySet(dst + j * BPS, value, size);
   }
 }
 
@@ -237,7 +243,7 @@
                                      const uint8_t* top, int size) {
   int j;
   if (top) {
-    for (j = 0; j < size; ++j) memcpy(dst + j * BPS, top, size);
+    for (j = 0; j < size; ++j) SbMemoryCopy(dst + j * BPS, top, size);
   } else {
     Fill(dst, 127, size);
   }
@@ -248,7 +254,7 @@
   if (left) {
     int j;
     for (j = 0; j < size; ++j) {
-      memset(dst + j * BPS, left[j], size);
+      SbMemorySet(dst + j * BPS, left[j], size);
     }
   } else {
     Fill(dst, 129, size);
@@ -354,7 +360,7 @@
   };
   int i;
   for (i = 0; i < 4; ++i) {
-    memcpy(dst + i * BPS, vals, 4);
+    SbMemoryCopy(dst + i * BPS, vals, 4);
   }
 }
 
@@ -658,7 +664,7 @@
 static WEBP_INLINE void Copy(const uint8_t* src, uint8_t* dst, int size) {
   int y;
   for (y = 0; y < size; ++y) {
-    memcpy(dst, src, size);
+    SbMemoryCopy(dst, src, size);
     src += BPS;
     dst += BPS;
   }
diff --git a/src/third_party/libwebp/dsp/lossless.c b/src/third_party/libwebp/dsp/lossless.c
index e445924..97f6a26 100644
--- a/src/third_party/libwebp/dsp/lossless.c
+++ b/src/third_party/libwebp/dsp/lossless.c
@@ -26,8 +26,14 @@
 #include <emmintrin.h>
 #endif
 
-#include <math.h>
+#if defined(STARBOARD)
+#include "starboard/client_porting/poem/stdlib_poem.h"
+#include "starboard/memory.h"
+#include "starboard/log.h"
+#else
 #include <stdlib.h>
+#endif
+#include <math.h>
 #include "./lossless.h"
 #include "../dec/vp8li.h"
 #include "./yuv.h"
@@ -236,7 +242,7 @@
 };
 
 float VP8LFastSLog2Slow(int v) {
-  assert(v >= LOG_LOOKUP_IDX_MAX);
+  SB_DCHECK(v >= LOG_LOOKUP_IDX_MAX);
   if (v < APPROX_LOG_MAX) {
     int log_cnt = 0;
     const float v_f = (float)v;
@@ -251,7 +257,7 @@
 }
 
 float VP8LFastLog2Slow(int v) {
-  assert(v >= LOG_LOOKUP_IDX_MAX);
+  SB_DCHECK(v >= LOG_LOOKUP_IDX_MAX);
   if (v < APPROX_LOG_MAX) {
     int log_cnt = 0;
     while (v >= LOG_LOOKUP_IDX_MAX) {
@@ -540,7 +546,7 @@
     const PredictorFunc pred_func = kPredictors[mode];
     float cur_diff;
     int y;
-    memset(&histo[0][0], 0, sizeof(histo));
+    SbMemorySet(&histo[0][0], 0, sizeof(histo));
     for (y = 0; y < ymax; ++y) {
       int x;
       const int row = row_start + y;
@@ -620,17 +626,17 @@
   uint32_t* const current_tile_rows = argb_scratch + width;
   int tile_y;
   int histo[4][256];
-  memset(histo, 0, sizeof(histo));
+  SbMemorySet(histo, 0, sizeof(histo));
   for (tile_y = 0; tile_y < tiles_per_col; ++tile_y) {
     const int tile_y_offset = tile_y * max_tile_size;
     const int this_tile_height =
         (tile_y < tiles_per_col - 1) ? max_tile_size : height - tile_y_offset;
     int tile_x;
     if (tile_y > 0) {
-      memcpy(upper_row, current_tile_rows + (max_tile_size - 1) * width,
+      SbMemoryCopy(upper_row, current_tile_rows + (max_tile_size - 1) * width,
              width * sizeof(*upper_row));
     }
-    memcpy(current_tile_rows, &argb[tile_y_offset * width],
+    SbMemoryCopy(current_tile_rows, &argb[tile_y_offset * width],
            this_tile_height * width * sizeof(*current_tile_rows));
     for (tile_x = 0; tile_x < tiles_per_row; ++tile_x) {
       int pred;
@@ -1156,8 +1162,8 @@
 void VP8LInverseTransform(const VP8LTransform* const transform,
                           int row_start, int row_end,
                           const uint32_t* const in, uint32_t* const out) {
-  assert(row_start < row_end);
-  assert(row_end <= transform->ysize_);
+  SB_DCHECK(row_start < row_end);
+  SB_DCHECK(row_end <= transform->ysize_);
   switch (transform->type_) {
     case SUBTRACT_GREEN:
       AddGreenToBlueAndRed(transform, row_start, row_end, out);
@@ -1168,7 +1174,7 @@
         // The last predicted row in this iteration will be the top-pred row
         // for the first row in next iteration.
         const int width = transform->xsize_;
-        memcpy(out - width, out + (row_end - row_start - 1) * width,
+        SbMemoryCopy(out - width, out + (row_end - row_start - 1) * width,
                width * sizeof(*out));
       }
       break;
@@ -1186,7 +1192,7 @@
         const int in_stride = (row_end - row_start) *
             VP8LSubSampleSize(transform->xsize_, transform->bits_);
         uint32_t* const src = out + out_stride - in_stride;
-        memmove(src, out, in_stride * sizeof(*src));
+        SbMemoryMove(src, out, in_stride * sizeof(*src));
         ColorIndexInverseTransform(transform, row_start, row_end, src, out);
       } else {
         ColorIndexInverseTransform(transform, row_start, row_end, in, out);
@@ -1310,7 +1316,7 @@
       dst += sizeof(argb);
     }
   } else {
-    memcpy(dst, src, num_pixels * sizeof(*src));
+    SbMemoryCopy(dst, src, num_pixels * sizeof(*src));
   }
 }
 
@@ -1355,7 +1361,7 @@
       ConvertBGRAToRGB565(in_data, num_pixels, rgba);
       break;
     default:
-      assert(0);          // Code flow should not reach here.
+      SB_DCHECK(0);          // Code flow should not reach here.
   }
 }
 
diff --git a/src/third_party/libwebp/dsp/upsampling_neon.c b/src/third_party/libwebp/dsp/upsampling_neon.c
index d118895..2e6a8e5 100644
--- a/src/third_party/libwebp/dsp/upsampling_neon.c
+++ b/src/third_party/libwebp/dsp/upsampling_neon.c
@@ -20,9 +20,14 @@
 
 #if defined(WEBP_USE_NEON)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
-#include <arm_neon.h>
 #include <string.h>
+#endif
+#include <arm_neon.h>
 #include "./yuv.h"
 
 #ifdef FANCY_UPSAMPLING
@@ -77,11 +82,11 @@
 
 #define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) {                  \
   uint8_t r1[9], r2[9];                                                 \
-  memcpy(r1, (tb), (num_pixels));                                       \
-  memcpy(r2, (bb), (num_pixels));                                       \
+  SbMemoryCopy(r1, (tb), (num_pixels));                                       \
+  SbMemoryCopy(r2, (bb), (num_pixels));                                       \
   /* replicate last byte */                                             \
-  memset(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels));    \
-  memset(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels));    \
+  SbMemorySet(r1 + (num_pixels), r1[(num_pixels) - 1], 9 - (num_pixels));    \
+  SbMemorySet(r2 + (num_pixels), r2[(num_pixels) - 1], 9 - (num_pixels));    \
   Upsample16Pixels(r1, r2, out);                                        \
 }
 
diff --git a/src/third_party/libwebp/dsp/upsampling_sse2.c b/src/third_party/libwebp/dsp/upsampling_sse2.c
index f31d048..491160c 100644
--- a/src/third_party/libwebp/dsp/upsampling_sse2.c
+++ b/src/third_party/libwebp/dsp/upsampling_sse2.c
@@ -19,9 +19,14 @@
 
 #if defined(WEBP_USE_SSE2)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
-#include <emmintrin.h>
 #include <string.h>
+#endif
+#include <emmintrin.h>
 #include "./yuv.h"
 
 #ifdef FANCY_UPSAMPLING
@@ -99,11 +104,11 @@
 
 #define UPSAMPLE_LAST_BLOCK(tb, bb, num_pixels, out) {                         \
   uint8_t r1[17], r2[17];                                                      \
-  memcpy(r1, (tb), (num_pixels));                                              \
-  memcpy(r2, (bb), (num_pixels));                                              \
+  SbMemoryCopy(r1, (tb), (num_pixels));                                              \
+  SbMemoryCopy(r2, (bb), (num_pixels));                                              \
   /* replicate last byte */                                                    \
-  memset(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels));          \
-  memset(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels));          \
+  SbMemorySet(r1 + (num_pixels), r1[(num_pixels) - 1], 17 - (num_pixels));          \
+  SbMemorySet(r2 + (num_pixels), r2[(num_pixels) - 1], 17 - (num_pixels));          \
   /* using the shared function instead of the macro saves ~3k code size */     \
   Upsample32Pixels(r1, r2, out);                                               \
 }
@@ -143,7 +148,7 @@
   const int u_diag = ((top_u[0] + cur_u[0]) >> 1) + 1;                         \
   const int v_diag = ((top_v[0] + cur_v[0]) >> 1) + 1;                         \
                                                                                \
-  assert(len > 0);                                                             \
+  SB_DCHECK(len > 0);                                                             \
   /* Treat the first pixel in regular way */                                   \
   if (top_y) {                                                                 \
     const int u0 = (top_u[0] + u_diag) >> 1;                                   \
diff --git a/src/third_party/libwebp/enc/alpha.c b/src/third_party/libwebp/enc/alpha.c
index 131e2fc..9b6c7e8 100644
--- a/src/third_party/libwebp/enc/alpha.c
+++ b/src/third_party/libwebp/enc/alpha.c
@@ -12,7 +12,8 @@
 // Author: Skal (pascal.massimino@gmail.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -42,7 +43,7 @@
 //
 // 'output' corresponds to the buffer containing compressed alpha data.
 //          This buffer is allocated by this method and caller should call
-//          free(*output) when done.
+//          SbMemoryDeallocate(*output) when done.
 // 'output_size' corresponds to size of this compressed alpha buffer.
 //
 // Returns 1 on successfully encoding the alpha and
@@ -87,7 +88,7 @@
   config.method = effort_level;  // impact is very small
   // Set a moderate default quality setting for alpha.
   config.quality = 10.f * effort_level;
-  assert(config.quality >= 0 && config.quality <= 100.f);
+  SB_DCHECK(config.quality >= 0 && config.quality <= 100.f);
 
   ok = VP8LBitWriterInit(&tmp_bw, (width * height) >> 3);
   ok = ok && (VP8LEncodeStream(&config, &picture, &tmp_bw) == VP8_ENC_OK);
@@ -116,11 +117,11 @@
   size_t expected_size;
   const size_t data_size = width * height;
 
-  assert((uint64_t)data_size == (uint64_t)width * height);  // as per spec
-  assert(filter >= 0 && filter < WEBP_FILTER_LAST);
-  assert(method >= ALPHA_NO_COMPRESSION);
-  assert(method <= ALPHA_LOSSLESS_COMPRESSION);
-  assert(sizeof(header) == ALPHA_HEADER_LEN);
+  SB_DCHECK((uint64_t)data_size == (uint64_t)width * height);  // as per spec
+  SB_DCHECK(filter >= 0 && filter < WEBP_FILTER_LAST);
+  SB_DCHECK(method >= ALPHA_NO_COMPRESSION);
+  SB_DCHECK(method <= ALPHA_LOSSLESS_COMPRESSION);
+  SB_DCHECK(sizeof(header) == ALPHA_HEADER_LEN);
   // TODO(skal): have a common function and #define's to validate alpha params.
 
   expected_size =
@@ -156,7 +157,7 @@
 static void CopyPlane(const uint8_t* src, int src_stride,
                       uint8_t* dst, int dst_stride, int width, int height) {
   while (height-- > 0) {
-    memcpy(dst, src, width);
+    SbMemoryCopy(dst, src, width);
     src += src_stride;
     dst += dst_stride;
   }
@@ -196,12 +197,12 @@
   const int reduce_levels = (quality < 100);
 
   // quick sanity checks
-  assert((uint64_t)data_size == (uint64_t)width * height);  // as per spec
-  assert(enc != NULL && pic != NULL && pic->a != NULL);
-  assert(output != NULL && output_size != NULL);
-  assert(width > 0 && height > 0);
-  assert(pic->a_stride >= width);
-  assert(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST);
+  SB_DCHECK((uint64_t)data_size == (uint64_t)width * height);  // as per spec
+  SB_DCHECK(enc != NULL && pic != NULL && pic->a != NULL);
+  SB_DCHECK(output != NULL && output_size != NULL);
+  SB_DCHECK(width > 0 && height > 0);
+  SB_DCHECK(pic->a_stride >= width);
+  SB_DCHECK(filter >= WEBP_FILTER_NONE && filter <= WEBP_FILTER_FAST);
 
   if (quality < 0 || quality > 100) {
     return 0;
@@ -211,7 +212,7 @@
     return 0;
   }
 
-  quant_alpha = (uint8_t*)malloc(data_size);
+  quant_alpha = (uint8_t*)SbMemoryAllocate(data_size);
   if (quant_alpha == NULL) {
     return 0;
   }
@@ -264,7 +265,7 @@
       goto Ok;
     }
 
-    filtered_alpha = (uint8_t*)malloc(data_size);
+    filtered_alpha = (uint8_t*)SbMemoryAllocate(data_size);
     ok = (filtered_alpha != NULL);
     if (!ok) {
       goto End;
@@ -277,7 +278,7 @@
                           VP8BitWriterSize(&bw) : (size_t)~0U;
       int wipe_tmp_bw = try_filter_none;
 
-      memset(&best_stats, 0, sizeof(best_stats));  // prevent spurious warning
+      SbMemorySet(&best_stats, 0, sizeof(best_stats));  // prevent spurious warning
       if (pic->stats != NULL) best_stats = *pic->stats;
       for (test_filter =
            try_filter_none ? WEBP_FILTER_HORIZONTAL : WEBP_FILTER_NONE;
@@ -320,10 +321,10 @@
         enc->sse_[3] = sse;
       }
     }
-    free(filtered_alpha);
+    SbMemoryDeallocate(filtered_alpha);
   }
  End:
-  free(quant_alpha);
+  SbMemoryDeallocate(quant_alpha);
   return ok;
 }
 
@@ -345,7 +346,7 @@
     return 0;
   }
   if (alpha_size != (uint32_t)alpha_size) {  // Sanity check.
-    free(alpha_data);
+    SbMemoryDeallocate(alpha_data);
     return 0;
   }
   enc->alpha_data_size_ = (uint32_t)alpha_size;
@@ -400,7 +401,7 @@
     ok = WebPWorkerSync(worker);  // finish anything left in flight
     WebPWorkerEnd(worker);  // still need to end the worker, even if !ok
   }
-  free(enc->alpha_data_);
+  SbMemoryDeallocate(enc->alpha_data_);
   enc->alpha_data_ = NULL;
   enc->alpha_data_size_ = 0;
   enc->has_alpha_ = 0;
diff --git a/src/third_party/libwebp/enc/analysis.c b/src/third_party/libwebp/enc/analysis.c
index 4ff3edd..f435807 100644
--- a/src/third_party/libwebp/enc/analysis.c
+++ b/src/third_party/libwebp/enc/analysis.c
@@ -11,9 +11,14 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#endif
 
 #include "./vp8enci.h"
 #include "./cost.h"
@@ -35,7 +40,7 @@
   const int h = enc->mb_h_;
   const int majority_cnt_3_x_3_grid = 5;
   uint8_t* const tmp = (uint8_t*)WebPSafeMalloc((uint64_t)w * h, sizeof(*tmp));
-  assert((uint64_t)(w * h) == (uint64_t)w * h);   // no overflow, as per spec
+  SB_DCHECK((uint64_t)(w * h) == (uint64_t)w * h);   // no overflow, as per spec
 
   if (tmp == NULL) return;
   for (y = 1; y < h - 1; ++y) {
@@ -66,7 +71,7 @@
       mb->segment_ = tmp[x + y * w];
     }
   }
-  free(tmp);
+  SbMemoryDeallocate(tmp);
 }
 
 //------------------------------------------------------------------------------
@@ -90,7 +95,7 @@
     }
   }
   if (max == min) max = min + 1;
-  assert(mid <= max && mid >= min);
+  SB_DCHECK(mid <= max && mid >= min);
   for (n = 0; n < nb; ++n) {
     const int alpha = 255 * (centers[n] - mid) / (max - min);
     const int beta = 255 * (centers[n] - min) / (max - min);
@@ -280,7 +285,7 @@
     for (mode = 0; mode < max_mode; ++mode) {
       int alpha;
 
-      memset(&histos[cur_histo], 0, sizeof(histos[cur_histo]));
+      SbMemorySet(&histos[cur_histo], 0, sizeof(histos[cur_histo]));
       VP8CollectHistogram(src, it->yuv_p_ + VP8I4ModeOffsets[mode],
                           0, 1, &histos[cur_histo]);
       alpha = GetAlpha(&histos[cur_histo]);
diff --git a/src/third_party/libwebp/enc/backward_references.c b/src/third_party/libwebp/enc/backward_references.c
index db4f430..3004f9d 100644
--- a/src/third_party/libwebp/enc/backward_references.c
+++ b/src/third_party/libwebp/enc/backward_references.c
@@ -10,9 +10,14 @@
 // Author: Jyrki Alakuijala (jyrki@google.com)
 //
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <math.h>
 #include <stdio.h>
+#endif
 
 #include "./backward_references.h"
 #include "./histogram.h"
@@ -88,13 +93,13 @@
 
 void VP8LClearBackwardRefs(VP8LBackwardRefs* const refs) {
   if (refs != NULL) {
-    free(refs->refs);
+    SbMemoryDeallocate(refs->refs);
     VP8LInitBackwardRefs(refs);
   }
 }
 
 int VP8LBackwardRefsAlloc(VP8LBackwardRefs* const refs, int max_size) {
-  assert(refs != NULL);
+  SB_DCHECK(refs != NULL);
   refs->size = 0;
   refs->max_size = 0;
   refs->refs = (PixOrCopy*)WebPSafeMalloc((uint64_t)max_size,
@@ -130,8 +135,8 @@
 
 static void HashChainDelete(HashChain* const p) {
   if (p != NULL) {
-    free(p->chain_);
-    free(p);
+    SbMemoryDeallocate(p->chain_);
+    SbMemoryDeallocate(p);
   }
 }
 
@@ -152,7 +157,7 @@
   const int max_window_size = (quality > 50) ? WINDOW_SIZE
                             : (quality > 25) ? (xsize << 8)
                             : (xsize << 4);
-  assert(xsize > 0);
+  SB_DCHECK(xsize > 0);
   *window_size = (max_window_size > WINDOW_SIZE) ? WINDOW_SIZE
                : max_window_size;
   *iter_pos = 8 + (quality >> 3);
@@ -175,7 +180,7 @@
   const int min_pos =
       (base_position > window_size) ? base_position - window_size : 0;
   int pos;
-  assert(xsize > 0);
+  SB_DCHECK(xsize > 0);
   for (pos = p->hash_to_first_index_[GetPixPairHash64(argb_start)];
        pos >= min_pos;
        pos = p->chain_[pos]) {
@@ -269,7 +274,7 @@
   int cc_init = 0;
   const int use_color_cache = (cache_bits > 0);
   const int pix_count = xsize * ysize;
-  HashChain* const hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+  HashChain* const hash_chain = (HashChain*)SbMemoryAllocate(sizeof(*hash_chain));
   VP8LColorCache hashers;
   int window_size = WINDOW_SIZE;
   int iter_pos = 1;
@@ -398,7 +403,7 @@
     }
   }
   if (nonzeros <= 1) {
-    memset(output, 0, num_symbols * sizeof(*output));
+    SbMemorySet(output, 0, num_symbols * sizeof(*output));
   } else {
     const double logsum = VP8LFastLog2(sum);
     for (i = 0; i < num_symbols; ++i) {
@@ -481,8 +486,8 @@
   const int use_color_cache = (cache_bits > 0);
   float* const cost =
       (float*)WebPSafeMalloc((uint64_t)pix_count, sizeof(*cost));
-  CostModel* cost_model = (CostModel*)malloc(sizeof(*cost_model));
-  HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+  CostModel* cost_model = (CostModel*)SbMemoryAllocate(sizeof(*cost_model));
+  HashChain* hash_chain = (HashChain*)SbMemoryAllocate(sizeof(*hash_chain));
   VP8LColorCache hashers;
   const double mul0 = (recursive_cost_model != 0) ? 1.0 : 0.68;
   const double mul1 = (recursive_cost_model != 0) ? 1.0 : 0.82;
@@ -593,8 +598,8 @@
 Error:
   if (cc_init) VP8LColorCacheClear(&hashers);
   HashChainDelete(hash_chain);
-  free(cost_model);
-  free(cost);
+  SbMemoryDeallocate(cost_model);
+  SbMemoryDeallocate(cost);
   return ok;
 }
 
@@ -633,7 +638,7 @@
   int window_size = WINDOW_SIZE;
   int iter_pos = 1;
   int iter_limit = -1;
-  HashChain* hash_chain = (HashChain*)malloc(sizeof(*hash_chain));
+  HashChain* hash_chain = (HashChain*)SbMemoryAllocate(sizeof(*hash_chain));
   VP8LColorCache hashers;
 
   if (hash_chain == NULL || !HashChainInit(hash_chain, pix_count)) {
@@ -655,7 +660,7 @@
       HashChainFindCopy(hash_chain, i, xsize, argb, maxlen,
                         window_size, iter_pos, iter_limit,
                         &offset, &len);
-      assert(len == maxlen);
+      SB_DCHECK(len == maxlen);
       refs->refs[size] = PixOrCopyCreateCopy(offset, len);
       if (use_color_cache) {
         for (k = 0; k < len; ++k) {
@@ -684,7 +689,7 @@
       ++i;
     }
   }
-  assert(size <= refs->max_size);
+  SB_DCHECK(size <= refs->max_size);
   refs->size = size;
   ok = 1;
 Error:
@@ -721,7 +726,7 @@
   }
   ok = 1;
  Error:
-  free(dist_array);
+  SbMemoryDeallocate(dist_array);
   return ok;
 }
 
@@ -765,7 +770,7 @@
 
   {
     double bit_cost_lz77, bit_cost_rle;
-    VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
+    VP8LHistogram* const histo = (VP8LHistogram*)SbMemoryAllocate(sizeof(*histo));
     if (histo == NULL) goto Error1;
     // Evaluate lz77 coding
     VP8LHistogramCreate(histo, &refs_lz77, cache_bits);
@@ -775,7 +780,7 @@
     bit_cost_rle = VP8LHistogramEstimateBits(histo);
     // Decide if LZ77 is useful.
     lz77_is_useful = (bit_cost_lz77 < bit_cost_rle);
-    free(histo);
+    SbMemoryDeallocate(histo);
   }
 
   // Choose appropriate backward reference.
@@ -854,7 +859,7 @@
     }
     pixel_index += PixOrCopyLength(v);
   }
-  assert(pixel_index == xsize * ysize);
+  SB_DCHECK(pixel_index == xsize * ysize);
   (void)xsize;  // xsize is not used in non-debug compilations otherwise.
   (void)ysize;  // ysize is not used in non-debug compilations otherwise.
   if (cc_init) VP8LColorCacheClear(&hashers);
diff --git a/src/third_party/libwebp/enc/backward_references.h b/src/third_party/libwebp/enc/backward_references.h
index b0d1813..e13441c 100644
--- a/src/third_party/libwebp/enc/backward_references.h
+++ b/src/third_party/libwebp/enc/backward_references.h
@@ -13,8 +13,12 @@
 #ifndef WEBP_ENC_BACKWARD_REFERENCES_H_
 #define WEBP_ENC_BACKWARD_REFERENCES_H_
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#else
 #include <assert.h>
 #include <stdlib.h>
+#endif
 #include "../webp/types.h"
 #include "../webp/format_constants.h"
 
@@ -37,7 +41,7 @@
 #if defined(__GNUC__) && \
     ((__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || __GNUC__ >= 4)
 static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
-  assert(n != 0);
+  SB_DCHECK(n != 0);
   return 31 ^ __builtin_clz(n);
 }
 #elif defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
@@ -46,7 +50,7 @@
 
 static WEBP_INLINE int BitsLog2Floor(uint32_t n) {
   unsigned long first_set_bit;
-  assert(n != 0);
+  SB_DCHECK(n != 0);
   _BitScanReverse(&first_set_bit, n);
   return first_set_bit;
 }
@@ -57,7 +61,7 @@
   uint32_t value = n;
   int i;
 
-  assert(n != 0);
+  SB_DCHECK(n != 0);
   for (i = 4; i >= 0; --i) {
     const int shift = (1 << i);
     const uint32_t x = value >> shift;
@@ -125,8 +129,8 @@
 
 static WEBP_INLINE PixOrCopy PixOrCopyCreateCacheIdx(int idx) {
   PixOrCopy retval;
-  assert(idx >= 0);
-  assert(idx < (1 << MAX_COLOR_CACHE_BITS));
+  SB_DCHECK(idx >= 0);
+  SB_DCHECK(idx < (1 << MAX_COLOR_CACHE_BITS));
   retval.mode = kCacheIdx;
   retval.argb_or_distance = idx;
   retval.len = 1;
@@ -155,7 +159,7 @@
 
 static WEBP_INLINE uint32_t PixOrCopyLiteral(const PixOrCopy* const p,
                                              int component) {
-  assert(p->mode == kLiteral);
+  SB_DCHECK(p->mode == kLiteral);
   return (p->argb_or_distance >> (component * 8)) & 0xff;
 }
 
@@ -164,18 +168,18 @@
 }
 
 static WEBP_INLINE uint32_t PixOrCopyArgb(const PixOrCopy* const p) {
-  assert(p->mode == kLiteral);
+  SB_DCHECK(p->mode == kLiteral);
   return p->argb_or_distance;
 }
 
 static WEBP_INLINE uint32_t PixOrCopyCacheIdx(const PixOrCopy* const p) {
-  assert(p->mode == kCacheIdx);
-  assert(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
+  SB_DCHECK(p->mode == kCacheIdx);
+  SB_DCHECK(p->argb_or_distance < (1U << MAX_COLOR_CACHE_BITS));
   return p->argb_or_distance;
 }
 
 static WEBP_INLINE uint32_t PixOrCopyDistance(const PixOrCopy* const p) {
-  assert(p->mode == kCopy);
+  SB_DCHECK(p->mode == kCopy);
   return p->argb_or_distance;
 }
 
diff --git a/src/third_party/libwebp/enc/filter.c b/src/third_party/libwebp/enc/filter.c
index aae2723..237727c 100644
--- a/src/third_party/libwebp/enc/filter.c
+++ b/src/third_party/libwebp/enc/filter.c
@@ -13,6 +13,10 @@
 
 #include "./vp8enci.h"
 
+#if definend(STARBOARD)
+#include "starboard/memory.h"
+#endif
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -218,7 +222,7 @@
   uint8_t* const v_dst = it->yuv_out2_ + V_OFF;
 
   // copy current block to yuv_out2_
-  memcpy(y_dst, it->yuv_out_, YUV_SIZE * sizeof(uint8_t));
+  SbMemoryCopy(y_dst, it->yuv_out_, YUV_SIZE * sizeof(uint8_t));
 
   if (enc->filter_hdr_.simple_ == 1) {   // simple
     VP8EncSimpleHFilter16i(y_dst, BPS, limit);
diff --git a/src/third_party/libwebp/enc/frame.c b/src/third_party/libwebp/enc/frame.c
index c56abed..3cbd14f 100644
--- a/src/third_party/libwebp/enc/frame.c
+++ b/src/third_party/libwebp/enc/frame.c
@@ -11,10 +11,15 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h."
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#endif
 
 #include "./vp8enci.h"
 #include "./cost.h"
@@ -93,7 +98,7 @@
 
 static void ResetTokenStats(VP8Encoder* const enc) {
   VP8Proba* const proba = &enc->proba_;
-  memset(proba->stats_, 0, sizeof(proba->stats_));
+  SbMemorySet(proba->stats_, 0, sizeof(proba->stats_));
 }
 
 // Record proba context used
@@ -168,7 +173,7 @@
 // Collect statistics and deduce probabilities for next coding pass.
 // Return the total bit-cost for coding the probability updates.
 static int CalcTokenProba(int nb, int total) {
-  assert(nb <= total);
+  SB_DCHECK(nb <= total);
   return nb ? (255 - nb * 255 / total) : 255;
 }
 
@@ -315,7 +320,7 @@
   // Last coefficient is always non-zero
   {
     const int v = abs(res->coeffs[n]);
-    assert(v != 0);
+    SB_DCHECK(v != 0);
     cost += VP8BitCost(1, p0);
     cost += VP8LevelCost(t, v);
     if (n < 15) {
@@ -625,7 +630,7 @@
 static void SetBlock(uint8_t* p, int value, int size) {
   int y;
   for (y = 0; y < size; ++y) {
-    memset(p, value, size);
+    SbMemorySet(p, value, size);
     p += BPS;
   }
 }
@@ -918,11 +923,11 @@
   if (max_count < MIN_COUNT) max_count = MIN_COUNT;
   cnt = max_count;
 
-  assert(enc->num_parts_ == 1);
-  assert(enc->use_tokens_);
-  assert(proba->use_skip_proba_ == 0);
-  assert(rd_opt >= RD_OPT_BASIC);   // otherwise, token-buffer won't be useful
-  assert(!enc->do_search_);         // TODO(skal): handle pass and dichotomy
+  SB_DCHECK(enc->num_parts_ == 1);
+  SB_DCHECK(enc->use_tokens_);
+  SB_DCHECK(proba->use_skip_proba_ == 0);
+  SB_DCHECK(rd_opt >= RD_OPT_BASIC);   // otherwise, token-buffer won't be useful
+  SB_DCHECK(!enc->do_search_);         // TODO(skal): handle pass and dichotomy
 
   SetLoopParams(enc, enc->config_->quality);
 
diff --git a/src/third_party/libwebp/enc/histogram.c b/src/third_party/libwebp/enc/histogram.c
index 787ea5d..474c377 100644
--- a/src/third_party/libwebp/enc/histogram.c
+++ b/src/third_party/libwebp/enc/histogram.c
@@ -13,8 +13,13 @@
 #include "config.h"
 #endif
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <math.h>
 #include <stdio.h>
+#endif
 
 #include "./backward_references.h"
 #include "./histogram.h"
@@ -22,11 +27,11 @@
 #include "../utils/utils.h"
 
 static void HistogramClear(VP8LHistogram* const p) {
-  memset(p->literal_, 0, sizeof(p->literal_));
-  memset(p->red_, 0, sizeof(p->red_));
-  memset(p->blue_, 0, sizeof(p->blue_));
-  memset(p->alpha_, 0, sizeof(p->alpha_));
-  memset(p->distance_, 0, sizeof(p->distance_));
+  SbMemorySet(p->literal_, 0, sizeof(p->literal_));
+  SbMemorySet(p->red_, 0, sizeof(p->red_));
+  SbMemorySet(p->blue_, 0, sizeof(p->blue_));
+  SbMemorySet(p->alpha_, 0, sizeof(p->alpha_));
+  SbMemorySet(p->distance_, 0, sizeof(p->distance_));
   p->bit_cost_ = 0;
 }
 
@@ -339,7 +344,7 @@
   int x = 0, y = 0;
   const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
   VP8LHistogram** const histograms = image->histograms;
-  assert(histo_bits > 0);
+  SB_DCHECK(histo_bits > 0);
   for (i = 0; i < backward_refs->size; ++i) {
     const PixOrCopy* const v = &backward_refs->refs[i];
     const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);
@@ -370,13 +375,13 @@
   int out_size = in->size;
   const int outer_iters = in->size * iter_mult;
   const int min_cluster_size = 2;
-  VP8LHistogram* const histos = (VP8LHistogram*)malloc(2 * sizeof(*histos));
+  VP8LHistogram* const histos = (VP8LHistogram*)SbMemoryAllocate(2 * sizeof(*histos));
   VP8LHistogram* cur_combo = histos + 0;    // trial merged histogram
   VP8LHistogram* best_combo = histos + 1;   // best merged histogram so far
   if (histos == NULL) goto End;
 
   // Copy histograms from in[] to out[].
-  assert(in->size <= out->size);
+  SB_DCHECK(in->size <= out->size);
   for (i = 0; i < in->size; ++i) {
     in->histograms[i]->bit_cost_ = VP8LHistogramEstimateBits(in->histograms[i]);
     *out->histograms[i] = *in->histograms[i];
@@ -433,7 +438,7 @@
   ok = 1;
 
  End:
-  free(histos);
+  SbMemoryDeallocate(histos);
   return ok;
 }
 
@@ -509,6 +514,6 @@
   ok = 1;
 
 Error:
-  free(image_out);
+  SbMemoryDeallocate(image_out);
   return ok;
 }
diff --git a/src/third_party/libwebp/enc/histogram.h b/src/third_party/libwebp/enc/histogram.h
index 583b5a4..70831a4 100644
--- a/src/third_party/libwebp/enc/histogram.h
+++ b/src/third_party/libwebp/enc/histogram.h
@@ -14,11 +14,16 @@
 #ifndef WEBP_ENC_HISTOGRAM_H_
 #define WEBP_ENC_HISTOGRAM_H_
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <stddef.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#endif
 
 #include "./backward_references.h"
 #include "../webp/format_constants.h"
@@ -43,7 +48,7 @@
 } VP8LHistogram;
 
 // Collection of histograms with fixed capacity, allocated as one
-// big memory chunk. Can be destroyed by simply calling 'free()'.
+// big memory chunk. Can be destroyed by simply calling 'SbMemoryDeallocate()'.
 typedef struct {
   int size;         // number of slots currently in use
   int max_size;     // maximum capacity
diff --git a/src/third_party/libwebp/enc/iterator.c b/src/third_party/libwebp/enc/iterator.c
index 0746659..2cd1bc0 100644
--- a/src/third_party/libwebp/enc/iterator.c
+++ b/src/third_party/libwebp/enc/iterator.c
@@ -15,6 +15,10 @@
 
 #include "./vp8enci.h"
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#endif
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -27,17 +31,17 @@
   const VP8Encoder* const enc = it->enc_;
   enc->y_left_[-1] = enc->u_left_[-1] = enc->v_left_[-1] =
       (it->y_ > 0) ? 129 : 127;
-  memset(enc->y_left_, 129, 16);
-  memset(enc->u_left_, 129, 8);
-  memset(enc->v_left_, 129, 8);
+  SbMemorySet(enc->y_left_, 129, 16);
+  SbMemorySet(enc->u_left_, 129, 8);
+  SbMemorySet(enc->v_left_, 129, 8);
   it->left_nz_[8] = 0;
 }
 
 static void InitTop(VP8EncIterator* const it) {
   const VP8Encoder* const enc = it->enc_;
   const size_t top_size = enc->mb_w_ * 16;
-  memset(enc->y_top_, 127, 2 * top_size);
-  memset(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_));
+  SbMemorySet(enc->y_top_, 127, 2 * top_size);
+  SbMemorySet(enc->nz_, 0, enc->mb_w_ * sizeof(*enc->nz_));
 }
 
 void VP8IteratorReset(VP8EncIterator* const it) {
@@ -53,7 +57,7 @@
   it->done_ = enc->mb_w_* enc->mb_h_;
   InitTop(it);
   InitLeft(it);
-  memset(it->bit_count_, 0, sizeof(it->bit_count_));
+  SbMemorySet(it->bit_count_, 0, sizeof(it->bit_count_));
   it->do_trellis_ = 0;
 }
 
@@ -90,15 +94,15 @@
                         uint8_t* dst, int w, int h, int size) {
   int i;
   for (i = 0; i < h; ++i) {
-    memcpy(dst, src, w);
+    SbMemoryCopy(dst, src, w);
     if (w < size) {
-      memset(dst + w, dst[w - 1], size - w);
+      SbMemorySet(dst + w, dst[w - 1], size - w);
     }
     dst += BPS;
     src += src_stride;
   }
   for (i = h; i < size; ++i) {
-    memcpy(dst, dst - BPS, size);
+    SbMemoryCopy(dst, dst - BPS, size);
     dst += BPS;
   }
 }
@@ -136,7 +140,7 @@
 static void ExportBlock(const uint8_t* src, uint8_t* dst, int dst_stride,
                         int w, int h) {
   while (h-- > 0) {
-    memcpy(dst, src, w);
+    SbMemoryCopy(dst, src, w);
     dst += dst_stride;
     src += BPS;
   }
@@ -266,8 +270,8 @@
       enc->v_left_[-1] = enc->uv_top_[x * 16 + 8 + 7];
     }
     if (y < enc->mb_h_ - 1) {  // top
-      memcpy(enc->y_top_ + x * 16, ysrc + 15 * BPS, 16);
-      memcpy(enc->uv_top_ + x * 16, usrc + 7 * BPS, 8 + 8);
+      SbMemoryCopy(enc->y_top_ + x * 16, ysrc + 15 * BPS, 16);
+      SbMemoryCopy(enc->uv_top_ + x * 16, usrc + 7 * BPS, 8 + 8);
     }
   }
 
@@ -293,7 +297,7 @@
   uint8_t* preds = it->preds_;
   int y;
   for (y = 0; y < 4; ++y) {
-    memset(preds, mode, 4);
+    SbMemorySet(preds, mode, 4);
     preds += it->enc_->preds_w_;
   }
   it->mb_->type_ = 1;
@@ -303,7 +307,7 @@
   uint8_t* preds = it->preds_;
   int y;
   for (y = 4; y > 0; --y) {
-    memcpy(preds, modes, 4 * sizeof(*modes));
+    SbMemoryCopy(preds, modes, 4 * sizeof(*modes));
     preds += it->enc_->preds_w_;
     modes += 4;
   }
diff --git a/src/third_party/libwebp/enc/layer.c b/src/third_party/libwebp/enc/layer.c
index fa89660..c6194c8 100644
--- a/src/third_party/libwebp/enc/layer.c
+++ b/src/third_party/libwebp/enc/layer.c
@@ -11,7 +11,11 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#else
 #include <stdlib.h>
+#endif
 
 #include "./vp8enci.h"
 
@@ -43,7 +47,7 @@
 }
 
 void VP8EncDeleteLayer(VP8Encoder* enc) {
-  free(enc->layer_data_);
+  SbMemoryDeallocate(enc->layer_data_);
 }
 
 #if defined(__cplusplus) || defined(c_plusplus)
diff --git a/src/third_party/libwebp/enc/picture.c b/src/third_party/libwebp/enc/picture.c
index 5aaa385..f94bf7c 100644
--- a/src/third_party/libwebp/enc/picture.c
+++ b/src/third_party/libwebp/enc/picture.c
@@ -11,9 +11,14 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <stdlib.h>
 #include <math.h>
+#endif
 
 #include "./vp8enci.h"
 #include "../utils/rescaler.h"
@@ -159,7 +164,7 @@
 // into 'dst'. Mark 'dst' as not owning any memory.
 static void WebPPictureGrabSpecs(const WebPPicture* const src,
                                  WebPPicture* const dst) {
-  assert(src != NULL && dst != NULL);
+  SB_DCHECK(src != NULL && dst != NULL);
   *dst = *src;
   PictureResetYUVA(dst);
   PictureResetARGB(dst);
@@ -169,7 +174,7 @@
 // the other YUV(A) buffer.
 static int PictureAllocARGB(WebPPicture* const picture) {
   WebPPicture tmp;
-  free(picture->memory_argb_);
+  SbMemoryDeallocate(picture->memory_argb_);
   PictureResetARGB(picture);
   picture->use_argb = 1;
   WebPPictureGrabSpecs(picture, &tmp);
@@ -185,8 +190,8 @@
 // Release memory owned by 'picture' (both YUV and ARGB buffers).
 void WebPPictureFree(WebPPicture* picture) {
   if (picture != NULL) {
-    free(picture->memory_);
-    free(picture->memory_argb_);
+    SbMemoryDeallocate(picture->memory_);
+    SbMemoryDeallocate(picture->memory_argb_);
     PictureResetYUVA(picture);
     PictureResetARGB(picture);
   }
@@ -199,7 +204,7 @@
 static void CopyPlane(const uint8_t* src, int src_stride,
                       uint8_t* dst, int dst_stride, int width, int height) {
   while (height-- > 0) {
-    memcpy(dst, src, width);
+    SbMemoryCopy(dst, src, width);
     src += src_stride;
     dst += dst_stride;
   }
@@ -387,7 +392,7 @@
                    src_width, dst_width,
                    src_height, dst_height,
                    work);
-  memset(work, 0, 2 * dst_width * num_channels * sizeof(*work));
+  SbMemorySet(work, 0, 2 * dst_width * num_channels * sizeof(*work));
   while (y < src_height) {
     y += WebPRescalerImport(&rescaler, src_height - y,
                             src + y * src_stride, src_stride);
@@ -466,7 +471,7 @@
                  work, 4);
   }
   WebPPictureFree(pic);
-  free(work);
+  SbMemoryDeallocate(work);
   *pic = tmp;
   return 1;
 }
@@ -498,15 +503,15 @@
       return 0;
     }
     if (w->size > 0) {
-      memcpy(new_mem, w->mem, w->size);
+      SbMemoryCopy(new_mem, w->mem, w->size);
     }
-    free(w->mem);
+    SbMemoryDeallocate(w->mem);
     w->mem = new_mem;
     // down-cast is ok, thanks to WebPSafeMalloc
     w->max_size = (size_t)next_max_size;
   }
   if (data_size > 0) {
-    memcpy(w->mem + w->size, data, data_size);
+    SbMemoryCopy(w->mem + w->size, data, data_size);
     w->size += data_size;
   }
   return 1;
@@ -583,8 +588,8 @@
   const int uv_width = HALVE(picture->width);
   const int uv_height = HALVE(picture->height);
   for (y = 0; y < uv_height; ++y) {
-    memset(picture->u + y * picture->uv_stride, 128, uv_width);
-    memset(picture->v + y * picture->uv_stride, 128, uv_width);
+    SbMemorySet(picture->u + y * picture->uv_stride, 128, uv_width);
+    SbMemorySet(picture->v + y * picture->uv_stride, 128, uv_width);
   }
 }
 
@@ -660,7 +665,7 @@
   }
 
   if (has_alpha) {
-    assert(step >= 4);
+    SB_DCHECK(step >= 4);
     for (y = 0; y < height; ++y) {
       for (x = 0; x < width; ++x) {
         picture->a[x + y * picture->a_stride] =
@@ -707,7 +712,7 @@
     }
   } else {
     int x, y;
-    assert(step >= 4);
+    SB_DCHECK(step >= 4);
     for (y = 0; y < height; ++y) {
       for (x = 0; x < width; ++x) {
         const int offset = step * x + y * rgb_stride;
@@ -832,7 +837,7 @@
     // We work on a tmp copy of 'picture', because ImportYUVAFromRGBA()
     // would be calling WebPPictureFree(picture) otherwise.
     WebPPicture tmp = *picture;
-    PictureResetARGB(&tmp);  // reset ARGB buffer so that it's not free()'d.
+    PictureResetARGB(&tmp);  // reset ARGB buffer so that it's not SbMemoryDeallocate()'d.
     tmp.use_argb = 0;
     tmp.colorspace = colorspace & WEBP_CSP_UV_MASK;
     if (!ImportYUVAFromRGBA(r, g, b, a, 4, 4 * picture->argb_stride, &tmp)) {
@@ -868,7 +873,7 @@
 static WEBP_INLINE void flatten(uint8_t* ptr, int v, int stride, int size) {
   int y;
   for (y = 0; y < size; ++y) {
-    memset(ptr, v, size);
+    SbMemorySet(ptr, v, size);
     ptr += stride;
   }
 }
@@ -984,7 +989,7 @@
     return 0;
   }
 
-  memset(stats, 0, sizeof(stats));
+  SbMemorySet(stats, 0, sizeof(stats));
 
   uv_w = HALVE(src->width);
   uv_h = HALVE(src->height);
@@ -1074,7 +1079,7 @@
   ok = import(&pic, rgba, stride) && WebPEncode(&config, &pic);
   WebPPictureFree(&pic);
   if (!ok) {
-    free(wrt.mem);
+    SbMemoryDeallocate(wrt.mem);
     *output = NULL;
     return 0;
   }
diff --git a/src/third_party/libwebp/enc/quant.c b/src/third_party/libwebp/enc/quant.c
index 462d4e9..f6ab0b6 100644
--- a/src/third_party/libwebp/enc/quant.c
+++ b/src/third_party/libwebp/enc/quant.c
@@ -11,8 +11,13 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <math.h>
+#endif
 
 #include "./vp8enci.h"
 #include "./cost.h"
@@ -314,7 +319,7 @@
     const double expn = 1. - amp * enc->dqm_[i].alpha_;
     const double c = pow(c_base, expn);
     const int q = (int)(127. * (1. - c));
-    assert(expn > 0.);
+    SB_DCHECK(expn > 0.);
     enc->dqm_[i].quant_ = clip(q, 0, 127);
   }
 
@@ -612,8 +617,8 @@
   }
 
   // Fresh start
-  memset(in + first, 0, (16 - first) * sizeof(*in));
-  memset(out + first, 0, (16 - first) * sizeof(*out));
+  SbMemorySet(in + first, 0, (16 - first) * sizeof(*in));
+  SbMemorySet(out + first, 0, (16 - first) * sizeof(*out));
   if (best_path[0] == -1) {
     return 0;   // skip!
   }
@@ -797,8 +802,8 @@
       CopyScore(rd, &rd16);
       rd->mode_i16 = mode;
       rd->nz = nz;
-      memcpy(rd->y_ac_levels, rd16.y_ac_levels, sizeof(rd16.y_ac_levels));
-      memcpy(rd->y_dc_levels, rd16.y_dc_levels, sizeof(rd16.y_dc_levels));
+      SbMemoryCopy(rd->y_ac_levels, rd16.y_ac_levels, sizeof(rd16.y_ac_levels));
+      SbMemoryCopy(rd->y_dc_levels, rd16.y_dc_levels, sizeof(rd16.y_dc_levels));
       SwapOut(it);
     }
   }
@@ -867,7 +872,7 @@
         CopyScore(&rd_i4, &rd_tmp);
         best_mode = mode;
         SwapPtr(&tmp_dst, &best_block);
-        memcpy(rd_best.y_ac_levels[it->i4_], tmp_levels, sizeof(tmp_levels));
+        SbMemoryCopy(rd_best.y_ac_levels[it->i4_], tmp_levels, sizeof(tmp_levels));
       }
     }
     SetRDScore(dqm->lambda_mode_, &rd_i4);
@@ -888,7 +893,7 @@
   CopyScore(rd, &rd_best);
   VP8SetIntra4Mode(it, rd->modes_i4);
   SwapOut(it);
-  memcpy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels));
+  SbMemoryCopy(rd->y_ac_levels, rd_best.y_ac_levels, sizeof(rd->y_ac_levels));
   return 1;   // select intra4x4 over intra16x16
 }
 
@@ -922,8 +927,8 @@
     if (mode == 0 || rd_uv.score < rd_best.score) {
       CopyScore(&rd_best, &rd_uv);
       rd->mode_uv = mode;
-      memcpy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels));
-      memcpy(dst0, tmp_dst, UV_SIZE);   //  TODO: SwapUVOut() ?
+      SbMemoryCopy(rd->uv_levels, rd_uv.uv_levels, sizeof(rd->uv_levels));
+      SbMemoryCopy(dst0, tmp_dst, UV_SIZE);   //  TODO: SwapUVOut() ?
     }
   }
   VP8SetIntraUVMode(it, rd->mode_uv);
diff --git a/src/third_party/libwebp/enc/syntax.c b/src/third_party/libwebp/enc/syntax.c
index b0f7676..a4e94e5 100644
--- a/src/third_party/libwebp/enc/syntax.c
+++ b/src/third_party/libwebp/enc/syntax.c
@@ -11,7 +11,11 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#else
 #include <assert.h>
+#endif
 
 #include "../utils/utils.h"
 #include "../webp/format_constants.h"  // RIFF constants
@@ -44,7 +48,7 @@
   uint8_t riff[RIFF_HEADER_SIZE] = {
     'R', 'I', 'F', 'F', 0, 0, 0, 0, 'W', 'E', 'B', 'P'
   };
-  assert(riff_size == (uint32_t)riff_size);
+  SB_DCHECK(riff_size == (uint32_t)riff_size);
   PutLE32(riff + TAG_SIZE, (uint32_t)riff_size);
   if (!pic->writer(riff, sizeof(riff), pic)) {
     return VP8_ENC_ERROR_BAD_WRITE;
@@ -59,9 +63,9 @@
   };
   uint32_t flags = 0;
 
-  assert(IsVP8XNeeded(enc));
-  assert(pic->width >= 1 && pic->height >= 1);
-  assert(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
+  SB_DCHECK(IsVP8XNeeded(enc));
+  SB_DCHECK(pic->width >= 1 && pic->height >= 1);
+  SB_DCHECK(pic->width <= MAX_CANVAS_SIZE && pic->height <= MAX_CANVAS_SIZE);
 
   if (enc->has_alpha_) {
     flags |= ALPHA_FLAG;
@@ -83,7 +87,7 @@
     'A', 'L', 'P', 'H'
   };
 
-  assert(enc->has_alpha_);
+  SB_DCHECK(enc->has_alpha_);
 
   // Alpha chunk header.
   PutLE32(alpha_chunk_hdr + TAG_SIZE, enc->alpha_data_size_);
@@ -108,7 +112,7 @@
   uint8_t vp8_chunk_hdr[CHUNK_HEADER_SIZE] = {
     'V', 'P', '8', ' '
   };
-  assert(vp8_size == (uint32_t)vp8_size);
+  SB_DCHECK(vp8_size == (uint32_t)vp8_size);
   PutLE32(vp8_chunk_hdr + TAG_SIZE, (uint32_t)vp8_size);
   if (!pic->writer(vp8_chunk_hdr, sizeof(vp8_chunk_hdr), pic)) {
     return VP8_ENC_ERROR_BAD_WRITE;
@@ -280,7 +284,7 @@
   PutLE24(buffer + 0, enc->layer_data_size_);
   buffer[3] = enc->pic_->colorspace & WEBP_CSP_UV_MASK;
   if (enc->layer_data_size_ > 0) {
-    assert(enc->use_layer_);
+    SB_DCHECK(enc->use_layer_);
     // append layer data to last partition
     if (!VP8BitWriterAppend(&enc->parts_[enc->num_parts_ - 1],
                             enc->layer_data_, enc->layer_data_size_)) {
diff --git a/src/third_party/libwebp/enc/token.c b/src/third_party/libwebp/enc/token.c
index bbe2f58..1280eb5 100644
--- a/src/third_party/libwebp/enc/token.c
+++ b/src/third_party/libwebp/enc/token.c
@@ -17,7 +17,8 @@
 // Author: Skal (pascal.massimino@gmail.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -32,7 +33,7 @@
 
 #if !defined(DISABLE_TOKEN_BUFFER)
 
-// we use pages to reduce the number of memcpy()
+// we use pages to reduce the number of SbMemoryCopy()
 #define MAX_NUM_TOKEN 8192          // max number of token per page
 #define FIXED_PROBA_BIT (1u << 14)
 
@@ -58,7 +59,7 @@
     const VP8Tokens* p = b->pages_;
     while (p != NULL) {
       const VP8Tokens* const next = p->next_;
-      free((void*)p);
+      SbMemoryDeallocate((void*)p);
       p = next;
     }
     VP8TBufferInit(b);
@@ -66,7 +67,7 @@
 }
 
 static int TBufferNewPage(VP8TBuffer* const b) {
-  VP8Tokens* const page = b->error_ ? NULL : (VP8Tokens*)malloc(sizeof(*page));
+  VP8Tokens* const page = b->error_ ? NULL : (VP8Tokens*)SbMemoryAllocate(sizeof(*page));
   if (page == NULL) {
     b->error_ = 1;
     return 0;
@@ -86,8 +87,8 @@
 
 static WEBP_INLINE int AddToken(VP8TBuffer* const b,
                                 int bit, uint32_t proba_idx) {
-  assert(proba_idx < FIXED_PROBA_BIT);
-  assert(bit == 0 || bit == 1);
+  SB_DCHECK(proba_idx < FIXED_PROBA_BIT);
+  SB_DCHECK(bit == 0 || bit == 1);
   if (b->left_ > 0 || TBufferNewPage(b)) {
     const int slot = --b->left_;
     b->tokens_[slot] = (bit << 15) | proba_idx;
@@ -97,8 +98,8 @@
 
 static WEBP_INLINE void AddConstantToken(VP8TBuffer* const b,
                                          int bit, int proba) {
-  assert(proba < 256);
-  assert(bit == 0 || bit == 1);
+  SB_DCHECK(proba < 256);
+  SB_DCHECK(bit == 0 || bit == 1);
   if (b->left_ > 0 || TBufferNewPage(b)) {
     const int slot = --b->left_;
     b->tokens_[slot] = (bit << 15) | FIXED_PROBA_BIT | proba;
@@ -235,7 +236,7 @@
         VP8PutBit(bw, bit, probas[token & 0x3fffu]);
       }
     }
-    if (final_pass) free((void*)p);
+    if (final_pass) SbMemoryDeallocate((void*)p);
     p = next;
   }
   if (final_pass) b->pages_ = NULL;
diff --git a/src/third_party/libwebp/enc/tree.c b/src/third_party/libwebp/enc/tree.c
index ecd8fb9..31df71f 100644
--- a/src/third_party/libwebp/enc/tree.c
+++ b/src/third_party/libwebp/enc/tree.c
@@ -13,6 +13,11 @@
 
 #include "./vp8enci.h"
 
+#if defined(STARBOARD)
+#include "starboard/memory.h"
+#endif
+
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -161,8 +166,8 @@
 void VP8DefaultProbas(VP8Encoder* const enc) {
   VP8Proba* const probas = &enc->proba_;
   probas->use_skip_proba_ = 0;
-  memset(probas->segments_, 255u, sizeof(probas->segments_));
-  memcpy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0));
+  SbMemorySet(probas->segments_, 255u, sizeof(probas->segments_));
+  SbMemoryCopy(probas->coeffs_, VP8CoeffsProba0, sizeof(VP8CoeffsProba0));
   // Note: we could hard-code the level_costs_ corresponding to VP8CoeffsProba0,
   // but that's ~11k of static data. Better call VP8CalculateLevelCosts() later.
   probas->dirty_ = 1;
diff --git a/src/third_party/libwebp/enc/vp8enci.h b/src/third_party/libwebp/enc/vp8enci.h
index 61d56be..fe37140 100644
--- a/src/third_party/libwebp/enc/vp8enci.h
+++ b/src/third_party/libwebp/enc/vp8enci.h
@@ -14,7 +14,12 @@
 #ifndef WEBP_ENC_VP8ENCI_H_
 #define WEBP_ENC_VP8ENCI_H_
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <string.h>     // for memcpy()
+#endif
 #include "../webp/encode.h"
 #include "../dsp/dsp.h"
 #include "../utils/bit_writer.h"
diff --git a/src/third_party/libwebp/enc/vp8l.c b/src/third_party/libwebp/enc/vp8l.c
index 945870c..34070b3 100644
--- a/src/third_party/libwebp/enc/vp8l.c
+++ b/src/third_party/libwebp/enc/vp8l.c
@@ -12,9 +12,14 @@
 // Author: Vikas Arora (vikaas.arora@gmail.com)
 //
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
+#endif
 
 #include "./backward_references.h"
 #include "./vp8enci.h"
@@ -39,7 +44,7 @@
 static int CompareColors(const void* p1, const void* p2) {
   const uint32_t a = *(const uint32_t*)p1;
   const uint32_t b = *(const uint32_t*)p2;
-  assert(a != b);
+  SB_DCHECK(a != b);
   return (a < b) ? -1 : 1;
 }
 
@@ -97,7 +102,7 @@
     }
   }
 
-  qsort(palette, num_colors, sizeof(*palette), CompareColors);
+  SbSystemSort(palette, num_colors, sizeof(*palette), CompareColors);
   *palette_size = num_colors;
   return 1;
 }
@@ -112,7 +117,7 @@
 
   VP8LHistogram* nonpredicted = NULL;
   VP8LHistogram* predicted =
-      (VP8LHistogram*)malloc(2 * sizeof(*predicted));
+      (VP8LHistogram*)SbMemoryAllocate(2 * sizeof(*predicted));
   if (predicted == NULL) return 0;
   nonpredicted = predicted + 1;
 
@@ -139,13 +144,13 @@
   }
   *nonpredicted_bits = VP8LHistogramEstimateBitsBulk(nonpredicted);
   *predicted_bits = VP8LHistogramEstimateBitsBulk(predicted);
-  free(predicted);
+  SbMemoryDeallocate(predicted);
   return 1;
 }
 
 static int VP8LEncAnalyze(VP8LEncoder* const enc, WebPImageHint image_hint) {
   const WebPPicture* const pic = enc->pic_;
-  assert(pic != NULL && pic->argb != NULL);
+  SB_DCHECK(pic != NULL && pic->argb != NULL);
 
   enc->use_palette_ =
       AnalyzeAndCreatePalette(pic, enc->palette_, &enc->palette_size_);
@@ -235,9 +240,9 @@
 
  End:
   if (!ok) {
-    free(mem_buf);
+    SbMemoryDeallocate(mem_buf);
     // If one VP8LCreateHuffmanTree() above fails, we need to clean up behind.
-    memset(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
+    SbMemorySet(huffman_codes, 0, 5 * histogram_image_size * sizeof(*huffman_codes));
   }
   return ok;
 }
@@ -362,14 +367,14 @@
       const int nbits = VP8LBitsLog2Ceiling(trimmed_length - 1);
       const int nbitpairs = (nbits == 0) ? 1 : (nbits + 1) / 2;
       VP8LWriteBits(bw, 3, nbitpairs - 1);
-      assert(trimmed_length >= 2);
+      SB_DCHECK(trimmed_length >= 2);
       VP8LWriteBits(bw, nbitpairs * 2, trimmed_length - 2);
     }
     StoreHuffmanTreeToBitMask(bw, tokens, length, &huffman_code);
   }
   ok = 1;
  End:
-  free(tokens);
+  SbMemoryDeallocate(tokens);
   return ok;
 }
 
@@ -488,7 +493,7 @@
   VP8LHistogramStoreRefs(&refs, histogram_image->histograms[0]);
 
   // Create Huffman bit lengths and codes for each histogram image.
-  assert(histogram_image->size == 1);
+  SB_DCHECK(histogram_image->size == 1);
   if (!GetHuffBitLengthsAndCodes(histogram_image, huffman_codes)) {
     goto Error;
   }
@@ -510,9 +515,9 @@
   ok = 1;
 
  Error:
-  free(histogram_image);
+  SbMemoryDeallocate(histogram_image);
   VP8LClearBackwardRefs(&refs);
-  free(huffman_codes[0].codes);
+  SbMemoryDeallocate(huffman_codes[0].codes);
   return ok;
 }
 
@@ -535,12 +540,12 @@
   uint16_t* const histogram_symbols =
       (uint16_t*)WebPSafeMalloc((uint64_t)histogram_image_xysize,
                                 sizeof(*histogram_symbols));
-  assert(histogram_bits >= MIN_HUFFMAN_BITS);
-  assert(histogram_bits <= MAX_HUFFMAN_BITS);
+  SB_DCHECK(histogram_bits >= MIN_HUFFMAN_BITS);
+  SB_DCHECK(histogram_bits <= MAX_HUFFMAN_BITS);
 
   if (histogram_image == NULL || histogram_symbols == NULL) {
-    free(histogram_image);
-    free(histogram_symbols);
+    SbMemoryDeallocate(histogram_image);
+    SbMemoryDeallocate(histogram_symbols);
     return 0;
   }
 
@@ -566,7 +571,7 @@
     goto Error;
   }
   // Free combined histograms.
-  free(histogram_image);
+  SbMemoryDeallocate(histogram_image);
   histogram_image = NULL;
 
   // Color Cache parameters.
@@ -600,7 +605,7 @@
                                 VP8LSubSampleSize(width, histogram_bits),
                                 VP8LSubSampleSize(height, histogram_bits),
                                 quality);
-      free(histogram_argb);
+      SbMemoryDeallocate(histogram_argb);
       if (!ok) goto Error;
     }
   }
@@ -621,14 +626,14 @@
   ok = 1;
 
  Error:
-  free(histogram_image);
+  SbMemoryDeallocate(histogram_image);
 
   VP8LClearBackwardRefs(&refs);
   if (huffman_codes != NULL) {
-    free(huffman_codes->codes);
-    free(huffman_codes);
+    SbMemoryDeallocate(huffman_codes->codes);
+    SbMemoryDeallocate(huffman_codes);
   }
-  free(histogram_symbols);
+  SbMemoryDeallocate(histogram_symbols);
   return ok;
 }
 
@@ -644,7 +649,7 @@
     int i;
     const uint32_t* const argb = enc->argb_;
     double bit_cost_before, bit_cost_after;
-    VP8LHistogram* const histo = (VP8LHistogram*)malloc(sizeof(*histo));
+    VP8LHistogram* const histo = (VP8LHistogram*)SbMemoryAllocate(sizeof(*histo));
     if (histo == NULL) return 0;
 
     VP8LHistogramInit(histo, 1);
@@ -663,7 +668,7 @@
       ++histo->blue_[((c >> 0) - green) & 0xff];
     }
     bit_cost_after = VP8LHistogramEstimateBits(histo);
-    free(histo);
+    SbMemoryDeallocate(histo);
 
     // Check if subtracting green yields low entropy.
     enc->use_subtract_green_ = (bit_cost_after < bit_cost_before);
@@ -687,7 +692,7 @@
                     enc->transform_data_);
   VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
   VP8LWriteBits(bw, 2, PREDICTOR_TRANSFORM);
-  assert(pred_bits >= 2);
+  SB_DCHECK(pred_bits >= 2);
   VP8LWriteBits(bw, 3, pred_bits - 2);
   if (!EncodeImageNoHuffman(bw, enc->transform_data_,
                             transform_width, transform_height, quality)) {
@@ -708,7 +713,7 @@
                           enc->argb_, enc->transform_data_);
   VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
   VP8LWriteBits(bw, 2, CROSS_COLOR_TRANSFORM);
-  assert(ccolor_transform_bits >= 2);
+  SB_DCHECK(ccolor_transform_bits >= 2);
   VP8LWriteBits(bw, 3, ccolor_transform_bits - 2);
   if (!EncodeImageNoHuffman(bw, enc->transform_data_,
                             transform_width, transform_height, quality)) {
@@ -737,7 +742,7 @@
                           VP8LBitWriter* const bw) {
   const int width = pic->width - 1;
   const int height = pic->height - 1;
-  assert(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
+  SB_DCHECK(width < WEBP_MAX_DIMENSION && height < WEBP_MAX_DIMENSION);
 
   VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, width);
   VP8LWriteBits(bw, VP8L_IMAGE_SIZE_BITS, height);
@@ -904,7 +909,7 @@
   // Save palette to bitstream.
   VP8LWriteBits(bw, 1, TRANSFORM_PRESENT);
   VP8LWriteBits(bw, 2, COLOR_INDEXING_TRANSFORM);
-  assert(palette_size >= 1);
+  SB_DCHECK(palette_size >= 1);
   VP8LWriteBits(bw, 8, palette_size - 1);
   for (i = palette_size - 1; i >= 1; --i) {
     palette[i] = VP8LSubPixels(palette[i], palette[i - 1]);
@@ -915,7 +920,7 @@
   }
 
  Error:
-  free(row);
+  SbMemoryDeallocate(row);
   return err;
 }
 
@@ -952,7 +957,7 @@
 
 static VP8LEncoder* VP8LEncoderNew(const WebPConfig* const config,
                                    const WebPPicture* const picture) {
-  VP8LEncoder* const enc = (VP8LEncoder*)calloc(1, sizeof(*enc));
+  VP8LEncoder* const enc = (VP8LEncoder*)SbMemoryCalloc(1, sizeof(*enc));
   if (enc == NULL) {
     WebPEncodingSetError(picture, VP8_ENC_ERROR_OUT_OF_MEMORY);
     return NULL;
@@ -963,8 +968,8 @@
 }
 
 static void VP8LEncoderDelete(VP8LEncoder* enc) {
-  free(enc->argb_);
-  free(enc);
+  SbMemoryDeallocate(enc->argb_);
+  SbMemoryDeallocate(enc);
 }
 
 // -----------------------------------------------------------------------------
@@ -1008,7 +1013,7 @@
     err = AllocateTransformBuffer(enc, width, height);
     if (err != VP8_ENC_OK) goto Error;
     for (y = 0; y < height; ++y) {
-      memcpy(enc->argb_ + y * width,
+      SbMemoryCopy(enc->argb_ + y * width,
              picture->argb + y * picture->argb_stride,
              width * sizeof(*enc->argb_));
     }
@@ -1110,7 +1115,7 @@
   // Reset stats (for pure lossless coding)
   if (picture->stats != NULL) {
     WebPAuxStats* const stats = picture->stats;
-    memset(stats, 0, sizeof(*stats));
+    SbMemorySet(stats, 0, sizeof(*stats));
     stats->PSNR[0] = 99.f;
     stats->PSNR[1] = 99.f;
     stats->PSNR[2] = 99.f;
@@ -1155,7 +1160,7 @@
   if (picture->extra_info != NULL) {
     const int mb_w = (width + 15) >> 4;
     const int mb_h = (height + 15) >> 4;
-    memset(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
+    SbMemorySet(picture->extra_info, 0, mb_w * mb_h * sizeof(*picture->extra_info));
   }
 
  Error:
diff --git a/src/third_party/libwebp/enc/webpenc.c b/src/third_party/libwebp/enc/webpenc.c
index d420d06..ae4fb3b 100644
--- a/src/third_party/libwebp/enc/webpenc.c
+++ b/src/third_party/libwebp/enc/webpenc.c
@@ -11,10 +11,15 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#endif
 
 #include "./vp8enci.h"
 #include "./vp8li.h"
@@ -54,7 +59,7 @@
     return 0;   // caller/system version mismatch!
   }
   if (picture != NULL) {
-    memset(picture, 0, sizeof(*picture));
+    SbMemorySet(picture, 0, sizeof(*picture));
     picture->writer = DummyWriter;
     WebPEncodingSetError(picture, VP8_ENC_OK);
   }
@@ -228,7 +233,7 @@
   }
   enc = (VP8Encoder*)mem;
   mem = (uint8_t*)DO_ALIGN(mem + sizeof(*enc));
-  memset(enc, 0, sizeof(*enc));
+  SbMemorySet(enc, 0, sizeof(*enc));
   enc->num_parts_ = 1 << config->partitions;
   enc->mb_w_ = mb_w;
   enc->mb_h_ = mb_h;
@@ -292,7 +297,7 @@
     VP8EncDeleteLayer(enc);
 #endif
     VP8TBufferClear(&enc->tokens_);
-    free(enc);
+    SbMemoryDeallocate(enc);
   }
   return ok;
 }
@@ -336,8 +341,8 @@
 
 int WebPEncodingSetError(const WebPPicture* const pic,
                          WebPEncodingError error) {
-  assert((int)error < VP8_ENC_ERROR_LAST);
-  assert((int)error >= VP8_ENC_OK);
+  SB_DCHECK((int)error < VP8_ENC_ERROR_LAST);
+  SB_DCHECK((int)error >= VP8_ENC_OK);
   ((WebPPicture*)pic)->error_code = error;
   return 0;
 }
@@ -371,7 +376,7 @@
   if (pic->width > WEBP_MAX_DIMENSION || pic->height > WEBP_MAX_DIMENSION)
     return WebPEncodingSetError(pic, VP8_ENC_ERROR_BAD_DIMENSION);
 
-  if (pic->stats != NULL) memset(pic->stats, 0, sizeof(*pic->stats));
+  if (pic->stats != NULL) SbMemorySet(pic->stats, 0, sizeof(*pic->stats));
 
   if (!config->lossless) {
     VP8Encoder* enc = NULL;
diff --git a/src/third_party/libwebp/starboard_private.h b/src/third_party/libwebp/starboard_private.h
deleted file mode 100644
index 242ef00..0000000
--- a/src/third_party/libwebp/starboard_private.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// 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.
-
-#ifndef WEBP_STARBOARD_PRIVATE_H_
-#define WEBP_STARBOARD_PRIVATE_H_
-
-#include "starboard/log.h"
-#include "starboard/memory.h"
-#include "starboard/system.h"
-
-
-static SB_C_INLINE int webp_abs(int a) {
-  return (a < 0 ? -a : a);
-}
-
-#undef assert
-#define assert(x) SB_DCHECK(x)
-
-#define abs(x) webp_abs(x)
-#define calloc SbMemoryCalloc
-#define free SbMemoryDeallocate
-#define malloc SbMemoryAllocate
-#define memcpy SbMemoryCopy
-#define memmove SbMemoryMove
-#define memset SbMemorySet
-#define qsort SbSystemSort
-
-
-#endif  /* WEBP_STARBOARD_PRIVATE_H_ */
diff --git a/src/third_party/libwebp/utils/bit_reader.c b/src/third_party/libwebp/utils/bit_reader.c
index ab7a827..ad6dee0 100644
--- a/src/third_party/libwebp/utils/bit_reader.c
+++ b/src/third_party/libwebp/utils/bit_reader.c
@@ -13,6 +13,10 @@
 
 #include "./bit_reader.h"
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#endif
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -28,9 +32,9 @@
 
 void VP8InitBitReader(VP8BitReader* const br,
                       const uint8_t* const start, const uint8_t* const end) {
-  assert(br != NULL);
-  assert(start != NULL);
-  assert(start <= end);
+  SB_DCHECK(br != NULL);
+  SB_DCHECK(start != NULL);
+  SB_DCHECK(start <= end);
   br->range_   = MK(255 - 1);
   br->buf_     = start;
   br->buf_end_ = end;
@@ -74,7 +78,7 @@
 #undef MK
 
 void VP8LoadFinalBytes(VP8BitReader* const br) {
-  assert(br != NULL && br->buf_ != NULL);
+  SB_DCHECK(br != NULL && br->buf_ != NULL);
   // Only read 8bits at a time
   if (br->buf_ < br->buf_end_) {
 #ifndef USE_RIGHT_JUSTIFY
@@ -128,9 +132,9 @@
                        const uint8_t* const start,
                        size_t length) {
   size_t i;
-  assert(br != NULL);
-  assert(start != NULL);
-  assert(length < 0xfffffff8u);   // can't happen with a RIFF chunk.
+  SB_DCHECK(br != NULL);
+  SB_DCHECK(start != NULL);
+  SB_DCHECK(length < 0xfffffff8u);   // can't happen with a RIFF chunk.
 
   br->buf_ = start;
   br->len_ = length;
@@ -147,9 +151,9 @@
 
 void VP8LBitReaderSetBuffer(VP8LBitReader* const br,
                             const uint8_t* const buf, size_t len) {
-  assert(br != NULL);
-  assert(buf != NULL);
-  assert(len < 0xfffffff8u);   // can't happen with a RIFF chunk.
+  SB_DCHECK(br != NULL);
+  SB_DCHECK(buf != NULL);
+  SB_DCHECK(len < 0xfffffff8u);   // can't happen with a RIFF chunk.
   br->eos_ = (br->pos_ >= len);
   br->buf_ = buf;
   br->len_ = len;
@@ -186,7 +190,7 @@
 }
 
 uint32_t VP8LReadBits(VP8LBitReader* const br, int n_bits) {
-  assert(n_bits >= 0);
+  SB_DCHECK(n_bits >= 0);
   // Flag an error if end_of_stream or n_bits is more than allowed limit.
   if (!br->eos_ && n_bits < MAX_NUM_BIT_READ) {
     const uint32_t val =
diff --git a/src/third_party/libwebp/utils/bit_reader.h b/src/third_party/libwebp/utils/bit_reader.h
index 1d022a5..e9e0ab8 100644
--- a/src/third_party/libwebp/utils/bit_reader.h
+++ b/src/third_party/libwebp/utils/bit_reader.h
@@ -16,7 +16,8 @@
 #define WEBP_UTILS_BIT_READER_H_
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #ifdef _MSC_VER
@@ -154,7 +155,7 @@
 void VP8LoadFinalBytes(VP8BitReader* const br);    // special case for the tail
 
 static WEBP_INLINE void VP8LoadNewBytes(VP8BitReader* const br) {
-  assert(br != NULL && br->buf_ != NULL);
+  SB_DCHECK(br != NULL && br->buf_ != NULL);
   // Read 'BITS' bits at a time if possible.
   if (br->buf_ + sizeof(lbit_t) <= br->buf_end_) {
     // convert memory type to register type (with some zero'ing!)
@@ -253,7 +254,7 @@
   br->bits_ -= shift;
 #else
   const int shift = kVP8Log2Range[br->range_];
-  assert(br->range_ < (range_t)128);
+  SB_DCHECK(br->range_ < (range_t)128);
   br->range_ = kVP8NewRange[br->range_];
   br->bits_ -= shift;
 #endif
diff --git a/src/third_party/libwebp/utils/bit_writer.c b/src/third_party/libwebp/utils/bit_writer.c
index 4da869d..8ee1cd1 100644
--- a/src/third_party/libwebp/utils/bit_writer.c
+++ b/src/third_party/libwebp/utils/bit_writer.c
@@ -13,7 +13,8 @@
 //         Vikas Arora (vikaas.arora@gmail.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <string.h>   // for memcpy()
@@ -43,13 +44,13 @@
   new_size = 2 * bw->max_pos_;
   if (new_size < needed_size) new_size = needed_size;
   if (new_size < 1024) new_size = 1024;
-  new_buf = (uint8_t*)malloc(new_size);
+  new_buf = (uint8_t*)SbMemoryAllocate(new_size);
   if (new_buf == NULL) {
     bw->error_ = 1;
     return 0;
   }
-  memcpy(new_buf, bw->buf_, bw->pos_);
-  free(bw->buf_);
+  SbMemoryCopy(new_buf, bw->buf_, bw->pos_);
+  SbMemoryDeallocate(bw->buf_);
   bw->buf_ = new_buf;
   bw->max_pos_ = new_size;
   return 1;
@@ -58,7 +59,7 @@
 static void kFlush(VP8BitWriter* const bw) {
   const int s = 8 + bw->nb_bits_;
   const int32_t bits = bw->value_ >> s;
-  assert(bw->nb_bits_ >= 0);
+  SB_DCHECK(bw->nb_bits_ >= 0);
   bw->value_ -= bits << s;
   bw->nb_bits_ -= 8;
   if ((bits & 0xff) != 0xff) {
@@ -182,18 +183,18 @@
 
 int VP8BitWriterAppend(VP8BitWriter* const bw,
                        const uint8_t* data, size_t size) {
-  assert(data);
+  SB_DCHECK(data);
   if (bw->nb_bits_ != -8) return 0;   // kFlush() must have been called
   if (!BitWriterResize(bw, size)) return 0;
-  memcpy(bw->buf_ + bw->pos_, data, size);
+  SbMemoryCopy(bw->buf_ + bw->pos_, data, size);
   bw->pos_ += size;
   return 1;
 }
 
 void VP8BitWriterWipeOut(VP8BitWriter* const bw) {
   if (bw) {
-    free(bw->buf_);
-    memset(bw, 0, sizeof(*bw));
+    SbMemoryDeallocate(bw->buf_);
+    SbMemorySet(bw, 0, sizeof(*bw));
   }
 }
 
@@ -216,28 +217,28 @@
   if (allocated_size < size_required) allocated_size = size_required;
   // make allocated size multiple of 1k
   allocated_size = (((allocated_size >> 10) + 1) << 10);
-  allocated_buf = (uint8_t*)malloc(allocated_size);
+  allocated_buf = (uint8_t*)SbMemoryAllocate(allocated_size);
   if (allocated_buf == NULL) {
     bw->error_ = 1;
     return 0;
   }
-  memcpy(allocated_buf, bw->buf_, current_size);
-  free(bw->buf_);
+  SbMemoryCopy(allocated_buf, bw->buf_, current_size);
+  SbMemoryDeallocate(bw->buf_);
   bw->buf_ = allocated_buf;
   bw->max_bytes_ = allocated_size;
-  memset(allocated_buf + current_size, 0, allocated_size - current_size);
+  SbMemorySet(allocated_buf + current_size, 0, allocated_size - current_size);
   return 1;
 }
 
 int VP8LBitWriterInit(VP8LBitWriter* const bw, size_t expected_size) {
-  memset(bw, 0, sizeof(*bw));
+  SbMemorySet(bw, 0, sizeof(*bw));
   return VP8LBitWriterResize(bw, expected_size);
 }
 
 void VP8LBitWriterDestroy(VP8LBitWriter* const bw) {
   if (bw != NULL) {
-    free(bw->buf_);
-    memset(bw, 0, sizeof(*bw));
+    SbMemoryDeallocate(bw->buf_);
+    SbMemorySet(bw, 0, sizeof(*bw));
   }
 }
 
@@ -269,7 +270,7 @@
         bits >>= 8;
       }
     }
-    assert(n_bits <= 25);
+    SB_DCHECK(n_bits <= 25);
     *p = bits;
     bw->bit_pos_ += n_bits;
   }
diff --git a/src/third_party/libwebp/utils/color_cache.c b/src/third_party/libwebp/utils/color_cache.c
index be6ed1f..a9a0d2a 100644
--- a/src/third_party/libwebp/utils/color_cache.c
+++ b/src/third_party/libwebp/utils/color_cache.c
@@ -12,7 +12,8 @@
 // Author: Jyrki Alakuijala (jyrki@google.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -30,8 +31,8 @@
 
 int VP8LColorCacheInit(VP8LColorCache* const cc, int hash_bits) {
   const int hash_size = 1 << hash_bits;
-  assert(cc != NULL);
-  assert(hash_bits > 0);
+  SB_DCHECK(cc != NULL);
+  SB_DCHECK(hash_bits > 0);
   cc->colors_ = (uint32_t*)WebPSafeCalloc((uint64_t)hash_size,
                                           sizeof(*cc->colors_));
   if (cc->colors_ == NULL) return 0;
@@ -41,7 +42,7 @@
 
 void VP8LColorCacheClear(VP8LColorCache* const cc) {
   if (cc != NULL) {
-    free(cc->colors_);
+    SbMemoryDeallocate(cc->colors_);
     cc->colors_ = NULL;
   }
 }
diff --git a/src/third_party/libwebp/utils/color_cache.h b/src/third_party/libwebp/utils/color_cache.h
index e5a0bd6..4876bd4 100644
--- a/src/third_party/libwebp/utils/color_cache.h
+++ b/src/third_party/libwebp/utils/color_cache.h
@@ -17,6 +17,10 @@
 
 #include "../webp/types.h"
 
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#endif
+
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
 #endif
@@ -31,7 +35,7 @@
 
 static WEBP_INLINE uint32_t VP8LColorCacheLookup(
     const VP8LColorCache* const cc, uint32_t key) {
-  assert(key <= (~0U >> cc->hash_shift_));
+  SB_DCHECK(key <= (~0U >> cc->hash_shift_));
   return cc->colors_[key];
 }
 
diff --git a/src/third_party/libwebp/utils/filters.c b/src/third_party/libwebp/utils/filters.c
index eb5bb34..000c6cd 100644
--- a/src/third_party/libwebp/utils/filters.c
+++ b/src/third_party/libwebp/utils/filters.c
@@ -12,9 +12,15 @@
 // Author: Urvang (urvang@google.com)
 
 #include "./filters.h"
+#if defined(STARBOARD)
+#include "starboard/client_porting/poem/stdlib_poem.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
 #include <assert.h>
 #include <stdlib.h>
 #include <string.h>
+#endif
 
 #if defined(__cplusplus) || defined(c_plusplus)
 extern "C" {
@@ -24,11 +30,11 @@
 // Helpful macro.
 
 # define SANITY_CHECK(in, out)                              \
-  assert(in != NULL);                                       \
-  assert(out != NULL);                                      \
-  assert(width > 0);                                        \
-  assert(height > 0);                                       \
-  assert(stride >= width);
+  SB_DCHECK(in != NULL);                                       \
+  SB_DCHECK(out != NULL);                                      \
+  SB_DCHECK(width > 0);                                        \
+  SB_DCHECK(height > 0);                                       \
+  SB_DCHECK(stride >= width);
 
 static WEBP_INLINE void PredictLine(const uint8_t* src, const uint8_t* pred,
                                     uint8_t* dst, int length, int inverse) {
@@ -165,7 +171,7 @@
                                     int width, int height, int stride) {
   int i, j;
   int bins[WEBP_FILTER_LAST][SMAX];
-  memset(bins, 0, sizeof(bins));
+  SbMemorySet(bins, 0, sizeof(bins));
 
   // We only sample every other pixels. That's enough.
   for (j = 2; j < height - 1; j += 2) {
diff --git a/src/third_party/libwebp/utils/huffman.c b/src/third_party/libwebp/utils/huffman.c
index 16a73f7..f6b883f 100644
--- a/src/third_party/libwebp/utils/huffman.c
+++ b/src/third_party/libwebp/utils/huffman.c
@@ -12,7 +12,8 @@
 // Author: Urvang Joshi (urvang@google.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -44,14 +45,14 @@
                            HuffmanTreeNode* const node) {
   HuffmanTreeNode* const children = tree->root_ + tree->num_nodes_;
   node->children_ = (int)(children - node);
-  assert(children - node == (int)(children - node));
+  SB_DCHECK(children - node == (int)(children - node));
   tree->num_nodes_ += 2;
   TreeNodeInit(children + 0);
   TreeNodeInit(children + 1);
 }
 
 static int TreeInit(HuffmanTree* const tree, int num_leaves) {
-  assert(tree != NULL);
+  SB_DCHECK(tree != NULL);
   if (num_leaves == 0) return 0;
   // We allocate maximum possible nodes in the tree at once.
   // Note that a Huffman tree is a full binary tree; and in a full binary tree
@@ -67,7 +68,7 @@
 
 void HuffmanTreeRelease(HuffmanTree* const tree) {
   if (tree != NULL) {
-    free(tree->root_);
+    SbMemoryDeallocate(tree->root_);
     tree->root_ = NULL;
     tree->max_nodes_ = 0;
     tree->num_nodes_ = 0;
@@ -83,9 +84,9 @@
   int next_codes[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
   int max_code_length = 0;
 
-  assert(code_lengths != NULL);
-  assert(code_lengths_size > 0);
-  assert(huff_codes != NULL);
+  SB_DCHECK(code_lengths != NULL);
+  SB_DCHECK(code_lengths_size > 0);
+  SB_DCHECK(huff_codes != NULL);
 
   // Calculate max code length.
   for (symbol = 0; symbol < code_lengths_size; ++symbol) {
@@ -154,8 +155,8 @@
   int num_symbols = 0;
   int root_symbol = 0;
 
-  assert(tree != NULL);
-  assert(code_lengths != NULL);
+  SB_DCHECK(tree != NULL);
+  SB_DCHECK(code_lengths != NULL);
 
   // Find out number of symbols and the root symbol.
   for (symbol = 0; symbol < code_lengths_size; ++symbol) {
@@ -199,7 +200,7 @@
     }
     ok = 1;
  End:
-    free(codes);
+    SbMemoryDeallocate(codes);
     ok = ok && IsFull(tree);
     if (!ok) HuffmanTreeRelease(tree);
     return ok;
@@ -214,10 +215,10 @@
   int ok = 0;
   int i;
 
-  assert(tree != NULL);
-  assert(code_lengths != NULL);
-  assert(codes != NULL);
-  assert(symbols != NULL);
+  SB_DCHECK(tree != NULL);
+  SB_DCHECK(code_lengths != NULL);
+  SB_DCHECK(codes != NULL);
+  SB_DCHECK(symbols != NULL);
 
   // Initialize the tree. Will fail if num_symbols = 0.
   if (!TreeInit(tree, num_symbols)) return 0;
diff --git a/src/third_party/libwebp/utils/huffman.h b/src/third_party/libwebp/utils/huffman.h
index 8629a27..5d59b7d 100644
--- a/src/third_party/libwebp/utils/huffman.h
+++ b/src/third_party/libwebp/utils/huffman.h
@@ -15,7 +15,7 @@
 #define WEBP_UTILS_HUFFMAN_H_
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
 #else
 #include <assert.h>
 #endif
diff --git a/src/third_party/libwebp/utils/huffman_encode.c b/src/third_party/libwebp/utils/huffman_encode.c
index 0d0fe5f..b66dd41 100644
--- a/src/third_party/libwebp/utils/huffman_encode.c
+++ b/src/third_party/libwebp/utils/huffman_encode.c
@@ -12,7 +12,8 @@
 // Entropy encoding (Huffman) for webp lossless.
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <assert.h>
 #include <stdlib.h>
@@ -48,7 +49,7 @@
   }
   // 2) Let's mark all population counts that already can be encoded
   // with an rle code.
-  good_for_rle = (uint8_t*)calloc(length, 1);
+  good_for_rle = (uint8_t*)SbMemoryCalloc(length, 1);
   if (good_for_rle == NULL) {
     return 0;
   }
@@ -124,7 +125,7 @@
       }
     }
   }
-  free(good_for_rle);
+  SbMemoryDeallocate(good_for_rle);
   return 1;
 }
 
@@ -145,7 +146,7 @@
   } else if (t1->total_count_ < t2->total_count_) {
     return 1;
   } else {
-    assert(t1->value_ != t2->value_);
+    SB_DCHECK(t1->value_ != t2->value_);
     return (t1->value_ < t2->value_) ? -1 : 1;
   }
 }
@@ -211,7 +212,7 @@
   // second iteration of this loop.
   // If we actually start running inside this loop a lot, we would perhaps
   // be better off with the Katajainen algorithm.
-  assert(tree_size_orig <= (1 << (tree_depth_limit - 1)));
+  SB_DCHECK(tree_size_orig <= (1 << (tree_depth_limit - 1)));
   for (count_min = 1; ; count_min *= 2) {
     int tree_size = tree_size_orig;
     // We need to pack the Huffman tree in tree_depth_limit bits.
@@ -231,7 +232,7 @@
     }
 
     // Build the Huffman tree.
-    qsort(tree, tree_size, sizeof(*tree), CompareHuffmanTrees);
+    SbSystemSort(tree, tree_size, sizeof(*tree), CompareHuffmanTrees);
 
     if (tree_size > 1) {  // Normal case.
       int tree_pool_size = 0;
@@ -250,7 +251,7 @@
               break;
             }
           }
-          memmove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree));
+          SbMemoryMove(tree + (k + 1), tree + k, (tree_size - k) * sizeof(*tree));
           tree[k].total_count_ = count;
           tree[k].value_ = -1;
 
@@ -277,7 +278,7 @@
       }
     }
   }
-  free(tree);
+  SbMemoryDeallocate(tree);
   return 1;
 }
 
@@ -287,7 +288,7 @@
 static HuffmanTreeToken* CodeRepeatedValues(int repetitions,
                                             HuffmanTreeToken* tokens,
                                             int value, int prev_value) {
-  assert(value <= MAX_ALLOWED_CODE_LENGTH);
+  SB_DCHECK(value <= MAX_ALLOWED_CODE_LENGTH);
   if (value != prev_value) {
     tokens->code = value;
     tokens->extra_bits = 0;
@@ -356,7 +357,7 @@
   const int depth_size = tree->num_symbols;
   int prev_value = 8;  // 8 is the initial value for rle.
   int i = 0;
-  assert(tokens != NULL);
+  SB_DCHECK(tokens != NULL);
   while (i < depth_size) {
     const int value = tree->code_lengths[i];
     int k = i + 1;
@@ -370,7 +371,7 @@
       prev_value = value;
     }
     i += runs;
-    assert(tokens <= ending_token);
+    SB_DCHECK(tokens <= ending_token);
   }
   (void)ending_token;    // suppress 'unused variable' warning
   return (int)(tokens - starting_token);
@@ -404,11 +405,11 @@
   uint32_t next_code[MAX_ALLOWED_CODE_LENGTH + 1];
   int depth_count[MAX_ALLOWED_CODE_LENGTH + 1] = { 0 };
 
-  assert(tree != NULL);
+  SB_DCHECK(tree != NULL);
   len = tree->num_symbols;
   for (i = 0; i < len; ++i) {
     const int code_length = tree->code_lengths[i];
-    assert(code_length <= MAX_ALLOWED_CODE_LENGTH);
+    SB_DCHECK(code_length <= MAX_ALLOWED_CODE_LENGTH);
     ++depth_count[code_length];
   }
   depth_count[0] = 0;  // ignore unused symbol
diff --git a/src/third_party/libwebp/utils/quant_levels.c b/src/third_party/libwebp/utils/quant_levels.c
index 9ac2ad9..2fb610b 100644
--- a/src/third_party/libwebp/utils/quant_levels.c
+++ b/src/third_party/libwebp/utils/quant_levels.c
@@ -13,7 +13,7 @@
 // Author: Skal (pascal.massimino@gmail.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
 #else
 #include <assert.h>
 #endif
@@ -76,8 +76,8 @@
   // Fixed values. Won't be changed.
   q_level[min_s] = 0;
   q_level[max_s] = num_levels - 1;
-  assert(inv_q_level[0] == min_s);
-  assert(inv_q_level[num_levels - 1] == max_s);
+  SB_DCHECK(inv_q_level[0] == min_s);
+  SB_DCHECK(inv_q_level[num_levels - 1] == max_s);
 
   // k-Means iterations.
   for (iter = 0; iter < MAX_ITER; ++iter) {
diff --git a/src/third_party/libwebp/utils/thread.c b/src/third_party/libwebp/utils/thread.c
index b1615d0..55403a8 100644
--- a/src/third_party/libwebp/utils/thread.c
+++ b/src/third_party/libwebp/utils/thread.c
@@ -11,8 +11,13 @@
 //
 // Author: Skal (pascal.massimino@gmail.com)
 
-#include <assert.h>
-#include <string.h>   // for memset()
+
+#if defined(STARBOARD)
+#include "starboard/log.h"
+#include "starboard/memory.h"
+#else
+#include <string.h>   // for SbMemorySet()
+#endif
 #include "./thread.h"
 
 #if defined(__cplusplus) || defined(c_plusplus)
@@ -180,7 +185,7 @@
 //------------------------------------------------------------------------------
 
 void WebPWorkerInit(WebPWorker* const worker) {
-  memset(worker, 0, sizeof(*worker));
+  SbMemorySet(worker, 0, sizeof(*worker));
   worker->status_ = NOT_OK;
 }
 
@@ -188,7 +193,7 @@
 #ifdef WEBP_USE_THREAD
   WebPWorkerChangeState(worker, OK);
 #endif
-  assert(worker->status_ <= OK);
+  SB_DCHECK(worker->status_ <= OK);
   return !worker->had_error;
 }
 
@@ -211,7 +216,7 @@
   } else if (worker->status_ > OK) {
     ok = WebPWorkerSync(worker);
   }
-  assert(!ok || (worker->status_ == OK));
+  SB_DCHECK(!ok || (worker->status_ == OK));
   return ok;
 }
 
@@ -235,7 +240,7 @@
     worker->status_ = NOT_OK;
 #endif
   }
-  assert(worker->status_ == NOT_OK);
+  SB_DCHECK(worker->status_ == NOT_OK);
 }
 
 //------------------------------------------------------------------------------
diff --git a/src/third_party/libwebp/utils/utils.c b/src/third_party/libwebp/utils/utils.c
index ed53fc2..69697c3 100644
--- a/src/third_party/libwebp/utils/utils.c
+++ b/src/third_party/libwebp/utils/utils.c
@@ -12,7 +12,8 @@
 // Author: Skal (pascal.massimino@gmail.com)
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
+#include "starboard/memory.h"
 #else
 #include <stdlib.h>
 #endif
@@ -36,14 +37,14 @@
 
 void* WebPSafeMalloc(uint64_t nmemb, size_t size) {
   if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
-  assert(nmemb * size > 0);
-  return malloc((size_t)(nmemb * size));
+  SB_DCHECK(nmemb * size > 0);
+  return SbMemoryAllocate((size_t)(nmemb * size));
 }
 
 void* WebPSafeCalloc(uint64_t nmemb, size_t size) {
   if (!CheckSizeArgumentsOverflow(nmemb, size)) return NULL;
-  assert(nmemb * size > 0);
-  return calloc((size_t)nmemb, size);
+  SB_DCHECK(nmemb * size > 0);
+  return SbMemoryCalloc((size_t)nmemb, size);
 }
 
 //------------------------------------------------------------------------------
diff --git a/src/third_party/libwebp/utils/utils.h b/src/third_party/libwebp/utils/utils.h
index f249b36..e65c339 100644
--- a/src/third_party/libwebp/utils/utils.h
+++ b/src/third_party/libwebp/utils/utils.h
@@ -16,7 +16,7 @@
 #define WEBP_UTILS_UTILS_H_
 
 #if defined(STARBOARD)
-#include "third_party/libwebp/starboard_private.h"
+#include "starboard/log.h"
 #else
 #include <assert.h>
 #endif
@@ -37,11 +37,11 @@
 // large, or return NULL. You don't need to call these for constructs like
 // malloc(sizeof(foo)), but only if there's picture-dependent size involved
 // somewhere (like: malloc(num_pixels * sizeof(*something))). That's why this
-// safe malloc() borrows the signature from calloc(), pointing at the dangerous
+// safe malloc() borrows the signature from malloc(), pointing at the dangerous
 // underlying multiply involved.
 void* WebPSafeMalloc(uint64_t nmemb, size_t size);
 // Note that WebPSafeCalloc() expects the second argument type to be 'size_t'
-// in order to favor the "calloc(num_foo, sizeof(foo))" pattern.
+// in order to favor the "SbMemoryCalloc(num_foo, sizeof(foo))" pattern.
 void* WebPSafeCalloc(uint64_t nmemb, size_t size);
 
 //------------------------------------------------------------------------------
@@ -62,13 +62,13 @@
 
 // Store 16, 24 or 32 bits in little-endian order.
 static WEBP_INLINE void PutLE16(uint8_t* const data, int val) {
-  assert(val < (1 << 16));
+  SB_DCHECK(val < (1 << 16));
   data[0] = (val >> 0);
   data[1] = (val >> 8);
 }
 
 static WEBP_INLINE void PutLE24(uint8_t* const data, int val) {
-  assert(val < (1 << 24));
+  SB_DCHECK(val < (1 << 24));
   PutLE16(data, val & 0xffff);
   data[2] = (val >> 16);
 }